mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
Better policy support for IPv6
Now, "accept *:80" means "accept all addresses on port 80", and not just IPv4. For just v4, say "accept *4:80"; for just v6 say "accept *6:80". We can parse these policies from torrc just fine, and we should be successfully keeping them out of descriptors for now. We also now include appropriate IPv6 addresses in "reject private:*"
This commit is contained in:
parent
2eb7eafc9d
commit
a96c0affcb
@ -2237,7 +2237,7 @@ routerstatus_format_entry(char *buf, size_t buf_len,
|
||||
}
|
||||
|
||||
if (desc) {
|
||||
summary = policy_summarize(desc->exit_policy);
|
||||
summary = policy_summarize(desc->exit_policy, AF_INET);
|
||||
r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary);
|
||||
if (r<0) {
|
||||
log_warn(LD_BUG, "Not enough space in buffer.");
|
||||
|
@ -3552,7 +3552,7 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
|
||||
|
||||
if (crypto_pk_write_public_key_to_string(ri->onion_pkey, &key, &keylen)<0)
|
||||
goto done;
|
||||
summary = policy_summarize(ri->exit_policy);
|
||||
summary = policy_summarize(ri->exit_policy, AF_INET);
|
||||
if (ri->declared_family)
|
||||
family = smartlist_join_strings(ri->declared_family, " ", 0, NULL);
|
||||
|
||||
|
10
src/or/or.h
10
src/or/or.h
@ -1730,7 +1730,15 @@ typedef struct addr_policy_t {
|
||||
maskbits_t maskbits; /**< Accept/reject all addresses <b>a</b> such that the
|
||||
* first <b>maskbits</b> bits of <b>a</b> match
|
||||
* <b>addr</b>. */
|
||||
tor_addr_t addr; /**< Base address to accept or reject. */
|
||||
/** Base address to accept or reject.
|
||||
*
|
||||
* Note that wildcards are treated
|
||||
* differntly depending on address family. An AF_UNSPEC address means
|
||||
* "All addresses, IPv4 or IPv6." An AF_INET address with maskbits==0 means
|
||||
* "All IPv4 addresses" and an AF_INET6 address with maskbits == 0 means
|
||||
* "All IPv6 addresses".
|
||||
**/
|
||||
tor_addr_t addr;
|
||||
uint16_t prt_min; /**< Lowest port number to accept/reject. */
|
||||
uint16_t prt_max; /**< Highest port number to accept/reject. */
|
||||
} addr_policy_t;
|
||||
|
@ -59,8 +59,10 @@ typedef struct policy_summary_item_t {
|
||||
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",
|
||||
// "fc00::/7", "fe80::/10", "fec0::/10", "::/127",
|
||||
NULL };
|
||||
"[::]/8",
|
||||
"[fc00::]/7", "[fe80::]/10", "[fec0::]/10", "[ff00::]/8", "[::]/127",
|
||||
NULL
|
||||
};
|
||||
|
||||
/** Replace all "private" entries in *<b>policy</b> with their expanded
|
||||
* equivalents. */
|
||||
@ -101,6 +103,49 @@ policy_expand_private(smartlist_t **policy)
|
||||
*policy = tmp;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a linked list of config lines containing "allow" and "deny"
|
||||
* tokens, parse them and append the result to <b>dest</b>. Return -1
|
||||
@ -145,6 +190,7 @@ parse_addr_policy(config_line_t *cfg, smartlist_t **dest,
|
||||
addr_policy_list_free(result);
|
||||
} else {
|
||||
policy_expand_private(&result);
|
||||
policy_expand_unspec(&result);
|
||||
|
||||
if (*dest) {
|
||||
smartlist_add_all(*dest, result);
|
||||
@ -735,6 +781,10 @@ compare_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port,
|
||||
static int
|
||||
addr_policy_covers(addr_policy_t *a, addr_policy_t *b)
|
||||
{
|
||||
if (tor_addr_family(&a->addr) != tor_addr_family(&b->addr)) {
|
||||
/* You can't cover a different family. */
|
||||
return 0;
|
||||
}
|
||||
/* We can ignore accept/reject, since "accept *:80, reject *:80" reduces
|
||||
* to "accept *:80". */
|
||||
if (a->maskbits > b->maskbits) {
|
||||
@ -790,20 +840,32 @@ append_exit_policy_string(smartlist_t **policy, const char *more)
|
||||
static void
|
||||
exit_policy_remove_redundancies(smartlist_t *dest)
|
||||
{
|
||||
addr_policy_t *ap, *tmp, *victim;
|
||||
addr_policy_t *ap, *tmp;
|
||||
int i, j;
|
||||
|
||||
/* Step one: find a *:* entry and cut off everything after it. */
|
||||
/* 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. */
|
||||
while (i+1 < smartlist_len(dest)) {
|
||||
victim = smartlist_get(dest, i+1);
|
||||
smartlist_del(dest, i+1);
|
||||
addr_policy_free(victim);
|
||||
if (family == AF_INET) {
|
||||
kill_v4 = 1;
|
||||
} else if (family == AF_INET6) {
|
||||
kill_v6 = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -869,6 +931,10 @@ exit_policy_remove_redundancies(smartlist_t *dest)
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
int
|
||||
policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
|
||||
@ -885,10 +951,12 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
|
||||
}
|
||||
if (parse_addr_policy(cfg, dest, -1))
|
||||
return -1;
|
||||
if (add_default_policy)
|
||||
if (add_default_policy) {
|
||||
append_exit_policy_string(dest, DEFAULT_EXIT_POLICY);
|
||||
else
|
||||
append_exit_policy_string(dest, "reject *:*");
|
||||
} else {
|
||||
append_exit_policy_string(dest, "reject *4:*");
|
||||
append_exit_policy_string(dest, "reject *6:*");
|
||||
}
|
||||
exit_policy_remove_redundancies(*dest);
|
||||
|
||||
return 0;
|
||||
@ -899,7 +967,8 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
|
||||
void
|
||||
policies_exit_policy_append_reject_star(smartlist_t **dest)
|
||||
{
|
||||
append_exit_policy_string(dest, "reject *:*");
|
||||
append_exit_policy_string(dest, "reject *4:*");
|
||||
append_exit_policy_string(dest, "reject *6:*");
|
||||
}
|
||||
|
||||
/** Replace the exit policy of <b>node</b> with reject *:* */
|
||||
@ -1001,17 +1070,26 @@ policy_write_item(char *buf, size_t buflen, addr_policy_t *policy,
|
||||
const char *addrpart;
|
||||
int result;
|
||||
const int is_accept = policy->policy_type == ADDR_POLICY_ACCEPT;
|
||||
const int is_ip6 = tor_addr_family(&policy->addr) == AF_INET6;
|
||||
const sa_family_t family = tor_addr_family(&policy->addr);
|
||||
const int is_ip6 = (family == AF_INET6);
|
||||
|
||||
tor_addr_to_str(addrbuf, &policy->addr, sizeof(addrbuf), 1);
|
||||
|
||||
/* write accept/reject 1.2.3.4 */
|
||||
if (policy->is_private)
|
||||
if (policy->is_private) {
|
||||
addrpart = "private";
|
||||
else if (policy->maskbits == 0)
|
||||
} 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 {
|
||||
addrpart = addrbuf;
|
||||
}
|
||||
|
||||
result = tor_snprintf(buf, buflen, "%s%s %s",
|
||||
is_accept ? "accept" : "reject",
|
||||
@ -1220,7 +1298,7 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p)
|
||||
* is an exception to the shorter-representation-wins rule).
|
||||
*/
|
||||
char *
|
||||
policy_summarize(smartlist_t *policy)
|
||||
policy_summarize(smartlist_t *policy, sa_family_t family)
|
||||
{
|
||||
smartlist_t *summary = policy_summary_create();
|
||||
smartlist_t *accepts, *rejects;
|
||||
@ -1232,9 +1310,16 @@ policy_summarize(smartlist_t *policy)
|
||||
tor_assert(policy);
|
||||
|
||||
/* Create the summary list */
|
||||
SMARTLIST_FOREACH(policy, addr_policy_t *, p, {
|
||||
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 */
|
||||
policy_summary_add_item(summary, p);
|
||||
});
|
||||
} SMARTLIST_FOREACH_END(p);
|
||||
|
||||
/* Now create two lists of strings, one for accepted and one
|
||||
* for rejected ports. We take care to merge ranges so that
|
||||
|
@ -31,6 +31,7 @@ int authdir_policy_badexit_address(uint32_t addr, uint16_t port);
|
||||
|
||||
int validate_addr_policies(const or_options_t *options, char **msg);
|
||||
void policy_expand_private(smartlist_t **policy);
|
||||
void policy_expand_unspec(smartlist_t **policy);
|
||||
int policies_parse_from_options(const or_options_t *options);
|
||||
|
||||
addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent);
|
||||
@ -58,7 +59,7 @@ void addr_policy_list_free(smartlist_t *p);
|
||||
void addr_policy_free(addr_policy_t *p);
|
||||
void policies_free_all(void);
|
||||
|
||||
char *policy_summarize(smartlist_t *policy);
|
||||
char *policy_summarize(smartlist_t *policy, sa_family_t family);
|
||||
|
||||
short_policy_t *parse_short_policy(const char *summary);
|
||||
char *write_short_policy(const short_policy_t *policy);
|
||||
|
@ -2001,7 +2001,6 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
|
||||
size_t onion_pkeylen, identity_pkeylen;
|
||||
size_t written;
|
||||
int result=0;
|
||||
addr_policy_t *tmpe;
|
||||
char *family_line;
|
||||
char *extra_or_address = NULL;
|
||||
const or_options_t *options = get_options();
|
||||
@ -2130,11 +2129,12 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
|
||||
if (!router->exit_policy || !smartlist_len(router->exit_policy)) {
|
||||
strlcat(s+written, "reject *:*\n", maxlen-written);
|
||||
written += strlen("reject *:*\n");
|
||||
tmpe = NULL;
|
||||
} else if (router->exit_policy) {
|
||||
int i;
|
||||
for (i = 0; i < smartlist_len(router->exit_policy); ++i) {
|
||||
tmpe = smartlist_get(router->exit_policy, i);
|
||||
addr_policy_t *tmpe = smartlist_get(router->exit_policy, i);
|
||||
if (tor_addr_family(&tmpe->addr) == AF_INET6)
|
||||
continue; /* Don't include IPv6 parts of address policy */
|
||||
result = policy_write_item(s+written, maxlen-written, tmpe, 1);
|
||||
if (result < 0) {
|
||||
log_warn(LD_BUG,"descriptor policy_write_item ran out of room!");
|
||||
|
@ -535,7 +535,8 @@ static token_rule_t microdesc_token_table[] = {
|
||||
|
||||
/* static function prototypes */
|
||||
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
|
||||
static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
|
||||
static addr_policy_t *router_parse_addr_policy(directory_token_t *tok,
|
||||
unsigned fmt_flags);
|
||||
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
|
||||
|
||||
static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
|
||||
@ -3633,6 +3634,10 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
|
||||
/** Parse the addr policy in the string <b>s</b> and return it. If
|
||||
* assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
|
||||
* ADDR_POLICY_REJECT) for items that specify no action.
|
||||
*
|
||||
* The addr_policy_t returned by this function can have its address set to
|
||||
* AF_UNSPEC for '*'. Use policy_expand_unspec() to turn this into a pair
|
||||
* of AF_INET and AF_INET6 items.
|
||||
*/
|
||||
addr_policy_t *
|
||||
router_parse_addr_policy_item_from_string(const char *s, int assume_action)
|
||||
@ -3672,7 +3677,7 @@ router_parse_addr_policy_item_from_string(const char *s, int assume_action)
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = router_parse_addr_policy(tok);
|
||||
r = router_parse_addr_policy(tok, TAPMP_EXTENDED_STAR);
|
||||
goto done;
|
||||
err:
|
||||
r = NULL;
|
||||
@ -3691,7 +3696,7 @@ static int
|
||||
router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
|
||||
{
|
||||
addr_policy_t *newe;
|
||||
newe = router_parse_addr_policy(tok);
|
||||
newe = router_parse_addr_policy(tok, 0);
|
||||
if (!newe)
|
||||
return -1;
|
||||
if (! router->exit_policy)
|
||||
@ -3716,7 +3721,7 @@ router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
|
||||
/** Given a K_ACCEPT or K_REJECT token and a router, create and return
|
||||
* a new exit_policy_t corresponding to the token. */
|
||||
static addr_policy_t *
|
||||
router_parse_addr_policy(directory_token_t *tok)
|
||||
router_parse_addr_policy(directory_token_t *tok, unsigned fmt_flags)
|
||||
{
|
||||
addr_policy_t newe;
|
||||
char *arg;
|
||||
@ -3738,7 +3743,7 @@ router_parse_addr_policy(directory_token_t *tok)
|
||||
else
|
||||
newe.policy_type = ADDR_POLICY_ACCEPT;
|
||||
|
||||
if (tor_addr_parse_mask_ports(arg, 0, &newe.addr, &newe.maskbits,
|
||||
if (tor_addr_parse_mask_ports(arg, fmt_flags, &newe.addr, &newe.maskbits,
|
||||
&newe.prt_min, &newe.prt_max) < 0) {
|
||||
log_warn(LD_DIR,"Couldn't parse line %s. Dropping", escaped(arg));
|
||||
return NULL;
|
||||
|
@ -148,6 +148,7 @@ routerset_parse(routerset_t *target, const char *s, const char *description)
|
||||
SMARTLIST_DEL_CURRENT(list, nick);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(nick);
|
||||
policy_expand_unspec(&target->policies);
|
||||
smartlist_add_all(target->list, list);
|
||||
smartlist_free(list);
|
||||
if (added_countries)
|
||||
|
@ -1046,7 +1046,7 @@ test_policy_summary_helper(const char *policy_str,
|
||||
|
||||
r = policies_parse_exit_policy(&line, &policy, 0, NULL, 1);
|
||||
test_eq(r, 0);
|
||||
summary = policy_summarize(policy);
|
||||
summary = policy_summarize(policy, AF_INET);
|
||||
|
||||
test_assert(summary != NULL);
|
||||
test_streq(summary, expected_summary);
|
||||
@ -1192,7 +1192,7 @@ test_policies(void)
|
||||
test_assert(policy);
|
||||
//test_streq(policy->string, "accept *:80");
|
||||
//test_streq(policy->next->string, "reject *:*");
|
||||
test_eq(smartlist_len(policy), 2);
|
||||
test_eq(smartlist_len(policy), 4);
|
||||
|
||||
/* test policy summaries */
|
||||
/* check if we properly ignore private IP addresses */
|
||||
|
Loading…
Reference in New Issue
Block a user