]> granicus.if.org Git - libevent/commitdiff
Change the type of nameserver.address from u32 to sockaddr_storage, so that we can...
authorNick Mathewson <nickm@torproject.org>
Fri, 2 Jan 2009 20:46:35 +0000 (20:46 +0000)
committerNick Mathewson <nickm@torproject.org>
Fri, 2 Jan 2009 20:46:35 +0000 (20:46 +0000)
svn:r985

ChangeLog
evdns.c

index b6b4ee1b9bdb8d56133bddcfbbee472be5fa5afe..19e3afc52781177da30b61e1e856a1115a7e85f6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -134,6 +134,7 @@ Changes in current version:
  o Make the http connection close detection work properly with bufferevents and fix a potential memory leak associated with it.
  o Restructure the event backends so that they do not need to keep track of events themselves, as a side effect multiple events can use the same fd or signal.
  o Add generic implementations for parsing and emiting IPv6 addresses on platforms that do not have inet_ntop and/or inet_pton.
+ o Allow DNS servers that have IPv6 addresses.
 
 Changes in 1.4.0:
  o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
diff --git a/evdns.c b/evdns.c
index f56f41ca0a5965eaacbcc466d7c093acaddc22b8..388eef7a10fcbb041a6e0e7113e3d7162bd9a55b 100644 (file)
--- a/evdns.c
+++ b/evdns.c
@@ -213,7 +213,7 @@ struct reply {
 
 struct nameserver {
        evutil_socket_t socket;  /* a connected UDP socket */
-       u32 address;
+       struct sockaddr_storage address;
        int failed_times;  /* number of times which we have given this server a chance */
        int timedout;  /* number of times in a row a request has timed out */
        struct event event;
@@ -405,6 +405,58 @@ debug_ntoa(u32 address)
        return buf;
 }
 
+static const char *
+debug_ntop(const struct sockaddr *sa)
+{
+       if (sa->sa_family == AF_INET) {
+               struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+               return debug_ntoa(sin->sin_addr.s_addr);
+       }
+#ifdef AF_INET6
+       if (sa->sa_family == AF_INET6) {
+               static char buf[128];
+               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
+               const char *result;
+               result = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof(buf));
+               return result ? result : "unknown";
+       }
+#endif
+       return "<unknown>";
+}
+
+static int
+sockaddr_eq(const struct sockaddr *sa1, const struct sockaddr *sa2,
+                       int include_port)
+{
+       if (sa1->sa_family != sa2->sa_family)
+               return 0;
+       if (sa1->sa_family == AF_INET) {
+               const struct sockaddr_in *sin1, *sin2;
+               sin1 = (const struct sockaddr_in *)sa1;
+               sin2 = (const struct sockaddr_in *)sa2;
+               if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr)
+                       return 0;
+               else if (include_port && sin1->sin_port != sin2->sin_port)
+                       return 0;
+               else
+                       return 1;
+       }
+#ifdef AF_INET6
+       if (sa1->sa_family == AF_INET6) {
+               const struct sockaddr_in6 *sin1, *sin2;
+               sin1 = (const struct sockaddr_in6 *)sa1;
+               sin2 = (const struct sockaddr_in6 *)sa2;
+               if (memcmp(sin1->sin6_addr.s6_addr, sin2->sin6_addr.s6_addr, 16))
+                       return 0;
+               else if (include_port && sin1->sin6_port != sin2->sin6_port)
+                       return 0;
+               else
+                       return 1;
+       }
+#endif
+       return 1;
+}
+
 static evdns_debug_log_fn_type evdns_log_fn = NULL;
 
 void
@@ -487,7 +539,7 @@ nameserver_probe_failed(struct nameserver *const ns) {
        if (evtimer_add(&ns->timeout_event, (struct timeval *) timeout) < 0) {
           log(EVDNS_LOG_WARN,
               "Error from libevent when adding timer event for %s",
-              debug_ntoa(ns->address));
+              debug_ntop((struct sockaddr *)&ns->address));
           /* ???? Do more? */
         }
 }
@@ -504,7 +556,7 @@ nameserver_failed(struct nameserver *const ns, const char *msg) {
        if (!ns->state) return;
 
        log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s",
-            debug_ntoa(ns->address), msg);
+               debug_ntop((struct sockaddr*)&ns->address), msg);
        base->global_good_nameservers--;
        assert(base->global_good_nameservers >= 0);
        if (base->global_good_nameservers == 0) {
@@ -519,7 +571,7 @@ nameserver_failed(struct nameserver *const ns, const char *msg) {
        if (evtimer_add(&ns->timeout_event, (struct timeval *) &global_nameserver_timeouts[0]) < 0) {
                log(EVDNS_LOG_WARN,
                    "Error from libevent when adding timer event for %s",
-                   debug_ntoa(ns->address));
+                   debug_ntop((struct sockaddr*)&ns->address));
                /* ???? Do more? */
         }
 
@@ -550,7 +602,7 @@ static void
 nameserver_up(struct nameserver *const ns) {
        if (ns->state) return;
        log(EVDNS_LOG_WARN, "Nameserver %s is back up",
-           debug_ntoa(ns->address));
+           debug_ntop((struct sockaddr *)&ns->address));
        evtimer_del(&ns->timeout_event);
        ns->state = 1;
        ns->failed_times = 0;
@@ -721,7 +773,7 @@ reply_handle(struct evdns_request *const req, u16 flags, u32 ttl, struct reply *
                         */
                        log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; "
                                "will allow the request to time out.",
-                               debug_ntoa(req->ns->address));
+                               debug_ntop((struct sockaddr *)&req->ns->address));
                        break;
                default:
                        /* we got a good reply from the nameserver */
@@ -1278,7 +1330,7 @@ nameserver_write_waiting(struct nameserver *ns, char waiting) {
                                 nameserver_ready_callback, ns);
        if (event_add(&ns->event, NULL) < 0) {
           log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
-              debug_ntoa(ns->address));
+              debug_ntop((struct sockaddr *)&ns->address));
           /* ???? Do more? */
         }
 }
@@ -2032,7 +2084,8 @@ nameserver_send_probe(struct nameserver *const ns) {
        /* here we need to send a probe to a given nameserver */
        /* in the hope that it is up now. */
 
-       log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntoa(ns->address));
+       log(EVDNS_LOG_DEBUG, "Sending probe to %s",
+               debug_ntop((struct sockaddr *)&ns->address));
 
        req = request_new(ns->base, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
        if (!req) return;
@@ -2167,20 +2220,21 @@ evdns_resume(void)
 }
 
 static int
-_evdns_nameserver_add_impl(struct evdns_base *base, unsigned long int address, int port) {
+_evdns_nameserver_add_impl(struct evdns_base *base, const struct sockaddr *address, int addrlen) {
        /* first check to see if we already have this nameserver */
 
        const struct nameserver *server = base->server_head, *const started_at = base->server_head;
        struct nameserver *ns;
-       struct sockaddr_in sin;
        int err = 0;
+
        if (server) {
                do {
-                       if (server->address == address) return 3;
+                       if (sockaddr_eq((struct sockaddr*)&server->address, address, 1)) return 3;
                        server = server->next;
                } while (server != started_at);
        }
 
+
        ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver));
        if (!ns) return -1;
 
@@ -2190,15 +2244,12 @@ _evdns_nameserver_add_impl(struct evdns_base *base, unsigned long int address, i
        ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
        if (ns->socket < 0) { err = 1; goto out1; }
        evutil_make_socket_nonblocking(ns->socket);
-       sin.sin_addr.s_addr = address;
-       sin.sin_port = htons(port);
-       sin.sin_family = AF_INET;
-       if (connect(ns->socket, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
+       if (connect(ns->socket, address, addrlen) != 0) {
                err = 2;
                goto out2;
        }
 
-       ns->address = address;
+       memcpy(&ns->address, address, addrlen);
        ns->state = 1;
        event_assign(&ns->event, ns->base->event_base, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
        if (event_add(&ns->event, NULL) < 0) {
@@ -2206,7 +2257,7 @@ _evdns_nameserver_add_impl(struct evdns_base *base, unsigned long int address, i
                goto out2;
        }
 
-       log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntoa(address));
+       log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntop(address));
 
        /* insert this nameserver into the list of them */
        if (!base->server_head) {
@@ -2229,15 +2280,20 @@ out2:
        CLOSE_SOCKET(ns->socket);
 out1:
        mm_free(ns);
-       log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntoa(address), err);
+       log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntop(address), err);
        return err;
 }
 
 /* exported function */
 int
 evdns_base_nameserver_add(struct evdns_base *base,
-                                                 unsigned long int address) {
-       return _evdns_nameserver_add_impl(base, address, 53);
+                                                 unsigned long int address)
+{
+       struct sockaddr_in sin;
+       sin.sin_addr.s_addr = address;
+       sin.sin_port = htons(53);
+       sin.sin_family = AF_INET;
+       return _evdns_nameserver_add_impl(base, (struct sockaddr*)&sin, sizeof(sin));
 }
 
 int
@@ -2250,30 +2306,34 @@ evdns_nameserver_add(unsigned long int address) {
 /* exported function */
 int
 evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) {
-       struct in_addr ina;
-       int port;
-       char buf[20];
-       const char *cp;
-       cp = strchr(ip_as_string, ':');
-       if (! cp) {
-               cp = ip_as_string;
-               port = 53;
-       } else {
-               port = strtoint(cp+1);
-               if (port < 0 || port > 65535) {
-                       return 4;
-               }
-               if ((cp-ip_as_string) >= (int)sizeof(buf)) {
-                       return 4;
-               }
-               memcpy(buf, ip_as_string, cp-ip_as_string);
-               buf[cp-ip_as_string] = '\0';
-               cp = buf;
-       }
-       if (!inet_aton(cp, &ina)) {
+       struct sockaddr_storage ss;
+       struct sockaddr *sa;
+       int len;
+       if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss,
+                                                                  sizeof(ss))) {
+               log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s",
+                       ip_as_string);
                return 4;
        }
-       return _evdns_nameserver_add_impl(base, ina.s_addr, port);
+       sa = (struct sockaddr *) &ss;
+       if (sa->sa_family == AF_INET) {
+               struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+               if (sin->sin_port == 0)
+                       sin->sin_port = htons(53);
+               len = sizeof(struct sockaddr_in);
+       }
+#ifdef AF_INET6
+       else if (sa->sa_family == AF_INET6) {
+               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+               if (sin6->sin6_port == 0)
+                       sin6->sin6_port = htons(53);
+               len = sizeof(struct sockaddr_in6);
+       }
+#endif
+       else
+               return -1;
+
+       return _evdns_nameserver_add_impl(base, sa, len);
 }
 
 int
@@ -2929,12 +2989,8 @@ resolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) {
 
        if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
                const char *const nameserver = NEXT_TOKEN;
-               struct in_addr ina;
 
-               if (inet_aton(nameserver, &ina)) {
-                       /* address is valid */
-                       evdns_base_nameserver_add(base, ina.s_addr);
-               }
+               evdns_base_nameserver_ip_add(base, nameserver);
        } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
                const char *const domain = NEXT_TOKEN;
                if (domain) {