]> granicus.if.org Git - libevent/commitdiff
New bind-to option to allow DNS clients to bind to arbitrary ports for their outgoing...
authorNick Mathewson <nickm@torproject.org>
Wed, 11 Feb 2009 17:24:11 +0000 (17:24 +0000)
committerNick Mathewson <nickm@torproject.org>
Wed, 11 Feb 2009 17:24:11 +0000 (17:24 +0000)
svn:r1119

ChangeLog
evdns.c
include/event2/dns.h

index ecd3bcd039b5255bdc36bc74e3c9b55a24810588..3192bbff17fcce05936854ce8acef6c6616b6fbe 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -142,6 +142,7 @@ Changes in current version:
  o Change the semantics of timeouts in conjunction with EV_PERSIST; timeouts in that case will now repeat until deleted.
  o sendfile, mmap and memory reference support for evbuffers.
  o New evutil_make_listen_socket_reuseable() to abstract SO_REUSEADDR.
+ o New bind-to option to allow DNS clients to bind to an arbitrary port for outgoing requests.
 
 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 166a0caf8f0069559e9ea0c803ec362a162bebed..c868fc0166d9ee33eb0c3ee13b2406fcb89a79ba 100644 (file)
--- a/evdns.c
+++ b/evdns.c
@@ -318,6 +318,11 @@ struct evdns_base {
        /* true iff we will use the 0x20 hack to prevent poisoning attacks. */
        int global_randomize_case;
 
+       /** Port to bind to for outgoing DNS packets. */
+       struct sockaddr_storage global_outgoing_address;
+       /** Socklen_t for global_outgoing_address. 0 if it isn't set. */
+       socklen_t global_outgoing_addrlen;
+
        struct search_state *global_search_state;
 };
 
@@ -2231,6 +2236,17 @@ _evdns_nameserver_add_impl(struct evdns_base *base, const struct sockaddr *addre
        ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
        if (ns->socket < 0) { err = 1; goto out1; }
        evutil_make_socket_nonblocking(ns->socket);
+
+       if (base->global_outgoing_addrlen) {
+               if (bind(ns->socket,
+                       (struct sockaddr*)&base->global_outgoing_address,
+                       base->global_outgoing_addrlen) < 0) {
+                       log(EVDNS_LOG_WARN,"Couldn't bind to outgoing address");
+                       err = 2;
+                       goto out2;
+               }
+       }
+
        if (connect(ns->socket, address, addrlen) != 0) {
                err = 2;
                goto out2;
@@ -2955,6 +2971,15 @@ evdns_base_set_option(struct evdns_base *base,
                int randcase = strtoint(val);
                if (!(flags & DNS_OPTION_MISC)) return 0;
                base->global_randomize_case = randcase;
+       } else if (!strncmp(option, "bind-to:", 8)) {
+                /* XXX This only applies to successive nameservers, not
+                 * to already-configured ones.  We might want to fix that. */
+                int len = sizeof(base->global_outgoing_address);
+               if (!(flags & DNS_OPTION_NAMESERVERS)) return 0;
+               if (evutil_parse_sockaddr_port(val,
+                       (struct sockaddr*)&base->global_outgoing_address, &len))
+                        return -1;
+                base->global_outgoing_addrlen = len;
        }
        return 0;
 }
index b9b47e822cfc321b4636576c71548d2ae5d24114..7920c3e9f79870276e66777dc4c6aeb49ace802d 100644 (file)
@@ -395,7 +395,10 @@ void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req);
 
   The currently available configuration options are:
 
-    ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case.
+    ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case,
+    bind-to.
+
+  The option name needs to end with a colon.
 
   @param base the evdns_base to which to apply this operation
   @param option the name of the configuration option to be modified