Hi Alex,

I could finally reproduce your issue with 1.5-dev8. You won the jackport, this
bug has been there forever since "balance source" was introduced in 1.2.11 six 
years ago ! The IP address pointer was erroneously mapped to IPv4, which is
wrong. The attached patch fixes it.

BTW, if your stud really emitted :

    "PROXY TCP6 ::ffff:127.0.0.1 :: 52460 7302"

Then it is wrong since the second field ("::") is the destination address and
it cannot be zero. It's possible that it logs the IP it's listening to instead
of logging the IP the client connected to. This is not critical since it's not
used here, but dst-based ACLs or transparent forwarding would not work.

Cheers,
Willy

>From 5dd7fa1f6b8eec57bff8ff4630afd7eb3e837b5e Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w...@1wt.eu>
Date: Sat, 31 Mar 2012 19:53:37 +0200
Subject: [PATCH] BUG/MEDIUM: balance source did not properly hash IPv6 addresses

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 |   19 ++++++++++---------
 1 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/src/backend.c b/src/backend.c
index 39ee58b..f6e2d73 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -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:
-- 
1.7.2.1.45.g54fbc

Reply via email to