Commit c3a0f757 authored by David Goulet's avatar David Goulet
Browse files

relay: Automatically Enable an IPv6 ORPort



This commit makes it that if the ORPort is set with a single port, it will
bind to both global listen IPv4 and IPv6 addresses.

To pin an "ORPort <PORT>" to be IPv4 or IPv6, the IPv4Only/IPv6Only flags are
honored thus this will _only_ bind on IPv6 for that port value:

  ORPort 9050 IPv6Only
    Results in: [::]:9050

  ORPort 9051 IPv4Only
    Results in: [0.0.0.0]:9051

Attempting to configure an explicit IPv4 address with IPv6Only flag is an
error and vice versa.

Closes #33246
Signed-off-by: David Goulet's avatarDavid Goulet <dgoulet@torproject.org>
parent 354eb0c0
o Major feature (relay, IPv6):
- Relays now automatically bind on IPv6 for their ORPort unless specified
otherwise with the IPv4Only flag. Closes ticket 33246.
...@@ -5831,6 +5831,15 @@ port_parse_config(smartlist_t *out, ...@@ -5831,6 +5831,15 @@ port_parse_config(smartlist_t *out,
int got_zero_port=0, got_nonzero_port=0; int got_zero_port=0, got_nonzero_port=0;
char *unix_socket_path = NULL; char *unix_socket_path = NULL;
port_cfg_t *cfg = NULL; port_cfg_t *cfg = NULL;
bool addr_is_explicit = false;
int family = -1;
/* Parse default address. This can fail for Unix socket for instance so
* family can be -1 and the default_addr will be made UNSPEC. */
tor_addr_t default_addr = TOR_ADDR_NULL;
if (defaultaddr) {
family = tor_addr_parse(&default_addr, defaultaddr);
}
/* If there's no FooPort, then maybe make a default one. */ /* If there's no FooPort, then maybe make a default one. */
if (! ports) { if (! ports) {
...@@ -5907,8 +5916,8 @@ port_parse_config(smartlist_t *out, ...@@ -5907,8 +5916,8 @@ port_parse_config(smartlist_t *out,
port = 1; port = 1;
} else if (!strcasecmp(addrport, "auto")) { } else if (!strcasecmp(addrport, "auto")) {
port = CFG_AUTO_PORT; port = CFG_AUTO_PORT;
int af = tor_addr_parse(&addr, defaultaddr); tor_assert(family >= 0);
tor_assert(af >= 0); tor_addr_copy(&addr, &default_addr);
} else if (!strcasecmpend(addrport, ":auto")) { } else if (!strcasecmpend(addrport, ":auto")) {
char *addrtmp = tor_strndup(addrport, strlen(addrport)-5); char *addrtmp = tor_strndup(addrport, strlen(addrport)-5);
port = CFG_AUTO_PORT; port = CFG_AUTO_PORT;
...@@ -5924,14 +5933,20 @@ port_parse_config(smartlist_t *out, ...@@ -5924,14 +5933,20 @@ port_parse_config(smartlist_t *out,
"9050" might be a valid address. */ "9050" might be a valid address. */
port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL); port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL);
if (ok) { if (ok) {
int af = tor_addr_parse(&addr, defaultaddr); tor_assert(family >= 0);
tor_assert(af >= 0); tor_addr_copy(&addr, &default_addr);
} else if (tor_addr_port_lookup(addrport, &addr, &ptmp) == 0) { } else if (tor_addr_port_lookup(addrport, &addr, &ptmp) == 0) {
if (ptmp == 0) { if (ptmp == 0) {
log_warn(LD_CONFIG, "%sPort line has address but no port", portname); log_warn(LD_CONFIG, "%sPort line has address but no port", portname);
goto err; goto err;
} }
if (family != -1 && tor_addr_family(&addr) != family) {
/* This means we are parsing another ORPort family but we are
* attempting to find the default address' family ORPort. */
goto ignore;
}
port = ptmp; port = ptmp;
addr_is_explicit = true;
} else { } else {
log_warn(LD_CONFIG, "Couldn't parse address %s for %sPort", log_warn(LD_CONFIG, "Couldn't parse address %s for %sPort",
escaped(addrport), portname); escaped(addrport), portname);
...@@ -5942,6 +5957,7 @@ port_parse_config(smartlist_t *out, ...@@ -5942,6 +5957,7 @@ port_parse_config(smartlist_t *out,
/* Default port_cfg_t object initialization */ /* Default port_cfg_t object initialization */
cfg = port_cfg_new(unix_socket_path ? strlen(unix_socket_path) : 0); cfg = port_cfg_new(unix_socket_path ? strlen(unix_socket_path) : 0);
cfg->explicit_addr = addr_is_explicit;
if (unix_socket_path && default_to_group_writable) if (unix_socket_path && default_to_group_writable)
cfg->is_group_writable = 1; cfg->is_group_writable = 1;
...@@ -5984,15 +6000,25 @@ port_parse_config(smartlist_t *out, ...@@ -5984,15 +6000,25 @@ port_parse_config(smartlist_t *out,
} }
if (cfg->server_cfg.bind_ipv4_only && if (cfg->server_cfg.bind_ipv4_only &&
tor_addr_family(&addr) != AF_INET) { tor_addr_family(&addr) != AF_INET) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4", if (cfg->explicit_addr) {
portname); log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
goto err; portname);
goto err;
}
/* This ORPort is IPv4Only but the default address is IPv6, ignore it
* since this will be configured with an IPv4 default address. */
goto ignore;
} }
if (cfg->server_cfg.bind_ipv6_only && if (cfg->server_cfg.bind_ipv6_only &&
tor_addr_family(&addr) != AF_INET6) { tor_addr_family(&addr) != AF_INET6) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6", if (cfg->explicit_addr) {
portname); log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
goto err; portname);
goto err;
}
/* This ORPort is IPv6Only but the default address is IPv4, ignore it
* since this will be configured with an IPv6 default address. */
goto ignore;
} }
} else { } else {
/* This is a client port; parse isolation options */ /* This is a client port; parse isolation options */
...@@ -6205,9 +6231,10 @@ port_parse_config(smartlist_t *out, ...@@ -6205,9 +6231,10 @@ port_parse_config(smartlist_t *out,
smartlist_add(out, cfg); smartlist_add(out, cfg);
/* out owns cfg now, don't re-use or free it */ /* out owns cfg now, don't re-use or free it */
cfg = NULL; cfg = NULL;
} else {
tor_free(cfg);
} }
ignore:
tor_free(cfg);
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_clear(elts); smartlist_clear(elts);
tor_free(addrport); tor_free(addrport);
......
...@@ -26,6 +26,8 @@ struct port_cfg_t { ...@@ -26,6 +26,8 @@ struct port_cfg_t {
unsigned is_group_writable : 1; unsigned is_group_writable : 1;
unsigned is_world_writable : 1; unsigned is_world_writable : 1;
unsigned relax_dirmode_check : 1; unsigned relax_dirmode_check : 1;
unsigned explicit_addr : 1; /** Indicate if address was explicitly set or
* we are using the default address. */
entry_port_cfg_t entry_cfg; entry_port_cfg_t entry_cfg;
......
...@@ -270,6 +270,14 @@ port_parse_ports_relay(or_options_t *options, ...@@ -270,6 +270,14 @@ port_parse_ports_relay(or_options_t *options,
*msg = tor_strdup("Invalid ORPort configuration"); *msg = tor_strdup("Invalid ORPort configuration");
goto err; goto err;
} }
if (port_parse_config(ports,
options->ORPort_lines,
"OR", CONN_TYPE_OR_LISTENER,
"[::]", 0,
CL_PORT_SERVER_OPTIONS) < 0) {
*msg = tor_strdup("Invalid ORPort configuration");
goto err;
}
if (port_parse_config(ports, if (port_parse_config(ports,
options->ExtORPort_lines, options->ExtORPort_lines,
"ExtOR", CONN_TYPE_EXT_OR_LISTENER, "ExtOR", CONN_TYPE_EXT_OR_LISTENER,
......
...@@ -5162,6 +5162,44 @@ test_config_parse_port_config__ports__server_options(void *data) ...@@ -5162,6 +5162,44 @@ test_config_parse_port_config__ports__server_options(void *data)
0, CL_PORT_SERVER_OPTIONS); 0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1); tt_int_op(ret, OP_EQ, -1);
/* Default address is IPv4 but pass IPv6Only flag. Should be ignored. */
config_free_lines(config_port_invalid); config_port_invalid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("ORPort", "9050 IPv6Only");
ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
"127.0.0.1", 0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
/* Default address is IPv6 but pass IPv4Only flag. Should be ignored. */
config_free_lines(config_port_invalid); config_port_invalid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("ORPort", "9050 IPv4Only");
ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
"[::]", 0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
/* Explicit address is IPv6 but pass IPv4Only flag. Should error. */
config_free_lines(config_port_invalid); config_port_invalid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("ORPort",
"[4242::4242]:9050 IPv4Only");
ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
"[::]", 0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
/* Explicit address is IPv4 but pass IPv6Only flag. Should error. */
config_free_lines(config_port_invalid); config_port_invalid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("ORPort",
"1.2.3.4:9050 IPv6Only");
ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
"127.0.0.1", 0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
done: done:
if (slout) if (slout)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment