diff --git a/include/haproxy/listener-t.h b/include/haproxy/listener-t.h index 45c5a11cc..cc5546c50 100644 --- a/include/haproxy/listener-t.h +++ b/include/haproxy/listener-t.h @@ -85,7 +85,7 @@ enum li_state { /* 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 foreign addresses ("transparent") */ +/* unused 0x0002 */ #define LI_O_NOQUICKACK 0x0004 /* disable quick ack of immediate data (linux) */ #define LI_O_DEF_ACCEPT 0x0008 /* wait up to 1 second for data before accepting */ #define LI_O_TCP_L4_RULES 0x0010 /* run TCP L4 rules checks on the incoming connection */ @@ -94,8 +94,8 @@ enum li_state { #define LI_O_ACC_PROXY 0x0080 /* find the proxied address in the first request line */ #define LI_O_UNLIMITED 0x0100 /* listener not subject to global limits (peers & stats socket) */ #define LI_O_TCP_FO 0x0200 /* enable TCP Fast Open (linux >= 3.7) */ -#define LI_O_V6ONLY 0x0400 /* bind to IPv6 only on Linux >= 2.4.21 */ -#define LI_O_V4V6 0x0800 /* bind to IPv4/IPv6 on Linux >= 2.4.21 */ +/* unused 0x0400 */ +/* unused 0x0800 */ #define LI_O_ACC_CIP 0x1000 /* find the proxied address in the NetScaler Client IP header */ /* unused 0x2000 */ #define LI_O_MWORKER 0x4000 /* keep the FD open in the master but close it in the children */ diff --git a/include/haproxy/receiver-t.h b/include/haproxy/receiver-t.h index babad44a0..7bf15fb34 100644 --- a/include/haproxy/receiver-t.h +++ b/include/haproxy/receiver-t.h @@ -33,6 +33,11 @@ #define RX_F_BOUND 0x00000001 /* receiver already bound */ #define RX_F_INHERITED 0x00000002 /* inherited FD from the parent process (fd@) */ +/* Bit values for rx_settings->options */ +#define RX_O_FOREIGN 0x00000001 /* receives on foreign addresses */ +#define RX_O_V4V6 0x00000002 /* binds to both IPv4 and IPv6 addresses if !V6ONLY */ +#define RX_O_V6ONLY 0x00000004 /* binds to IPv6 addresses only */ + /* All the settings that are used to configure a receiver */ struct rx_settings { unsigned long bind_proc; /* bitmask of processes allowed to use these listeners */ @@ -44,6 +49,7 @@ struct rx_settings { } ux; char *interface; /* interface name or NULL */ const struct netns_entry *netns; /* network namespace of the listener*/ + unsigned int options; /* receiver options (RX_O_*) */ }; /* This describes a receiver with all its characteristics (address, options, etc) */ diff --git a/src/cfgparse-tcp.c b/src/cfgparse-tcp.c index 7346d652b..0bf347bcc 100644 --- a/src/cfgparse-tcp.c +++ b/src/cfgparse-tcp.c @@ -40,26 +40,14 @@ /* parse the "v4v6" bind keyword */ static int bind_parse_v4v6(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - struct listener *l; - - list_for_each_entry(l, &conf->listeners, by_bind) { - if (l->rx.addr.ss_family == AF_INET6) - l->options |= LI_O_V4V6; - } - + conf->settings.options |= RX_O_V4V6; return 0; } /* parse the "v6only" bind keyword */ static int bind_parse_v6only(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - struct listener *l; - - list_for_each_entry(l, &conf->listeners, by_bind) { - if (l->rx.addr.ss_family == AF_INET6) - l->options |= LI_O_V6ONLY; - } - + conf->settings.options |= RX_O_V6ONLY; return 0; } #endif @@ -68,13 +56,7 @@ static int bind_parse_v6only(char **args, int cur_arg, struct proxy *px, struct /* parse the "transparent" bind keyword */ static int bind_parse_transparent(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - struct listener *l; - - list_for_each_entry(l, &conf->listeners, by_bind) { - if (l->rx.addr.ss_family == AF_INET || l->rx.addr.ss_family == AF_INET6) - l->options |= LI_O_FOREIGN; - } - + conf->settings.options |= RX_O_FOREIGN; return 0; } #endif diff --git a/src/proto_tcp.c b/src/proto_tcp.c index fe0fdcad0..a842e61b8 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -633,7 +633,7 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); #endif - if (!ext && (listener->options & LI_O_FOREIGN)) { + if (!ext && (listener->rx.settings->options & RX_O_FOREIGN)) { switch (listener->rx.addr.ss_family) { case AF_INET: if (!sock_inet4_make_foreign(fd)) { @@ -736,10 +736,17 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) } #endif #if defined(IPV6_V6ONLY) - if (!ext && listener->options & LI_O_V6ONLY) - setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); - else if (!ext && listener->options & LI_O_V4V6) - setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)); + if (!ext && listener->rx.addr.ss_family == AF_INET6) { + /* Prepare to match the v6only option against what we really want. Note + * that sadly the two options are not exclusive to each other and that + * v6only is stronger than v4v6. + */ + if ((listener->rx.settings->options & RX_O_V6ONLY) || + (sock_inet6_v6only_default && !(listener->rx.settings->options & RX_O_V4V6))) + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + else + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)); + } #endif if (!ext && bind(fd, (struct sockaddr *)&listener->rx.addr, listener->rx.proto->sock_addrlen) == -1) { diff --git a/src/proto_udp.c b/src/proto_udp.c index 64ea63931..82a93873e 100644 --- a/src/proto_udp.c +++ b/src/proto_udp.c @@ -239,7 +239,7 @@ int udp_bind_listener(struct listener *listener, char *errmsg, int errlen) setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); #endif - if (listener->options & LI_O_FOREIGN) { + if (listener->rx.settings->options & RX_O_FOREIGN) { switch (addr_inet.ss_family) { case AF_INET: if (!sock_inet4_make_foreign(fd)) { @@ -268,10 +268,17 @@ int udp_bind_listener(struct listener *listener, char *errmsg, int errlen) } #endif #if defined(IPV6_V6ONLY) - if (listener->options & LI_O_V6ONLY) - setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); - else if (listener->options & LI_O_V4V6) - setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)); + if (listener->rx.addr.ss_family == AF_INET6) { + /* Prepare to match the v6only option against what we really want. Note + * that sadly the two options are not exclusive to each other and that + * v6only is stronger than v4v6. + */ + if ((listener->rx.settings->options & RX_O_V6ONLY) || + (sock_inet6_v6only_default && !(listener->rx.settings->options & RX_O_V4V6))) + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + else + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)); + } #endif if (bind(fd, (struct sockaddr *)&addr_inet, listener->rx.proto->sock_addrlen) < 0) { diff --git a/src/sock.c b/src/sock.c index 2ff615b2e..4077d69a3 100644 --- a/src/sock.c +++ b/src/sock.c @@ -369,7 +369,7 @@ int sock_find_compatible_fd(const struct listener *l) if (l->rx.proto->sock_type == SOCK_DGRAM) options |= SOCK_XFER_OPT_DGRAM; - if (l->options & LI_O_FOREIGN) + if (l->rx.settings->options & RX_O_FOREIGN) options |= SOCK_XFER_OPT_FOREIGN; if (l->rx.addr.ss_family == AF_INET6) { @@ -377,8 +377,8 @@ int sock_find_compatible_fd(const struct listener *l) * that sadly the two options are not exclusive to each other and that * v6only is stronger than v4v6. */ - if ((l->options & LI_O_V6ONLY) || - (sock_inet6_v6only_default && !(l->options & LI_O_V4V6))) + if ((l->rx.settings->options & RX_O_V6ONLY) || + (sock_inet6_v6only_default && !(l->rx.settings->options & RX_O_V4V6))) options |= SOCK_XFER_OPT_V6ONLY; } diff --git a/src/sock_inet.c b/src/sock_inet.c index 3f4edcb1d..0506c16fb 100644 --- a/src/sock_inet.c +++ b/src/sock_inet.c @@ -116,7 +116,7 @@ int sock_inet_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir) } } -/* Returns true if the passed FD corresponds to a socket bound with LI_O_FOREIGN +/* Returns true if the passed FD corresponds to a socket bound with RX_O_FOREIGN * according to the various supported socket options. The socket's address family * must be passed in . */