]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: receiver: move the FOREIGN and V6ONLY options from listener to settings
authorWilly Tarreau <w@1wt.eu>
Tue, 1 Sep 2020 13:12:08 +0000 (15:12 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 16 Sep 2020 20:08:07 +0000 (22:08 +0200)
The new RX_O_FOREIGN, RX_O_V6ONLY and RX_O_V4V6 options are now set into
the rx_settings part during the parsing, so that we don't need to adjust
them in each and every listener anymore. We have to keep both v4v6 and
v6only due to the precedence from v6only over v4v6.

include/haproxy/listener-t.h
include/haproxy/receiver-t.h
src/cfgparse-tcp.c
src/proto_tcp.c
src/proto_udp.c
src/sock.c
src/sock_inet.c

index 45c5a11cc0e164eca18c3cbcf26cc335c94feb9c..cc5546c503b2113a482931a85ee2de21c72d839d 100644 (file)
@@ -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 */
index babad44a0f83c537e0c4cffb28c081ae2eff45ab..7bf15fb347fa864e620dd8a23795f3f7919920e2 100644 (file)
 #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) */
index 7346d652b9f6d979d60d9a0c53d812b2ab83654b..0bf347bcc3ecd6c6ab38a2a16b056a9cb88c3640 100644 (file)
 /* 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
index fe0fdcad0f1811ec99f609b62f9307265b8b792c..a842e61b8e2ad360fe16de3fe6d5e761877b2824 100644 (file)
@@ -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) {
index 64ea63931895cc38e808d86973064f0ecb89f533..82a93873ec1cbc3986631ed3bb02b8aa8ab463ed 100644 (file)
@@ -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) {
index 2ff615b2ee82ed8cd7a95123a3f49b37fec8fd69..4077d69a3f1f8d5c30b59c10341c1cc254e8f15c 100644 (file)
@@ -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;
        }
 
index 3f4edcb1d42a248ecd5f4ddac87b255254772a70..0506c16fbaeed052e7a9e2471e26120e28d3e1d3 100644 (file)
@@ -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 <family>.
  */