From: Nick M. <ni...@us...> - 2010-01-20 17:57:12
|
Author: Nick Mathewson <ni...@to...> Date: Wed, 20 Jan 2010 12:56:54 -0500 Subject: Don't use a bind address for nameservers on loopback Commit: 8d4aaf9086b721c0379891ca4a1fea8736f19d8f If the user sets a bind address to use for nameservers, and a nameserver happens to be on 127.0.0.1, the nameserver will generally fail. This patch alters this behavior so that the bind address is only applied when the nameserver is on a non-loopback address. --- evdns.c | 3 ++- evutil.c | 22 ++++++++++++++++++++++ test/regress_util.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ util-internal.h | 7 +++++-- 4 files changed, 74 insertions(+), 3 deletions(-) diff --git a/evdns.c b/evdns.c index ab7c1c7..0d3906d 100644 --- a/evdns.c +++ b/evdns.c @@ -2448,7 +2448,8 @@ _evdns_nameserver_add_impl(struct evdns_base *base, const struct sockaddr *addre if (ns->socket < 0) { err = 1; goto out1; } evutil_make_socket_nonblocking(ns->socket); - if (base->global_outgoing_addrlen) { + if (base->global_outgoing_addrlen && + !evutil_sockaddr_is_loopback(address)) { if (bind(ns->socket, (struct sockaddr*)&base->global_outgoing_address, base->global_outgoing_addrlen) < 0) { diff --git a/evutil.c b/evutil.c index bfe554e..7bd7a8b 100644 --- a/evutil.c +++ b/evutil.c @@ -1849,3 +1849,25 @@ _evutil_weakrand(void) #endif } +int +evutil_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; + /* + int i; + for (i=0;i<14;++i) + if (sin6->sin6_addr.s6_addr[i] != 0) + return 1; + return sin6->sin6_addr.s6_addr[15] == 1; + */ + return !memcmp(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16); + } + return 0; +} + diff --git a/test/regress_util.c b/test/regress_util.c index 2476d7c..c949536 100644 --- a/test/regress_util.c +++ b/test/regress_util.c @@ -275,6 +275,50 @@ regress_sockaddr_port_parse(void *ptr) } } +static struct sa_pred_ent { + const char *parse; + + int is_loopback; +} sa_pred_entries[] = { + { "127.0.0.1", 1 }, + { "127.0.3.2", 1 }, + { "128.1.2.3", 0 }, + { "18.0.0.1", 0 }, + { "129.168.1.1", 0 }, + + { "::1", 1 }, + { "::0", 0 }, + { "f::1", 0 }, + { "::501", 0 }, + { NULL, 0 }, + +}; + +static void +test_evutil_sockaddr_predicates(void *ptr) +{ + struct sockaddr_storage ss; + int r, i; + + for (i=0; sa_pred_entries[i].parse; ++i) { + struct sa_pred_ent *ent = &sa_pred_entries[i]; + int len = sizeof(ss); + + r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, &len); + + if (r<0) { + TT_FAIL(("Couldn't parse %s!", ent->parse)); + continue; + } + + /* sockaddr_is_loopback */ + if (ent->is_loopback != evutil_sockaddr_is_loopback((struct sockaddr*)&ss)) { + TT_FAIL(("evutil_sockaddr_loopback(%s) not as expected", + ent->parse)); + } + } +} + static void test_evutil_strtoll(void *ptr) { @@ -758,6 +802,7 @@ struct testcase_t util_testcases[] = { { "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL }, { "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL }, { "sockaddr_port_parse", regress_sockaddr_port_parse, 0, NULL, NULL }, + { "sockaddr_predicates", test_evutil_sockaddr_predicates, 0,NULL,NULL }, { "evutil_snprintf", test_evutil_snprintf, 0, NULL, NULL }, { "evutil_strtoll", test_evutil_strtoll, 0, NULL, NULL }, { "evutil_casecmp", test_evutil_casecmp, 0, NULL, NULL }, diff --git a/util-internal.h b/util-internal.h index cd4afd1..5fcb86c 100644 --- a/util-internal.h +++ b/util-internal.h @@ -232,12 +232,15 @@ void evutil_adjust_hints_for_addrconfig(struct evutil_addrinfo *hints); int evutil_getaddrinfo_common(const char *nodename, const char *servname, struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum); -int -evutil_getaddrinfo_async(struct evdns_base *dns_base, +int evutil_getaddrinfo_async(struct evdns_base *dns_base, const char *nodename, const char *servname, const struct evutil_addrinfo *hints_in, void (*cb)(int, struct evutil_addrinfo *, void *), void *arg); +/** Return true iff sa is a looback address. (That is, it is 127.0.0.1/8, or + * ::1). */ +int evutil_sockaddr_is_loopback(const struct sockaddr *sa); + #ifdef __cplusplus } #endif -- 1.6.3 |