diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 672c858a7a..2b34f7e6ee 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -212,6 +212,34 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
return best ? TO_ORIGIN_CIRCUIT(best) : NULL;
}
+/** Check whether, according to the policies in options, the
+ * circuit circ makes sense. */
+/* XXXX021 currently only checks Exclude{Exit}Nodes. */
+int
+circuit_conforms_to_options(const origin_circuit_t *circ,
+ const or_options_t *options)
+{
+ const crypt_path_t *cpath, *cpath_next = NULL;
+
+ for (cpath = circ->cpath; cpath && cpath_next != circ->cpath;
+ cpath = cpath_next) {
+ cpath_next = cpath->next;
+
+ if (routerset_contains_extendinfo(options->ExcludeNodes,
+ cpath->extend_info))
+ return 0;
+
+ if (cpath->next == circ->cpath) {
+ /* This is apparently the exit node. */
+
+ if (routerset_contains_extendinfo(options->ExcludeExitNodes,
+ cpath->extend_info))
+ return 0;
+ }
+ }
+ return 1;
+}
+
/** Close all circuits that start at us, aren't open, and were born
* at least CircuitBuildTimeout seconds ago.
*/
diff --git a/src/or/or.h b/src/or/or.h
index 5ad3d59b21..09abeb50e9 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2701,6 +2701,8 @@ void circuit_expire_building(time_t now);
void circuit_remove_handled_ports(smartlist_t *needed_ports);
int circuit_stream_is_being_handled(edge_connection_t *conn, uint16_t port,
int min);
+int circuit_conforms_to_options(const origin_circuit_t *circ,
+ const or_options_t *options);
void circuit_build_needed_circs(time_t now);
void circuit_detach_stream(circuit_t *circ, edge_connection_t *conn);
@@ -4257,6 +4259,7 @@ void routerset_union(routerset_t *target, const routerset_t *source);
int routerset_contains_router(const routerset_t *set, routerinfo_t *ri);
int routerset_contains_routerstatus(const routerset_t *set,
routerstatus_t *rs);
+int routerset_contains_extendinfo(const routerset_t *set, extend_info_t *ei);
void routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
int running_only);
void routerset_subtract_routers(smartlist_t *out,
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 32595b8080..66ca2bf479 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -4782,27 +4782,42 @@ routerset_union(routerset_t *target, const routerset_t *source)
/** Helper. Return true iff set contains a router based on the other
* provided fields. */
static int
-routerset_contains(const routerset_t *set, uint32_t addr, uint16_t orport,
+routerset_contains(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport,
const char *nickname, const char *id_digest, int is_named)
{
if (!set || !set->list) return 0;
(void) is_named; /* not supported */
- if (strmap_get_lc(set->names, nickname))
+ if (nickname && strmap_get_lc(set->names, nickname))
return 1;
- if (digestmap_get(set->digests, id_digest))
+ if (id_digest && digestmap_get(set->digests, id_digest))
return 1;
- if (compare_addr_to_addr_policy(addr, orport, set->policies)
+ if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies)
== ADDR_POLICY_REJECTED)
return 1;
return 0;
}
+/** Return true iff we can tell that ei is a member of set. */
+int
+routerset_contains_extendinfo(const routerset_t *set, extend_info_t *ei)
+{
+ return routerset_contains(set,
+ &ei->addr,
+ ei->port,
+ ei->nickname,
+ ei->identity_digest,
+ -1);
+}
+
/** Return true iff ri is in set. */
int
routerset_contains_router(const routerset_t *set, routerinfo_t *ri)
{
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, ri->addr);
return routerset_contains(set,
- ri->addr,
+ &addr,
ri->or_port,
ri->nickname,
ri->cache_info.identity_digest,
@@ -4813,8 +4828,10 @@ routerset_contains_router(const routerset_t *set, routerinfo_t *ri)
int
routerset_contains_routerstatus(const routerset_t *set, routerstatus_t *rs)
{
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, rs->addr);
return routerset_contains(set,
- rs->addr,
+ &addr,
rs->or_port,
rs->nickname,
rs->identity_digest,