]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix TCP so it uses a random outgoing-interface.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 13 Oct 2010 08:52:29 +0000 (08:52 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 13 Oct 2010 08:52:29 +0000 (08:52 +0000)
git-svn-id: file:///svn/unbound/trunk@2280 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
services/outside_network.c

index bb31b5b2efc7231049bd33645fe47773cd3b6743..5b57f3351feffa6a77f17bcd25ac1abae2da1f93 100644 (file)
@@ -1,3 +1,6 @@
+13 October 2010: Wouter
+       - Fix TCP so it uses a random outgoing-interface.
+
 11 October 2010: Wouter
        - Fix bug when DLV below a trust-anchor that uses NSEC3 optout where
          the zone has a secure delegation hosted on the same server did not
index 18ce9f3480bfaaf8f300e6bb90d9991e86c5d797..151abf1d2d94a55f1ea1bc1e573d1f9cbd4aebd0 100644 (file)
@@ -130,6 +130,65 @@ waiting_tcp_delete(struct waiting_tcp* w)
        free(w);
 }
 
+/** 
+ * Pick random outgoing-interface of that family, and bind it.
+ * port set to 0 so OS picks a port number for us.
+ * if it is the ANY address, do not bind.
+ * @param w: tcp structure with destination address.
+ * @param s: socket fd.
+ * @return false on error, socket closed.
+ */
+static int
+pick_outgoing_tcp(struct waiting_tcp* w, int s)
+{
+       struct port_if* pi = NULL;
+       int num;
+#ifdef INET6
+       if(addr_is_ip6(&w->addr, w->addrlen))
+               num = w->outnet->num_ip6;
+       else
+#endif
+               num = w->outnet->num_ip4;
+       if(num == 0) {
+               log_err("no TCP outgoing interfaces of family");
+               log_addr(VERB_OPS, "for addr", &w->addr, w->addrlen);
+#ifndef USE_WINSOCK
+               close(s);
+#else
+               closesocket(s);
+#endif
+               return 0;
+       }
+#ifdef INET6
+       if(addr_is_ip6(&w->addr, w->addrlen))
+               pi = &w->outnet->ip6_ifs[ub_random_max(w->outnet->rnd, num)];
+       else
+#endif
+               pi = &w->outnet->ip4_ifs[ub_random_max(w->outnet->rnd, num)];
+       log_assert(pi);
+       if(addr_is_any(&pi->addr, pi->addrlen)) {
+               /* binding to the ANY interface is for listening sockets */
+               return 1;
+       }
+       /* set port to 0 */
+       if(addr_is_ip6(&pi->addr, pi->addrlen))
+               ((struct sockaddr_in6*)&pi->addr)->sin6_port = 0;
+       else    ((struct sockaddr_in*)&pi->addr)->sin_port = 0;
+       if(bind(s, (struct sockaddr*)&pi->addr, pi->addrlen) != 0) {
+#ifndef USE_WINSOCK
+               log_err("outgoing tcp: bind: %s", strerror(errno));
+               close(s);
+#else
+               log_err("outgoing tcp: bind: %s", 
+                       wsa_strerror(WSAGetLastError()));
+               closesocket(s);
+#endif
+               return 0;
+       }
+       log_addr(VERB_ALGO, "tcp bound to src", &pi->addr, pi->addrlen);
+       return 1;
+}
+
 /** use next free buffer to service a tcp query */
 static int
 outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
@@ -156,9 +215,8 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
                log_addr(0, "failed address", &w->addr, w->addrlen);
                return 0;
        }
-       /* pick random outgoing-interface of that family, and bind it.
-        * port set to 0 so OS picks a port number for us.
-        * if it is the ANY address, do not bind. */
+       if(!pick_outgoing_tcp(w, s))
+               return 0;
 
        fd_set_nonblock(s);
        if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) {