]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] fix server health checks source address selection
authorWilly Tarreau <w@1wt.eu>
Sun, 13 Jan 2008 17:40:14 +0000 (18:40 +0100)
committerWilly Tarreau <w@1wt.eu>
Sun, 13 Jan 2008 17:40:14 +0000 (18:40 +0100)
The source address selection for health checks did not consider
the new transparent proxy method. Rely on the same unified function
as the other connect() calls.

This patch also fixes a bug by which the proxy's source address was
ignored if cttproxy was used.

include/proto/proto_tcp.h
src/backend.c
src/checks.c
src/proto_tcp.c

index 23d009286a3c9fc72412676a7891b82be097ebf0..2c432cb94625e73e14fa3a428c5e74481bfb4015 100644 (file)
@@ -2,7 +2,7 @@
   include/proto/proto_tcp.h
   This file contains TCP socket protocol definitions.
 
-  Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
+  Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -27,6 +27,7 @@
 #include <types/task.h>
 
 int tcp_event_accept(int fd);
+int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote);
 void tcpv4_add_listener(struct listener *listener);
 void tcpv6_add_listener(struct listener *listener);
 int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen);
index beba14d3c7be52abd169960dc0ad9fea9c42a7e9..1617a1877c43d380dfd4d9385f6aeaf52367cedd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Backend variables and functions.
  *
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #include <proto/httperr.h>
 #include <proto/log.h>
 #include <proto/proto_http.h>
+#include <proto/proto_tcp.h>
 #include <proto/queue.h>
 #include <proto/stream_sock.h>
 #include <proto/task.h>
 
-#ifdef CONFIG_HAP_CTTPROXY
-#include <import/ip_tproxy.h>
-#endif
-
 #ifdef CONFIG_HAP_TCPSPLICE
 #include <libtcpsplice.h>
 #endif
@@ -1113,89 +1110,6 @@ int assign_server_and_queue(struct session *s)
        }
 }
 
-/* Binds ipv4 address <local> to socket <fd>, unless <flags> is set, in which
- * case we try to bind <remote>. <flags> is a 2-bit field consisting of :
- *  - 0 : ignore remote address (may even be a NULL pointer)
- *  - 1 : use provided address
- *  - 2 : use provided port
- *  - 3 : use both
- *
- * The function supports multiple foreign binding methods :
- *   - linux_tproxy: we directly bind to the foreign address
- *   - cttproxy: we bind to a local address then nat.
- * The second one can be used as a fallback for the first one.
- * This function returns 0 when everything's OK, 1 if it could not bind, to the
- * local address, 2 if it could not bind to the foreign address.
- */
-static int bind_ipv4(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote)
-{
-       struct sockaddr_in bind_addr;
-       int foreign_ok = 0;
-       int ret;
-
-#ifdef CONFIG_HAP_LINUX_TPROXY
-       static int ip_transp_working = 1;
-       if (flags && ip_transp_working) {
-               if (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &one, sizeof(one)) == 0
-                   || setsockopt(fd, SOL_IP, IP_FREEBIND, (char *) &one, sizeof(one)) == 0)
-                       foreign_ok = 1;
-               else
-                       ip_transp_working = 0;
-       }
-#endif
-
-       if (flags) {
-               memset(&bind_addr, 0, sizeof(bind_addr));
-               if (flags & 1)
-                       bind_addr.sin_addr = remote->sin_addr;
-               if (flags & 2)
-                       bind_addr.sin_port = remote->sin_port;
-       }
-
-       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
-       if (foreign_ok) {
-               ret = bind(fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
-               if (ret < 0)
-                       return 2;
-       }
-       else {
-               ret = bind(fd, (struct sockaddr *)local, sizeof(*local));
-               if (ret < 0)
-                       return 1;
-       }
-
-       if (!flags)
-               return 0;
-
-#ifdef CONFIG_HAP_CTTPROXY
-       if (!foreign_ok) {
-               struct in_tproxy itp1, itp2;
-               memset(&itp1, 0, sizeof(itp1));
-
-               itp1.op = TPROXY_ASSIGN;
-               itp1.v.addr.faddr = bind_addr.sin_addr;
-               itp1.v.addr.fport = bind_addr.sin_port;
-
-               /* set connect flag on socket */
-               itp2.op = TPROXY_FLAGS;
-               itp2.v.flags = ITP_CONNECT | ITP_ONCE;
-
-               if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp1, sizeof(itp1)) != -1 &&
-                   setsockopt(fd, SOL_IP, IP_TPROXY, &itp2, sizeof(itp2)) != -1) {
-                       foreign_ok = 1;
-               }
-       }
-#endif
-
-       if (!foreign_ok) {
-               /* we could not bind to a foreign address */
-               close(fd);
-               return 2;
-       }
-
-       return 0;
-}
-
 /*
  * This function initiates a connection to the server assigned to this session
  * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
@@ -1288,7 +1202,7 @@ int connect_server(struct session *s)
                        remote = (struct sockaddr_in *)&s->cli_addr;
                        break;
                }
-               ret = bind_ipv4(fd, flags, &s->srv->source_addr, remote);
+               ret = tcpv4_bind_socket(fd, flags, &s->srv->source_addr, remote);
                if (ret) {
                        close(fd);
                        if (ret == 1) {
@@ -1326,7 +1240,7 @@ int connect_server(struct session *s)
                        break;
                }
 
-               ret = bind_ipv4(fd, flags, &s->be->source_addr, remote);
+               ret = tcpv4_bind_socket(fd, flags, &s->be->source_addr, remote);
                if (ret) {
                        close(fd);
                        if (ret == 1) {
index c63194656ba2abb7104512dc153c9037f85dc654..f0f18d3fdd553a793f3c4b13aac0c0433b0fb1ec 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Health-checks functions.
  *
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #include <proto/log.h>
 #include <proto/queue.h>
 #include <proto/proto_http.h>
+#include <proto/proto_tcp.h>
 #include <proto/proxy.h>
 #include <proto/server.h>
 #include <proto/task.h>
 
-#ifdef CONFIG_HAP_CTTPROXY
-#include <import/ip_tproxy.h>
-#endif
-
 /* sends a log message when a backend goes down, and also sets last
  * change date.
  */
