Don't use OutboundBindAddress to connect to localhost

The OutboundBindAddress option is useful for making sure that all of
your outbond connections use a given interface.  But when connecting
to 127.0.0.1 (or ::1 even) it's important to actually have the
connection come _from_ localhost, since lots of programs running on
localhost use the source address to authenticate that the connection
is really coming from the same host.

Our old code always bound to OutboundBindAddress, whether connecting
to localhost or not.  This would potentially break DNS servers on
localhost, and socks proxies on localhost.  This patch changes the
behavior so that we only look at OutboundBindAddress when connecting
to a non-loopback address.
This commit is contained in:
Nick Mathewson 2010-01-20 12:36:14 -05:00
parent c939509051
commit d4354b506b
3 changed files with 26 additions and 2 deletions

View File

@ -1,3 +1,11 @@
Changes in version 0.2.2.8-alpha - 2010-??-??
o Minor bugfixes:
- Ignore OutboundBindAddress when connecting to localhost.
Connections to localhost need to come _from_ localhost, or else
local servers (like DNS and outgoing HTTP/SOCKS proxies) will often
refuse to listen.
Changes in version 0.2.1.23 - 2010-0?-?? Changes in version 0.2.1.23 - 2010-0?-??
o Major bugfixes (performance): o Major bugfixes (performance):
- We were selecting our guards uniformly at random, and then weighting - We were selecting our guards uniformly at random, and then weighting

View File

@ -1236,7 +1236,7 @@ connection_connect(connection_t *conn, const char *address,
return -1; return -1;
} }
if (options->OutboundBindAddress) { if (options->OutboundBindAddress && !tor_addr_is_loopback(addr)) {
struct sockaddr_in ext_addr; struct sockaddr_in ext_addr;
memset(&ext_addr, 0, sizeof(ext_addr)); memset(&ext_addr, 0, sizeof(ext_addr));

View File

@ -2238,6 +2238,21 @@ evdns_resume(void)
return 0; return 0;
} }
static int
sockaddr_is_loopback(const struct sockaddr *addr)
{
static const char LOOPBACK_S6[16] =
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1";
if (addr->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
return (ntohl(sin->sin_addr.s_addr) & 0xff000000) == 0x7f000000;
} else if (addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
return !memcmp(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16);
}
return 0;
}
static int static int
_evdns_nameserver_add_impl(const struct sockaddr *address, _evdns_nameserver_add_impl(const struct sockaddr *address,
socklen_t addrlen) { socklen_t addrlen) {
@ -2279,7 +2294,8 @@ _evdns_nameserver_add_impl(const struct sockaddr *address,
fcntl(ns->socket, F_SETFL, O_NONBLOCK); fcntl(ns->socket, F_SETFL, O_NONBLOCK);
#endif #endif
if (global_bind_addr_is_set) { if (global_bind_addr_is_set &&
!sockaddr_is_loopback((struct sockaddr*)&global_bind_address)) {
if (bind(ns->socket, (struct sockaddr *)&global_bind_address, if (bind(ns->socket, (struct sockaddr *)&global_bind_address,
global_bind_addrlen) < 0) { global_bind_addrlen) < 0) {
log(EVDNS_LOG_DEBUG, "Couldn't bind to outgoing address."); log(EVDNS_LOG_DEBUG, "Couldn't bind to outgoing address.");