[MEDIUM] support fully transparent proxy on Linux (USE_LINUX_TPROXY)

Using some Linux kernel patches, it is possible to redirect non-local
traffic to local sockets when IP forwarding is enabled. In order to
enable this option, we introduce the "transparent" option keyword on
the "bind" command line. It will make the socket reachable by remote
sources even if the destination address does not belong to the machine.
This commit is contained in:
Willy Tarreau 2008-01-13 14:49:51 +01:00
parent fe10a0619d
commit b1e52e8c44
6 changed files with 67 additions and 13 deletions

View File

@ -19,6 +19,7 @@
# USE_STATIC_PCRE : enable static libpcre. Recommended.
# USE_TCPSPLICE : enable tcp_splice() on Linux (needs kernel patch).
# USE_TPROXY : enable transparent proxy. Automatic.
# USE_LINUX_TPROXY : enable full transparent proxy (need kernel patch).
#
# Options can be forced by specifying "USE_xxx=1" or can be disabled by using
# "USE_xxx=" (empty string).
@ -291,6 +292,11 @@ OPTIONS_CFLAGS += -DTPROXY
BUILD_OPTIONS += $(call ignore_implicit,USE_TPROXY)
endif
ifneq ($(USE_LINUX_TPROXY),)
OPTIONS_CFLAGS += -DCONFIG_HAP_LINUX_TPROXY
BUILD_OPTIONS += $(call ignore_implicit,USE_LINUX_TPROXY)
endif
ifneq ($(USE_POLL),)
OPTIONS_CFLAGS += -DENABLE_POLL
OPTIONS_OBJS += src/ev_poll.o

View File

@ -2,9 +2,9 @@
HAProxy
Configuration Manual
----------------------
version 1.3.14.2
version 1.3.15
willy tarreau
2008/01/05
2008/01/13
This document covers the configuration language as implemented in the version
@ -758,19 +758,30 @@ balance <algorithm> [ <arguments> ]
bind [<address>]:<port> [, ...]
bind [<address>]:<port> [, ...] transparent
Define one or several listening addresses and/or ports in a frontend.
May be used in sections : defaults | frontend | listen | backend
no | yes | yes | no
Arguments :
<address> is optional and can be a host name, an IPv4 address, an IPv6
address, or '*'. It designates the address the frontend will
listen on. If unset, all IPv4 addresses of the system will be
listened on. The same will apply for '*' or the system's special
address "0.0.0.0".
<address> is optional and can be a host name, an IPv4 address, an IPv6
address, or '*'. It designates the address the frontend will
listen on. If unset, all IPv4 addresses of the system will be
listened on. The same will apply for '*' or the system's
special address "0.0.0.0".
<port> is the TCP port number the proxy will listen on. The port is
mandatory. Note that in the case of an IPv6 address, the port is
always the number after the last colon (':').
<port> is the TCP port number the proxy will listen on. The port is
mandatory. Note that in the case of an IPv6 address, the port
is always the number after the last colon (':').
transparent is an optional keyword which is supported only on certain
Linux kernels. It indicates that the addresses will be bound
even if they do not belong to the local machine. Any packet
targetting any of these addresses will be caught just as if
the address was locally configured. This normally requires
that IP forwarding is enabled. Caution! do not use this with
the default address '*', as it would redirect any traffic for
the specified port. This keyword is available only when
HAProxy is built with USE_LINUX_TPROXY=1.
It is possible to specify a list of address:port combinations delimited by
commas. The frontend will then listen on all of these addresses. There is no

View File

@ -2,7 +2,7 @@
include/common/compat.h
Operating system compatibility interface.
Copyright (C) 2000-2006 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
@ -66,6 +66,13 @@
#include <linux/netfilter_ipv4.h>
#endif
/* On Linux, IP_TRANSPARENT generally requires a kernel patch */
#if defined(CONFIG_HAP_LINUX_TPROXY)
#if !defined(IP_TRANSPARENT)
#define IP_TRANSPARENT 19
#endif /* !IP_TRANSPARENT */
#endif /* CONFIG_HAP_LINUX_TPROXY */
/* We'll try to enable SO_REUSEPORT on Linux 2.4 and 2.6 if not defined.
* There are two families of values depending on the architecture. Those
* are at least valid on Linux 2.4 and 2.6, reason why we'll rely on the

View File

@ -2,7 +2,7 @@
include/types/protocols.h
This file defines the structures used by generic network protocols.
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
@ -65,6 +65,7 @@
/* listener socket options */
#define LI_O_NONE 0x0000
#define LI_O_NOLINGER 0x0001 /* disable linger on this socket */
#define LI_O_FOREIGN 0x0002 /* permit listening on foreing addresses */
/* The listener will be directly referenced by the fdtab[] which holds its
* socket. The listener provides the protocol-specific accept() function to

View File

@ -728,6 +728,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
/* Now let's parse the proxy-specific keywords */
if (!strcmp(args[0], "bind")) { /* new listen addresses */
struct listener *last_listen;
if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
return -1;
@ -740,9 +741,30 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
file, linenum, args[0]);
return -1;
}
curproxy->listen = str2listener(args[1], curproxy->listen);
last_listen = curproxy->listen;
curproxy->listen = str2listener(args[1], last_listen);
if (!curproxy->listen)
return -1;
if (*args[2]) {
#ifdef CONFIG_HAP_LINUX_TPROXY
if (!strcmp(args[2], "transparent")) { /* transparently bind to these addresses */
struct listener *l;
for (l = curproxy->listen; l != last_listen; l = l->next)
l->options |= LI_O_FOREIGN;
}
else {
Alert("parsing [%s:%d] : '%s' only supports the 'transparent' option.\n",
file, linenum, args[0]);
return -1;
}
#else
Alert("parsing [%s:%d] : '%s' supports no option after the address list.\n",
file, linenum, args[0]);
return -1;
#endif
}
global.maxsock++;
return 0;
}

View File

@ -153,6 +153,13 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
* it might return an error that we will silently ignore.
*/
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
#endif
#ifdef CONFIG_HAP_LINUX_TPROXY
if ((listener->options & LI_O_FOREIGN)
&& (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &one, sizeof(one)) == -1)) {
msg = "cannot make listening socket transparent";
err |= ERR_ALERT;
}
#endif
if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
err |= ERR_RETRYABLE | ERR_ALERT;