]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: balance source did not properly hash IPv6 addresses
authorWilly Tarreau <w@1wt.eu>
Sat, 31 Mar 2012 17:53:37 +0000 (19:53 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 31 Mar 2012 17:53:37 +0000 (19:53 +0200)
The hash of IPv6 addresses was not properly aligned and resulted in the
last quarter of the address not being hashed. In practice, this is rarely
detected since MAC addresses are used in the second half. But this becomes
very visible with IPv6-mapped IPv4 addresses such as ::FFFF:1.2.3.4 where
the IPv4 part is never hashed.

This bug has been there forever, since introduction of "balance source" in
v1.2.11. The fix must then be backported to all stable versions.

Thanks to Alex Markham for reporting this issue to the list !

src/backend.c

index 39ee58bce7385bf0aa8395164ee7f0fc1aba016b..f6e2d731ba8b787f0a04c77b63b016a589f7df70 100644 (file)
@@ -497,7 +497,6 @@ int assign_server(struct session *s)
        clear_target(&s->target);
 
        if (s->be->lbprm.algo & BE_LB_KIND) {
-               int len;
                /* we must check if we have at least one server available */
                if (!s->be->lbprm.tot_weight) {
                        err = SRV_STATUS_NOSRV;
@@ -538,19 +537,21 @@ int assign_server(struct session *s)
 
                        switch (s->be->lbprm.algo & BE_LB_PARM) {
                        case BE_LB_HASH_SRC:
-                               if (s->req->prod->addr.from.ss_family == AF_INET)
-                                       len = 4;
-                               else if (s->req->prod->addr.from.ss_family == AF_INET6)
-                                       len = 16;
+                               if (s->req->prod->addr.from.ss_family == AF_INET) {
+                                       srv = get_server_sh(s->be,
+                                                           (void *)&((struct sockaddr_in *)&s->req->prod->addr.from)->sin_addr,
+                                                           4);
+                               }
+                               else if (s->req->prod->addr.from.ss_family == AF_INET6) {
+                                       srv = get_server_sh(s->be,
+                                                           (void *)&((struct sockaddr_in6 *)&s->req->prod->addr.from)->sin6_addr,
+                                                           16);
+                               }
                                else {
                                        /* unknown IP family */
                                        err = SRV_STATUS_INTERNAL;
                                        goto out;
                                }
-               
-                               srv = get_server_sh(s->be,
-                                                   (void *)&((struct sockaddr_in *)&s->req->prod->addr.from)->sin_addr,
-                                                   len);
                                break;
 
                        case BE_LB_HASH_URI: