/* 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 */
#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 */
#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 */
} 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) */
/* 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
/* 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
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)) {
}
#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) {
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)) {
}
#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) {
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) {
* 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;
}
}
}
-/* 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>.
*/