📄 policies.c
字号:
/** Add the exit policy described by <b>more</b> to <b>policy</b>.
*/
static void
append_exit_policy_string(smartlist_t **policy, const char *more)
{
config_line_t tmp;
tmp.key = NULL;
tmp.value = (char*) more;
tmp.next = NULL;
if (parse_addr_policy(&tmp, policy, -1)<0) {
log_warn(LD_BUG, "Unable to parse internally generated policy %s",more);
}
}
/** Detect and excise "dead code" from the policy *<b>dest</b>. */
static void
exit_policy_remove_redundancies(smartlist_t *dest)
{
addr_policy_t *ap, *tmp, *victim;
int i, j;
/* Step one: find a *:* entry and cut off everything after it. */
for (i = 0; i < smartlist_len(dest); ++i) {
ap = smartlist_get(dest, i);
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);
}
break;
}
}
/* Step two: for every entry, see if there's a redundant entry
* later on, and remove it. */
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)) {
char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN];
policy_write_item(p1, sizeof(p1), tmp);
policy_write_item(p2, sizeof(p2), ap);
log(LOG_DEBUG, LD_CONFIG, "Removing exit policy %s (%d). It is made "
"redundant by %s (%d).", p1, j, p2, i);
smartlist_del_keeporder(dest, j--);
addr_policy_free(tmp);
}
}
}
/* 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.
*
* Anybody want to doublecheck the logic here? XXX
*/
for (i = 0; i < smartlist_len(dest)-1; ++i) {
ap = smartlist_get(dest, i);
for (j = i+1; j < smartlist_len(dest); ++j) {
// tor_assert(j > i); // j starts out at i+1; j only increases; i only
// // decreases.
tmp = smartlist_get(dest, j);
if (ap->policy_type != tmp->policy_type) {
if (addr_policy_intersects(ap, tmp))
break;
} else { /* policy_types are equal. */
if (addr_policy_covers(tmp, ap)) {
char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN];
policy_write_item(p1, sizeof(p1), ap);
policy_write_item(p2, sizeof(p2), tmp);
log(LOG_DEBUG, LD_CONFIG, "Removing exit policy %s. It is already "
"covered by %s.", p1, p2);
smartlist_del_keeporder(dest, i--);
addr_policy_free(ap);
break;
}
}
}
}
}
#define DEFAULT_EXIT_POLICY \
"reject *:25,reject *:119,reject *:135-139,reject *:445," \
"reject *:465,reject *:563,reject *:587," \
"reject *:1214,reject *:4661-4666," \
"reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*"
/** Parse the exit policy <b>cfg</b> into the linked list *<b>dest</b>. If
* cfg doesn't end in an absolute accept or reject, add the default exit
* 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.
*/
int
policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
int rejectprivate, const char *local_address)
{
if (rejectprivate) {
append_exit_policy_string(dest, "reject private:*");
if (local_address) {
char buf[POLICY_BUF_LEN];
tor_snprintf(buf, sizeof(buf), "reject %s:*", local_address);
append_exit_policy_string(dest, buf);
}
}
if (parse_addr_policy(cfg, dest, -1))
return -1;
append_exit_policy_string(dest, DEFAULT_EXIT_POLICY);
exit_policy_remove_redundancies(*dest);
return 0;
}
/** Replace the exit policy of <b>r</b> with reject *:*. */
void
policies_set_router_exitpolicy_to_reject_all(routerinfo_t *r)
{
addr_policy_t *item;
addr_policy_list_free(r->exit_policy);
r->exit_policy = smartlist_create();
item = router_parse_addr_policy_item_from_string("reject *:*", -1);
smartlist_add(r->exit_policy, item);
}
/** 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
* two of ports 80, 443, and 6667. */
int
exit_policy_is_general_exit(smartlist_t *policy)
{
static const int ports[] = { 80, 443, 6667 };
int n_allowed = 0;
int i;
if (!policy) /*XXXX021 disallow NULL policies */
return 0;
for (i = 0; i < 3; ++i) {
SMARTLIST_FOREACH(policy, addr_policy_t *, p, {
if (p->prt_min > ports[i] || p->prt_max < ports[i])
continue; /* Doesn't cover our port. */
if (p->maskbits > 8)
continue; /* Narrower than a /8. */
if ((p->addr & 0xff000000ul) == 0x7f000000ul)
continue; /* 127.x */
/* We have a match that is at least a /8. */
if (p->policy_type == ADDR_POLICY_ACCEPT) {
++n_allowed;
break; /* stop considering this port */
}
});
}
return n_allowed >= 2;
}
/** Return false if <b>policy</b> might permit access to some addr:port;
* otherwise if we are certain it rejects everything, return true. */
int
policy_is_reject_star(smartlist_t *policy)
{
if (!policy) /*XXXX021 disallow NULL policies */
return 1;
SMARTLIST_FOREACH(policy, addr_policy_t *, p, {
if (p->policy_type == ADDR_POLICY_ACCEPT)
return 0;
else if (p->policy_type == ADDR_POLICY_REJECT &&
p->prt_min <= 1 && p->prt_max == 65535 &&
p->maskbits == 0)
return 1;
});
return 1;
}
/** Write a single address policy to the buf_len byte buffer at buf. Return
* the number of characters written, or -1 on failure. */
int
policy_write_item(char *buf, size_t buflen, addr_policy_t *policy)
{
struct in_addr in;
size_t written = 0;
char addrbuf[INET_NTOA_BUF_LEN];
const char *addrpart;
int result;
in.s_addr = htonl(policy->addr);
tor_inet_ntoa(&in, addrbuf, sizeof(addrbuf));
/* write accept/reject 1.2.3.4 */
if (policy->is_private)
addrpart = "private";
else if (policy->maskbits == 0)
addrpart = "*";
else
addrpart = addrbuf;
result = tor_snprintf(buf, buflen, "%s %s",
policy->policy_type == ADDR_POLICY_ACCEPT ? "accept" : "reject",
addrpart);
if (result < 0)
return -1;
written += strlen(buf);
/* If the maskbits is 32 we don't need to give it. If the mask is 0,
* we already wrote "*". */
if (policy->maskbits < 32 && policy->maskbits > 0) {
if (tor_snprintf(buf+written, buflen-written, "/%d", policy->maskbits)<0)
return -1;
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);
written += 2;
} 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;
}
/** Implementation for GETINFO control command: knows the answer for questions
* about "exit-policy/..." */
int
getinfo_helper_policies(control_connection_t *conn,
const char *question, char **answer)
{
(void) conn;
if (!strcmp(question, "exit-policy/default")) {
*answer = tor_strdup(DEFAULT_EXIT_POLICY);
}
return 0;
}
/** Release all storage held by <b>p</b>. */
void
addr_policy_list_free(smartlist_t *lst)
{
if (!lst) return;
SMARTLIST_FOREACH(lst, addr_policy_t *, policy, addr_policy_free(policy));
smartlist_free(lst);
}
/** Release all storage held by <b>p</b>. */
void
addr_policy_free(addr_policy_t *p)
{
if (p) {
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);
}
}
tor_free(p);
}
}
}
/** Release all storage held by policy variables. */
void
policies_free_all(void)
{
addr_policy_list_free(reachable_or_addr_policy);
reachable_or_addr_policy = NULL;
addr_policy_list_free(reachable_dir_addr_policy);
reachable_dir_addr_policy = NULL;
addr_policy_list_free(socks_policy);
socks_policy = NULL;
addr_policy_list_free(dir_policy);
dir_policy = NULL;
addr_policy_list_free(authdir_reject_policy);
authdir_reject_policy = NULL;
addr_policy_list_free(authdir_invalid_policy);
authdir_invalid_policy = NULL;
addr_policy_list_free(authdir_baddir_policy);
authdir_baddir_policy = NULL;
addr_policy_list_free(authdir_badexit_policy);
authdir_badexit_policy = NULL;
if (!HT_EMPTY(&policy_root))
log_warn(LD_MM, "Still had some address policies cached at shutdown.");
HT_CLEAR(policy_map, &policy_root);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -