diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h index 23d009286..2c432cb94 100644 --- a/include/proto/proto_tcp.h +++ b/include/proto/proto_tcp.h @@ -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 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); diff --git a/src/backend.c b/src/backend.c index beba14d3c..1617a1877 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1,7 +1,7 @@ /* * Backend variables and functions. * - * Copyright 2000-2007 Willy Tarreau + * Copyright 2000-2008 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -37,14 +37,11 @@ #include #include #include +#include #include #include #include -#ifdef CONFIG_HAP_CTTPROXY -#include -#endif - #ifdef CONFIG_HAP_TCPSPLICE #include #endif @@ -1113,89 +1110,6 @@ int assign_server_and_queue(struct session *s) } } -/* Binds ipv4 address to socket , unless is set, in which - * case we try to bind . 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) { diff --git a/src/checks.c b/src/checks.c index c63194656..f0f18d3fd 100644 --- a/src/checks.c +++ b/src/checks.c @@ -1,7 +1,7 @@ /* * Health-checks functions. * - * Copyright 2000-2007 Willy Tarreau + * Copyright 2000-2008 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -37,14 +37,11 @@ #include #include #include +#include #include #include #include -#ifdef CONFIG_HAP_CTTPROXY -#include -#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) { diff --git a/src/proto_tcp.c b/src/proto_tcp.c index d68941b2c..0891faa3b 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -1,7 +1,7 @@ /* * AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp) * - * Copyright 2000-2007 Willy Tarreau + * Copyright 2000-2008 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -53,6 +53,10 @@ #include #include +#ifdef CONFIG_HAP_CTTPROXY +#include +#endif + static int tcp_bind_listeners(struct protocol *proto); /* Note: must not be declared as its list will be overwritten */ @@ -92,6 +96,85 @@ static struct protocol proto_tcpv6 = { }; +/* Binds ipv4 address to socket , unless is set, in which + * case we try to bind . 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 if the message is at most bytes long * (including '\0'). The return value is composed from ERR_ABORT, ERR_WARN,