mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-14 07:03:44 +01:00
Implement policies for nodes (and for microdescriptors too)
This commit is contained in:
parent
42acef68ad
commit
1bb9734e3a
@ -4,12 +4,13 @@
|
|||||||
#include "or.h"
|
#include "or.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "directory.h"
|
#include "directory.h"
|
||||||
#include "microdesc.h"
|
|
||||||
#include "nodelist.h"
|
|
||||||
#include "routerparse.h"
|
|
||||||
#include "networkstatus.h"
|
|
||||||
#include "routerlist.h"
|
|
||||||
#include "dirserv.h"
|
#include "dirserv.h"
|
||||||
|
#include "microdesc.h"
|
||||||
|
#include "networkstatus.h"
|
||||||
|
#include "nodelist.h"
|
||||||
|
#include "policies.h"
|
||||||
|
#include "routerlist.h"
|
||||||
|
#include "routerparse.h"
|
||||||
|
|
||||||
/** A data structure to hold a bunch of cached microdescriptors. There are
|
/** A data structure to hold a bunch of cached microdescriptors. There are
|
||||||
* two active files in the cache: a "cache file" that we mmap, and a "journal
|
* two active files in the cache: a "cache file" that we mmap, and a "journal
|
||||||
@ -458,7 +459,7 @@ microdesc_free(microdesc_t *md)
|
|||||||
SMARTLIST_FOREACH(md->family, char *, cp, tor_free(cp));
|
SMARTLIST_FOREACH(md->family, char *, cp, tor_free(cp));
|
||||||
smartlist_free(md->family);
|
smartlist_free(md->family);
|
||||||
}
|
}
|
||||||
tor_free(md->exitsummary);
|
short_policy_free(md->exit_policy);
|
||||||
|
|
||||||
tor_free(md);
|
tor_free(md);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "microdesc.h"
|
#include "microdesc.h"
|
||||||
#include "networkstatus.h"
|
#include "networkstatus.h"
|
||||||
#include "nodelist.h"
|
#include "nodelist.h"
|
||||||
|
#include "policies.h"
|
||||||
#include "router.h"
|
#include "router.h"
|
||||||
#include "routerlist.h"
|
#include "routerlist.h"
|
||||||
|
|
||||||
@ -597,14 +598,18 @@ node_allows_single_hop_exits(const node_t *node)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return true iff it seems that <b>node</b> has an exit policy that
|
/** Return true iff it seems that <b>node</b> has an exit policy that doesn't
|
||||||
* doesn't actually permit anything to exit. */
|
* actually permit anything to exit, or we don't know its exit policy */
|
||||||
int
|
int
|
||||||
node_exit_policy_rejects_all(const node_t *node)
|
node_exit_policy_rejects_all(const node_t *node)
|
||||||
{
|
{
|
||||||
(void)node;
|
if (node->ri)
|
||||||
UNIMPLEMENTED_NODELIST();
|
return node->ri->policy_is_reject_star;
|
||||||
return 0;
|
else if (node->md)
|
||||||
|
return node->md->exit_policy == NULL ||
|
||||||
|
short_policy_is_reject_star(node->md->exit_policy);
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy the address for <b>node</b> into *<b>addr_out</b>. */
|
/** Copy the address for <b>node</b> into *<b>addr_out</b>. */
|
||||||
|
19
src/or/or.h
19
src/or/or.h
@ -1648,6 +1648,18 @@ typedef struct routerstatus_t {
|
|||||||
|
|
||||||
} routerstatus_t;
|
} routerstatus_t;
|
||||||
|
|
||||||
|
/** DOCDOC */
|
||||||
|
typedef struct short_policy_entry_t {
|
||||||
|
uint16_t min_port, max_port;
|
||||||
|
} short_policy_entry_t;
|
||||||
|
|
||||||
|
/** DOCDOC */
|
||||||
|
typedef struct short_policy_t {
|
||||||
|
unsigned int is_accept : 1;
|
||||||
|
unsigned int n_entries : 31;
|
||||||
|
short_policy_entry_t entries[1];
|
||||||
|
} short_policy_t;
|
||||||
|
|
||||||
/** A microdescriptor is the smallest amount of information needed to build a
|
/** A microdescriptor is the smallest amount of information needed to build a
|
||||||
* circuit through a router. They are generated by the directory authorities,
|
* circuit through a router. They are generated by the directory authorities,
|
||||||
* using information from the uploaded routerinfo documents. They are not
|
* using information from the uploaded routerinfo documents. They are not
|
||||||
@ -1689,9 +1701,8 @@ typedef struct microdesc_t {
|
|||||||
crypto_pk_env_t *onion_pkey;
|
crypto_pk_env_t *onion_pkey;
|
||||||
/** As routerinfo_t.family */
|
/** As routerinfo_t.family */
|
||||||
smartlist_t *family;
|
smartlist_t *family;
|
||||||
/** Encoded exit policy summary */
|
/** Exit policy summary */
|
||||||
char *exitsummary; /**< exit policy summary -
|
short_policy_t *exit_policy;
|
||||||
* XXX this probably should not stay a string. */
|
|
||||||
} microdesc_t;
|
} microdesc_t;
|
||||||
|
|
||||||
/** A node_t represents a Tor router.
|
/** A node_t represents a Tor router.
|
||||||
@ -3444,7 +3455,7 @@ typedef enum {
|
|||||||
ADDR_POLICY_PROBABLY_ACCEPTED=1,
|
ADDR_POLICY_PROBABLY_ACCEPTED=1,
|
||||||
/** Part of the address was unknown, but as far as we can tell, it was
|
/** Part of the address was unknown, but as far as we can tell, it was
|
||||||
* rejected. */
|
* rejected. */
|
||||||
ADDR_POLICY_PROBABLY_REJECTED=2
|
ADDR_POLICY_PROBABLY_REJECTED=2,
|
||||||
} addr_policy_result_t;
|
} addr_policy_result_t;
|
||||||
|
|
||||||
/********************************* rephist.c ***************************/
|
/********************************* rephist.c ***************************/
|
||||||
|
@ -1315,6 +1315,157 @@ policy_summarize(smartlist_t *policy)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DOCDOC */
|
||||||
|
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];
|
||||||
|
|
||||||
|
next = comma ? comma+1 : strchr(summary, '\0');
|
||||||
|
|
||||||
|
if (n_entries == MAX_EXITPOLICY_SUMMARY_LEN) {
|
||||||
|
log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Impossibly long policy summary %s",
|
||||||
|
escaped(orig_summary));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! TOR_ISDIGIT(*summary) || next-summary > (int)(sizeof(ent_buf)-1)) {
|
||||||
|
/* unrecognized entry format. skip it. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (next-summary < 2) {
|
||||||
|
/* empty; skip it. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ent_buf, summary, next-summary-1);
|
||||||
|
ent_buf[next-summary-1] = '\0';
|
||||||
|
|
||||||
|
if (tor_sscanf(ent_buf, "%u-%u%c", &low, &high, &dummy) == 2) {
|
||||||
|
if (low<1 || low>65535 || high<1 || high>65535) {
|
||||||
|
log_fn(LOG_PROTOCOL_WARN, LD_DIR,"Found bad entry in policy summary %s",
|
||||||
|
escaped(orig_summary));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else if (tor_sscanf(ent_buf, "%u%c", &low, &dummy) == 1) {
|
||||||
|
if (low<1 || low>65535) {
|
||||||
|
log_fn(LOG_PROTOCOL_WARN, LD_DIR,"Found bad entry in policy summary %s",
|
||||||
|
escaped(orig_summary));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t size = sizeof(short_policy_t) +
|
||||||
|
sizeof(short_policy_entry_t)*(n_entries-1);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DOCDOC */
|
||||||
|
void
|
||||||
|
short_policy_free(short_policy_t *policy)
|
||||||
|
{
|
||||||
|
tor_free(policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DOCDOC */
|
||||||
|
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;
|
||||||
|
(void)addr;
|
||||||
|
|
||||||
|
tor_assert(port != 0);
|
||||||
|
|
||||||
|
if (addr && (tor_addr_is_internal(addr, 0) ||
|
||||||
|
tor_addr_is_null(addr) ||
|
||||||
|
tor_addr_is_loopback(addr)))
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* ???? are these right? */
|
||||||
|
if (accept)
|
||||||
|
return ADDR_POLICY_PROBABLY_ACCEPTED;
|
||||||
|
else
|
||||||
|
return ADDR_POLICY_REJECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DOCDOC */
|
||||||
|
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,
|
||||||
|
* since policy summaries are from the consensus or from consensus microdescs.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/** Decides whether addr:port is probably or definitely accepted or rejcted by
|
/** Decides whether addr:port is probably or definitely accepted or rejcted by
|
||||||
* <b>node</b>. See compare_tor_addr_to_addr_policy for details on addr/port
|
* <b>node</b>. See compare_tor_addr_to_addr_policy for details on addr/port
|
||||||
* interpretation. */
|
* interpretation. */
|
||||||
@ -1333,11 +1484,16 @@ addr_policy_result_t
|
|||||||
compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port,
|
compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port,
|
||||||
const node_t *node)
|
const node_t *node)
|
||||||
{
|
{
|
||||||
(void)addr;
|
if (node->ri)
|
||||||
(void)port;
|
return compare_tor_addr_to_addr_policy(addr, port, node->ri->exit_policy);
|
||||||
(void)node;
|
else if (node->md && node->md) {
|
||||||
UNIMPLEMENTED_NODELIST();
|
if (node->md->exit_policy == NULL)
|
||||||
return 0;
|
return ADDR_POLICY_REJECTED;
|
||||||
|
else
|
||||||
|
return compare_tor_addr_to_short_policy(addr, port,
|
||||||
|
node->md->exit_policy);
|
||||||
|
} else
|
||||||
|
return ADDR_POLICY_PROBABLY_REJECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implementation for GETINFO control command: knows the answer for questions
|
/** Implementation for GETINFO control command: knows the answer for questions
|
||||||
|
@ -63,5 +63,12 @@ void policies_free_all(void);
|
|||||||
|
|
||||||
char *policy_summarize(smartlist_t *policy);
|
char *policy_summarize(smartlist_t *policy);
|
||||||
|
|
||||||
|
short_policy_t *parse_short_policy(const char *summary);
|
||||||
|
void short_policy_free(short_policy_t *policy);
|
||||||
|
int short_policy_is_reject_star(const short_policy_t *policy);
|
||||||
|
addr_policy_result_t compare_tor_addr_to_short_policy(
|
||||||
|
const tor_addr_t *addr, uint16_t port,
|
||||||
|
const short_policy_t *policy);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -4302,7 +4302,7 @@ microdescs_parse_from_string(const char *s, const char *eos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((tok = find_opt_by_keyword(tokens, K_P))) {
|
if ((tok = find_opt_by_keyword(tokens, K_P))) {
|
||||||
md->exitsummary = tor_strdup(tok->args[0]);
|
md->exit_policy = parse_short_policy(tok->args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
|
crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
|
||||||
|
@ -560,6 +560,7 @@ test_policy_summary_helper(const char *policy_str,
|
|||||||
smartlist_t *policy = smartlist_create();
|
smartlist_t *policy = smartlist_create();
|
||||||
char *summary = NULL;
|
char *summary = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
short_policy_t *short_policy = NULL;
|
||||||
|
|
||||||
line.key = (char*)"foo";
|
line.key = (char*)"foo";
|
||||||
line.value = (char *)policy_str;
|
line.value = (char *)policy_str;
|
||||||
@ -572,10 +573,14 @@ test_policy_summary_helper(const char *policy_str,
|
|||||||
test_assert(summary != NULL);
|
test_assert(summary != NULL);
|
||||||
test_streq(summary, expected_summary);
|
test_streq(summary, expected_summary);
|
||||||
|
|
||||||
|
short_policy = parse_short_policy(summary);
|
||||||
|
tt_assert(short_policy);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
tor_free(summary);
|
tor_free(summary);
|
||||||
if (policy)
|
if (policy)
|
||||||
addr_policy_list_free(policy);
|
addr_policy_list_free(policy);
|
||||||
|
short_policy_free(short_policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Run unit tests for generating summary lines of exit policies */
|
/** Run unit tests for generating summary lines of exit policies */
|
||||||
|
Loading…
Reference in New Issue
Block a user