diff options
Diffstat (limited to 'src/feature/client')
-rw-r--r-- | src/feature/client/addressmap.c | 4 | ||||
-rw-r--r-- | src/feature/client/bridges.c | 160 | ||||
-rw-r--r-- | src/feature/client/bridges.h | 2 | ||||
-rw-r--r-- | src/feature/client/circpathbias.c | 2 | ||||
-rw-r--r-- | src/feature/client/entrynodes.c | 14 | ||||
-rw-r--r-- | src/feature/client/transports.c | 121 | ||||
-rw-r--r-- | src/feature/client/transports.h | 3 |
7 files changed, 214 insertions, 92 deletions
diff --git a/src/feature/client/addressmap.c b/src/feature/client/addressmap.c index 9ad2d7f934..e5bf2cc49c 100644 --- a/src/feature/client/addressmap.c +++ b/src/feature/client/addressmap.c @@ -422,7 +422,7 @@ addressmap_rewrite(char *address, size_t maxlen, goto done; } - /* Check wither the flags we were passed tell us not to use this + /* Check whether the flags we were passed tell us not to use this * mapping. */ switch (ent->source) { case ADDRMAPSRC_DNS: @@ -515,7 +515,7 @@ addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags, else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS)) return 0; /* FFFF we should reverse-map virtual addresses even if we haven't - * enabled DNS cacheing. */ + * enabled DNS caching. */ } tor_asprintf(&s, "REVERSE[%s]", address); diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index 66b04f3bc2..96c3497c6f 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -164,6 +164,28 @@ bridge_get_addr_port(const bridge_info_t *bridge) return &bridge->addrport_configured; } +/** + * Given a <b>bridge</b>, return the transport name. If none were configured, + * NULL is returned. + */ +const char * +bridget_get_transport_name(const bridge_info_t *bridge) +{ + tor_assert(bridge); + return bridge->transport_name; +} + +/** + * Return true if @a bridge has a transport name for which we don't actually + * know a transport. + */ +bool +bridge_has_invalid_transport(const bridge_info_t *bridge) +{ + const char *tname = bridget_get_transport_name(bridge); + return tname && transport_get_by_name(tname) == NULL; +} + /** If we have a bridge configured whose digest matches <b>digest</b>, or a * bridge with no known digest whose address matches any of the * tor_addr_port_t's in <b>orports</b>, return that bridge. Else return @@ -249,8 +271,8 @@ get_configured_bridge_by_exact_addr_port_digest(const tor_addr_t *addr, * address/port matches only. */ int addr_is_a_configured_bridge(const tor_addr_t *addr, - uint16_t port, - const char *digest) + uint16_t port, + const char *digest) { tor_assert(addr); return get_configured_bridge_by_addr_port_digest(addr, port, digest) ? 1 : 0; @@ -259,12 +281,26 @@ addr_is_a_configured_bridge(const tor_addr_t *addr, /** If we have a bridge configured whose digest matches * <b>ei->identity_digest</b>, or a bridge with no known digest whose address * matches <b>ei->addr</b>:<b>ei->port</b>, return 1. Else return 0. - * If <b>ei->onion_key</b> is NULL, check for address/port matches only. */ + * If <b>ei->onion_key</b> is NULL, check for address/port matches only. + * + * Note that if the extend_info_t contains multiple addresses, we return true + * only if _every_ address is a bridge. + */ int extend_info_is_a_configured_bridge(const extend_info_t *ei) { const char *digest = ei->onion_key ? ei->identity_digest : NULL; - return addr_is_a_configured_bridge(&ei->addr, ei->port, digest); + const tor_addr_port_t *ap1 = NULL, *ap2 = NULL; + if (! tor_addr_is_null(&ei->orports[0].addr)) + ap1 = &ei->orports[0]; + if (! tor_addr_is_null(&ei->orports[1].addr)) + ap2 = &ei->orports[1]; + IF_BUG_ONCE(ap1 == NULL) { + return 0; + } + return addr_is_a_configured_bridge(&ap1->addr, ap1->port, digest) && + (ap2 == NULL || + addr_is_a_configured_bridge(&ap2->addr, ap2->port, digest)); } /** Wrapper around get_configured_bridge_by_addr_port_digest() to look @@ -289,51 +325,21 @@ routerinfo_is_a_configured_bridge(const routerinfo_t *ri) } /** - * Return 1 iff <b>bridge_list</b> contains entry matching - * given; IPv4 address in host byte order (<b>ipv4_addr</b> - * and <b>port</b> (and no identity digest) OR it contains an - * entry whose identity matches <b>digest</b>. Otherwise, - * return 0. - */ -static int -bridge_exists_with_ipv4h_addr_and_port(const uint32_t ipv4_addr, - const uint16_t port, - const char *digest) -{ - tor_addr_t node_ipv4; - - if (tor_addr_port_is_valid_ipv4h(ipv4_addr, port, 0)) { - tor_addr_from_ipv4h(&node_ipv4, ipv4_addr); - - bridge_info_t *bridge = - get_configured_bridge_by_addr_port_digest(&node_ipv4, - port, - digest); - - return (bridge != NULL); - } - - return 0; -} - -/** * Return 1 iff <b>bridge_list</b> contains entry matching given - * <b>ipv6_addr</b> and <b>port</b> (and no identity digest) OR + * <b>addr</b> and <b>port</b> (and no identity digest) OR * it contains an entry whose identity matches <b>digest</b>. * Otherwise, return 0. */ static int -bridge_exists_with_ipv6_addr_and_port(const tor_addr_t *ipv6_addr, - const uint16_t port, - const char *digest) +bridge_exists_with_addr_and_port(const tor_addr_t *addr, + const uint16_t port, + const char *digest) { - if (!tor_addr_port_is_valid(ipv6_addr, port, 0)) + if (!tor_addr_port_is_valid(addr, port, 0)) return 0; bridge_info_t *bridge = - get_configured_bridge_by_addr_port_digest(ipv6_addr, - port, - digest); + get_configured_bridge_by_addr_port_digest(addr, port, digest); return (bridge != NULL); } @@ -360,29 +366,29 @@ node_is_a_configured_bridge(const node_t *node) * check for absence of identity digest in a bridge. */ if (node->ri) { - if (bridge_exists_with_ipv4h_addr_and_port(node->ri->addr, - node->ri->or_port, - node->identity)) + if (bridge_exists_with_addr_and_port(&node->ri->ipv4_addr, + node->ri->ipv4_orport, + node->identity)) return 1; - if (bridge_exists_with_ipv6_addr_and_port(&node->ri->ipv6_addr, - node->ri->ipv6_orport, - node->identity)) + if (bridge_exists_with_addr_and_port(&node->ri->ipv6_addr, + node->ri->ipv6_orport, + node->identity)) return 1; } else if (node->rs) { - if (bridge_exists_with_ipv4h_addr_and_port(node->rs->addr, - node->rs->or_port, - node->identity)) + if (bridge_exists_with_addr_and_port(&node->rs->ipv4_addr, + node->rs->ipv4_orport, + node->identity)) return 1; - if (bridge_exists_with_ipv6_addr_and_port(&node->rs->ipv6_addr, - node->rs->ipv6_orport, - node->identity)) + if (bridge_exists_with_addr_and_port(&node->rs->ipv6_addr, + node->rs->ipv6_orport, + node->identity)) return 1; } else if (node->md) { - if (bridge_exists_with_ipv6_addr_and_port(&node->md->ipv6_addr, - node->md->ipv6_orport, - node->identity)) + if (bridge_exists_with_addr_and_port(&node->md->ipv6_addr, + node->md->ipv6_orport, + node->identity)) return 1; } @@ -612,7 +618,7 @@ find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) */ int get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, - const transport_t **transport) + const transport_t **transport) { *transport = NULL; if (!bridge_list) @@ -661,6 +667,15 @@ launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge) DIR_PURPOSE_FETCH_SERVERDESC)) return; /* it's already on the way */ + if (bridge_has_invalid_transport(bridge)) { + download_status_mark_impossible(&bridge->fetch_status); + log_warn(LD_CONFIG, "Can't use bridge at %s: there is no configured " + "transport called \"%s\".", + safe_str_client(fmt_and_decorate_addr(&bridge->addr)), + bridget_get_transport_name(bridge)); + return; /* Can't use this bridge; it has not */ + } + if (routerset_contains_bridge(options->ExcludeNodes, bridge)) { download_status_mark_impossible(&bridge->fetch_status); log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.", @@ -670,7 +685,7 @@ launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge) /* Until we get a descriptor for the bridge, we only know one address for * it. */ - if (!fascist_firewall_allows_address_addr(&bridge->addr, bridge->port, + if (!reachable_addr_allows_addr(&bridge->addr, bridge->port, FIREWALL_OR_CONNECTION, 0, 0)) { log_notice(LD_CONFIG, "Tried to fetch a descriptor directly from a " "bridge, but that bridge is not reachable through our " @@ -762,7 +777,7 @@ fetch_bridge_descriptors(const or_options_t *options, time_t now) !options->UpdateBridgesFromAuthority, !num_bridge_auths); if (ask_bridge_directly && - !fascist_firewall_allows_address_addr(&bridge->addr, bridge->port, + !reachable_addr_allows_addr(&bridge->addr, bridge->port, FIREWALL_OR_CONNECTION, 0, 0)) { log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our " @@ -811,25 +826,23 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) * do that safely if we know that no function that connects to an OR * does so through an address from any source other than node_get_addr(). */ - tor_addr_t addr; const or_options_t *options = get_options(); if (node->ri) { routerinfo_t *ri = node->ri; - tor_addr_from_ipv4h(&addr, ri->addr); - if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && - bridge->port == ri->or_port) || + if ((!tor_addr_compare(&bridge->addr, &ri->ipv4_addr, CMP_EXACT) && + bridge->port == ri->ipv4_orport) || (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) && bridge->port == ri->ipv6_orport)) { /* they match, so no need to do anything */ } else { if (tor_addr_family(&bridge->addr) == AF_INET) { - ri->addr = tor_addr_to_ipv4h(&bridge->addr); - ri->or_port = bridge->port; + tor_addr_copy(&ri->ipv4_addr, &bridge->addr); + ri->ipv4_orport = bridge->port; log_info(LD_DIR, "Adjusted bridge routerinfo for '%s' to match configured " "address %s:%d.", - ri->nickname, fmt_addr32(ri->addr), ri->or_port); + ri->nickname, fmt_addr(&ri->ipv4_addr), ri->ipv4_orport); } else if (tor_addr_family(&bridge->addr) == AF_INET6) { tor_addr_copy(&ri->ipv6_addr, &bridge->addr); ri->ipv6_orport = bridge->port; @@ -850,7 +863,7 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) !tor_addr_is_null(&node->ri->ipv6_addr)); } else { /* Mark which address to use based on user preference */ - node->ipv6_preferred = (fascist_firewall_prefer_ipv6_orport(options) && + node->ipv6_preferred = (reachable_addr_prefer_ipv6_orport(options) && !tor_addr_is_null(&node->ri->ipv6_addr)); } @@ -872,21 +885,20 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) } if (node->rs) { routerstatus_t *rs = node->rs; - tor_addr_from_ipv4h(&addr, rs->addr); - if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && - bridge->port == rs->or_port) || + if ((!tor_addr_compare(&bridge->addr, &rs->ipv4_addr, CMP_EXACT) && + bridge->port == rs->ipv4_orport) || (!tor_addr_compare(&bridge->addr, &rs->ipv6_addr, CMP_EXACT) && bridge->port == rs->ipv6_orport)) { /* they match, so no need to do anything */ } else { if (tor_addr_family(&bridge->addr) == AF_INET) { - rs->addr = tor_addr_to_ipv4h(&bridge->addr); - rs->or_port = bridge->port; + tor_addr_copy(&rs->ipv4_addr, &bridge->addr); + rs->ipv4_orport = bridge->port; log_info(LD_DIR, "Adjusted bridge routerstatus for '%s' to match " "configured address %s.", - rs->nickname, fmt_addrport(&bridge->addr, rs->or_port)); + rs->nickname, fmt_addrport(&bridge->addr, rs->ipv4_orport)); /* set IPv6 preferences even if there is no ri */ } else if (tor_addr_family(&bridge->addr) == AF_INET6) { tor_addr_copy(&rs->ipv6_addr, &bridge->addr); @@ -908,7 +920,7 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) !tor_addr_is_null(&node->rs->ipv6_addr)); } else { /* Mark which address to use based on user preference */ - node->ipv6_preferred = (fascist_firewall_prefer_ipv6_orport(options) && + node->ipv6_preferred = (reachable_addr_prefer_ipv6_orport(options) && !tor_addr_is_null(&node->rs->ipv6_addr)); } @@ -953,7 +965,7 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache) if (!from_cache) { /* This schedules the re-fetch at a constant interval, which produces * a pattern of bridge traffic. But it's better than trying all - * configured briges several times in the first few minutes. */ + * configured bridges several times in the first few minutes. */ download_status_reset(&bridge->fetch_status); } diff --git a/src/feature/client/bridges.h b/src/feature/client/bridges.h index 174149cf97..f5ecc1b76d 100644 --- a/src/feature/client/bridges.h +++ b/src/feature/client/bridges.h @@ -23,6 +23,8 @@ void sweep_bridge_list(void); const smartlist_t *bridge_list_get(void); const uint8_t *bridge_get_rsa_id_digest(const bridge_info_t *bridge); const tor_addr_port_t * bridge_get_addr_port(const bridge_info_t *bridge); +const char *bridget_get_transport_name(const bridge_info_t *bridge); +bool bridge_has_invalid_transport(const bridge_info_t *bridge); bridge_info_t *get_configured_bridge_by_addr_port_digest( const tor_addr_t *addr, uint16_t port, diff --git a/src/feature/client/circpathbias.c b/src/feature/client/circpathbias.c index 74260171fe..4d27553926 100644 --- a/src/feature/client/circpathbias.c +++ b/src/feature/client/circpathbias.c @@ -683,7 +683,7 @@ pathbias_mark_use_success(origin_circuit_t *circ) } /** - * If a stream ever detatches from a circuit in a retriable way, + * If a stream ever detaches from a circuit in a retriable way, * we need to mark this circuit as still needing either another * successful stream, or in need of a probe. * diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 70ef64cc86..82866ea668 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -342,7 +342,7 @@ entry_guard_get_pathbias_state(entry_guard_t *guard) HANDLE_IMPL(entry_guard, entry_guard_t, ATTR_UNUSED STATIC) -/** Return an interval betweeen 'now' and 'max_backdate' seconds in the past, +/** Return an interval between 'now' and 'max_backdate' seconds in the past, * chosen uniformly at random. We use this before recording persistent * dates, so that we aren't leaking exactly when we recorded it. */ @@ -1466,7 +1466,7 @@ node_passes_guard_filter(const or_options_t *options, !routerset_contains_node(options->EntryNodes, node)) return 0; - if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0)) + if (!reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION, 0)) return 0; if (node_is_a_configured_bridge(node)) @@ -1492,7 +1492,7 @@ bridge_passes_guard_filter(const or_options_t *options, /* Ignore entrynodes */ const tor_addr_port_t *addrport = bridge_get_addr_port(bridge); - if (!fascist_firewall_allows_address_addr(&addrport->addr, + if (!reachable_addr_allows_addr(&addrport->addr, addrport->port, FIREWALL_OR_CONNECTION, 0, 0)) @@ -1554,7 +1554,7 @@ guard_in_node_family(const entry_guard_t *guard, const node_t *node) if (get_options()->EnforceDistinctSubnets && guard->bridge_addr) { tor_addr_t node_addr; node_get_addr(node, &node_addr); - if (addrs_in_same_network_family(&node_addr, + if (router_addrs_in_same_network(&node_addr, &guard->bridge_addr->addr)) { return 1; } @@ -1576,12 +1576,12 @@ guard_create_exit_restriction(const uint8_t *exit_id) } /** If we have fewer than this many possible usable guards, don't set - * MD-availability-based restrictions: we might blacklist all of them. */ + * MD-availability-based restrictions: we might denylist all of them. */ #define MIN_GUARDS_FOR_MD_RESTRICTION 10 /** Return true if we should set md dirserver restrictions. We might not want * to set those if our guard options are too restricted, since we don't want - * to blacklist all of them. */ + * to denylist all of them. */ static int should_set_md_dirserver_restriction(void) { @@ -3359,7 +3359,7 @@ get_guard_state_for_bridge_desc_fetch(const char *digest) } /* Update the guard last_tried_to_connect time since it's checked by the - * guard susbsystem. */ + * guard subsystem. */ guard->last_tried_to_connect = approx_time(); /* Create the guard state */ diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c index 2bdc0ae151..4b05d55494 100644 --- a/src/feature/client/transports.c +++ b/src/feature/client/transports.c @@ -16,7 +16,7 @@ * managed proxies that are still unconfigured. * * In every run_scheduled_event() tick, we attempt to launch and then - * configure the unconfiged managed proxies, using the configuration + * configure the unconfigured managed proxies, using the configuration * protocol defined in the 180_pluggable_transport.txt proposal. A * managed proxy might need several ticks to get fully configured. * @@ -71,7 +71,7 @@ * * We then start parsing torrc again. * - * Everytime we encounter a transport line using a managed proxy that + * Every time we encounter a transport line using a managed proxy that * was around before the config read, we cleanse that proxy from the * removal mark. We also toggle the <b>check_if_restarts_needed</b> * flag, so that on the next <b>pt_configure_remaining_proxies</b> @@ -368,6 +368,28 @@ static int unconfigured_proxies_n = 0; /** Boolean: True iff we might need to restart some proxies. */ static int check_if_restarts_needed = 0; +/** Return true iff we have a managed_proxy_t in the global list is for the + * given transport name. */ +bool +managed_proxy_has_transport(const char *transport_name) +{ + tor_assert(transport_name); + + if (!managed_proxy_list) { + return false; + } + + SMARTLIST_FOREACH_BEGIN(managed_proxy_list, const managed_proxy_t *, mp) { + SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, const char *, name) { + if (!strcasecmp(name, transport_name)) { + return true; + } + } SMARTLIST_FOREACH_END(name); + } SMARTLIST_FOREACH_END(mp); + + return false; +} + /** Return true if there are still unconfigured managed proxies, or proxies * that need restarting. */ int @@ -1447,6 +1469,37 @@ create_managed_proxy_environment(const managed_proxy_t *mp) */ smartlist_add_asprintf(envs, "TOR_PT_EXIT_ON_STDIN_CLOSE=1"); + /* Specify which IPv4 and IPv6 addresses the PT should make its outgoing + * connections from. See: https://bugs.torproject.org/5304 for more + * information about this. */ + { + /* Set TOR_PT_OUTBOUND_BIND_ADDRESS_V4. */ + const tor_addr_t *ipv4_addr = managed_proxy_outbound_address(options, + AF_INET); + + /* managed_proxy_outbound_address() only returns a non-NULL value if + * tor_addr_is_null() was false, which means we don't have to check that + * here. */ + if (ipv4_addr) { + char *ipv4_addr_str = tor_addr_to_str_dup(ipv4_addr); + smartlist_add_asprintf(envs, + "TOR_PT_OUTBOUND_BIND_ADDRESS_V4=%s", + ipv4_addr_str); + tor_free(ipv4_addr_str); + } + + /* Set TOR_PT_OUTBOUND_BIND_ADDRESS_V6. */ + const tor_addr_t *ipv6_addr = managed_proxy_outbound_address(options, + AF_INET6); + if (ipv6_addr) { + char *ipv6_addr_str = tor_addr_to_str_dup(ipv6_addr); + smartlist_add_asprintf(envs, + "TOR_PT_OUTBOUND_BIND_ADDRESS_V6=[%s]", + ipv6_addr_str); + tor_free(ipv6_addr_str); + } + } + SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) { set_environment_variable_in_smartlist(merged_env_vars, env_var, tor_free_, 1); @@ -1643,17 +1696,26 @@ pt_get_extra_info_descriptor_string(void) SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) { char *transport_args = NULL; + const char *addrport = NULL; /* If the transport proxy returned "0.0.0.0" as its address, and * we know our external IP address, use it. Otherwise, use the * returned address. */ - const char *addrport = NULL; - uint32_t external_ip_address = 0; - if (tor_addr_is_null(&t->addr) && - router_pick_published_address(get_options(), - &external_ip_address, 0) >= 0) { + if (tor_addr_is_null(&t->addr)) { tor_addr_t addr; - tor_addr_from_ipv4h(&addr, external_ip_address); + /* Attempt to find the IPv4 and then attempt to find the IPv6 if we + * can't find it. */ + bool found = relay_find_addr_to_publish(get_options(), AF_INET, + RELAY_FIND_ADDR_NO_FLAG, + &addr); + if (!found) { + found = relay_find_addr_to_publish(get_options(), AF_INET6, + RELAY_FIND_ADDR_NO_FLAG, &addr); + } + if (!found) { + log_err(LD_PT, "Unable to find address for transport %s", t->name); + continue; + } addrport = fmt_addrport(&addr, t->port); } else { addrport = fmt_addrport(&t->addr, t->port); @@ -1910,3 +1972,46 @@ managed_proxy_severity_parse(const char *severity) return -1; } + +/** Return the outbound address from the given <b>family</b>. Returns NULL if + * the user haven't specified a specific outbound address in either + * OutboundBindAddress or OutboundBindAddressPT. */ +STATIC const tor_addr_t * +managed_proxy_outbound_address(const or_options_t *options, sa_family_t family) +{ + tor_assert(options); + + const tor_addr_t *address = NULL; + int family_index; + + switch (family) { + case AF_INET: + family_index = 0; + break; + case AF_INET6: + family_index = 1; + break; + default: + /* LCOV_EXCL_START */ + tor_assert_unreached(); + return NULL; + /* LCOV_EXCL_STOP */ + } + + /* We start by checking if the user specified an address in + * OutboundBindAddressPT. */ + address = &options->OutboundBindAddresses[OUTBOUND_ADDR_PT][family_index]; + + if (! tor_addr_is_null(address)) + return address; + + /* We fallback to check if the user specified an address in + * OutboundBindAddress. */ + address = &options->OutboundBindAddresses[OUTBOUND_ADDR_ANY][family_index]; + + if (! tor_addr_is_null(address)) + return address; + + /* The user have not specified a preference for outgoing connections. */ + return NULL; +} diff --git a/src/feature/client/transports.h b/src/feature/client/transports.h index 1ed942c175..47b118e77b 100644 --- a/src/feature/client/transports.h +++ b/src/feature/client/transports.h @@ -41,6 +41,7 @@ void transport_free_(transport_t *transport); #define transport_free(tr) FREE_AND_NULL(transport_t, transport_free_, (tr)) MOCK_DECL(transport_t*, transport_get_by_name, (const char *name)); +bool managed_proxy_has_transport(const char *transport_name); MOCK_DECL(void, pt_kickstart_proxy, (const smartlist_t *transport_list, char **proxy_argv, @@ -149,6 +150,8 @@ STATIC void managed_proxy_stderr_callback(process_t *, const char *, size_t); STATIC bool managed_proxy_exit_callback(process_t *, process_exit_code_t); STATIC int managed_proxy_severity_parse(const char *); +STATIC const tor_addr_t *managed_proxy_outbound_address(const or_options_t *, + sa_family_t); #endif /* defined(PT_PRIVATE) */ |