aboutsummaryrefslogtreecommitdiff
path: root/src/or/routers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/routers.c')
-rw-r--r--src/or/routers.c175
1 files changed, 136 insertions, 39 deletions
diff --git a/src/or/routers.c b/src/or/routers.c
index 29effd1da0..248a07d936 100644
--- a/src/or/routers.c
+++ b/src/or/routers.c
@@ -164,8 +164,6 @@ void routerinfo_free(routerinfo_t *router)
e = router->exit_policy;
router->exit_policy = e->next;
tor_free(e->string);
- tor_free(e->address);
- tor_free(e->port);
free(e);
}
free(router);
@@ -915,11 +913,12 @@ void router_add_exit_policy_from_config(routerinfo_t *router) {
e = strchr(s,',');
if(!e) {
last = 1;
- strcpy(line,s);
+ strncpy(line,s,1023);
} else {
- memcpy(line,s,e-s);
+ memcpy(line,s, ((e-s)<1023)?(e-s):1023);
line[e-s] = 0;
}
+ line[1023]=0;
log_fn(LOG_DEBUG,"Adding new entry '%s'",line);
if(router_add_exit_policy_from_string(router,line) < 0)
log_fn(LOG_WARN,"Malformed exit policy %s; skipping.", line);
@@ -963,7 +962,9 @@ router_add_exit_policy_from_string(routerinfo_t *router,
static int router_add_exit_policy(routerinfo_t *router,
directory_token_t *tok) {
struct exit_policy_t *tmpe, *newe;
- char *arg, *colon;
+ struct in_addr in;
+ char *arg, *address, *mask, *port, *endptr;
+ int bits;
if (tok->val.cmd.n_args != 1)
return -1;
@@ -982,17 +983,63 @@ static int router_add_exit_policy(routerinfo_t *router,
newe->policy_type = EXIT_POLICY_ACCEPT;
}
strcat(newe->string, arg);
-
- colon = strchr(arg,':');
- if(!colon)
+
+ address = arg;
+ mask = strchr(arg,'/');
+ port = strchr(mask?mask:arg,':');
+ if(!port)
goto policy_read_failed;
- *colon = 0;
- newe->address = tor_strdup(arg);
- newe->port = tor_strdup(colon+1);
+ if (mask)
+ *mask++ = 0;
+ *port++ = 0;
+
+ if (strcmp(address, "*") == 0) {
+ newe->addr = 0;
+ } else if (inet_aton(address, &in) != 0) {
+ newe->addr = in.s_addr;
+ } else {
+ log_fn(LOG_WARN, "Malformed IP %s in exit policy; rejecting.",
+ address);
+ goto policy_read_failed;
+ }
+ if (!mask) {
+ if (strcmp(address, "*") == 0)
+ newe->msk = 0;
+ else
+ newe->msk = 0xFFFFFFFFu;
+ } else {
+ endptr = NULL;
+ bits = (int) strtol(mask, &endptr, 10);
+ if (!*endptr) {
+ /* strtol handled the whole mask. */
+ newe->msk = ~((1<<(32-bits))-1);
+ } else if (inet_aton(mask, &in) != 0) {
+ newe->msk = in.s_addr;
+ } else {
+ log_fn(LOG_WARN, "Malformed mask %s on exit policy; rejecting.",
+ mask);
+ goto policy_read_failed;
+ }
+ }
+ if (strcmp(port, "*") == 0) {
+ newe->prt = 0;
+ } else {
+ endptr = NULL;
+ newe->prt = strtol(port, &endptr, 10);
+ if (*endptr) {
+ log_fn(LOG_WARN, "Malformed port %s on exit policy; rejecting.",
+ port);
+ goto policy_read_failed;
+ }
+ }
- log_fn(LOG_DEBUG,"%s %s:%s",
- newe->policy_type == EXIT_POLICY_REJECT ? "reject" : "accept",
- newe->address, newe->port);
+ in.s_addr = newe->addr;
+ address = tor_strdup(inet_ntoa(in));
+ in.s_addr = newe->msk;
+ log_fn(LOG_DEBUG,"%s %s/%s:%d",
+ newe->policy_type == EXIT_POLICY_REJECT ? "reject" : "accept",
+ address, inet_ntoa(in), newe->prt);
+ tor_free(address);
/* now link newe onto the end of exit_policy */
@@ -1010,44 +1057,75 @@ policy_read_failed:
assert(newe->string);
log_fn(LOG_WARN,"Couldn't parse line '%s'. Dropping", newe->string);
tor_free(newe->string);
- tor_free(newe->address);
- tor_free(newe->port);
free(newe);
return -1;
}
-/* Return 0 if my exit policy says to allow connection to conn.
- * Else return -1.
+
+/* Addr is 0 for "IP unknown".
+ *
+ * Returns -1 for 'rejected', 0 for accepted, 1 for 'maybe' (since IP is
+ * unknown.
*/
-int router_compare_to_exit_policy(connection_t *conn) {
- struct exit_policy_t *tmpe;
+int router_compare_addr_to_exit_policy(uint32_t addr, uint16_t port,
+ struct exit_policy_t *policy)
+{
+ int maybe_reject = 0;
+ int match = 0;
struct in_addr in;
+ struct exit_policy_t *tmpe;
assert(desc_routerinfo);
- for(tmpe=desc_routerinfo->exit_policy; tmpe; tmpe=tmpe->next) {
- assert(tmpe->address);
- assert(tmpe->port);
-
- log_fn(LOG_DEBUG,"Considering exit policy %s:%s",tmpe->address, tmpe->port);
- if(strcmp(tmpe->address,"*") &&
- inet_aton(tmpe->address,&in) == 0) { /* malformed IP. reject. */
- log_fn(LOG_WARN,"Malformed IP %s in exit policy. Rejecting.",tmpe->address);
- return -1;
+ for(tmpe=policy; tmpe; tmpe=tmpe->next) {
+ log_fn(LOG_DEBUG,"Considering exit policy %s", tmpe->string);
+ if (!addr) {
+ /* Address is unknown. */
+ if (tmpe->msk == 0 && port == tmpe->prt) {
+ /* The exit policy is accept/reject *:port */
+ match = 1;
+ } else if ((!tmpe->prt || port == tmpe->prt) &&
+ tmpe->policy_type == EXIT_POLICY_REJECT) {
+ /* The exit policy is reject ???:port */
+ maybe_reject = 1;
+ }
+ } else {
+ /* Address is known */
+ if ( (addr & tmpe->msk) == (tmpe->addr & tmpe->msk) &&
+ (!tmpe->prt || port == tmpe->prt) ) {
+ /* Exact match for the policy */
+ match = 1;
+ }
}
- if((!strcmp(tmpe->address,"*") || conn->addr == ntohl(in.s_addr)) &&
- (!strcmp(tmpe->port,"*") || atoi(tmpe->port) == conn->port)) {
- log_fn(LOG_INFO,"Address '%s' matches '%s' and port '%s' matches '%d'. %s.",
- tmpe->address, conn->address,
- tmpe->port, conn->port,
- tmpe->policy_type == EXIT_POLICY_ACCEPT ? "Accepting" : "Rejecting");
+ if (match) {
+ in.s_addr = addr;
+ log_fn(LOG_INFO,"Address %s:%d matches exit policy '%s'",
+ inet_ntoa(in), port, tmpe->string);
if(tmpe->policy_type == EXIT_POLICY_ACCEPT)
return 0;
else
return -1;
}
}
- return 0; /* accept all by default. */
+ if (maybe_reject)
+ return 1;
+ else
+ return 0; /* accept all by default. */
+}
+
+/* Return 0 if my exit policy says to allow connection to conn.
+ * Else return -1.
+ */
+int router_compare_to_exit_policy(connection_t *conn) {
+ struct exit_policy_t *tmpe;
+
+ assert(desc_routerinfo);
+
+ if (router_compare_addr_to_exit_policy(conn->addr, conn->port,
+ desc_routerinfo->exit_policy))
+ return -1;
+ else
+ return 0;
}
const char *router_get_my_descriptor(void) {
@@ -1120,6 +1198,7 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
char *onion_pkey;
char *link_pkey;
char *identity_pkey;
+ struct in_addr in;
char platform[256];
char digest[20];
char signature[128];
@@ -1187,14 +1266,32 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
written = result;
for(tmpe=router->exit_policy; tmpe; tmpe=tmpe->next) {
- result = snprintf(s+written, maxlen-written, "%s %s:%s\n",
- tmpe->policy_type == EXIT_POLICY_ACCEPT ? "accept" : "reject",
- tmpe->address, tmpe->port);
+ in.s_addr = tmpe->addr;
+ result = snprintf(s+written, maxlen-written, "%s %s",
+ tmpe->policy_type == EXIT_POLICY_ACCEPT ? "accept" : "reject",
+ tmpe->msk == 0 ? "*" : inet_ntoa(in));
if(result < 0 || result+written > maxlen) {
/* apparently different glibcs do different things on snprintf error.. so check both */
return -1;
}
written += result;
+ if (tmpe->msk != 0xFFFFFFFFu) {
+ in.s_addr = tmpe->msk;
+ result = snprintf(s+written, maxlen-written, "/%s", inet_ntoa(in));
+ if (result<0 || result+written > maxlen)
+ return -1;
+ written += result;
+ }
+ if (tmpe->prt) {
+ result = snprintf(s+written, maxlen-written, ":%d", tmpe->prt);
+ if (result<0 || result+written > maxlen)
+ return -1;
+ written += result;
+ } else {
+ if (written > maxlen-3)
+ return -1;
+ strcat(s+written, ":*");
+ }
}
if (written > maxlen-256) /* Not enough room for signature. */
return -1;