@@ -416,62 +413,50 @@ void process_chk(struct task *t, struct timeval *next)
                                 * - proxy-specific next
                                 */
                                if (s->state & SRV_BIND_SRC) {
-                                       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
-                                       if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
-                                               Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
-                                                     s->proxy->id, s->id);
-                                               s->result |= SRV_CHK_ERROR;
-                                       }
-#ifdef CONFIG_HAP_CTTPROXY
+                                       struct sockaddr_in *remote = NULL;
+                                       int ret, flags = 0;
+
                                        if ((s->state & SRV_TPROXY_MASK) == SRV_TPROXY_ADDR) {
-                                               struct in_tproxy itp1, itp2;
-                                               memset(&itp1, 0, sizeof(itp1));
-                                               
-                                               itp1.op = TPROXY_ASSIGN;
-                                               itp1.v.addr.faddr = s->tproxy_addr.sin_addr;
-                                               itp1.v.addr.fport = s->tproxy_addr.sin_port;
-
-                                               /* set connect flag on socket */
-                                               itp2.op = TPROXY_FLAGS;
-                                               itp2.v.flags = ITP_CONNECT | ITP_ONCE;
-
-                                               if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp1, sizeof(itp1)) == -1 ||
-                                                   setsockopt(fd, SOL_IP, IP_TPROXY, &itp2, sizeof(itp2)) == -1) {
+                                               remote = (struct sockaddr_in *)&s->tproxy_addr;
+                                               flags  = 3;
+                                       }
+                                       ret = tcpv4_bind_socket(fd, flags, &s->source_addr, remote);
+                                       if (ret) {
+                                               s->result |= SRV_CHK_ERROR;
+                                               switch (ret) {
+                                               case 1:
+                                                       Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
+                                                             s->proxy->id, s->id);
+                                                       break;
+                                               case 2:
                                                        Alert("Cannot bind to tproxy source address before connect() for server %s/%s. Aborting.\n",
                                                              s->proxy->id, s->id);
-                                                       s->result |= SRV_CHK_ERROR;
+                                                       break;
                                                }
                                        }
-#endif
                                }
                                else if (s->proxy->options & PR_O_BIND_SRC) {
-                                       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
-                                       if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
-                                               Alert("Cannot bind to source address before connect() for %s '%s'. Aborting.\n",
-                                                     proxy_type_str(s->proxy), s->proxy->id);
-                                               s->result |= SRV_CHK_ERROR;
-                                       }
-#ifdef CONFIG_HAP_CTTPROXY
+                                       struct sockaddr_in *remote = NULL;
+                                       int ret, flags = 0;
+
                                        if ((s->proxy->options & PR_O_TPXY_MASK) == PR_O_TPXY_ADDR) {
-                                               struct in_tproxy itp1, itp2;
-                                               memset(&itp1, 0, sizeof(itp1));
-                                               
-                                               itp1.op = TPROXY_ASSIGN;
-                                               itp1.v.addr.faddr = s->tproxy_addr.sin_addr;
-                                               itp1.v.addr.fport = s->tproxy_addr.sin_port;
-                                               
-                                               /* set connect flag on socket */
-                                               itp2.op = TPROXY_FLAGS;
-                                               itp2.v.flags = ITP_CONNECT | ITP_ONCE;
-                                               
-                                               if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp1, sizeof(itp1)) == -1 ||
-                                                   setsockopt(fd, SOL_IP, IP_TPROXY, &itp2, sizeof(itp2)) == -1) {
+                                               remote = (struct sockaddr_in *)&s->proxy->tproxy_addr;
+                                               flags  = 3;
+                                       }
+                                       ret = tcpv4_bind_socket(fd, flags, &s->proxy->source_addr, remote);
+                                       if (ret) {
+                                               s->result |= SRV_CHK_ERROR;
+                                               switch (ret) {
+                                               case 1:
+                                                       Alert("Cannot bind to source address before connect() for %s '%s'. Aborting.\n",
+                                                             proxy_type_str(s->proxy), s->proxy->id);
+                                                       break;
+                                               case 2:
                                                        Alert("Cannot bind to tproxy source address before connect() for %s '%s'. Aborting.\n",
                                                              proxy_type_str(s->proxy), s->proxy->id);
-                                                       s->result |= SRV_CHK_ERROR;
+                                                       break;
                                                }
                                        }
-#endif
                                }
 
                                if (s->result == SRV_CHK_UNKNOWN) {
index d68941b2c8378b68bb8c62781e6420b7f5859ebd..0891faa3bb3f7c42def84973525a6740b7edce1b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp)
  *
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #include <proto/stream_sock.h>
 #include <proto/task.h>
 
+#ifdef CONFIG_HAP_CTTPROXY
+#include <import/ip_tproxy.h>
+#endif
+
 static int tcp_bind_listeners(struct protocol *proto);
 
 /* Note: must not be declared <const> as its list will be overwritten */
@@ -92,6 +96,85 @@ static struct protocol proto_tcpv6 = {
 };
 
 
+/* Binds ipv4 address <local> to socket <fd>, unless <flags> is set, in which
+ * case we try to bind <remote>. <flags> is a 2-bit field consisting of :
+ *  - 0 : ignore remote address (may even be a NULL pointer)
+ *  - 1 : use provided address
+ *  - 2 : use provided port
+ *  - 3 : use both
+ *
+ * The function supports multiple foreign binding methods :
+ *   - linux_tproxy: we directly bind to the foreign address
+ *   - cttproxy: we bind to a local address then nat.
+ * The second one can be used as a fallback for the first one.
+ * This function returns 0 when everything's OK, 1 if it could not bind, to the
+ * local address, 2 if it could not bind to the foreign address.
+ */
+int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote)
+{
+       struct sockaddr_in bind_addr;
+       int foreign_ok = 0;
+       int ret;
+
+#ifdef CONFIG_HAP_LINUX_TPROXY
+       static int ip_transp_working = 1;
+       if (flags && ip_transp_working) {
+               if (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &one, sizeof(one)) == 0
+                   || setsockopt(fd, SOL_IP, IP_FREEBIND, (char *) &one, sizeof(one)) == 0)
+                       foreign_ok = 1;
+               else
+                       ip_transp_working = 0;
+       }
+#endif
+       if (flags) {
+               memset(&bind_addr, 0, sizeof(bind_addr));
+               if (flags & 1)
+                       bind_addr.sin_addr = remote->sin_addr;
+               if (flags & 2)
+                       bind_addr.sin_port = remote->sin_port;
+       }
+
+       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
+       if (foreign_ok) {
+               ret = bind(fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
+               if (ret < 0)
+                       return 2;
+       }
+       else {
+               ret = bind(fd, (struct sockaddr *)local, sizeof(*local));
+               if (ret < 0)
+                       return 1;
+       }
+
+       if (!flags)
+               return 0;
+
+#ifdef CONFIG_HAP_CTTPROXY
+       if (!foreign_ok) {
+               struct in_tproxy itp1, itp2;
+               memset(&itp1, 0, sizeof(itp1));
+
+               itp1.op = TPROXY_ASSIGN;
+               itp1.v.addr.faddr = bind_addr.sin_addr;
+               itp1.v.addr.fport = bind_addr.sin_port;
+
+               /* set connect flag on socket */
+               itp2.op = TPROXY_FLAGS;
+               itp2.v.flags = ITP_CONNECT | ITP_ONCE;
+
+               if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp1, sizeof(itp1)) != -1 &&
+                   setsockopt(fd, SOL_IP, IP_TPROXY, &itp2, sizeof(itp2)) != -1) {
+                       foreign_ok = 1;
+               }
+       }
+#endif
+       if (!foreign_ok)
+               /* we could not bind to a foreign address */
+               return 2;
+
+       return 0;
+}
+
 /* This function tries to bind a TCPv4/v6 listener. It may return a warning or
  * an error message in <err> if the message is at most <errlen> bytes long
  * (including '\0'). The return value is composed from ERR_ABORT, ERR_WARN,