2006-03-27 04:25:34 +02:00
|
|
|
/* Copyright (c) 2001-2004, Roger Dingledine.
|
2007-12-12 22:09:01 +01:00
|
|
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
2013-01-16 07:54:56 +01:00
|
|
|
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
2006-03-27 04:25:34 +02:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \file policies.c
|
|
|
|
* \brief Code to parse and use address policies and exit policies.
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "or.h"
|
2010-07-22 10:22:51 +02:00
|
|
|
#include "config.h"
|
2010-07-22 12:09:49 +02:00
|
|
|
#include "dirserv.h"
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
#include "nodelist.h"
|
2010-07-23 20:51:25 +02:00
|
|
|
#include "policies.h"
|
2013-08-23 20:06:42 +02:00
|
|
|
#include "router.h"
|
2010-07-23 23:23:43 +02:00
|
|
|
#include "routerparse.h"
|
2012-01-13 18:28:32 +01:00
|
|
|
#include "geoip.h"
|
2008-01-02 05:43:44 +01:00
|
|
|
#include "ht.h"
|
2006-03-27 04:25:34 +02:00
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Policy that addresses for incoming SOCKS connections must match. */
|
2008-01-02 05:43:44 +01:00
|
|
|
static smartlist_t *socks_policy = NULL;
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Policy that addresses for incoming directory connections must match. */
|
2008-01-02 05:43:44 +01:00
|
|
|
static smartlist_t *dir_policy = NULL;
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Policy that addresses for incoming router descriptors must match in order
|
|
|
|
* to be published by us. */
|
2008-01-02 05:43:44 +01:00
|
|
|
static smartlist_t *authdir_reject_policy = NULL;
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Policy that addresses for incoming router descriptors must match in order
|
|
|
|
* to be marked as valid in our networkstatus. */
|
2008-01-02 05:43:44 +01:00
|
|
|
static smartlist_t *authdir_invalid_policy = NULL;
|
2007-12-10 17:49:54 +01:00
|
|
|
/** Policy that addresses for incoming router descriptors must <b>not</b>
|
|
|
|
* match in order to not be marked as BadDirectory. */
|
2008-01-02 05:43:44 +01:00
|
|
|
static smartlist_t *authdir_baddir_policy = NULL;
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Policy that addresses for incoming router descriptors must <b>not</b>
|
|
|
|
* match in order to not be marked as BadExit. */
|
2008-01-02 05:43:44 +01:00
|
|
|
static smartlist_t *authdir_badexit_policy = NULL;
|
2006-03-27 04:25:34 +02:00
|
|
|
|
|
|
|
/** Parsed addr_policy_t describing which addresses we believe we can start
|
|
|
|
* circuits at. */
|
2008-01-02 05:43:44 +01:00
|
|
|
static smartlist_t *reachable_or_addr_policy = NULL;
|
2006-03-27 04:25:34 +02:00
|
|
|
/** Parsed addr_policy_t describing which addresses we believe we can connect
|
|
|
|
* to directories at. */
|
2008-01-02 05:43:44 +01:00
|
|
|
static smartlist_t *reachable_dir_addr_policy = NULL;
|
|
|
|
|
2008-08-13 14:45:28 +02:00
|
|
|
/** Element of an exit policy summary */
|
|
|
|
typedef struct policy_summary_item_t {
|
|
|
|
uint16_t prt_min; /**< Lowest port number to accept/reject. */
|
|
|
|
uint16_t prt_max; /**< Highest port number to accept/reject. */
|
|
|
|
uint64_t reject_count; /**< Number of IP-Addresses that are rejected to
|
2009-05-27 23:55:51 +02:00
|
|
|
this port range. */
|
2011-06-08 21:27:32 +02:00
|
|
|
unsigned int accepted:1; /** Has this port already been accepted */
|
2008-08-13 14:45:28 +02:00
|
|
|
} policy_summary_item_t;
|
|
|
|
|
2008-08-13 14:45:01 +02:00
|
|
|
/** Private networks. This list is used in two places, once to expand the
|
|
|
|
* "private" keyword when parsing our own exit policy, secondly to ignore
|
|
|
|
* just such networks when building exit policy summaries. It is important
|
|
|
|
* that all authorities agree on that list when creating summaries, so don't
|
|
|
|
* just change this without a proper migration plan and a proposal and stuff.
|
|
|
|
*/
|
|
|
|
static const char *private_nets[] = {
|
|
|
|
"0.0.0.0/8", "169.254.0.0/16",
|
|
|
|
"127.0.0.0/8", "192.168.0.0/16", "10.0.0.0/8", "172.16.0.0/12",
|
2012-10-24 21:03:29 +02:00
|
|
|
"[::]/8",
|
|
|
|
"[fc00::]/7", "[fe80::]/10", "[fec0::]/10", "[ff00::]/8", "[::]/127",
|
|
|
|
NULL
|
|
|
|
};
|
2008-08-13 14:45:01 +02:00
|
|
|
|
2008-01-02 05:43:44 +01:00
|
|
|
/** Replace all "private" entries in *<b>policy</b> with their expanded
|
|
|
|
* equivalents. */
|
|
|
|
void
|
|
|
|
policy_expand_private(smartlist_t **policy)
|
|
|
|
{
|
|
|
|
uint16_t port_min, port_max;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
smartlist_t *tmp;
|
|
|
|
|
2008-12-18 17:11:24 +01:00
|
|
|
if (!*policy) /*XXXX disallow NULL policies? */
|
2008-01-02 05:43:44 +01:00
|
|
|
return;
|
|
|
|
|
2012-01-18 21:53:30 +01:00
|
|
|
tmp = smartlist_new();
|
2008-01-02 05:43:44 +01:00
|
|
|
|
2012-07-17 15:33:38 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(*policy, addr_policy_t *, p) {
|
2008-01-02 05:43:44 +01:00
|
|
|
if (! p->is_private) {
|
|
|
|
smartlist_add(tmp, p);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (i = 0; private_nets[i]; ++i) {
|
2011-07-01 17:33:07 +02:00
|
|
|
addr_policy_t newpolicy;
|
|
|
|
memcpy(&newpolicy, p, sizeof(addr_policy_t));
|
|
|
|
newpolicy.is_private = 0;
|
|
|
|
newpolicy.is_canonical = 0;
|
2012-10-24 18:33:18 +02:00
|
|
|
if (tor_addr_parse_mask_ports(private_nets[i], 0,
|
|
|
|
&newpolicy.addr,
|
2011-07-01 17:33:07 +02:00
|
|
|
&newpolicy.maskbits, &port_min, &port_max)<0) {
|
2008-01-02 05:43:44 +01:00
|
|
|
tor_assert(0);
|
|
|
|
}
|
2011-07-01 17:33:07 +02:00
|
|
|
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy));
|
2008-01-02 05:43:44 +01:00
|
|
|
}
|
|
|
|
addr_policy_free(p);
|
2012-07-17 15:33:38 +02:00
|
|
|
} SMARTLIST_FOREACH_END(p);
|
2008-01-02 05:43:44 +01:00
|
|
|
|
|
|
|
smartlist_free(*policy);
|
|
|
|
*policy = tmp;
|
|
|
|
}
|
2006-03-27 04:25:34 +02:00
|
|
|
|
2012-10-24 21:03:29 +02:00
|
|
|
/** Expand each of the AF_UNSPEC elements in *<b>policy</b> (which indicate
|
|
|
|
* protocol-neutral wildcards) into a pair of wildcard elements: one IPv4-
|
|
|
|
* specific and one IPv6-specific. */
|
|
|
|
void
|
|
|
|
policy_expand_unspec(smartlist_t **policy)
|
|
|
|
{
|
|
|
|
smartlist_t *tmp;
|
|
|
|
if (!*policy)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tmp = smartlist_new();
|
|
|
|
SMARTLIST_FOREACH_BEGIN(*policy, addr_policy_t *, p) {
|
|
|
|
sa_family_t family = tor_addr_family(&p->addr);
|
|
|
|
if (family == AF_INET6 || family == AF_INET || p->is_private) {
|
|
|
|
smartlist_add(tmp, p);
|
|
|
|
} else if (family == AF_UNSPEC) {
|
|
|
|
addr_policy_t newpolicy_ipv4;
|
|
|
|
addr_policy_t newpolicy_ipv6;
|
|
|
|
memcpy(&newpolicy_ipv4, p, sizeof(addr_policy_t));
|
|
|
|
memcpy(&newpolicy_ipv6, p, sizeof(addr_policy_t));
|
|
|
|
newpolicy_ipv4.is_canonical = 0;
|
|
|
|
newpolicy_ipv6.is_canonical = 0;
|
|
|
|
if (p->maskbits != 0) {
|
|
|
|
log_warn(LD_BUG, "AF_UNSPEC policy with maskbits==%d", p->maskbits);
|
|
|
|
newpolicy_ipv4.maskbits = 0;
|
|
|
|
newpolicy_ipv6.maskbits = 0;
|
|
|
|
}
|
|
|
|
tor_addr_from_ipv4h(&newpolicy_ipv4.addr, 0);
|
|
|
|
tor_addr_from_ipv6_bytes(&newpolicy_ipv6.addr,
|
|
|
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
|
|
|
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv4));
|
|
|
|
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv6));
|
|
|
|
addr_policy_free(p);
|
|
|
|
} else {
|
|
|
|
log_warn(LD_BUG, "Funny-looking address policy with family %d", family);
|
|
|
|
smartlist_add(tmp, p);
|
|
|
|
}
|
|
|
|
} SMARTLIST_FOREACH_END(p);
|
|
|
|
|
|
|
|
smartlist_free(*policy);
|
|
|
|
*policy = tmp;
|
|
|
|
}
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
/**
|
|
|
|
* Given a linked list of config lines containing "allow" and "deny"
|
|
|
|
* tokens, parse them and append the result to <b>dest</b>. Return -1
|
2008-01-24 02:14:50 +01:00
|
|
|
* if any tokens are malformed (and don't append any), else return 0.
|
2008-09-09 05:48:01 +02:00
|
|
|
*
|
|
|
|
* If <b>assume_action</b> is nonnegative, then insert its action
|
|
|
|
* (ADDR_POLICY_ACCEPT or ADDR_POLICY_REJECT) for items that specify no
|
|
|
|
* action.
|
2006-03-27 04:25:34 +02:00
|
|
|
*/
|
|
|
|
static int
|
2008-01-02 05:43:44 +01:00
|
|
|
parse_addr_policy(config_line_t *cfg, smartlist_t **dest,
|
2006-03-27 04:25:34 +02:00
|
|
|
int assume_action)
|
|
|
|
{
|
2008-01-02 05:43:44 +01:00
|
|
|
smartlist_t *result;
|
2006-03-27 04:25:34 +02:00
|
|
|
smartlist_t *entries;
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_t *item;
|
2006-03-27 04:25:34 +02:00
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
if (!cfg)
|
|
|
|
return 0;
|
|
|
|
|
2012-01-18 21:53:30 +01:00
|
|
|
result = smartlist_new();
|
|
|
|
entries = smartlist_new();
|
2006-03-27 04:25:34 +02:00
|
|
|
for (; cfg; cfg = cfg->next) {
|
|
|
|
smartlist_split_string(entries, cfg->value, ",",
|
|
|
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
2012-07-17 15:33:38 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(entries, const char *, ent) {
|
2006-03-27 04:25:34 +02:00
|
|
|
log_debug(LD_CONFIG,"Adding new entry '%s'",ent);
|
2008-01-02 05:43:44 +01:00
|
|
|
item = router_parse_addr_policy_item_from_string(ent, assume_action);
|
|
|
|
if (item) {
|
|
|
|
smartlist_add(result, item);
|
2006-03-27 04:25:34 +02:00
|
|
|
} else {
|
|
|
|
log_warn(LD_CONFIG,"Malformed policy '%s'.", ent);
|
|
|
|
r = -1;
|
|
|
|
}
|
2012-07-17 15:33:38 +02:00
|
|
|
} SMARTLIST_FOREACH_END(ent);
|
2006-03-27 04:25:34 +02:00
|
|
|
SMARTLIST_FOREACH(entries, char *, ent, tor_free(ent));
|
|
|
|
smartlist_clear(entries);
|
|
|
|
}
|
|
|
|
smartlist_free(entries);
|
2008-01-02 05:43:44 +01:00
|
|
|
if (r == -1) {
|
|
|
|
addr_policy_list_free(result);
|
|
|
|
} else {
|
|
|
|
policy_expand_private(&result);
|
2012-10-24 21:03:29 +02:00
|
|
|
policy_expand_unspec(&result);
|
2008-01-02 05:43:44 +01:00
|
|
|
|
|
|
|
if (*dest) {
|
|
|
|
smartlist_add_all(*dest, result);
|
|
|
|
smartlist_free(result);
|
|
|
|
} else {
|
|
|
|
*dest = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Helper: parse the Reachable(Dir|OR)?Addresses fields into
|
2008-02-05 22:39:32 +01:00
|
|
|
* reachable_(or|dir)_addr_policy. The options should already have
|
|
|
|
* been validated by validate_addr_policies.
|
|
|
|
*/
|
|
|
|
static int
|
2006-03-27 04:25:34 +02:00
|
|
|
parse_reachable_addresses(void)
|
|
|
|
{
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2008-02-05 22:39:32 +01:00
|
|
|
int ret = 0;
|
2006-03-27 04:25:34 +02:00
|
|
|
|
|
|
|
if (options->ReachableDirAddresses &&
|
|
|
|
options->ReachableORAddresses &&
|
|
|
|
options->ReachableAddresses) {
|
|
|
|
log_warn(LD_CONFIG,
|
|
|
|
"Both ReachableDirAddresses and ReachableORAddresses are set. "
|
|
|
|
"ReachableAddresses setting will be ignored.");
|
|
|
|
}
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(reachable_or_addr_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
reachable_or_addr_policy = NULL;
|
|
|
|
if (!options->ReachableORAddresses && options->ReachableAddresses)
|
|
|
|
log_info(LD_CONFIG,
|
|
|
|
"Using ReachableAddresses as ReachableORAddresses.");
|
|
|
|
if (parse_addr_policy(options->ReachableORAddresses ?
|
|
|
|
options->ReachableORAddresses :
|
|
|
|
options->ReachableAddresses,
|
|
|
|
&reachable_or_addr_policy, ADDR_POLICY_ACCEPT)) {
|
|
|
|
log_warn(LD_CONFIG,
|
|
|
|
"Error parsing Reachable%sAddresses entry; ignoring.",
|
|
|
|
options->ReachableORAddresses ? "OR" : "");
|
2008-02-05 22:39:32 +01:00
|
|
|
ret = -1;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(reachable_dir_addr_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
reachable_dir_addr_policy = NULL;
|
|
|
|
if (!options->ReachableDirAddresses && options->ReachableAddresses)
|
|
|
|
log_info(LD_CONFIG,
|
|
|
|
"Using ReachableAddresses as ReachableDirAddresses");
|
|
|
|
if (parse_addr_policy(options->ReachableDirAddresses ?
|
|
|
|
options->ReachableDirAddresses :
|
|
|
|
options->ReachableAddresses,
|
|
|
|
&reachable_dir_addr_policy, ADDR_POLICY_ACCEPT)) {
|
|
|
|
if (options->ReachableDirAddresses)
|
|
|
|
log_warn(LD_CONFIG,
|
|
|
|
"Error parsing ReachableDirAddresses entry; ignoring.");
|
2008-02-05 22:39:32 +01:00
|
|
|
ret = -1;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
2008-02-05 22:39:32 +01:00
|
|
|
return ret;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return true iff the firewall options might block any address:port
|
|
|
|
* combination.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
firewall_is_fascist_or(void)
|
|
|
|
{
|
2006-09-21 23:48:37 +02:00
|
|
|
return reachable_or_addr_policy != NULL;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return true iff <b>policy</b> (possibly NULL) will allow a
|
|
|
|
* connection to <b>addr</b>:<b>port</b>.
|
|
|
|
*/
|
|
|
|
static int
|
2008-08-05 22:08:19 +02:00
|
|
|
addr_policy_permits_tor_addr(const tor_addr_t *addr, uint16_t port,
|
2008-01-02 05:43:44 +01:00
|
|
|
smartlist_t *policy)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
|
|
|
addr_policy_result_t p;
|
2008-08-05 22:08:19 +02:00
|
|
|
p = compare_tor_addr_to_addr_policy(addr, port, policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
switch (p) {
|
|
|
|
case ADDR_POLICY_PROBABLY_ACCEPTED:
|
|
|
|
case ADDR_POLICY_ACCEPTED:
|
|
|
|
return 1;
|
|
|
|
case ADDR_POLICY_PROBABLY_REJECTED:
|
|
|
|
case ADDR_POLICY_REJECTED:
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
log_warn(LD_BUG, "Unexpected result: %d", (int)p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-22 18:53:04 +01:00
|
|
|
/** Return true iff <b> policy</b> (possibly NULL) will allow a connection to
|
|
|
|
* <b>addr</b>:<b>port</b>. <b>addr</b> is an IPv4 address given in host
|
|
|
|
* order. */
|
|
|
|
/* XXXX deprecate when possible. */
|
2008-08-05 22:08:19 +02:00
|
|
|
static int
|
|
|
|
addr_policy_permits_address(uint32_t addr, uint16_t port,
|
|
|
|
smartlist_t *policy)
|
|
|
|
{
|
|
|
|
tor_addr_t a;
|
|
|
|
tor_addr_from_ipv4h(&a, addr);
|
|
|
|
return addr_policy_permits_tor_addr(&a, port, policy);
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:39:37 +01:00
|
|
|
/** Return true iff we think our firewall will let us make an OR connection to
|
|
|
|
* addr:port. */
|
2006-03-27 04:25:34 +02:00
|
|
|
int
|
2008-08-05 22:08:19 +02:00
|
|
|
fascist_firewall_allows_address_or(const tor_addr_t *addr, uint16_t port)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2008-08-05 22:08:19 +02:00
|
|
|
return addr_policy_permits_tor_addr(addr, port,
|
2006-03-27 04:25:34 +02:00
|
|
|
reachable_or_addr_policy);
|
|
|
|
}
|
|
|
|
|
2008-12-22 18:53:04 +01:00
|
|
|
/** Return true iff we think our firewall will let us make an OR connection to
|
|
|
|
* <b>ri</b>. */
|
2008-08-05 22:08:19 +02:00
|
|
|
int
|
2010-09-29 06:38:32 +02:00
|
|
|
fascist_firewall_allows_or(const routerinfo_t *ri)
|
2008-08-05 22:08:19 +02:00
|
|
|
{
|
2008-12-18 17:11:24 +01:00
|
|
|
/* XXXX proposal 118 */
|
2008-08-05 22:08:19 +02:00
|
|
|
tor_addr_t addr;
|
|
|
|
tor_addr_from_ipv4h(&addr, ri->addr);
|
|
|
|
return fascist_firewall_allows_address_or(&addr, ri->or_port);
|
|
|
|
}
|
|
|
|
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
/** Return true iff we think our firewall will let us make an OR connection to
|
|
|
|
* <b>node</b>. */
|
|
|
|
int
|
|
|
|
fascist_firewall_allows_node(const node_t *node)
|
|
|
|
{
|
|
|
|
if (node->ri) {
|
|
|
|
return fascist_firewall_allows_or(node->ri);
|
|
|
|
} else if (node->rs) {
|
|
|
|
tor_addr_t addr;
|
|
|
|
tor_addr_from_ipv4h(&addr, node->rs->addr);
|
|
|
|
return fascist_firewall_allows_address_or(&addr, node->rs->or_port);
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:39:37 +01:00
|
|
|
/** Return true iff we think our firewall will let us make a directory
|
|
|
|
* connection to addr:port. */
|
2006-03-27 04:25:34 +02:00
|
|
|
int
|
2008-08-05 22:08:19 +02:00
|
|
|
fascist_firewall_allows_address_dir(const tor_addr_t *addr, uint16_t port)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2008-08-05 22:08:19 +02:00
|
|
|
return addr_policy_permits_tor_addr(addr, port,
|
|
|
|
reachable_dir_addr_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return 1 if <b>addr</b> is permitted to connect to our dir port,
|
|
|
|
* based on <b>dir_policy</b>. Else return 0.
|
|
|
|
*/
|
|
|
|
int
|
2008-08-05 22:08:19 +02:00
|
|
|
dir_policy_permits_address(const tor_addr_t *addr)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2008-08-05 22:08:19 +02:00
|
|
|
return addr_policy_permits_tor_addr(addr, 1, dir_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return 1 if <b>addr</b> is permitted to connect to our socks port,
|
|
|
|
* based on <b>socks_policy</b>. Else return 0.
|
|
|
|
*/
|
|
|
|
int
|
2008-08-05 22:08:19 +02:00
|
|
|
socks_policy_permits_address(const tor_addr_t *addr)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2008-08-05 22:08:19 +02:00
|
|
|
return addr_policy_permits_tor_addr(addr, 1, socks_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
2012-01-13 18:28:32 +01:00
|
|
|
/** Return true iff the address <b>addr</b> is in a country listed in the
|
2012-01-16 20:45:12 +01:00
|
|
|
* case-insensitive list of country codes <b>cc_list</b>. */
|
2012-01-13 18:28:32 +01:00
|
|
|
static int
|
|
|
|
addr_is_in_cc_list(uint32_t addr, const smartlist_t *cc_list)
|
|
|
|
{
|
|
|
|
country_t country;
|
|
|
|
const char *name;
|
2012-03-01 02:04:45 +01:00
|
|
|
tor_addr_t tar;
|
|
|
|
|
2012-01-13 18:28:32 +01:00
|
|
|
if (!cc_list)
|
|
|
|
return 0;
|
2012-10-19 23:23:04 +02:00
|
|
|
/* XXXXipv6 */
|
2012-03-01 02:04:45 +01:00
|
|
|
tor_addr_from_ipv4h(&tar, addr);
|
|
|
|
country = geoip_get_country_by_addr(&tar);
|
2012-01-13 18:28:32 +01:00
|
|
|
name = geoip_get_country_name(country);
|
2012-04-11 18:50:50 +02:00
|
|
|
return smartlist_contains_string_case(cc_list, name);
|
2012-01-13 18:28:32 +01:00
|
|
|
}
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
/** Return 1 if <b>addr</b>:<b>port</b> is permitted to publish to our
|
|
|
|
* directory, based on <b>authdir_reject_policy</b>. Else return 0.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
authdir_policy_permits_address(uint32_t addr, uint16_t port)
|
|
|
|
{
|
2012-01-13 18:28:32 +01:00
|
|
|
if (! addr_policy_permits_address(addr, port, authdir_reject_policy))
|
|
|
|
return 0;
|
2012-01-17 03:20:46 +01:00
|
|
|
return !addr_is_in_cc_list(addr, get_options()->AuthDirRejectCCs);
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Return 1 if <b>addr</b>:<b>port</b> is considered valid in our
|
|
|
|
* directory, based on <b>authdir_invalid_policy</b>. Else return 0.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
authdir_policy_valid_address(uint32_t addr, uint16_t port)
|
|
|
|
{
|
2012-01-13 18:28:32 +01:00
|
|
|
if (! addr_policy_permits_address(addr, port, authdir_invalid_policy))
|
|
|
|
return 0;
|
2012-01-17 03:20:46 +01:00
|
|
|
return !addr_is_in_cc_list(addr, get_options()->AuthDirInvalidCCs);
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
2007-12-10 17:49:54 +01:00
|
|
|
/** Return 1 if <b>addr</b>:<b>port</b> should be marked as a bad dir,
|
|
|
|
* based on <b>authdir_baddir_policy</b>. Else return 0.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
authdir_policy_baddir_address(uint32_t addr, uint16_t port)
|
|
|
|
{
|
2012-01-13 18:28:32 +01:00
|
|
|
if (! addr_policy_permits_address(addr, port, authdir_baddir_policy))
|
|
|
|
return 1;
|
2012-01-17 03:20:46 +01:00
|
|
|
return addr_is_in_cc_list(addr, get_options()->AuthDirBadDirCCs);
|
2007-12-10 17:49:54 +01:00
|
|
|
}
|
|
|
|
|
2006-10-23 05:48:42 +02:00
|
|
|
/** Return 1 if <b>addr</b>:<b>port</b> should be marked as a bad exit,
|
|
|
|
* based on <b>authdir_badexit_policy</b>. Else return 0.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
authdir_policy_badexit_address(uint32_t addr, uint16_t port)
|
|
|
|
{
|
2012-01-13 18:28:32 +01:00
|
|
|
if (! addr_policy_permits_address(addr, port, authdir_badexit_policy))
|
|
|
|
return 1;
|
2012-01-17 03:20:46 +01:00
|
|
|
return addr_is_in_cc_list(addr, get_options()->AuthDirBadExitCCs);
|
2006-10-23 05:48:42 +02:00
|
|
|
}
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
#define REJECT(arg) \
|
2007-06-17 20:22:39 +02:00
|
|
|
STMT_BEGIN *msg = tor_strdup(arg); goto err; STMT_END
|
2007-02-02 21:06:43 +01:00
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Config helper: If there's any problem with the policy configuration
|
|
|
|
* options in <b>options</b>, return -1 and set <b>msg</b> to a newly
|
|
|
|
* allocated description of the error. Else return 0. */
|
2006-03-27 04:25:34 +02:00
|
|
|
int
|
2011-06-14 19:01:38 +02:00
|
|
|
validate_addr_policies(const or_options_t *options, char **msg)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2008-02-05 22:39:32 +01:00
|
|
|
/* XXXX Maybe merge this into parse_policies_from_options, to make sure
|
|
|
|
* that the two can't go out of sync. */
|
|
|
|
|
2008-01-02 05:43:44 +01:00
|
|
|
smartlist_t *addr_policy=NULL;
|
2006-03-27 04:25:34 +02:00
|
|
|
*msg = NULL;
|
|
|
|
|
|
|
|
if (policies_parse_exit_policy(options->ExitPolicy, &addr_policy,
|
2012-10-25 06:20:41 +02:00
|
|
|
options->IPv6Exit,
|
2013-02-10 03:17:44 +01:00
|
|
|
options->ExitPolicyRejectPrivate, 0,
|
2009-10-27 09:03:41 +01:00
|
|
|
!options->BridgeRelay))
|
2006-03-27 04:25:34 +02:00
|
|
|
REJECT("Error in ExitPolicy entry.");
|
|
|
|
|
|
|
|
/* The rest of these calls *append* to addr_policy. So don't actually
|
|
|
|
* use the results for anything other than checking if they parse! */
|
|
|
|
if (parse_addr_policy(options->DirPolicy, &addr_policy, -1))
|
|
|
|
REJECT("Error in DirPolicy entry.");
|
|
|
|
if (parse_addr_policy(options->SocksPolicy, &addr_policy, -1))
|
|
|
|
REJECT("Error in SocksPolicy entry.");
|
2008-02-05 22:39:32 +01:00
|
|
|
if (parse_addr_policy(options->AuthDirReject, &addr_policy,
|
|
|
|
ADDR_POLICY_REJECT))
|
|
|
|
REJECT("Error in AuthDirReject entry.");
|
|
|
|
if (parse_addr_policy(options->AuthDirInvalid, &addr_policy,
|
|
|
|
ADDR_POLICY_REJECT))
|
|
|
|
REJECT("Error in AuthDirInvalid entry.");
|
|
|
|
if (parse_addr_policy(options->AuthDirBadDir, &addr_policy,
|
|
|
|
ADDR_POLICY_REJECT))
|
|
|
|
REJECT("Error in AuthDirBadDir entry.");
|
|
|
|
if (parse_addr_policy(options->AuthDirBadExit, &addr_policy,
|
|
|
|
ADDR_POLICY_REJECT))
|
|
|
|
REJECT("Error in AuthDirBadExit entry.");
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
if (parse_addr_policy(options->ReachableAddresses, &addr_policy,
|
|
|
|
ADDR_POLICY_ACCEPT))
|
|
|
|
REJECT("Error in ReachableAddresses entry.");
|
|
|
|
if (parse_addr_policy(options->ReachableORAddresses, &addr_policy,
|
|
|
|
ADDR_POLICY_ACCEPT))
|
|
|
|
REJECT("Error in ReachableORAddresses entry.");
|
|
|
|
if (parse_addr_policy(options->ReachableDirAddresses, &addr_policy,
|
|
|
|
ADDR_POLICY_ACCEPT))
|
|
|
|
REJECT("Error in ReachableDirAddresses entry.");
|
|
|
|
|
2010-08-16 00:29:27 +02:00
|
|
|
err:
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(addr_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
return *msg ? -1 : 0;
|
|
|
|
#undef REJECT
|
|
|
|
}
|
|
|
|
|
2007-02-02 21:06:43 +01:00
|
|
|
/** Parse <b>string</b> in the same way that the exit policy
|
2006-03-27 04:25:34 +02:00
|
|
|
* is parsed, and put the processed version in *<b>policy</b>.
|
|
|
|
* Ignore port specifiers.
|
|
|
|
*/
|
2008-02-05 22:39:32 +01:00
|
|
|
static int
|
2014-03-03 16:45:39 +01:00
|
|
|
load_policy_from_option(config_line_t *config, const char *option_name,
|
|
|
|
smartlist_t **policy,
|
2006-03-27 04:25:34 +02:00
|
|
|
int assume_action)
|
|
|
|
{
|
2008-01-14 20:00:23 +01:00
|
|
|
int r;
|
2014-03-03 16:45:39 +01:00
|
|
|
int killed_any_ports = 0;
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(*policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
*policy = NULL;
|
2008-01-14 20:00:23 +01:00
|
|
|
r = parse_addr_policy(config, policy, assume_action);
|
2008-02-05 22:39:32 +01:00
|
|
|
if (r < 0) {
|
|
|
|
return -1;
|
2008-01-24 02:14:50 +01:00
|
|
|
}
|
2008-02-05 22:39:32 +01:00
|
|
|
if (*policy) {
|
2008-09-09 05:48:01 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(*policy, addr_policy_t *, n) {
|
|
|
|
/* ports aren't used in these. */
|
|
|
|
if (n->prt_min > 1 || n->prt_max != 65535) {
|
|
|
|
addr_policy_t newp, *c;
|
|
|
|
memcpy(&newp, n, sizeof(newp));
|
|
|
|
newp.prt_min = 1;
|
|
|
|
newp.prt_max = 65535;
|
2009-06-06 01:41:40 +02:00
|
|
|
newp.is_canonical = 0;
|
2008-09-09 05:48:01 +02:00
|
|
|
c = addr_policy_get_canonical_entry(&newp);
|
|
|
|
SMARTLIST_REPLACE_CURRENT(*policy, n, c);
|
|
|
|
addr_policy_free(n);
|
2014-03-03 16:45:39 +01:00
|
|
|
killed_any_ports = 1;
|
2008-09-09 05:48:01 +02:00
|
|
|
}
|
|
|
|
} SMARTLIST_FOREACH_END(n);
|
2008-02-05 22:39:32 +01:00
|
|
|
}
|
2014-03-03 16:45:39 +01:00
|
|
|
if (killed_any_ports) {
|
|
|
|
log_warn(LD_CONFIG, "Ignoring ports in %s option.", option_name);
|
|
|
|
}
|
2008-02-05 22:39:32 +01:00
|
|
|
return 0;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Set all policies based on <b>options</b>, which should have been validated
|
2008-02-05 22:39:32 +01:00
|
|
|
* first by validate_addr_policies. */
|
|
|
|
int
|
2011-06-14 19:01:38 +02:00
|
|
|
policies_parse_from_options(const or_options_t *options)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2008-02-05 22:39:32 +01:00
|
|
|
int ret = 0;
|
2014-03-03 16:45:39 +01:00
|
|
|
if (load_policy_from_option(options->SocksPolicy, "SocksPolicy",
|
|
|
|
&socks_policy, -1) < 0)
|
2008-02-05 22:39:32 +01:00
|
|
|
ret = -1;
|
2014-03-03 16:45:39 +01:00
|
|
|
if (load_policy_from_option(options->DirPolicy, "DirPolicy",
|
|
|
|
&dir_policy, -1) < 0)
|
2008-02-05 22:39:32 +01:00
|
|
|
ret = -1;
|
2014-03-03 16:45:39 +01:00
|
|
|
if (load_policy_from_option(options->AuthDirReject, "AuthDirReject",
|
2008-02-05 22:39:32 +01:00
|
|
|
&authdir_reject_policy, ADDR_POLICY_REJECT) < 0)
|
|
|
|
ret = -1;
|
2014-03-03 16:45:39 +01:00
|
|
|
if (load_policy_from_option(options->AuthDirInvalid, "AuthDirInvalid",
|
2008-02-05 22:39:32 +01:00
|
|
|
&authdir_invalid_policy, ADDR_POLICY_REJECT) < 0)
|
|
|
|
ret = -1;
|
2014-03-03 16:45:39 +01:00
|
|
|
if (load_policy_from_option(options->AuthDirBadDir, "AuthDirBadDir",
|
2008-02-05 22:39:32 +01:00
|
|
|
&authdir_baddir_policy, ADDR_POLICY_REJECT) < 0)
|
|
|
|
ret = -1;
|
2014-03-03 16:45:39 +01:00
|
|
|
if (load_policy_from_option(options->AuthDirBadExit, "AuthDirBadExit",
|
2008-02-05 22:39:32 +01:00
|
|
|
&authdir_badexit_policy, ADDR_POLICY_REJECT) < 0)
|
|
|
|
ret = -1;
|
|
|
|
if (parse_reachable_addresses() < 0)
|
|
|
|
ret = -1;
|
|
|
|
return ret;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Compare two provided address policy items, and return -1, 0, or 1
|
|
|
|
* if the first is less than, equal to, or greater than the second. */
|
|
|
|
static int
|
|
|
|
cmp_single_addr_policy(addr_policy_t *a, addr_policy_t *b)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
if ((r=((int)a->policy_type - (int)b->policy_type)))
|
|
|
|
return r;
|
2008-01-02 05:43:44 +01:00
|
|
|
if ((r=((int)a->is_private - (int)b->is_private)))
|
|
|
|
return r;
|
2008-07-25 17:11:21 +02:00
|
|
|
if ((r=tor_addr_compare(&a->addr, &b->addr, CMP_EXACT)))
|
2006-03-27 04:25:34 +02:00
|
|
|
return r;
|
2007-07-19 21:40:45 +02:00
|
|
|
if ((r=((int)a->maskbits - (int)b->maskbits)))
|
2006-03-27 04:25:34 +02:00
|
|
|
return r;
|
|
|
|
if ((r=((int)a->prt_min - (int)b->prt_min)))
|
|
|
|
return r;
|
|
|
|
if ((r=((int)a->prt_max - (int)b->prt_max)))
|
|
|
|
return r;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Like cmp_single_addr_policy() above, but looks at the
|
|
|
|
* whole set of policies in each case. */
|
|
|
|
int
|
2008-01-02 05:43:44 +01:00
|
|
|
cmp_addr_policies(smartlist_t *a, smartlist_t *b)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2008-01-02 05:43:44 +01:00
|
|
|
int r, i;
|
|
|
|
int len_a = a ? smartlist_len(a) : 0;
|
|
|
|
int len_b = b ? smartlist_len(b) : 0;
|
|
|
|
|
|
|
|
for (i = 0; i < len_a && i < len_b; ++i) {
|
|
|
|
if ((r = cmp_single_addr_policy(smartlist_get(a, i), smartlist_get(b, i))))
|
2006-03-27 04:25:34 +02:00
|
|
|
return r;
|
|
|
|
}
|
2008-01-02 05:43:44 +01:00
|
|
|
if (i == len_a && i == len_b)
|
2006-03-27 04:25:34 +02:00
|
|
|
return 0;
|
2008-01-02 05:43:44 +01:00
|
|
|
if (i < len_a)
|
2006-03-27 04:25:34 +02:00
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-01-02 05:43:44 +01:00
|
|
|
/** Node in hashtable used to store address policy entries. */
|
|
|
|
typedef struct policy_map_ent_t {
|
|
|
|
HT_ENTRY(policy_map_ent_t) node;
|
|
|
|
addr_policy_t *policy;
|
|
|
|
} policy_map_ent_t;
|
|
|
|
|
2012-06-05 01:51:00 +02:00
|
|
|
/* DOCDOC policy_root */
|
2008-03-27 16:05:28 +01:00
|
|
|
static HT_HEAD(policy_map, policy_map_ent_t) policy_root = HT_INITIALIZER();
|
2008-01-02 05:43:44 +01:00
|
|
|
|
|
|
|
/** Return true iff a and b are equal. */
|
|
|
|
static INLINE int
|
|
|
|
policy_eq(policy_map_ent_t *a, policy_map_ent_t *b)
|
|
|
|
{
|
|
|
|
return cmp_single_addr_policy(a->policy, b->policy) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return a hashcode for <b>ent</b> */
|
|
|
|
static unsigned int
|
2014-02-07 23:38:16 +01:00
|
|
|
policy_hash(const policy_map_ent_t *ent)
|
2008-01-02 05:43:44 +01:00
|
|
|
{
|
2014-02-07 23:38:16 +01:00
|
|
|
const addr_policy_t *a = ent->policy;
|
|
|
|
addr_policy_t aa;
|
|
|
|
memset(&aa, 0, sizeof(aa));
|
|
|
|
|
|
|
|
aa.prt_min = a->prt_min;
|
|
|
|
aa.prt_max = a->prt_max;
|
|
|
|
aa.maskbits = a->maskbits;
|
|
|
|
aa.policy_type = a->policy_type;
|
|
|
|
aa.is_private = a->is_private;
|
|
|
|
|
|
|
|
if (a->is_private) {
|
|
|
|
aa.is_private = 1;
|
|
|
|
} else {
|
|
|
|
tor_addr_copy_tight(&aa.addr, &a->addr);
|
|
|
|
}
|
2008-01-02 05:43:44 +01:00
|
|
|
|
2014-02-07 23:38:16 +01:00
|
|
|
return (unsigned) siphash24g(&aa, sizeof(aa));
|
2008-01-02 05:43:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
HT_PROTOTYPE(policy_map, policy_map_ent_t, node, policy_hash,
|
|
|
|
policy_eq)
|
|
|
|
HT_GENERATE(policy_map, policy_map_ent_t, node, policy_hash,
|
|
|
|
policy_eq, 0.6, malloc, realloc, free)
|
|
|
|
|
|
|
|
/** Given a pointer to an addr_policy_t, return a copy of the pointer to the
|
|
|
|
* "canonical" copy of that addr_policy_t; the canonical copy is a single
|
|
|
|
* reference-counted object. */
|
|
|
|
addr_policy_t *
|
|
|
|
addr_policy_get_canonical_entry(addr_policy_t *e)
|
|
|
|
{
|
|
|
|
policy_map_ent_t search, *found;
|
|
|
|
if (e->is_canonical)
|
|
|
|
return e;
|
|
|
|
|
|
|
|
search.policy = e;
|
|
|
|
found = HT_FIND(policy_map, &policy_root, &search);
|
|
|
|
if (!found) {
|
|
|
|
found = tor_malloc_zero(sizeof(policy_map_ent_t));
|
|
|
|
found->policy = tor_memdup(e, sizeof(addr_policy_t));
|
|
|
|
found->policy->is_canonical = 1;
|
2008-03-26 22:08:39 +01:00
|
|
|
found->policy->refcnt = 0;
|
2008-01-02 05:43:44 +01:00
|
|
|
HT_INSERT(policy_map, &policy_root, found);
|
|
|
|
}
|
|
|
|
|
|
|
|
tor_assert(!cmp_single_addr_policy(found->policy, e));
|
|
|
|
++found->policy->refcnt;
|
|
|
|
return found->policy;
|
|
|
|
}
|
|
|
|
|
2008-12-29 02:47:28 +01:00
|
|
|
/** Helper for compare_tor_addr_to_addr_policy. Implements the case where
|
|
|
|
* addr and port are both known. */
|
|
|
|
static addr_policy_result_t
|
|
|
|
compare_known_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port,
|
|
|
|
const smartlist_t *policy)
|
|
|
|
{
|
|
|
|
/* We know the address and port, and we know the policy, so we can just
|
|
|
|
* compute an exact match. */
|
|
|
|
SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, tmpe) {
|
|
|
|
/* Address is known */
|
|
|
|
if (!tor_addr_compare_masked(addr, &tmpe->addr, tmpe->maskbits,
|
2008-12-29 02:47:33 +01:00
|
|
|
CMP_EXACT)) {
|
2008-12-29 02:47:28 +01:00
|
|
|
if (port >= tmpe->prt_min && port <= tmpe->prt_max) {
|
|
|
|
/* Exact match for the policy */
|
|
|
|
return tmpe->policy_type == ADDR_POLICY_ACCEPT ?
|
|
|
|
ADDR_POLICY_ACCEPTED : ADDR_POLICY_REJECTED;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
2008-12-29 02:47:28 +01:00
|
|
|
}
|
|
|
|
} SMARTLIST_FOREACH_END(tmpe);
|
|
|
|
|
|
|
|
/* accept all by default. */
|
|
|
|
return ADDR_POLICY_ACCEPTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Helper for compare_tor_addr_to_addr_policy. Implements the case where
|
|
|
|
* addr is known but port is not. */
|
|
|
|
static addr_policy_result_t
|
|
|
|
compare_known_tor_addr_to_addr_policy_noport(const tor_addr_t *addr,
|
|
|
|
const smartlist_t *policy)
|
|
|
|
{
|
|
|
|
/* We look to see if there's a definite match. If so, we return that
|
|
|
|
match's value, unless there's an intervening possible match that says
|
|
|
|
something different. */
|
|
|
|
int maybe_accept = 0, maybe_reject = 0;
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, tmpe) {
|
|
|
|
if (!tor_addr_compare_masked(addr, &tmpe->addr, tmpe->maskbits,
|
2008-12-29 02:47:33 +01:00
|
|
|
CMP_EXACT)) {
|
2008-12-29 02:47:28 +01:00
|
|
|
if (tmpe->prt_min <= 1 && tmpe->prt_max >= 65535) {
|
|
|
|
/* Definitely matches, since it covers all ports. */
|
|
|
|
if (tmpe->policy_type == ADDR_POLICY_ACCEPT) {
|
|
|
|
/* If we already hit a clause that might trigger a 'reject', than we
|
|
|
|
* can't be sure of this certain 'accept'.*/
|
|
|
|
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED :
|
|
|
|
ADDR_POLICY_ACCEPTED;
|
|
|
|
} else {
|
|
|
|
return maybe_accept ? ADDR_POLICY_PROBABLY_REJECTED :
|
|
|
|
ADDR_POLICY_REJECTED;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
2008-12-29 02:47:28 +01:00
|
|
|
} else {
|
|
|
|
/* Might match. */
|
|
|
|
if (tmpe->policy_type == ADDR_POLICY_REJECT)
|
|
|
|
maybe_reject = 1;
|
|
|
|
else
|
|
|
|
maybe_accept = 1;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
}
|
2008-12-29 02:47:28 +01:00
|
|
|
} SMARTLIST_FOREACH_END(tmpe);
|
|
|
|
|
|
|
|
/* accept all by default. */
|
|
|
|
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Helper for compare_tor_addr_to_addr_policy. Implements the case where
|
|
|
|
* port is known but address is not. */
|
|
|
|
static addr_policy_result_t
|
|
|
|
compare_unknown_tor_addr_to_addr_policy(uint16_t port,
|
|
|
|
const smartlist_t *policy)
|
|
|
|
{
|
|
|
|
/* We look to see if there's a definite match. If so, we return that
|
|
|
|
match's value, unless there's an intervening possible match that says
|
|
|
|
something different. */
|
|
|
|
int maybe_accept = 0, maybe_reject = 0;
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, tmpe) {
|
|
|
|
if (tmpe->prt_min <= port && port <= tmpe->prt_max) {
|
2012-02-29 19:17:52 +01:00
|
|
|
if (tmpe->maskbits == 0) {
|
2008-12-29 02:47:28 +01:00
|
|
|
/* Definitely matches, since it covers all addresses. */
|
|
|
|
if (tmpe->policy_type == ADDR_POLICY_ACCEPT) {
|
|
|
|
/* If we already hit a clause that might trigger a 'reject', than we
|
|
|
|
* can't be sure of this certain 'accept'.*/
|
|
|
|
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED :
|
|
|
|
ADDR_POLICY_ACCEPTED;
|
|
|
|
} else {
|
|
|
|
return maybe_accept ? ADDR_POLICY_PROBABLY_REJECTED :
|
|
|
|
ADDR_POLICY_REJECTED;
|
|
|
|
}
|
2006-03-27 04:25:34 +02:00
|
|
|
} else {
|
2008-12-29 02:47:28 +01:00
|
|
|
/* Might match. */
|
|
|
|
if (tmpe->policy_type == ADDR_POLICY_REJECT)
|
|
|
|
maybe_reject = 1;
|
|
|
|
else
|
|
|
|
maybe_accept = 1;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
}
|
2008-12-29 02:47:28 +01:00
|
|
|
} SMARTLIST_FOREACH_END(tmpe);
|
2008-01-02 05:43:44 +01:00
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
/* accept all by default. */
|
|
|
|
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED;
|
|
|
|
}
|
|
|
|
|
2008-12-29 02:47:28 +01:00
|
|
|
/** Decide whether a given addr:port is definitely accepted,
|
|
|
|
* definitely rejected, probably accepted, or probably rejected by a
|
|
|
|
* given policy. If <b>addr</b> is 0, we don't know the IP of the
|
|
|
|
* target address. If <b>port</b> is 0, we don't know the port of the
|
|
|
|
* target address. (At least one of <b>addr</b> and <b>port</b> must be
|
|
|
|
* provided. If you want to know whether a policy would definitely reject
|
|
|
|
* an unknown address:port, use policy_is_reject_star().)
|
|
|
|
*
|
|
|
|
* We could do better by assuming that some ranges never match typical
|
|
|
|
* addresses (127.0.0.1, and so on). But we'll try this for now.
|
|
|
|
*/
|
|
|
|
addr_policy_result_t
|
|
|
|
compare_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port,
|
|
|
|
const smartlist_t *policy)
|
|
|
|
{
|
|
|
|
if (!policy) {
|
|
|
|
/* no policy? accept all. */
|
|
|
|
return ADDR_POLICY_ACCEPTED;
|
2011-07-15 18:58:13 +02:00
|
|
|
} else if (addr == NULL || tor_addr_is_null(addr)) {
|
2012-08-27 17:52:51 +02:00
|
|
|
if (port == 0) {
|
|
|
|
log_info(LD_BUG, "Rejecting null address with 0 port (family %d)",
|
|
|
|
addr ? tor_addr_family(addr) : -1);
|
|
|
|
return ADDR_POLICY_REJECTED;
|
|
|
|
}
|
2008-12-29 02:47:28 +01:00
|
|
|
return compare_unknown_tor_addr_to_addr_policy(port, policy);
|
|
|
|
} else if (port == 0) {
|
|
|
|
return compare_known_tor_addr_to_addr_policy_noport(addr, policy);
|
|
|
|
} else {
|
|
|
|
return compare_known_tor_addr_to_addr_policy(addr, port, policy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
/** Return true iff the address policy <b>a</b> covers every case that
|
|
|
|
* would be covered by <b>b</b>, so that a,b is redundant. */
|
|
|
|
static int
|
|
|
|
addr_policy_covers(addr_policy_t *a, addr_policy_t *b)
|
|
|
|
{
|
2012-10-24 21:03:29 +02:00
|
|
|
if (tor_addr_family(&a->addr) != tor_addr_family(&b->addr)) {
|
|
|
|
/* You can't cover a different family. */
|
|
|
|
return 0;
|
|
|
|
}
|
2006-03-27 04:25:34 +02:00
|
|
|
/* We can ignore accept/reject, since "accept *:80, reject *:80" reduces
|
|
|
|
* to "accept *:80". */
|
2007-07-19 21:40:45 +02:00
|
|
|
if (a->maskbits > b->maskbits) {
|
|
|
|
/* a has more fixed bits than b; it can't possibly cover b. */
|
2006-03-27 04:25:34 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2008-12-29 02:47:33 +01:00
|
|
|
if (tor_addr_compare_masked(&a->addr, &b->addr, a->maskbits, CMP_EXACT)) {
|
2006-03-27 04:25:34 +02:00
|
|
|
/* There's a fixed bit in a that's set differently in b. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return (a->prt_min <= b->prt_min && a->prt_max >= b->prt_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return true iff the address policies <b>a</b> and <b>b</b> intersect,
|
|
|
|
* that is, there exists an address/port that is covered by <b>a</b> that
|
|
|
|
* is also covered by <b>b</b>.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
addr_policy_intersects(addr_policy_t *a, addr_policy_t *b)
|
|
|
|
{
|
2007-07-19 21:40:45 +02:00
|
|
|
maskbits_t minbits;
|
2006-03-27 04:25:34 +02:00
|
|
|
/* All the bits we care about are those that are set in both
|
|
|
|
* netmasks. If they are equal in a and b's networkaddresses
|
|
|
|
* then the networks intersect. If there is a difference,
|
|
|
|
* then they do not. */
|
2007-07-19 21:40:45 +02:00
|
|
|
if (a->maskbits < b->maskbits)
|
|
|
|
minbits = a->maskbits;
|
|
|
|
else
|
|
|
|
minbits = b->maskbits;
|
2008-12-29 02:47:33 +01:00
|
|
|
if (tor_addr_compare_masked(&a->addr, &b->addr, minbits, CMP_EXACT))
|
2006-03-27 04:25:34 +02:00
|
|
|
return 0;
|
|
|
|
if (a->prt_max < b->prt_min || b->prt_max < a->prt_min)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Add the exit policy described by <b>more</b> to <b>policy</b>.
|
|
|
|
*/
|
|
|
|
static void
|
2008-01-02 05:43:44 +01:00
|
|
|
append_exit_policy_string(smartlist_t **policy, const char *more)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
|
|
|
config_line_t tmp;
|
|
|
|
|
|
|
|
tmp.key = NULL;
|
|
|
|
tmp.value = (char*) more;
|
|
|
|
tmp.next = NULL;
|
2008-01-14 20:00:23 +01:00
|
|
|
if (parse_addr_policy(&tmp, policy, -1)<0) {
|
|
|
|
log_warn(LD_BUG, "Unable to parse internally generated policy %s",more);
|
|
|
|
}
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
2013-03-12 04:37:47 +01:00
|
|
|
/** Add "reject <b>addr</b>:*" to <b>dest</b>, creating the list as needed. */
|
|
|
|
void
|
|
|
|
addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr)
|
|
|
|
{
|
|
|
|
addr_policy_t p, *add;
|
|
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
p.policy_type = ADDR_POLICY_REJECT;
|
|
|
|
p.maskbits = tor_addr_family(addr) == AF_INET6 ? 128 : 32;
|
|
|
|
tor_addr_copy(&p.addr, addr);
|
|
|
|
p.prt_min = 1;
|
|
|
|
p.prt_max = 65535;
|
|
|
|
|
|
|
|
add = addr_policy_get_canonical_entry(&p);
|
|
|
|
if (!*dest)
|
|
|
|
*dest = smartlist_new();
|
|
|
|
smartlist_add(*dest, add);
|
|
|
|
}
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
/** Detect and excise "dead code" from the policy *<b>dest</b>. */
|
|
|
|
static void
|
2008-01-02 05:43:44 +01:00
|
|
|
exit_policy_remove_redundancies(smartlist_t *dest)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2012-10-24 21:03:29 +02:00
|
|
|
addr_policy_t *ap, *tmp;
|
2008-01-02 05:43:44 +01:00
|
|
|
int i, j;
|
2006-03-27 04:25:34 +02:00
|
|
|
|
2012-10-24 21:03:29 +02:00
|
|
|
/* Step one: kill every ipv4 thing after *4:*, every IPv6 thing after *6:*
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
int kill_v4=0, kill_v6=0;
|
|
|
|
for (i = 0; i < smartlist_len(dest); ++i) {
|
|
|
|
sa_family_t family;
|
|
|
|
ap = smartlist_get(dest, i);
|
|
|
|
family = tor_addr_family(&ap->addr);
|
|
|
|
if ((family == AF_INET && kill_v4) ||
|
|
|
|
(family == AF_INET6 && kill_v6)) {
|
|
|
|
smartlist_del_keeporder(dest, i--);
|
|
|
|
addr_policy_free(ap);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ap->maskbits == 0 && ap->prt_min <= 1 && ap->prt_max >= 65535) {
|
|
|
|
/* This is a catch-all line -- later lines are unreachable. */
|
|
|
|
if (family == AF_INET) {
|
|
|
|
kill_v4 = 1;
|
|
|
|
} else if (family == AF_INET6) {
|
|
|
|
kill_v6 = 1;
|
|
|
|
}
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step two: for every entry, see if there's a redundant entry
|
|
|
|
* later on, and remove it. */
|
2008-01-02 05:43:44 +01:00
|
|
|
for (i = 0; i < smartlist_len(dest)-1; ++i) {
|
|
|
|
ap = smartlist_get(dest, i);
|
|
|
|
for (j = i+1; j < smartlist_len(dest); ++j) {
|
|
|
|
tmp = smartlist_get(dest, j);
|
|
|
|
tor_assert(j > i);
|
|
|
|
if (addr_policy_covers(ap, tmp)) {
|
2007-11-30 21:09:09 +01:00
|
|
|
char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN];
|
2008-07-24 15:44:04 +02:00
|
|
|
policy_write_item(p1, sizeof(p1), tmp, 0);
|
|
|
|
policy_write_item(p2, sizeof(p2), ap, 0);
|
2013-02-01 21:43:37 +01:00
|
|
|
log_debug(LD_CONFIG, "Removing exit policy %s (%d). It is made "
|
2008-01-02 05:43:44 +01:00
|
|
|
"redundant by %s (%d).", p1, j, p2, i);
|
|
|
|
smartlist_del_keeporder(dest, j--);
|
|
|
|
addr_policy_free(tmp);
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step three: for every entry A, see if there's an entry B making this one
|
|
|
|
* redundant later on. This is the case if A and B are of the same type
|
|
|
|
* (accept/reject), A is a subset of B, and there is no other entry of
|
|
|
|
* different type in between those two that intersects with A.
|
|
|
|
*
|
2009-05-27 23:55:51 +02:00
|
|
|
* Anybody want to double-check the logic here? XXX
|
2006-03-27 04:25:34 +02:00
|
|
|
*/
|
2008-01-02 05:43:44 +01:00
|
|
|
for (i = 0; i < smartlist_len(dest)-1; ++i) {
|
|
|
|
ap = smartlist_get(dest, i);
|
|
|
|
for (j = i+1; j < smartlist_len(dest); ++j) {
|
2008-01-12 06:52:59 +01:00
|
|
|
// tor_assert(j > i); // j starts out at i+1; j only increases; i only
|
|
|
|
// // decreases.
|
2008-01-02 05:43:44 +01:00
|
|
|
tmp = smartlist_get(dest, j);
|
2007-05-17 00:16:13 +02:00
|
|
|
if (ap->policy_type != tmp->policy_type) {
|
2008-01-02 05:43:44 +01:00
|
|
|
if (addr_policy_intersects(ap, tmp))
|
2007-05-17 00:16:13 +02:00
|
|
|
break;
|
|
|
|
} else { /* policy_types are equal. */
|
|
|
|
if (addr_policy_covers(tmp, ap)) {
|
2007-11-30 21:09:09 +01:00
|
|
|
char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN];
|
2008-07-24 15:44:04 +02:00
|
|
|
policy_write_item(p1, sizeof(p1), ap, 0);
|
|
|
|
policy_write_item(p2, sizeof(p2), tmp, 0);
|
2013-02-01 21:43:37 +01:00
|
|
|
log_debug(LD_CONFIG, "Removing exit policy %s. It is already "
|
2007-12-01 00:32:25 +01:00
|
|
|
"covered by %s.", p1, p2);
|
2008-01-02 05:43:44 +01:00
|
|
|
smartlist_del_keeporder(dest, i--);
|
|
|
|
addr_policy_free(ap);
|
2007-05-17 00:16:13 +02:00
|
|
|
break;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DEFAULT_EXIT_POLICY \
|
|
|
|
"reject *:25,reject *:119,reject *:135-139,reject *:445," \
|
2008-09-13 12:04:42 +02:00
|
|
|
"reject *:563,reject *:1214,reject *:4661-4666," \
|
2006-03-27 04:25:34 +02:00
|
|
|
"reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*"
|
|
|
|
|
|
|
|
/** Parse the exit policy <b>cfg</b> into the linked list *<b>dest</b>. If
|
2009-10-27 09:03:41 +01:00
|
|
|
* cfg doesn't end in an absolute accept or reject and if
|
|
|
|
* <b>add_default_policy</b> is true, add the default exit
|
2006-03-27 04:25:34 +02:00
|
|
|
* policy afterwards. If <b>rejectprivate</b> is true, prepend
|
|
|
|
* "reject private:*" to the policy. Return -1 if we can't parse cfg,
|
|
|
|
* else return 0.
|
2012-10-24 21:03:29 +02:00
|
|
|
*
|
|
|
|
* This function is used to parse the exit policy from our torrc. For
|
|
|
|
* the functions used to parse the exit policy from a router descriptor,
|
|
|
|
* see router_add_exit_policy.
|
2006-03-27 04:25:34 +02:00
|
|
|
*/
|
|
|
|
int
|
2008-01-02 05:43:44 +01:00
|
|
|
policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
|
2012-10-25 06:20:41 +02:00
|
|
|
int ipv6_exit,
|
2013-02-10 03:17:44 +01:00
|
|
|
int rejectprivate, uint32_t local_address,
|
2009-10-27 09:03:41 +01:00
|
|
|
int add_default_policy)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2012-10-25 06:20:41 +02:00
|
|
|
if (!ipv6_exit) {
|
|
|
|
append_exit_policy_string(dest, "reject *6:*");
|
|
|
|
}
|
2007-11-10 22:17:51 +01:00
|
|
|
if (rejectprivate) {
|
2006-03-27 04:25:34 +02:00
|
|
|
append_exit_policy_string(dest, "reject private:*");
|
2007-11-10 22:17:51 +01:00
|
|
|
if (local_address) {
|
|
|
|
char buf[POLICY_BUF_LEN];
|
2013-02-10 03:17:44 +01:00
|
|
|
tor_snprintf(buf, sizeof(buf), "reject %s:*", fmt_addr32(local_address));
|
2007-11-10 22:17:51 +01:00
|
|
|
append_exit_policy_string(dest, buf);
|
|
|
|
}
|
|
|
|
}
|
2006-03-27 04:25:34 +02:00
|
|
|
if (parse_addr_policy(cfg, dest, -1))
|
|
|
|
return -1;
|
2012-10-24 21:03:29 +02:00
|
|
|
if (add_default_policy) {
|
2009-10-27 09:03:41 +01:00
|
|
|
append_exit_policy_string(dest, DEFAULT_EXIT_POLICY);
|
2012-10-24 21:03:29 +02:00
|
|
|
} else {
|
|
|
|
append_exit_policy_string(dest, "reject *4:*");
|
|
|
|
append_exit_policy_string(dest, "reject *6:*");
|
|
|
|
}
|
2008-01-02 05:43:44 +01:00
|
|
|
exit_policy_remove_redundancies(*dest);
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-02-22 20:06:28 +01:00
|
|
|
/** Add "reject *:*" to the end of the policy in *<b>dest</b>, allocating
|
|
|
|
* *<b>dest</b> as needed. */
|
|
|
|
void
|
|
|
|
policies_exit_policy_append_reject_star(smartlist_t **dest)
|
|
|
|
{
|
2012-10-24 21:03:29 +02:00
|
|
|
append_exit_policy_string(dest, "reject *4:*");
|
|
|
|
append_exit_policy_string(dest, "reject *6:*");
|
2011-02-22 20:06:28 +01:00
|
|
|
}
|
|
|
|
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
/** Replace the exit policy of <b>node</b> with reject *:* */
|
|
|
|
void
|
|
|
|
policies_set_node_exitpolicy_to_reject_all(node_t *node)
|
|
|
|
{
|
2010-10-14 02:30:40 +02:00
|
|
|
node->rejects_all = 1;
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
}
|
2008-01-02 05:43:44 +01:00
|
|
|
|
2010-02-02 14:51:51 +01:00
|
|
|
/** Return 1 if there is at least one /8 subnet in <b>policy</b> that
|
2010-02-03 06:12:31 +01:00
|
|
|
* allows exiting to <b>port</b>. Otherwise, return 0. */
|
2010-02-02 14:51:51 +01:00
|
|
|
static int
|
|
|
|
exit_policy_is_general_exit_helper(smartlist_t *policy, int port)
|
|
|
|
{
|
2010-02-05 16:58:24 +01:00
|
|
|
uint32_t mask, ip, i;
|
2010-02-02 14:51:51 +01:00
|
|
|
/* Is this /8 rejected (1), or undecided (0)? */
|
|
|
|
char subnet_status[256];
|
|
|
|
|
|
|
|
memset(subnet_status, 0, sizeof(subnet_status));
|
2012-07-17 15:33:38 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) {
|
2011-03-06 19:20:21 +01:00
|
|
|
if (tor_addr_family(&p->addr) != AF_INET)
|
|
|
|
continue; /* IPv4 only for now */
|
2010-02-02 14:51:51 +01:00
|
|
|
if (p->prt_min > port || p->prt_max < port)
|
|
|
|
continue; /* Doesn't cover our port. */
|
2010-02-05 16:58:24 +01:00
|
|
|
mask = 0;
|
|
|
|
tor_assert(p->maskbits <= 32);
|
|
|
|
|
|
|
|
if (p->maskbits)
|
|
|
|
mask = UINT32_MAX<<(32-p->maskbits);
|
|
|
|
ip = tor_addr_to_ipv4h(&p->addr);
|
|
|
|
|
|
|
|
/* Calculate the first and last subnet that this exit policy touches
|
|
|
|
* and set it as loop boundaries. */
|
|
|
|
for (i = ((mask & ip)>>24); i <= (~((mask & ip) ^ mask)>>24); ++i) {
|
2010-02-02 14:51:51 +01:00
|
|
|
tor_addr_t addr;
|
2010-02-05 16:58:24 +01:00
|
|
|
if (subnet_status[i] != 0)
|
2010-02-02 14:51:51 +01:00
|
|
|
continue; /* We already reject some part of this /8 */
|
2010-02-05 16:58:24 +01:00
|
|
|
tor_addr_from_ipv4h(&addr, i<<24);
|
2010-02-05 13:40:31 +01:00
|
|
|
if (tor_addr_is_internal(&addr, 0))
|
2010-02-02 14:51:51 +01:00
|
|
|
continue; /* Local or non-routable addresses */
|
2010-02-05 16:58:24 +01:00
|
|
|
if (p->policy_type == ADDR_POLICY_ACCEPT) {
|
|
|
|
if (p->maskbits > 8)
|
|
|
|
continue; /* Narrower than a /8. */
|
|
|
|
/* We found an allowed subnet of at least size /8. Done
|
|
|
|
* for this port! */
|
|
|
|
return 1;
|
|
|
|
} else if (p->policy_type == ADDR_POLICY_REJECT) {
|
|
|
|
subnet_status[i] = 1;
|
2010-02-02 14:51:51 +01:00
|
|
|
}
|
|
|
|
}
|
2012-07-17 15:33:38 +02:00
|
|
|
} SMARTLIST_FOREACH_END(p);
|
2010-02-02 14:51:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
/** Return true iff <b>ri</b> is "useful as an exit node", meaning
|
|
|
|
* it allows exit to at least one /8 address space for at least
|
2006-06-13 04:48:06 +02:00
|
|
|
* two of ports 80, 443, and 6667. */
|
2006-03-27 04:25:34 +02:00
|
|
|
int
|
2008-01-02 05:43:44 +01:00
|
|
|
exit_policy_is_general_exit(smartlist_t *policy)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
|
|
|
static const int ports[] = { 80, 443, 6667 };
|
2006-06-13 04:48:06 +02:00
|
|
|
int n_allowed = 0;
|
2006-03-27 04:25:34 +02:00
|
|
|
int i;
|
2008-12-18 17:11:24 +01:00
|
|
|
if (!policy) /*XXXX disallow NULL policies? */
|
2008-03-17 17:51:48 +01:00
|
|
|
return 0;
|
|
|
|
|
2006-03-27 04:25:34 +02:00
|
|
|
for (i = 0; i < 3; ++i) {
|
2010-02-02 14:51:51 +01:00
|
|
|
n_allowed += exit_policy_is_general_exit_helper(policy, ports[i]);
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
2006-06-13 04:48:06 +02:00
|
|
|
return n_allowed >= 2;
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|
2006-09-21 23:48:42 +02:00
|
|
|
/** Return false if <b>policy</b> might permit access to some addr:port;
|
|
|
|
* otherwise if we are certain it rejects everything, return true. */
|
|
|
|
int
|
2012-11-15 02:51:41 +01:00
|
|
|
policy_is_reject_star(const smartlist_t *policy, sa_family_t family)
|
2006-09-21 23:48:42 +02:00
|
|
|
{
|
2008-12-18 17:11:24 +01:00
|
|
|
if (!policy) /*XXXX disallow NULL policies? */
|
2008-03-17 17:51:48 +01:00
|
|
|
return 1;
|
2012-11-15 02:51:41 +01:00
|
|
|
SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) {
|
|
|
|
if (p->policy_type == ADDR_POLICY_ACCEPT &&
|
|
|
|
(tor_addr_family(&p->addr) == family ||
|
|
|
|
tor_addr_family(&p->addr) == AF_UNSPEC)) {
|
2006-09-21 23:48:42 +02:00
|
|
|
return 0;
|
2012-11-15 02:51:41 +01:00
|
|
|
} else if (p->policy_type == ADDR_POLICY_REJECT &&
|
|
|
|
p->prt_min <= 1 && p->prt_max == 65535 &&
|
|
|
|
p->maskbits == 0 &&
|
|
|
|
(tor_addr_family(&p->addr) == family ||
|
|
|
|
tor_addr_family(&p->addr) == AF_UNSPEC)) {
|
2006-09-21 23:48:42 +02:00
|
|
|
return 1;
|
2012-11-15 02:51:41 +01:00
|
|
|
}
|
|
|
|
} SMARTLIST_FOREACH_END(p);
|
2006-09-21 23:48:42 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-12-29 03:49:12 +01:00
|
|
|
/** Write a single address policy to the buf_len byte buffer at buf. Return
|
|
|
|
* the number of characters written, or -1 on failure. */
|
|
|
|
int
|
2008-07-24 15:44:04 +02:00
|
|
|
policy_write_item(char *buf, size_t buflen, addr_policy_t *policy,
|
|
|
|
int format_for_desc)
|
2006-12-29 03:49:12 +01:00
|
|
|
{
|
|
|
|
size_t written = 0;
|
2008-07-24 15:44:04 +02:00
|
|
|
char addrbuf[TOR_ADDR_BUF_LEN];
|
2008-01-02 05:43:44 +01:00
|
|
|
const char *addrpart;
|
2006-12-29 03:49:12 +01:00
|
|
|
int result;
|
2008-07-24 15:44:04 +02:00
|
|
|
const int is_accept = policy->policy_type == ADDR_POLICY_ACCEPT;
|
2012-10-24 21:03:29 +02:00
|
|
|
const sa_family_t family = tor_addr_family(&policy->addr);
|
|
|
|
const int is_ip6 = (family == AF_INET6);
|
2008-07-24 15:44:04 +02:00
|
|
|
|
2008-08-03 14:43:18 +02:00
|
|
|
tor_addr_to_str(addrbuf, &policy->addr, sizeof(addrbuf), 1);
|
2006-12-29 03:49:12 +01:00
|
|
|
|
|
|
|
/* write accept/reject 1.2.3.4 */
|
2012-10-24 21:03:29 +02:00
|
|
|
if (policy->is_private) {
|
2008-01-02 05:43:44 +01:00
|
|
|
addrpart = "private";
|
2012-10-24 21:03:29 +02:00
|
|
|
} else if (policy->maskbits == 0) {
|
|
|
|
if (format_for_desc)
|
|
|
|
addrpart = "*";
|
|
|
|
else if (family == AF_INET6)
|
|
|
|
addrpart = "*6";
|
|
|
|
else if (family == AF_INET)
|
|
|
|
addrpart = "*4";
|
|
|
|
else
|
|
|
|
addrpart = "*";
|
|
|
|
} else {
|
2008-01-02 05:43:44 +01:00
|
|
|
addrpart = addrbuf;
|
2012-10-24 21:03:29 +02:00
|
|
|
}
|
2008-07-24 15:44:04 +02:00
|
|
|
|
2012-06-28 21:47:07 +02:00
|
|
|
result = tor_snprintf(buf, buflen, "%s%s %s",
|
2008-07-24 15:44:04 +02:00
|
|
|
is_accept ? "accept" : "reject",
|
|
|
|
(is_ip6&&format_for_desc)?"6":"",
|
2008-01-02 05:43:44 +01:00
|
|
|
addrpart);
|
2006-12-29 03:49:12 +01:00
|
|
|
if (result < 0)
|
|
|
|
return -1;
|
|
|
|
written += strlen(buf);
|
2007-07-19 21:40:45 +02:00
|
|
|
/* If the maskbits is 32 we don't need to give it. If the mask is 0,
|
2006-12-29 03:49:12 +01:00
|
|
|
* we already wrote "*". */
|
2007-07-19 21:40:45 +02:00
|
|
|
if (policy->maskbits < 32 && policy->maskbits > 0) {
|
|
|
|
if (tor_snprintf(buf+written, buflen-written, "/%d", policy->maskbits)<0)
|
|
|
|
return -1;
|
2006-12-29 03:49:12 +01:00
|
|
|
written += strlen(buf+written);
|
|
|
|
}
|
|
|
|
if (policy->prt_min <= 1 && policy->prt_max == 65535) {
|
|
|
|
/* There is no port set; write ":*" */
|
|
|
|
if (written+4 > buflen)
|
|
|
|
return -1;
|
|
|
|
strlcat(buf+written, ":*", buflen-written);
|
2006-12-29 17:49:33 +01:00
|
|
|
written += 2;
|
2006-12-29 03:49:12 +01:00
|
|
|
} else if (policy->prt_min == policy->prt_max) {
|
|
|
|
/* There is only one port; write ":80". */
|
|
|
|
result = tor_snprintf(buf+written, buflen-written, ":%d", policy->prt_min);
|
|
|
|
if (result<0)
|
|
|
|
return -1;
|
|
|
|
written += result;
|
|
|
|
} else {
|
|
|
|
/* There is a range of ports; write ":79-80". */
|
|
|
|
result = tor_snprintf(buf+written, buflen-written, ":%d-%d",
|
|
|
|
policy->prt_min, policy->prt_max);
|
|
|
|
if (result<0)
|
|
|
|
return -1;
|
|
|
|
written += result;
|
|
|
|
}
|
|
|
|
if (written < buflen)
|
|
|
|
buf[written] = '\0';
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return (int)written;
|
|
|
|
}
|
|
|
|
|
2008-08-13 14:45:01 +02:00
|
|
|
/** Create a new exit policy summary, initially only with a single
|
|
|
|
* port 1-64k item */
|
2008-08-13 14:45:23 +02:00
|
|
|
/* XXXX This entire thing will do most stuff in O(N^2), or worse. Use an
|
|
|
|
* RB-tree if that turns out to matter. */
|
2008-08-14 13:24:03 +02:00
|
|
|
static smartlist_t *
|
2008-08-13 14:45:01 +02:00
|
|
|
policy_summary_create(void)
|
|
|
|
{
|
|
|
|
smartlist_t *summary;
|
|
|
|
policy_summary_item_t* item;
|
|
|
|
|
|
|
|
item = tor_malloc_zero(sizeof(policy_summary_item_t));
|
|
|
|
item->prt_min = 1;
|
|
|
|
item->prt_max = 65535;
|
|
|
|
item->reject_count = 0;
|
2008-08-13 14:45:09 +02:00
|
|
|
item->accepted = 0;
|
2008-08-13 14:45:01 +02:00
|
|
|
|
2012-01-18 21:53:30 +01:00
|
|
|
summary = smartlist_new();
|
2008-08-13 14:45:01 +02:00
|
|
|
smartlist_add(summary, item);
|
|
|
|
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
2008-08-13 14:45:09 +02:00
|
|
|
/** Split the summary item in <b>item</b> at the port <b>new_starts</b>.
|
|
|
|
* The current item is changed to end at new-starts - 1, the new item
|
|
|
|
* copies reject_count and accepted from the old item,
|
|
|
|
* starts at new_starts and ends at the port where the original item
|
|
|
|
* previously ended.
|
|
|
|
*/
|
2008-08-14 13:24:03 +02:00
|
|
|
static policy_summary_item_t*
|
2008-08-13 14:46:13 +02:00
|
|
|
policy_summary_item_split(policy_summary_item_t* old, uint16_t new_starts)
|
|
|
|
{
|
2008-08-13 14:45:09 +02:00
|
|
|
policy_summary_item_t* new;
|
|
|
|
|
|
|
|
new = tor_malloc_zero(sizeof(policy_summary_item_t));
|
|
|
|
new->prt_min = new_starts;
|
|
|
|
new->prt_max = old->prt_max;
|
|
|
|
new->reject_count = old->reject_count;
|
|
|
|
new->accepted = old->accepted;
|
|
|
|
|
|
|
|
old->prt_max = new_starts-1;
|
|
|
|
|
2008-08-13 14:45:44 +02:00
|
|
|
tor_assert(old->prt_min <= old->prt_max);
|
|
|
|
tor_assert(new->prt_min <= new->prt_max);
|
2008-08-13 14:45:09 +02:00
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
2008-08-13 14:45:15 +02:00
|
|
|
/* XXXX Nick says I'm going to hell for this. If he feels charitably towards
|
|
|
|
* my immortal soul, he can clean it up himself. */
|
2008-08-13 14:45:09 +02:00
|
|
|
#define AT(x) ((policy_summary_item_t*)smartlist_get(summary, x))
|
2008-08-13 14:45:15 +02:00
|
|
|
|
2008-08-13 14:45:09 +02:00
|
|
|
#define REJECT_CUTOFF_COUNT (1<<25)
|
2008-12-22 15:56:28 +01:00
|
|
|
/** Split an exit policy summary so that prt_min and prt_max
|
2008-08-13 14:45:09 +02:00
|
|
|
* fall at exactly the start and end of an item respectively.
|
|
|
|
*/
|
2008-08-14 13:24:03 +02:00
|
|
|
static int
|
2008-08-13 14:45:09 +02:00
|
|
|
policy_summary_split(smartlist_t *summary,
|
|
|
|
uint16_t prt_min, uint16_t prt_max)
|
|
|
|
{
|
|
|
|
int start_at_index;
|
|
|
|
|
|
|
|
int i = 0;
|
2010-10-15 17:21:33 +02:00
|
|
|
|
2008-08-13 14:45:09 +02:00
|
|
|
while (AT(i)->prt_max < prt_min)
|
|
|
|
i++;
|
|
|
|
if (AT(i)->prt_min != prt_min) {
|
|
|
|
policy_summary_item_t* new_item;
|
|
|
|
new_item = policy_summary_item_split(AT(i), prt_min);
|
|
|
|
smartlist_insert(summary, i+1, new_item);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
start_at_index = i;
|
|
|
|
|
2008-08-13 14:46:13 +02:00
|
|
|
while (AT(i)->prt_max < prt_max)
|
2008-08-13 14:45:09 +02:00
|
|
|
i++;
|
|
|
|
if (AT(i)->prt_max != prt_max) {
|
|
|
|
policy_summary_item_t* new_item;
|
|
|
|
new_item = policy_summary_item_split(AT(i), prt_max+1);
|
|
|
|
smartlist_insert(summary, i+1, new_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
return start_at_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Mark port ranges as accepted if they are below the reject_count */
|
2008-08-14 13:24:03 +02:00
|
|
|
static void
|
2008-08-13 14:45:09 +02:00
|
|
|
policy_summary_accept(smartlist_t *summary,
|
2008-08-13 14:45:01 +02:00
|
|
|
uint16_t prt_min, uint16_t prt_max)
|
|
|
|
{
|
2008-08-13 14:45:09 +02:00
|
|
|
int i = policy_summary_split(summary, prt_min, prt_max);
|
2008-08-13 14:45:34 +02:00
|
|
|
while (i < smartlist_len(summary) &&
|
|
|
|
AT(i)->prt_max <= prt_max) {
|
|
|
|
if (!AT(i)->accepted &&
|
|
|
|
AT(i)->reject_count <= REJECT_CUTOFF_COUNT)
|
|
|
|
AT(i)->accepted = 1;
|
2008-08-13 14:45:09 +02:00
|
|
|
i++;
|
|
|
|
}
|
2008-08-13 14:45:34 +02:00
|
|
|
tor_assert(i < smartlist_len(summary) || prt_max==65535);
|
2008-08-13 14:45:01 +02:00
|
|
|
}
|
|
|
|
|
2008-08-13 14:45:09 +02:00
|
|
|
/** Count the number of addresses in a network with prefixlen maskbits
|
|
|
|
* against the given portrange. */
|
2008-08-14 13:24:03 +02:00
|
|
|
static void
|
2008-08-13 14:45:09 +02:00
|
|
|
policy_summary_reject(smartlist_t *summary,
|
|
|
|
maskbits_t maskbits,
|
2008-08-13 14:45:01 +02:00
|
|
|
uint16_t prt_min, uint16_t prt_max)
|
|
|
|
{
|
2008-08-13 14:45:09 +02:00
|
|
|
int i = policy_summary_split(summary, prt_min, prt_max);
|
|
|
|
/* XXX: ipv4 specific */
|
2008-08-13 21:25:18 +02:00
|
|
|
uint64_t count = (U64_LITERAL(1) << (32-maskbits));
|
2008-08-13 14:45:34 +02:00
|
|
|
while (i < smartlist_len(summary) &&
|
|
|
|
AT(i)->prt_max <= prt_max) {
|
2008-08-13 14:45:09 +02:00
|
|
|
AT(i)->reject_count += count;
|
|
|
|
i++;
|
|
|
|
}
|
2008-08-13 14:45:34 +02:00
|
|
|
tor_assert(i < smartlist_len(summary) || prt_max==65535);
|
2008-08-13 14:45:01 +02:00
|
|
|
}
|
|
|
|
|
2008-08-13 14:45:23 +02:00
|
|
|
/** Add a single exit policy item to our summary:
|
|
|
|
* If it is an accept ignore it unless it is for all IP addresses
|
|
|
|
* ("*"), i.e. it's prefixlen/maskbits is 0, else call
|
|
|
|
* policy_summary_accept().
|
|
|
|
* If it's a reject ignore it if it is about one of the private
|
|
|
|
* networks, else call policy_summary_reject().
|
|
|
|
*/
|
2008-08-14 13:24:03 +02:00
|
|
|
static void
|
2008-08-13 14:45:01 +02:00
|
|
|
policy_summary_add_item(smartlist_t *summary, addr_policy_t *p)
|
|
|
|
{
|
|
|
|
if (p->policy_type == ADDR_POLICY_ACCEPT) {
|
2008-08-13 14:45:44 +02:00
|
|
|
if (p->maskbits == 0) {
|
2008-08-13 14:45:01 +02:00
|
|
|
policy_summary_accept(summary, p->prt_min, p->prt_max);
|
|
|
|
}
|
|
|
|
} else if (p->policy_type == ADDR_POLICY_REJECT) {
|
|
|
|
|
|
|
|
int is_private = 0;
|
|
|
|
int i;
|
|
|
|
for (i = 0; private_nets[i]; ++i) {
|
|
|
|
tor_addr_t addr;
|
|
|
|
maskbits_t maskbits;
|
2012-10-24 18:33:18 +02:00
|
|
|
if (tor_addr_parse_mask_ports(private_nets[i], 0, &addr,
|
|
|
|
&maskbits, NULL, NULL)<0) {
|
2008-08-13 14:45:01 +02:00
|
|
|
tor_assert(0);
|
|
|
|
}
|
|
|
|
if (tor_addr_compare(&p->addr, &addr, CMP_EXACT) == 0 &&
|
|
|
|
p->maskbits == maskbits) {
|
|
|
|
is_private = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_private) {
|
2008-08-13 14:45:09 +02:00
|
|
|
policy_summary_reject(summary, p->maskbits, p->prt_min, p->prt_max);
|
2008-08-13 14:45:01 +02:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
tor_assert(0);
|
|
|
|
}
|
|
|
|
|
2008-08-13 14:45:23 +02:00
|
|
|
/** Create a string representing a summary for an exit policy.
|
2009-05-27 23:55:51 +02:00
|
|
|
* The summary will either be an "accept" plus a comma-separated list of port
|
|
|
|
* ranges or a "reject" plus port-ranges, depending on which is shorter.
|
2008-08-13 14:45:53 +02:00
|
|
|
*
|
2008-08-13 14:46:00 +02:00
|
|
|
* If no exits are allowed at all then NULL is returned, if no ports
|
|
|
|
* are blocked instead of "reject " we return "accept 1-65535" (this
|
|
|
|
* is an exception to the shorter-representation-wins rule).
|
2008-08-13 14:45:23 +02:00
|
|
|
*/
|
|
|
|
char *
|
2012-10-24 21:03:29 +02:00
|
|
|
policy_summarize(smartlist_t *policy, sa_family_t family)
|
2008-08-13 14:45:01 +02:00
|
|
|
{
|
|
|
|
smartlist_t *summary = policy_summary_create();
|
2008-08-13 14:45:23 +02:00
|
|
|
smartlist_t *accepts, *rejects;
|
|
|
|
int i, last, start_prt;
|
2012-01-11 20:02:59 +01:00
|
|
|
size_t accepts_len, rejects_len;
|
2008-08-13 14:46:00 +02:00
|
|
|
char *accepts_str = NULL, *rejects_str = NULL, *shorter_str, *result;
|
2008-08-13 14:45:23 +02:00
|
|
|
const char *prefix;
|
|
|
|
|
2008-08-13 14:45:01 +02:00
|
|
|
tor_assert(policy);
|
|
|
|
|
2008-08-13 14:45:23 +02:00
|
|
|
/* Create the summary list */
|
2012-10-24 21:03:29 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) {
|
|
|
|
sa_family_t f = tor_addr_family(&p->addr);
|
|
|
|
if (f != AF_INET && f != AF_INET6) {
|
|
|
|
log_warn(LD_BUG, "Weird family when summarizing address policy");
|
|
|
|
}
|
|
|
|
if (f != family)
|
|
|
|
continue;
|
|
|
|
/* XXXX-ipv6 More family work is needed */
|
2008-08-13 14:45:01 +02:00
|
|
|
policy_summary_add_item(summary, p);
|
2012-10-24 21:03:29 +02:00
|
|
|
} SMARTLIST_FOREACH_END(p);
|
2008-08-13 14:45:01 +02:00
|
|
|
|
2008-08-13 14:45:23 +02:00
|
|
|
/* Now create two lists of strings, one for accepted and one
|
|
|
|
* for rejected ports. We take care to merge ranges so that
|
|
|
|
* we avoid getting stuff like "1-4,5-9,10", instead we want
|
|
|
|
* "1-10"
|
|
|
|
*/
|
|
|
|
i = 0;
|
|
|
|
start_prt = 1;
|
2012-01-18 21:53:30 +01:00
|
|
|
accepts = smartlist_new();
|
|
|
|
rejects = smartlist_new();
|
2008-08-13 14:45:23 +02:00
|
|
|
while (1) {
|
|
|
|
last = i == smartlist_len(summary)-1;
|
|
|
|
if (last ||
|
|
|
|
AT(i)->accepted != AT(i+1)->accepted) {
|
|
|
|
char buf[POLICY_BUF_LEN];
|
|
|
|
|
|
|
|
if (start_prt == AT(i)->prt_max)
|
|
|
|
tor_snprintf(buf, sizeof(buf), "%d", start_prt);
|
|
|
|
else
|
|
|
|
tor_snprintf(buf, sizeof(buf), "%d-%d", start_prt, AT(i)->prt_max);
|
|
|
|
|
|
|
|
if (AT(i)->accepted)
|
|
|
|
smartlist_add(accepts, tor_strdup(buf));
|
|
|
|
else
|
|
|
|
smartlist_add(rejects, tor_strdup(buf));
|
|
|
|
|
|
|
|
if (last)
|
|
|
|
break;
|
|
|
|
|
|
|
|
start_prt = AT(i+1)->prt_min;
|
|
|
|
};
|
|
|
|
i++;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Figure out which of the two stringlists will be shorter and use
|
|
|
|
* that to build the result
|
|
|
|
*/
|
2008-08-13 14:46:00 +02:00
|
|
|
if (smartlist_len(accepts) == 0) { /* no exits at all */
|
2008-08-14 14:37:50 +02:00
|
|
|
result = tor_strdup("reject 1-65535");
|
2008-08-13 14:46:00 +02:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (smartlist_len(rejects) == 0) { /* no rejects at all */
|
|
|
|
result = tor_strdup("accept 1-65535");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-08-13 14:45:53 +02:00
|
|
|
|
2008-08-13 14:45:23 +02:00
|
|
|
accepts_str = smartlist_join_strings(accepts, ",", 0, &accepts_len);
|
|
|
|
rejects_str = smartlist_join_strings(rejects, ",", 0, &rejects_len);
|
|
|
|
|
2011-01-20 20:17:57 +01:00
|
|
|
if (rejects_len > MAX_EXITPOLICY_SUMMARY_LEN-strlen("reject")-1 &&
|
|
|
|
accepts_len > MAX_EXITPOLICY_SUMMARY_LEN-strlen("accept")-1) {
|
2008-08-13 21:25:18 +02:00
|
|
|
char *c;
|
|
|
|
shorter_str = accepts_str;
|
|
|
|
prefix = "accept";
|
|
|
|
|
|
|
|
c = shorter_str + (MAX_EXITPOLICY_SUMMARY_LEN-strlen(prefix)-1);
|
|
|
|
while (*c != ',' && c >= shorter_str)
|
|
|
|
c--;
|
|
|
|
tor_assert(c >= shorter_str);
|
|
|
|
tor_assert(*c == ',');
|
|
|
|
*c = '\0';
|
|
|
|
|
|
|
|
} else if (rejects_len < accepts_len) {
|
2008-08-13 14:45:23 +02:00
|
|
|
shorter_str = rejects_str;
|
|
|
|
prefix = "reject";
|
|
|
|
} else {
|
|
|
|
shorter_str = accepts_str;
|
|
|
|
prefix = "accept";
|
|
|
|
}
|
|
|
|
|
2012-01-11 20:02:59 +01:00
|
|
|
tor_asprintf(&result, "%s %s", prefix, shorter_str);
|
2008-08-13 14:45:23 +02:00
|
|
|
|
2010-08-16 00:29:27 +02:00
|
|
|
cleanup:
|
2008-08-13 14:45:23 +02:00
|
|
|
/* cleanup */
|
|
|
|
SMARTLIST_FOREACH(summary, policy_summary_item_t *, s, tor_free(s));
|
2008-09-05 22:52:15 +02:00
|
|
|
smartlist_free(summary);
|
2008-08-13 14:45:23 +02:00
|
|
|
|
|
|
|
tor_free(accepts_str);
|
|
|
|
SMARTLIST_FOREACH(accepts, char *, s, tor_free(s));
|
2008-09-05 22:52:15 +02:00
|
|
|
smartlist_free(accepts);
|
2008-08-13 14:45:23 +02:00
|
|
|
|
|
|
|
tor_free(rejects_str);
|
|
|
|
SMARTLIST_FOREACH(rejects, char *, s, tor_free(s));
|
2008-09-05 22:52:15 +02:00
|
|
|
smartlist_free(rejects);
|
2008-08-13 14:45:23 +02:00
|
|
|
|
|
|
|
return result;
|
2008-08-13 14:45:01 +02:00
|
|
|
}
|
|
|
|
|
2010-10-07 23:10:06 +02:00
|
|
|
/** Convert a summarized policy string into a short_policy_t. Return NULL
|
|
|
|
* if the string is not well-formed. */
|
2010-10-02 00:12:30 +02:00
|
|
|
short_policy_t *
|
|
|
|
parse_short_policy(const char *summary)
|
|
|
|
{
|
|
|
|
const char *orig_summary = summary;
|
|
|
|
short_policy_t *result;
|
|
|
|
int is_accept;
|
|
|
|
int n_entries;
|
|
|
|
short_policy_entry_t entries[MAX_EXITPOLICY_SUMMARY_LEN]; /* overkill */
|
|
|
|
const char *next;
|
|
|
|
|
|
|
|
if (!strcmpstart(summary, "accept ")) {
|
|
|
|
is_accept = 1;
|
|
|
|
summary += strlen("accept ");
|
|
|
|
} else if (!strcmpstart(summary, "reject ")) {
|
|
|
|
is_accept = 0;
|
|
|
|
summary += strlen("reject ");
|
|
|
|
} else {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Unrecognized policy summary keyword");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
n_entries = 0;
|
|
|
|
for ( ; *summary; summary = next) {
|
|
|
|
const char *comma = strchr(summary, ',');
|
|
|
|
unsigned low, high;
|
|
|
|
char dummy;
|
|
|
|
char ent_buf[32];
|
2012-10-22 23:34:05 +02:00
|
|
|
size_t len;
|
2010-10-02 00:12:30 +02:00
|
|
|
|
|
|
|
next = comma ? comma+1 : strchr(summary, '\0');
|
2012-10-22 23:34:05 +02:00
|
|
|
len = comma ? (size_t)(comma - summary) : strlen(summary);
|
2010-10-02 00:12:30 +02:00
|
|
|
|
|
|
|
if (n_entries == MAX_EXITPOLICY_SUMMARY_LEN) {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Impossibly long policy summary %s",
|
|
|
|
escaped(orig_summary));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-10-22 23:34:05 +02:00
|
|
|
if (! TOR_ISDIGIT(*summary) || len > (sizeof(ent_buf)-1)) {
|
2010-10-02 00:12:30 +02:00
|
|
|
/* unrecognized entry format. skip it. */
|
|
|
|
continue;
|
|
|
|
}
|
2012-10-22 23:34:05 +02:00
|
|
|
if (len < 1) {
|
2010-10-02 00:12:30 +02:00
|
|
|
/* empty; skip it. */
|
2012-10-22 23:34:05 +02:00
|
|
|
/* XXX This happens to be unreachable, since if len==0, then *summary is
|
|
|
|
* ',' or '\0', and the TOR_ISDIGIT test above would have failed. */
|
2010-10-02 00:12:30 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-10-22 23:34:05 +02:00
|
|
|
memcpy(ent_buf, summary, len);
|
|
|
|
ent_buf[len] = '\0';
|
2010-10-02 00:12:30 +02:00
|
|
|
|
|
|
|
if (tor_sscanf(ent_buf, "%u-%u%c", &low, &high, &dummy) == 2) {
|
2012-10-22 23:34:05 +02:00
|
|
|
if (low<1 || low>65535 || high<1 || high>65535 || low>high) {
|
2010-10-14 17:54:45 +02:00
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_DIR,
|
|
|
|
"Found bad entry in policy summary %s", escaped(orig_summary));
|
2010-10-02 00:12:30 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else if (tor_sscanf(ent_buf, "%u%c", &low, &dummy) == 1) {
|
|
|
|
if (low<1 || low>65535) {
|
2010-10-14 17:54:45 +02:00
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_DIR,
|
|
|
|
"Found bad entry in policy summary %s", escaped(orig_summary));
|
2010-10-02 00:12:30 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
high = low;
|
|
|
|
} else {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_DIR,"Found bad entry in policy summary %s",
|
|
|
|
escaped(orig_summary));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
entries[n_entries].min_port = low;
|
|
|
|
entries[n_entries].max_port = high;
|
|
|
|
n_entries++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n_entries == 0) {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_DIR,
|
|
|
|
"Found no port-range entries in summary %s", escaped(orig_summary));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2011-01-06 21:59:05 +01:00
|
|
|
size_t size = STRUCT_OFFSET(short_policy_t, entries) +
|
|
|
|
sizeof(short_policy_entry_t)*(n_entries);
|
2010-10-02 00:12:30 +02:00
|
|
|
result = tor_malloc_zero(size);
|
|
|
|
|
|
|
|
tor_assert( (char*)&result->entries[n_entries-1] < ((char*)result)+size);
|
|
|
|
}
|
|
|
|
|
|
|
|
result->is_accept = is_accept;
|
|
|
|
result->n_entries = n_entries;
|
|
|
|
memcpy(result->entries, entries, sizeof(short_policy_entry_t)*n_entries);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-10-22 23:09:43 +02:00
|
|
|
/** Write <b>policy</b> back out into a string. Used only for unit tests
|
|
|
|
* currently. */
|
2012-10-22 23:34:05 +02:00
|
|
|
char *
|
2012-10-22 23:09:43 +02:00
|
|
|
write_short_policy(const short_policy_t *policy)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *answer;
|
|
|
|
smartlist_t *sl = smartlist_new();
|
|
|
|
|
|
|
|
smartlist_add_asprintf(sl, "%s", policy->is_accept ? "accept " : "reject ");
|
|
|
|
|
2012-10-22 23:34:05 +02:00
|
|
|
for (i=0; i < policy->n_entries; i++) {
|
2012-10-22 23:09:43 +02:00
|
|
|
const short_policy_entry_t *e = &policy->entries[i];
|
|
|
|
if (e->min_port == e->max_port) {
|
|
|
|
smartlist_add_asprintf(sl, "%d", e->min_port);
|
|
|
|
} else {
|
|
|
|
smartlist_add_asprintf(sl, "%d-%d", e->min_port, e->max_port);
|
|
|
|
}
|
|
|
|
if (i < policy->n_entries-1)
|
|
|
|
smartlist_add(sl, tor_strdup(","));
|
|
|
|
}
|
|
|
|
answer = smartlist_join_strings(sl, "", 0, NULL);
|
|
|
|
SMARTLIST_FOREACH(sl, char *, a, tor_free(a));
|
|
|
|
smartlist_free(sl);
|
|
|
|
return answer;
|
|
|
|
}
|
|
|
|
|
2010-10-07 23:10:06 +02:00
|
|
|
/** Release all storage held in <b>policy</b>. */
|
2010-10-02 00:12:30 +02:00
|
|
|
void
|
|
|
|
short_policy_free(short_policy_t *policy)
|
|
|
|
{
|
|
|
|
tor_free(policy);
|
|
|
|
}
|
|
|
|
|
2010-10-07 23:10:06 +02:00
|
|
|
/** See whether the <b>addr</b>:<b>port</b> address is likely to be accepted
|
|
|
|
* or rejected by the summarized policy <b>policy</b>. Return values are as
|
|
|
|
* for compare_tor_addr_to_addr_policy. Unlike the regular addr_policy
|
|
|
|
* functions, requires the <b>port</b> be specified. */
|
2010-10-02 00:12:30 +02:00
|
|
|
addr_policy_result_t
|
|
|
|
compare_tor_addr_to_short_policy(const tor_addr_t *addr, uint16_t port,
|
|
|
|
const short_policy_t *policy)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int found_match = 0;
|
|
|
|
int accept;
|
|
|
|
|
|
|
|
tor_assert(port != 0);
|
|
|
|
|
2011-07-15 18:44:51 +02:00
|
|
|
if (addr && tor_addr_is_null(addr))
|
|
|
|
addr = NULL; /* Unspec means 'no address at all,' in this context. */
|
|
|
|
|
2012-10-22 21:45:39 +02:00
|
|
|
if (addr && get_options()->ClientRejectInternalAddresses &&
|
|
|
|
(tor_addr_is_internal(addr, 0) || tor_addr_is_loopback(addr)))
|
2010-10-02 00:12:30 +02:00
|
|
|
return ADDR_POLICY_REJECTED;
|
|
|
|
|
|
|
|
for (i=0; i < policy->n_entries; ++i) {
|
|
|
|
const short_policy_entry_t *e = &policy->entries[i];
|
|
|
|
if (e->min_port <= port && port <= e->max_port) {
|
|
|
|
found_match = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found_match)
|
|
|
|
accept = policy->is_accept;
|
|
|
|
else
|
|
|
|
accept = ! policy->is_accept;
|
|
|
|
|
2012-02-17 20:02:25 +01:00
|
|
|
/* ???? are these right? -NM */
|
|
|
|
/* We should be sure not to return ADDR_POLICY_ACCEPTED in the accept
|
|
|
|
* case here, because it would cause clients to believe that the node
|
|
|
|
* allows exit enclaving. Trying it anyway would open up a cool attack
|
|
|
|
* where the node refuses due to exitpolicy, the client reacts in
|
|
|
|
* surprise by rewriting the node's exitpolicy to reject *:*, and then
|
|
|
|
* a bad guy targets users by causing them to attempt such connections
|
|
|
|
* to 98% of the exits.
|
|
|
|
*
|
|
|
|
* Once microdescriptors can handle addresses in special cases (e.g. if
|
|
|
|
* we ever solve ticket 1774), we can provide certainty here. -RD */
|
2010-10-02 00:12:30 +02:00
|
|
|
if (accept)
|
|
|
|
return ADDR_POLICY_PROBABLY_ACCEPTED;
|
|
|
|
else
|
|
|
|
return ADDR_POLICY_REJECTED;
|
|
|
|
}
|
|
|
|
|
2010-10-07 23:10:06 +02:00
|
|
|
/** Return true iff <b>policy</b> seems reject all ports */
|
2010-10-02 00:12:30 +02:00
|
|
|
int
|
|
|
|
short_policy_is_reject_star(const short_policy_t *policy)
|
|
|
|
{
|
|
|
|
/* This doesn't need to be as much on the lookout as policy_is_reject_star,
|
2010-10-14 17:54:45 +02:00
|
|
|
* since policy summaries are from the consensus or from consensus
|
|
|
|
* microdescs.
|
2010-10-02 00:12:30 +02:00
|
|
|
*/
|
|
|
|
tor_assert(policy);
|
|
|
|
/* Check for an exact match of "reject 1-65535". */
|
|
|
|
return (policy->is_accept == 0 && policy->n_entries == 1 &&
|
|
|
|
policy->entries[0].min_port == 1 &&
|
|
|
|
policy->entries[0].max_port == 65535);
|
|
|
|
}
|
|
|
|
|
2012-12-03 19:33:43 +01:00
|
|
|
/** Decide whether addr:port is probably or definitely accepted or rejected by
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
* <b>node</b>. See compare_tor_addr_to_addr_policy for details on addr/port
|
|
|
|
* interpretation. */
|
|
|
|
addr_policy_result_t
|
|
|
|
compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port,
|
|
|
|
const node_t *node)
|
|
|
|
{
|
2010-10-14 02:30:40 +02:00
|
|
|
if (node->rejects_all)
|
|
|
|
return ADDR_POLICY_REJECTED;
|
|
|
|
|
2012-10-25 05:05:44 +02:00
|
|
|
if (addr && tor_addr_family(addr) == AF_INET6) {
|
|
|
|
const short_policy_t *p = NULL;
|
|
|
|
if (node->ri)
|
|
|
|
p = node->ri->ipv6_exit_policy;
|
|
|
|
else if (node->md)
|
|
|
|
p = node->md->ipv6_exit_policy;
|
|
|
|
if (p)
|
|
|
|
return compare_tor_addr_to_short_policy(addr, port, p);
|
|
|
|
else
|
|
|
|
return ADDR_POLICY_REJECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->ri) {
|
2010-10-02 00:12:30 +02:00
|
|
|
return compare_tor_addr_to_addr_policy(addr, port, node->ri->exit_policy);
|
2012-10-25 05:05:44 +02:00
|
|
|
} else if (node->md) {
|
2010-10-02 00:12:30 +02:00
|
|
|
if (node->md->exit_policy == NULL)
|
|
|
|
return ADDR_POLICY_REJECTED;
|
|
|
|
else
|
|
|
|
return compare_tor_addr_to_short_policy(addr, port,
|
|
|
|
node->md->exit_policy);
|
2012-10-25 05:05:44 +02:00
|
|
|
} else {
|
2010-10-02 00:12:30 +02:00
|
|
|
return ADDR_POLICY_PROBABLY_REJECTED;
|
2012-10-25 05:05:44 +02:00
|
|
|
}
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Implementation for GETINFO control command: knows the answer for questions
|
|
|
|
* about "exit-policy/..." */
|
2006-06-13 11:16:09 +02:00
|
|
|
int
|
2006-12-08 05:39:13 +01:00
|
|
|
getinfo_helper_policies(control_connection_t *conn,
|
2010-07-18 17:05:58 +02:00
|
|
|
const char *question, char **answer,
|
|
|
|
const char **errmsg)
|
2006-06-13 11:16:09 +02:00
|
|
|
{
|
2006-12-08 05:39:13 +01:00
|
|
|
(void) conn;
|
2010-07-18 17:05:58 +02:00
|
|
|
(void) errmsg;
|
2006-06-13 11:16:09 +02:00
|
|
|
if (!strcmp(question, "exit-policy/default")) {
|
|
|
|
*answer = tor_strdup(DEFAULT_EXIT_POLICY);
|
2013-08-23 20:06:42 +02:00
|
|
|
} else if (!strcmpstart(question, "exit-policy/")) {
|
|
|
|
const routerinfo_t *me = router_get_my_routerinfo();
|
|
|
|
|
|
|
|
int include_ipv4 = 0;
|
|
|
|
int include_ipv6 = 0;
|
|
|
|
|
|
|
|
if (!strcmp(question, "exit-policy/ipv4")) {
|
|
|
|
include_ipv4 = 1;
|
|
|
|
} else if (!strcmp(question, "exit-policy/ipv6")) {
|
|
|
|
include_ipv6 = 1;
|
|
|
|
} else if (!strcmp(question, "exit-policy/full")) {
|
|
|
|
include_ipv4 = include_ipv6 = 1;
|
|
|
|
} else {
|
|
|
|
return 0; /* No such key. */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!me) {
|
|
|
|
*errmsg = "router_get_my_routerinfo returned NULL";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*answer = router_dump_exit_policy_to_string(me,include_ipv4,include_ipv6);
|
2006-06-13 11:16:09 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-05-25 21:41:31 +02:00
|
|
|
/** Release all storage held by <b>p</b>. */
|
2006-03-27 04:25:34 +02:00
|
|
|
void
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(smartlist_t *lst)
|
2006-03-27 04:25:34 +02:00
|
|
|
{
|
2009-09-28 16:37:01 +02:00
|
|
|
if (!lst)
|
|
|
|
return;
|
2008-01-02 05:43:44 +01:00
|
|
|
SMARTLIST_FOREACH(lst, addr_policy_t *, policy, addr_policy_free(policy));
|
|
|
|
smartlist_free(lst);
|
|
|
|
}
|
2006-03-27 04:25:34 +02:00
|
|
|
|
2008-01-02 05:43:44 +01:00
|
|
|
/** Release all storage held by <b>p</b>. */
|
|
|
|
void
|
|
|
|
addr_policy_free(addr_policy_t *p)
|
|
|
|
{
|
2009-09-28 16:37:01 +02:00
|
|
|
if (!p)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (--p->refcnt <= 0) {
|
|
|
|
if (p->is_canonical) {
|
|
|
|
policy_map_ent_t search, *found;
|
|
|
|
search.policy = p;
|
|
|
|
found = HT_REMOVE(policy_map, &policy_root, &search);
|
|
|
|
if (found) {
|
|
|
|
tor_assert(p == found->policy);
|
|
|
|
tor_free(found);
|
2008-01-02 05:43:44 +01:00
|
|
|
}
|
|
|
|
}
|
2009-09-28 16:37:01 +02:00
|
|
|
tor_free(p);
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-16 21:01:02 +01:00
|
|
|
/** Release all storage held by policy variables. */
|
2006-03-27 04:25:34 +02:00
|
|
|
void
|
|
|
|
policies_free_all(void)
|
|
|
|
{
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(reachable_or_addr_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
reachable_or_addr_policy = NULL;
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(reachable_dir_addr_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
reachable_dir_addr_policy = NULL;
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(socks_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
socks_policy = NULL;
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(dir_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
dir_policy = NULL;
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(authdir_reject_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
authdir_reject_policy = NULL;
|
2008-01-02 05:43:44 +01:00
|
|
|
addr_policy_list_free(authdir_invalid_policy);
|
2006-03-27 04:25:34 +02:00
|
|
|
authdir_invalid_policy = NULL;
|
2008-04-23 22:47:53 +02:00
|
|
|
addr_policy_list_free(authdir_baddir_policy);
|
|
|
|
authdir_baddir_policy = NULL;
|
|
|
|
addr_policy_list_free(authdir_badexit_policy);
|
|
|
|
authdir_badexit_policy = NULL;
|
2008-03-27 16:05:28 +01:00
|
|
|
|
2009-03-09 16:53:37 +01:00
|
|
|
if (!HT_EMPTY(&policy_root)) {
|
|
|
|
policy_map_ent_t **ent;
|
|
|
|
int n = 0;
|
|
|
|
char buf[POLICY_BUF_LEN];
|
|
|
|
|
|
|
|
log_warn(LD_MM, "Still had %d address policies cached at shutdown.",
|
|
|
|
(int)HT_SIZE(&policy_root));
|
|
|
|
|
|
|
|
/* Note the first 10 cached policies to try to figure out where they
|
|
|
|
* might be coming from. */
|
|
|
|
HT_FOREACH(ent, policy_map, &policy_root) {
|
|
|
|
if (++n > 10)
|
|
|
|
break;
|
|
|
|
if (policy_write_item(buf, sizeof(buf), (*ent)->policy, 0) >= 0)
|
|
|
|
log_warn(LD_MM," %d [%d]: %s", n, (*ent)->policy->refcnt, buf);
|
|
|
|
}
|
|
|
|
}
|
2008-03-27 16:05:28 +01:00
|
|
|
HT_CLEAR(policy_map, &policy_root);
|
2006-03-27 04:25:34 +02:00
|
|
|
}
|
|
|
|
|