Make option OutboundBindAddress accept IPv6 addresses too.

Implements ticket 6786.
This commit is contained in:
Linus Nordberg 2012-09-20 17:09:25 +02:00
parent cff3b8c93c
commit 1cbf45bed1
4 changed files with 103 additions and 21 deletions

View File

@ -472,8 +472,10 @@ GENERAL OPTIONS
**OutboundBindAddress** __IP__::
Make all outbound connections originate from the IP address specified. This
is only useful when you have multiple network interfaces, and you want all
of Tor's outgoing connections to use a single one. This setting will be
ignored for connections to the loopback addresses (127.0.0.0/8 and ::1).
of Tor's outgoing connections to use a single one. This option may
be used twice, once with an IPv4 address and once with an IPv6 address.
This setting will be ignored for connections to the loopback addresses
(127.0.0.0/8 and ::1).
**PidFile** __FILE__::
On startup, write our PID to FILE. On clean shutdown, remove

View File

@ -302,7 +302,7 @@ static config_var_t _option_vars[] = {
V(NumEntryGuards, UINT, "3"),
V(ORListenAddress, LINELIST, NULL),
VPORT(ORPort, LINELIST, NULL),
V(OutboundBindAddress, STRING, NULL),
V(OutboundBindAddress, LINELIST, NULL),
V(PathBiasCircThreshold, INT, "-1"),
V(PathBiasNoticeRate, DOUBLE, "-1"),
@ -474,6 +474,8 @@ static int options_init_logs(or_options_t *options, int validate_only);
static void init_libevent(const or_options_t *options);
static int opt_streq(const char *s1, const char *s2);
static int parse_outbound_addresses(or_options_t *options, int validate_only,
char **msg);
/** Magic value for or_options_t. */
#define OR_OPTIONS_MAGIC 9090909
@ -1390,6 +1392,12 @@ options_act(const or_options_t *old_options)
tor_free(http_authenticator);
}
if (parse_outbound_addresses(options, 0, &msg) < 0) {
log_warn(LD_BUG, "Failed parsing oubound bind addresses: %s", msg);
tor_free(msg);
return -1;
}
/* Check for transitions that need action. */
if (old_options) {
int revise_trackexithosts = 0;
@ -2164,6 +2172,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (parse_ports(options, 1, msg, &n_ports) < 0)
return -1;
if (parse_outbound_addresses(options, 1, msg) < 0)
return -1;
if (validate_data_directory(options)<0)
REJECT("Invalid DataDirectory");
@ -5482,3 +5493,57 @@ getinfo_helper_config(control_connection_t *conn,
return 0;
}
/** Parse outbound bind address option lines. If <b>validate_only</b>
* is not 0 update _OutboundBindAddressIPv4 and
* _OutboundBindAddressIPv6 in <b>options</b>. On failure, set
* <b>msg</b> (if provided) to a newly allocated string containing a
* description of the problem and return -1. */
static int
parse_outbound_addresses(or_options_t *options, int validate_only, char **msg)
{
const config_line_t *lines = options->OutboundBindAddress;
int found_v4 = 0, found_v6 = 0;
if (!validate_only) {
memset(&options->_OutboundBindAddressIPv4, 0,
sizeof(options->_OutboundBindAddressIPv4));
memset(&options->_OutboundBindAddressIPv6, 0,
sizeof(options->_OutboundBindAddressIPv6));
}
while (lines) {
tor_addr_t addr, *dst_addr = NULL;
int af = tor_addr_parse(&addr, lines->value);
switch (af) {
case AF_INET:
if (found_v4) {
if (msg)
tor_asprintf(msg, "Multiple IPv4 outbound bind addresses "
"configured: %s", lines->value);
return -1;
}
found_v4 = 1;
dst_addr = &options->_OutboundBindAddressIPv4;
break;
case AF_INET6:
if (found_v6) {
if (msg)
tor_asprintf(msg, "Multiple IPv6 outbound bind addresses "
"configured: %s", lines->value);
return -1;
}
found_v6 = 1;
dst_addr = &options->_OutboundBindAddressIPv6;
break;
default:
if (msg)
tor_asprintf(msg, "Outbound bind address '%s' didn't parse.",
lines->value);
return -1;
}
if (!validate_only)
tor_addr_copy(dst_addr, &addr);
lines = lines->next;
}
return 0;
}

View File

@ -1377,26 +1377,37 @@ connection_connect(connection_t *conn, const char *address,
make_socket_reuseable(s);
if (options->OutboundBindAddress && !tor_addr_is_loopback(addr)) {
struct sockaddr_in ext_addr;
memset(&ext_addr, 0, sizeof(ext_addr));
ext_addr.sin_family = AF_INET;
ext_addr.sin_port = 0;
if (!tor_inet_aton(options->OutboundBindAddress, &ext_addr.sin_addr)) {
log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
options->OutboundBindAddress);
if (!tor_addr_is_loopback(addr)) {
const tor_addr_t *ext_addr = NULL;
if (protocol_family == AF_INET &&
!tor_addr_is_null(&options->_OutboundBindAddressIPv4))
ext_addr = &options->_OutboundBindAddressIPv4;
else if (protocol_family == AF_INET6 &&
!tor_addr_is_null(&options->_OutboundBindAddressIPv6))
ext_addr = &options->_OutboundBindAddressIPv6;
if (ext_addr) {
struct sockaddr_storage ext_addr_sa;
socklen_t ext_addr_len = 0;
memset(&ext_addr_sa, 0, sizeof(ext_addr_sa));
ext_addr_len = tor_addr_to_sockaddr(ext_addr, 0,
(struct sockaddr *) &ext_addr_sa,
sizeof(ext_addr_sa));
if (ext_addr_len == 0) {
log_warn(LD_NET,
"Error converting OutboundBindAddress %s into sockaddr. "
"Ignoring.", fmt_addr(ext_addr));
} else {
if (bind(s, (struct sockaddr*)&ext_addr,
(socklen_t)sizeof(ext_addr)) < 0) {
if (bind(s, (struct sockaddr *) &ext_addr_sa, ext_addr_len) < 0) {
*socket_error = tor_socket_errno(s);
log_warn(LD_NET,"Error binding network socket: %s",
log_warn(LD_NET,"Error binding network socket to %s: %s",
fmt_addr(ext_addr),
tor_socket_strerror(*socket_error));
tor_close_socket(s);
return -1;
}
}
}
}
set_socket_nonblocking(s);

View File

@ -3028,7 +3028,11 @@ typedef struct {
/** Addresses to bind for listening for control connections. */
config_line_t *ControlListenAddress;
/** Local address to bind outbound sockets */
char *OutboundBindAddress;
config_line_t *OutboundBindAddress;
/** IPv4 address derived from OutboundBindAddress. */
tor_addr_t _OutboundBindAddressIPv4;
/** IPv6 address derived from OutboundBindAddress. */
tor_addr_t _OutboundBindAddressIPv6;
/** Directory server only: which versions of
* Tor should we tell users to run? */
config_line_t *RecommendedVersions;