]> granicus.if.org Git - libevent/commitdiff
Don't use a bind address for nameservers on loopback
authorNick Mathewson <nickm@torproject.org>
Wed, 20 Jan 2010 17:56:54 +0000 (12:56 -0500)
committerNick Mathewson <nickm@torproject.org>
Wed, 20 Jan 2010 17:56:54 +0000 (12:56 -0500)
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
evutil.c
test/regress_util.c
util-internal.h

diff --git a/evdns.c b/evdns.c
index ab7c1c75f5da007f9a7cf844504997f671badcc2..0d3906d4b27316ff16a2e357b05d2eff4dc22de6 100644 (file)
--- 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) {
index bfe554ed493439fdc40841f21bc1233e0d6c40d3..7bd7a8b3d718a575eba8994830407d0e948ff570 100644 (file)
--- 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;
+}
+
index 2476d7c0df5dc9db238faaf3c8c4a094877644fe..c949536bf7d9b30165b2b0316d153c0721a83ded 100644 (file)
@@ -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 },
index cd4afd195fa4136e85a0cb04c404bff0599ca639..5fcb86c869eee6e30c3c1287708125ada30099f3 100644 (file)
@@ -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