applications to do DNS resolves themselves is usually a bad idea and
can leak your location to attackers. (Default: 1)
-**VirtualAddrNetwork** __Address__/__bits__::
+**VirtualAddrNetworkIPv4** __Address__/__bits__ +
+
+**VirtualAddrNetworkIPv6** [__Address__]/__bits__::
When Tor needs to assign a virtual (unused) address because of a MAPADDRESS
command from the controller or the AutomapHostsOnResolve feature, Tor
- picks an unassigned address from this range. (Default:
- 127.192.0.0/10) +
+ picks an unassigned address from this range. (Defaults:
+ 127.192.0.0/10 and [FE80::]/10 respectively.) +
+
When providing proxy server service to a network of computers using a tool
- like dns-proxy-tor, change this address to "10.192.0.0/10" or
- "172.16.0.0/12". The default **VirtualAddrNetwork** address range on a
- properly configured machine will route to the loopback interface. For
+ like dns-proxy-tor, change the IPv4 network to "10.192.0.0/10" or
+ "172.16.0.0/12" and change the IPv6 network to "[FC00]/7".
+ The default **VirtualAddrNetwork** address ranges on a
+ properly configured machine will route to the loopback or link-local
+ interface. For
local use, no change to the default VirtualAddrNetwork setting is needed.
**AllowNonRFC953Hostnames** **0**|**1**::
* Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#define ADDRESSMAP_PRIVATE
+
#include "or.h"
#include "addressmap.h"
#include "circuituse.h"
/** Entry for mapping addresses to which virtual address we mapped them to. */
typedef struct {
char *ipv4_address;
+ char *ipv6_address;
char *hostname_address;
} virtaddress_entry_t;
/** A hash table to store client-side address rewrite instructions. */
static strmap_t *addressmap=NULL;
+
/**
* Table mapping addresses to which virtual address, if any, we
* assigned them to.
*
* These options are configured by parse_virtual_addr_network().
*/
-/** Which network should we use for virtual IPv4 addresses? Only the first
- * bits of this value are fixed. */
-static uint32_t virtual_addr_network = 0x7fc00000u;
-/** How many bits of <b>virtual_addr_network</b> are fixed? */
-static maskbits_t virtual_addr_netmask_bits = 10;
-/** What's the next virtual address we will hand out? */
-static uint32_t next_virtual_addr = 0x7fc00000u;
+
+static virtual_addr_conf_t virtaddr_conf_ipv4;
+static virtual_addr_conf_t virtaddr_conf_ipv6;
/** Read a netmask of the form 127.192.0.0/10 from "val", and check whether
* it's a valid set of virtual addresses to hand out in response to MAPADDRESS
* string and return -1 on failure. If validate_only is false, sets the
* actual virtual address range to the parsed value. */
int
-parse_virtual_addr_network(const char *val, int validate_only,
+parse_virtual_addr_network(const char *val, sa_family_t family,
+ int validate_only,
char **msg)
{
- uint32_t addr;
- uint16_t port_min, port_max;
+ const int ipv6 = (family == AF_INET6);
+ tor_addr_t addr;
maskbits_t bits;
+ const int max_bits = ipv6 ? 40 : 16;
+ virtual_addr_conf_t *conf = ipv6 ? &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
- if (parse_addr_and_port_range(val, &addr, &bits, &port_min, &port_max)) {
- if (msg) *msg = tor_strdup("Error parsing VirtualAddressNetwork");
+ if (tor_addr_parse_mask_ports(val, 0, &addr, &bits, NULL, NULL) < 0) {
+ if (msg)
+ tor_asprintf(msg, "Error parsing VirtualAddressNetwork%s %s",
+ ipv6?"IPv6":"", val);
return -1;
}
-
+ if (tor_addr_family(&addr) != family) {
+ if (msg)
+ tor_asprintf(msg, "Incorrect address type for VirtualAddressNetwork%s",
+ ipv6?"IPv6":"");
+ return -1;
+ }
+#if 0
if (port_min != 1 || port_max != 65535) {
- if (msg) *msg = tor_strdup("Can't specify ports on VirtualAddressNetwork");
+ if (msg)
+ tor_asprintf(msg, "Can't specify ports on VirtualAddressNetwork%s",
+ ipv6?"IPv6":"");
return -1;
}
+#endif
- if (bits > 16) {
- if (msg) *msg = tor_strdup("VirtualAddressNetwork expects a /16 "
- "network or larger");
+ if (bits > max_bits) {
+ if (msg)
+ tor_asprintf(msg, "VirtualAddressNetwork%s expects a /%d "
+ "network or larger",ipv6?"IPv6":"", max_bits);
return -1;
}
if (validate_only)
return 0;
- virtual_addr_network = (uint32_t)( addr & (0xfffffffful << (32-bits)) );
- virtual_addr_netmask_bits = bits;
-
- if (addr_mask_cmp_bits(next_virtual_addr, addr, bits))
- next_virtual_addr = addr;
+ tor_addr_copy(&conf->addr, &addr);
+ conf->bits = bits;
return 0;
}
int
address_is_in_virtual_range(const char *address)
{
- struct in_addr in;
+ tor_addr_t addr;
tor_assert(address);
if (!strcasecmpend(address, ".virtual")) {
return 1;
- } else if (tor_inet_aton(address, &in)) {
- uint32_t addr = ntohl(in.s_addr);
- if (!addr_mask_cmp_bits(addr, virtual_addr_network,
- virtual_addr_netmask_bits))
+ } else if (tor_addr_parse(&addr, address) >= 0) {
+ const virtual_addr_conf_t *conf = (tor_addr_family(&addr) == AF_INET6) ?
+ &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
+ if (tor_addr_compare_masked(&addr, &conf->addr, conf->bits, CMP_EXACT)==0)
return 1;
}
return 0;
}
-/** Increment the value of next_virtual_addr; reset it to the start of the
- * virtual address range if it wraps around.
+/** Return a random address conforming to the virtual address configuration
+ * in <b>conf</b>.
*/
-static INLINE void
-increment_virtual_addr(void)
+/* private */ void
+get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
{
- ++next_virtual_addr;
- if (addr_mask_cmp_bits(next_virtual_addr, virtual_addr_network,
- virtual_addr_netmask_bits))
- next_virtual_addr = virtual_addr_network;
+ uint8_t tmp[4];
+ const uint8_t *addr_bytes;
+ uint8_t bytes[16];
+ const int ipv6 = tor_addr_family(&conf->addr) == AF_INET6;
+ const int total_bytes = ipv6 ? 16 : 4;
+
+ tor_assert(conf->bits <= total_bytes * 8);
+
+ /* Set addr_bytes to the bytes of the virtual network, in host order */
+ if (ipv6) {
+ addr_bytes = tor_addr_to_in6_addr8(&conf->addr);
+ } else {
+ set_uint32(tmp, tor_addr_to_ipv4n(&conf->addr));
+ addr_bytes = tmp;
+ }
+
+ /* Get an appropriate number of random bytes. */
+ crypto_rand((char*)bytes, total_bytes);
+
+ /* Now replace the first "conf->bits" bits of 'bytes' with addr_bytes*/
+ if (conf->bits >= 8)
+ memcpy(bytes, addr_bytes, conf->bits / 8);
+ if (conf->bits & 7) {
+ uint8_t mask = 0xff >> (conf->bits & 7);
+ bytes[conf->bits/8] &= mask;
+ bytes[conf->bits/8] |= addr_bytes[conf->bits/8] & ~mask;
+ }
+
+ if (ipv6)
+ tor_addr_from_ipv6_bytes(addr_out, (char*) bytes);
+ else
+ tor_addr_from_ipv4n(addr_out, get_uint32(bytes));
+
+ tor_assert(tor_addr_compare_masked(addr_out, &conf->addr,
+ conf->bits, CMP_EXACT)==0);
}
/** Return a newly allocated string holding an address of <b>type</b>
strlcat(buf, ".virtual", sizeof(buf));
} while (strmap_get(addressmap, buf));
return tor_strdup(buf);
- } else if (type == RESOLVED_TYPE_IPV4) {
+ } else if (type == RESOLVED_TYPE_IPV4 || type == RESOLVED_TYPE_IPV6) {
+ const int ipv6 = (type == RESOLVED_TYPE_IPV6);
+ const virtual_addr_conf_t *conf = ipv6 ?
+ &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
+
// This is an imperfect estimate of how many addresses are available, but
- // that's ok.
- struct in_addr in;
- uint32_t available = 1u << (32-virtual_addr_netmask_bits);
- while (available) {
- /* Don't hand out any .0 or .255 address. */
- while ((next_virtual_addr & 0xff) == 0 ||
- (next_virtual_addr & 0xff) == 0xff) {
- increment_virtual_addr();
- if (! --available) {
- log_warn(LD_CONFIG, "Ran out of virtual addresses!");
- return NULL;
- }
+ // that's ok. We also don't try every one.
+ uint32_t attempts = ipv6 ? UINT32_MAX : (1u << (32- conf->bits));
+
+ tor_addr_t addr;
+
+ while (attempts--) {
+ get_random_virtual_addr(conf, &addr);
+
+ if (!ipv6) {
+ /* Don't hand out any .0 or .255 address. */
+ const uint32_t a = tor_addr_to_ipv4h(&addr);
+ if ((a & 0xff) == 0 || (a & 0xff) == 0xff)
+ continue;
}
- in.s_addr = htonl(next_virtual_addr);
- tor_inet_ntoa(&in, buf, sizeof(buf));
+
+ tor_addr_to_str(buf, &addr, sizeof(buf), 1);
if (!strmap_get(addressmap, buf)) {
- increment_virtual_addr();
- break;
- }
+ /* XXXX This code is to make sure I didn't add an undecorated version
+ * by mistake. I hope it's needless. */
+ char tmp[TOR_ADDR_BUF_LEN];
+ tor_addr_to_str(buf, &addr, sizeof(tmp), 0);
+ if (strmap_get(addressmap, tmp)) {
+ log_warn(LD_BUG, "%s wasn't in the addressmap, but %s was.",
+ buf, tmp);
+ continue;
+ }
- increment_virtual_addr();
- --available;
- // log_info(LD_CONFIG, "%d addrs available", (int)available);
- if (! available) {
- log_warn(LD_CONFIG, "Ran out of virtual addresses!");
- return NULL;
+ return tor_strdup(buf);
}
}
- return tor_strdup(buf);
+ log_warn(LD_CONFIG, "Ran out of virtual addresses!");
+ return NULL;
} else {
log_warn(LD_BUG, "Called with unsupported address type (%d)", type);
return NULL;
vent_needs_to_be_added = 1;
}
- addrp = (type == RESOLVED_TYPE_IPV4) ?
- &vent->ipv4_address : &vent->hostname_address;
+ if (type == RESOLVED_TYPE_IPV4)
+ addrp = &vent->ipv4_address;
+ else if (type == RESOLVED_TYPE_IPV6)
+ addrp = &vent->ipv6_address;
+ else
+ addrp = &vent->hostname_address;
+
if (*addrp) {
addressmap_entry_t *ent = strmap_get(addressmap, *addrp);
if (ent && ent->new_address &&
tor_free(new_address);
tor_assert(!vent_needs_to_be_added);
return tor_strdup(*addrp);
- } else
+ } else {
log_warn(LD_BUG,
"Internal confusion: I thought that '%s' was mapped to by "
"'%s', but '%s' really maps to '%s'. This is a harmless bug.",
safe_str_client(*addrp),
safe_str_client(*addrp),
ent?safe_str_client(ent->new_address):"(nothing)");
+ }
}
tor_free(*addrp);
time_t expires, addressmap_entry_source_t source,
const int address_wildcard,
const int new_address_wildcard);
-int parse_virtual_addr_network(const char *val, int validate_only,
+int parse_virtual_addr_network(const char *val,
+ sa_family_t family, int validate_only,
char **msg);
int client_dns_incr_failures(const char *address);
void client_dns_clear_failures(const char *address);
int addressmap_address_should_automap(const char *address,
const or_options_t *options);
+#ifdef ADDRESSMAP_PRIVATE
+typedef struct virtual_addr_conf_t {
+ tor_addr_t addr;
+ maskbits_t bits;
+} virtual_addr_conf_t;
+
+void get_random_virtual_addr(const virtual_addr_conf_t *conf,
+ tor_addr_t *addr_out);
+#endif
+
#endif
{ "HashedControlPassword", "__HashedControlSessionPassword", 1, 0},
{ "StrictEntryNodes", "StrictNodes", 0, 1},
{ "StrictExitNodes", "StrictNodes", 0, 1},
+ { "VirtualAddrNetwork", "VirtualAddrNetworkIPv4", 0, 0},
{ "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1},
{ NULL, NULL, 0, 0},
};
V(V3AuthUseLegacyKey, BOOL, "0"),
V(V3BandwidthsFile, FILENAME, NULL),
VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
- V(VirtualAddrNetwork, STRING, "127.192.0.0/10"),
+ V(VirtualAddrNetworkIPv4, STRING, "127.192.0.0/10"),
+ V(VirtualAddrNetworkIPv6, STRING, "[FE80::]/10"),
V(WarnPlaintextPorts, CSV, "23,109,110,143"),
V(UseFilteringSSLBufferevents, BOOL, "0"),
VAR("__ReloadTorrcOnSIGHUP", BOOL, ReloadTorrcOnSIGHUP, "1"),
/* Register addressmap directives */
config_register_addressmaps(options);
- parse_virtual_addr_network(options->VirtualAddrNetwork, 0, NULL);
+ parse_virtual_addr_network(options->VirtualAddrNetworkIPv4, AF_INET,0,NULL);
+ parse_virtual_addr_network(options->VirtualAddrNetworkIPv6, AF_INET6,0,NULL);
/* Update address policies. */
if (policies_parse_from_options(options) < 0) {
if (!smartlist_strings_eq(old_options->AutomapHostsSuffixes,
options->AutomapHostsSuffixes))
revise_automap_entries = 1;
- else if (!opt_streq(old_options->VirtualAddrNetwork,
- options->VirtualAddrNetwork))
+ else if (!opt_streq(old_options->VirtualAddrNetworkIPv4,
+ options->VirtualAddrNetworkIPv4) ||
+ !opt_streq(old_options->VirtualAddrNetworkIPv6,
+ options->VirtualAddrNetworkIPv6))
revise_automap_entries = 1;
}
REJECT("Failed to configure client authorization for hidden services. "
"See logs for details.");
- if (parse_virtual_addr_network(options->VirtualAddrNetwork, 1, NULL)<0)
+ if (parse_virtual_addr_network(options->VirtualAddrNetworkIPv4,
+ AF_INET, 1, msg)<0)
+ return -1;
+ if (parse_virtual_addr_network(options->VirtualAddrNetworkIPv6,
+ AF_INET6, 1, msg)<0)
return -1;
if (options->PreferTunneledDirConns && !options->TunnelDirConns)
socks_request_t *socks = conn->socks_request;
hostname_type_t addresstype;
const or_options_t *options = get_options();
- struct in_addr addr_tmp;
+ tor_addr_t addr_tmp;
/* We set this to true if this is an address we should automatically
* remap to a local address in VirtualAddrNetwork */
int automap = 0;
conn->original_dest_address = tor_strdup(conn->socks_request->address);
if (socks->command == SOCKS_COMMAND_RESOLVE &&
- !tor_inet_aton(socks->address, &addr_tmp) &&
+ tor_addr_parse(&addr_tmp, socks->address)<0 &&
options->AutomapHostsOnResolve) {
automap = addressmap_address_should_automap(socks->address, options);
if (automap) {
const char *new_addr;
+ /*XXXX IPv6 Sometimes this should be RESOLVED_TYPE_IPV6 */
new_addr = addressmap_register_virtual_address(
RESOLVED_TYPE_IPV4, tor_strdup(socks->address));
if (! new_addr) {
"512-syntax error: invalid address '%s'", to);
log_warn(LD_CONTROL,
"Skipping invalid argument '%s' in MapAddress msg", to);
- } else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0")) {
+ } else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0") ||
+ !strcmp(from, "::")) {
+ const char type =
+ !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME :
+ (!strcmp(from, "0.0.0.0") ? RESOLVED_TYPE_IPV4 : RESOLVED_TYPE_IPV6);
const char *address = addressmap_register_virtual_address(
- !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : RESOLVED_TYPE_IPV4,
- tor_strdup(to));
+ type, tor_strdup(to));
if (!address) {
smartlist_add_asprintf(reply,
"451-resource exhausted: skipping '%s'", line);
/** Should we fetch our dir info at the start of the consensus period? */
int FetchDirInfoExtraEarly;
- char *VirtualAddrNetwork; /**< Address and mask to hand out for virtual
- * MAPADDRESS requests. */
+ char *VirtualAddrNetworkIPv4; /**< Address and mask to hand out for virtual
+ * MAPADDRESS requests for IPv4 addresses */
+ char *VirtualAddrNetworkIPv6; /**< Address and mask to hand out for virtual
+ * MAPADDRESS requests for IPv6 addresses */
int ServerDNSSearchDomains; /**< Boolean: If set, we don't force exit
* addresses to be FQDNs, but rather search for them in
* the local domains. */
* Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#define ADDRESSMAP_PRIVATE
#include "orconfig.h"
#include "or.h"
#include "test.h"
+#include "addressmap.h"
static void
test_addr_basic(void)
;
}
+static void
+update_difference(int ipv6, uint8_t *d,
+ const tor_addr_t *a, const tor_addr_t *b)
+{
+ const int n_bytes = ipv6 ? 16 : 4;
+ uint8_t a_tmp[4], b_tmp[4];
+ const uint8_t *ba, *bb;
+ int i;
+
+ if (ipv6) {
+ ba = tor_addr_to_in6_addr8(a);
+ bb = tor_addr_to_in6_addr8(b);
+ } else {
+ set_uint32(a_tmp, tor_addr_to_ipv4n(a));
+ set_uint32(b_tmp, tor_addr_to_ipv4n(b));
+ ba = a_tmp; bb = b_tmp;
+ }
+
+ for (i = 0; i < n_bytes; ++i) {
+ d[i] |= ba[i] ^ bb[i];
+ }
+}
+
+static void
+test_virtaddrmap(void *data)
+{
+ /* Let's start with a bunch of random addresses. */
+ int ipv6, bits, iter, b;
+ virtual_addr_conf_t cfg[2];
+ uint8_t bytes[16];
+
+ (void)data;
+
+ tor_addr_parse(&cfg[0].addr, "64.65.0.0");
+ tor_addr_parse(&cfg[1].addr, "3491:c0c0::");
+
+ for (ipv6 = 0; ipv6 <= 1; ++ipv6) {
+ for (bits = 0; bits < 18; ++bits) {
+ tor_addr_t last_a;
+ cfg[ipv6].bits = bits;
+ memset(bytes, 0, sizeof(bytes));
+ tor_addr_copy(&last_a, &cfg[ipv6].addr);
+ /* Generate 128 addresses with each addr/bits combination. */
+ for (iter = 0; iter < 128; ++iter) {
+ tor_addr_t a;
+
+ get_random_virtual_addr(&cfg[ipv6], &a);
+ //printf("%s\n", fmt_addr(&a));
+ /* Make sure that the first b bits match the configured network */
+ tt_int_op(0, ==, tor_addr_compare_masked(&a, &cfg[ipv6].addr,
+ bits, CMP_EXACT));
+
+ /* And track which bits have been different between pairs of
+ * addresses */
+ update_difference(ipv6, bytes, &last_a, &a);
+ }
+
+ /* Now make sure all but the first 'bits' bits of bytes are true */
+ for (b = bits+1; b < (ipv6?128:32); ++b) {
+ tt_assert(1 & (bytes[b/8] >> (7-(b&7))));
+ }
+ }
+ }
+
+ done:
+ ;
+}
+
#define ADDR_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_addr_ ## name }
ADDR_LEGACY(basic),
ADDR_LEGACY(ip6_helpers),
ADDR_LEGACY(parse),
+ { "virtaddr", test_virtaddrmap, 0, NULL, NULL },
END_OF_TESTCASES
};