blob: 028ffaa6809b10dfe570a4d7e85074f5553f8a39 [file] [log] [blame]
Willy Tarreau0d06df62020-08-28 15:10:11 +02001/*
2 * AF_INET/AF_INET6 socket management
3 *
4 * Copyright 2000-2020 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreauf2cda102020-09-17 14:02:01 +020013#include <errno.h>
Willy Tarreau0d06df62020-08-28 15:10:11 +020014#include <string.h>
Willy Tarreaud69ce1f2020-09-01 14:18:04 +020015#include <unistd.h>
Willy Tarreau0d06df62020-08-28 15:10:11 +020016
17#include <sys/param.h>
18#include <sys/socket.h>
19#include <sys/types.h>
20
21#include <netinet/tcp.h>
22#include <netinet/in.h>
23
24#include <haproxy/api.h>
Willy Tarreaud69ce1f2020-09-01 14:18:04 +020025#include <haproxy/errors.h>
26#include <haproxy/fd.h>
Willy Tarreau37bafdc2020-08-28 17:23:40 +020027#include <haproxy/global.h>
Willy Tarreaud69ce1f2020-09-01 14:18:04 +020028#include <haproxy/namespace.h>
29#include <haproxy/receiver-t.h>
30#include <haproxy/sock.h>
Willy Tarreau0d06df62020-08-28 15:10:11 +020031#include <haproxy/sock_inet.h>
32#include <haproxy/tools.h>
33
Willy Tarreaub0254cb2020-09-04 08:07:11 +020034struct proto_fam proto_fam_inet4 = {
35 .name = "inet4",
36 .sock_domain = PF_INET,
37 .sock_family = AF_INET,
38 .sock_addrlen = sizeof(struct sockaddr_in),
39 .l3_addrlen = 32/8,
40 .addrcmp = sock_inet4_addrcmp,
41 .bind = sock_inet_bind_receiver,
42 .get_src = sock_get_src,
43 .get_dst = sock_inet_get_dst,
Willy Tarreau73bed9f2020-12-04 14:43:36 +010044 .set_port = sock_inet_set_port,
Willy Tarreaub0254cb2020-09-04 08:07:11 +020045};
46
47struct proto_fam proto_fam_inet6 = {
48 .name = "inet6",
49 .sock_domain = PF_INET6,
50 .sock_family = AF_INET6,
51 .sock_addrlen = sizeof(struct sockaddr_in6),
52 .l3_addrlen = 128/8,
53 .addrcmp = sock_inet6_addrcmp,
54 .bind = sock_inet_bind_receiver,
55 .get_src = sock_get_src,
56 .get_dst = sock_get_dst,
Willy Tarreau73bed9f2020-12-04 14:43:36 +010057 .set_port = sock_inet_set_port,
Willy Tarreaub0254cb2020-09-04 08:07:11 +020058};
Willy Tarreau0d06df62020-08-28 15:10:11 +020059
60/* PLEASE NOTE for function below:
61 * - sock_inet4_* is solely for AF_INET (IPv4)
62 * - sock_inet6_* is solely for AF_INET6 (IPv6)
63 * - sock_inet_* is for either
64 *
65 * The address family SHOULD always be checked. In some cases a function will
66 * be used in a situation where the address family is guaranteed (e.g. protocol
67 * definitions), so the test may be avoided. This special case must then be
68 * mentioned in the comment before the function definition.
69 */
70
Willy Tarreaud88e8c02020-08-28 16:06:01 +020071/* determine if the operating system uses IPV6_V6ONLY by default. 0=no, 1=yes.
72 * It also remains if IPv6 is not enabled/configured.
73 */
74int sock_inet6_v6only_default = 0;
Willy Tarreau0d06df62020-08-28 15:10:11 +020075
Willy Tarreaue5bdc512020-08-28 18:03:10 +020076/* Default TCPv4/TCPv6 MSS settings. -1=unknown. */
77int sock_inet_tcp_maxseg_default = -1;
78int sock_inet6_tcp_maxseg_default = -1;
79
Willy Tarreau0d06df62020-08-28 15:10:11 +020080/* Compares two AF_INET sockaddr addresses. Returns 0 if they match or non-zero
81 * if they do not match.
82 */
83int sock_inet4_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b)
84{
85 const struct sockaddr_in *a4 = (const struct sockaddr_in *)a;
86 const struct sockaddr_in *b4 = (const struct sockaddr_in *)b;
87
88 if (a->ss_family != b->ss_family)
89 return -1;
90
91 if (a->ss_family != AF_INET)
92 return -1;
93
94 if (a4->sin_port != b4->sin_port)
95 return -1;
96
97 return memcmp(&a4->sin_addr, &b4->sin_addr, sizeof(a4->sin_addr));
98}
99
100/* Compares two AF_INET6 sockaddr addresses. Returns 0 if they match or
101 * non-zero if they do not match.
102 */
103int sock_inet6_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b)
104{
105 const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)a;
106 const struct sockaddr_in6 *b6 = (const struct sockaddr_in6 *)b;
107
108 if (a->ss_family != b->ss_family)
109 return -1;
110
111 if (a->ss_family != AF_INET6)
112 return -1;
113
114 if (a6->sin6_port != b6->sin6_port)
115 return -1;
116
117 return memcmp(&a6->sin6_addr, &b6->sin6_addr, sizeof(a6->sin6_addr));
118}
Willy Tarreauc5a94c92020-08-28 15:19:45 +0200119
Willy Tarreau73bed9f2020-12-04 14:43:36 +0100120/* Sets the port <port> on IPv4 or IPv6 address <addr>. The address family is
121 * determined from the sockaddr_storage's address family. Nothing is done for
122 * other families.
123 */
124void sock_inet_set_port(struct sockaddr_storage *addr, int port)
125{
126 if (addr->ss_family == AF_INET)
127 ((struct sockaddr_in *)addr)->sin_port = htons(port);
128 else if (addr->ss_family == AF_INET6)
129 ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
130}
131
Willy Tarreauc5a94c92020-08-28 15:19:45 +0200132/*
133 * Retrieves the original destination address for the socket <fd> which must be
134 * of family AF_INET (not AF_INET6), with <dir> indicating if we're a listener
135 * (=0) or an initiator (!=0). In the case of a listener, if the original
136 * destination address was translated, the original address is retrieved. It
137 * returns 0 in case of success, -1 in case of error. The socket's source
138 * address is stored in <sa> for <salen> bytes.
139 */
140int sock_inet_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir)
141{
142 if (dir)
143 return getpeername(fd, sa, &salen);
144 else {
145 int ret = getsockname(fd, sa, &salen);
146
147 if (ret < 0)
148 return ret;
149
150#if defined(USE_TPROXY) && defined(SO_ORIGINAL_DST)
151 /* For TPROXY and Netfilter's NAT, we can retrieve the original
152 * IPv4 address before DNAT/REDIRECT. We must not do that with
153 * other families because v6-mapped IPv4 addresses are still
154 * reported as v4.
155 */
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200156 if (getsockopt(fd, IPPROTO_IP, SO_ORIGINAL_DST, sa, &salen) == 0)
Willy Tarreauc5a94c92020-08-28 15:19:45 +0200157 return 0;
158#endif
159 return ret;
160 }
161}
Willy Tarreau25140cc2020-08-28 15:40:33 +0200162
Willy Tarreau3fd3bdc2020-09-01 15:12:08 +0200163/* Returns true if the passed FD corresponds to a socket bound with RX_O_FOREIGN
Willy Tarreau25140cc2020-08-28 15:40:33 +0200164 * according to the various supported socket options. The socket's address family
165 * must be passed in <family>.
166 */
167int sock_inet_is_foreign(int fd, sa_family_t family)
168{
169 int val __maybe_unused;
170 socklen_t len __maybe_unused;
171
172 switch (family) {
173 case AF_INET:
174#if defined(IP_TRANSPARENT)
175 val = 0; len = sizeof(val);
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200176 if (getsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &val, &len) == 0 && val)
Willy Tarreau25140cc2020-08-28 15:40:33 +0200177 return 1;
178#endif
179#if defined(IP_FREEBIND)
180 val = 0; len = sizeof(val);
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200181 if (getsockopt(fd, IPPROTO_IP, IP_FREEBIND, &val, &len) == 0 && val)
Willy Tarreau25140cc2020-08-28 15:40:33 +0200182 return 1;
183#endif
184#if defined(IP_BINDANY)
185 val = 0; len = sizeof(val);
186 if (getsockopt(fd, IPPROTO_IP, IP_BINDANY, &val, &len) == 0 && val)
187 return 1;
188#endif
189#if defined(SO_BINDANY)
190 val = 0; len = sizeof(val);
191 if (getsockopt(fd, SOL_SOCKET, SO_BINDANY, &val, &len) == 0 && val)
192 return 1;
193#endif
194 break;
195
196 case AF_INET6:
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200197#if defined(IPV6_TRANSPARENT)
Willy Tarreau25140cc2020-08-28 15:40:33 +0200198 val = 0; len = sizeof(val);
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200199 if (getsockopt(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, &val, &len) == 0 && val)
Willy Tarreau25140cc2020-08-28 15:40:33 +0200200 return 1;
201#endif
202#if defined(IP_FREEBIND)
203 val = 0; len = sizeof(val);
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200204 if (getsockopt(fd, IPPROTO_IP, IP_FREEBIND, &val, &len) == 0 && val)
Willy Tarreau25140cc2020-08-28 15:40:33 +0200205 return 1;
206#endif
207#if defined(IPV6_BINDANY)
208 val = 0; len = sizeof(val);
209 if (getsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, &val, &len) == 0 && val)
210 return 1;
211#endif
212#if defined(SO_BINDANY)
213 val = 0; len = sizeof(val);
214 if (getsockopt(fd, SOL_SOCKET, SO_BINDANY, &val, &len) == 0 && val)
215 return 1;
216#endif
217 break;
218 }
219 return 0;
220}
Willy Tarreaud88e8c02020-08-28 16:06:01 +0200221
Willy Tarreau37bafdc2020-08-28 17:23:40 +0200222/* Attempt all known socket options to prepare an AF_INET4 socket to be bound
223 * to a foreign address. The socket must already exist and must not be bound.
224 * 1 is returned on success, 0 on failure. The caller must check the address
225 * family before calling this function.
226 */
227int sock_inet4_make_foreign(int fd)
228{
229 return
230#if defined(IP_TRANSPARENT)
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200231 setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) == 0 ||
Willy Tarreau37bafdc2020-08-28 17:23:40 +0200232#endif
233#if defined(IP_FREEBIND)
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200234 setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) == 0 ||
Willy Tarreau37bafdc2020-08-28 17:23:40 +0200235#endif
236#if defined(IP_BINDANY)
237 setsockopt(fd, IPPROTO_IP, IP_BINDANY, &one, sizeof(one)) == 0 ||
238#endif
239#if defined(SO_BINDANY)
240 setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == 0 ||
241#endif
242 0;
243}
244
245/* Attempt all known socket options to prepare an AF_INET6 socket to be bound
246 * to a foreign address. The socket must already exist and must not be bound.
247 * 1 is returned on success, 0 on failure. The caller must check the address
248 * family before calling this function.
249 */
250int sock_inet6_make_foreign(int fd)
251{
252 return
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200253#if defined(IPV6_TRANSPARENT)
254 setsockopt(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, &one, sizeof(one)) == 0 ||
Willy Tarreau37bafdc2020-08-28 17:23:40 +0200255#endif
256#if defined(IP_FREEBIND)
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200257 setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) == 0 ||
Willy Tarreau37bafdc2020-08-28 17:23:40 +0200258#endif
259#if defined(IPV6_BINDANY)
260 setsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) == 0 ||
261#endif
262#if defined(SO_BINDANY)
263 setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == 0 ||
264#endif
265 0;
266}
267
Willy Tarreau233ad282020-10-15 21:45:15 +0200268/* Binds receiver <rx>, and assigns rx->iocb and rx->owner as the callback and
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200269 * context, respectively. Returns and error code made of ERR_* bits on failure
270 * or ERR_NONE on success. On failure, an error message may be passed into
271 * <errmsg>.
272 */
Willy Tarreau233ad282020-10-15 21:45:15 +0200273int sock_inet_bind_receiver(struct receiver *rx, char **errmsg)
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200274{
275 int fd, err, ext;
276 /* copy listener addr because sometimes we need to switch family */
277 struct sockaddr_storage addr_inet = rx->addr;
278
279 /* force to classic sock family, not AF_CUST_* */
Willy Tarreauf1f66092020-09-04 08:15:31 +0200280 addr_inet.ss_family = rx->proto->fam->sock_family;
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200281
282 /* ensure we never return garbage */
283 if (errmsg)
284 *errmsg = 0;
285
286 err = ERR_NONE;
287
288 if (rx->flags & RX_F_BOUND)
289 return ERR_NONE;
290
Willy Tarreau0e1aaf42023-02-27 16:39:32 +0100291 if (rx->flags & RX_F_MUST_DUP) {
292 /* this is a secondary receiver that is an exact copy of a
293 * reference which must already be bound (or has failed).
294 * We'll try to dup() the other one's FD and take it. We
295 * try hard not to reconfigure the socket since it's shared.
296 */
297 BUG_ON(!rx->shard_info);
298 if (!(rx->shard_info->ref->flags & RX_F_BOUND)) {
299 /* it's assumed that the first one has already reported
300 * the error, let's not spam with another one, and do
301 * not set ERR_ALERT.
302 */
303 err |= ERR_RETRYABLE;
304 goto bind_ret_err;
305 }
306 /* taking the other one's FD will result in it being marked
307 * extern and being dup()ed. Let's mark the receiver as
308 * inherited so that it properly bypasses all second-stage
309 * setup and avoids being passed to new processes.
310 */
311 rx->flags |= RX_F_INHERITED;
312 rx->fd = rx->shard_info->ref->fd;
313 }
314
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200315 /* if no FD was assigned yet, we'll have to either find a compatible
316 * one or create a new one.
317 */
318 if (rx->fd == -1)
319 rx->fd = sock_find_compatible_fd(rx);
320
321 /* if the receiver now has an fd assigned, then we were offered the fd
322 * by an external process (most likely the parent), and we don't want
323 * to create a new socket. However we still want to set a few flags on
324 * the socket.
325 */
326 fd = rx->fd;
327 ext = (fd >= 0);
328
329 if (!ext) {
Willy Tarreauf1f66092020-09-04 08:15:31 +0200330 fd = my_socketat(rx->settings->netns, rx->proto->fam->sock_domain,
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200331 rx->proto->sock_type, rx->proto->sock_prot);
332 if (fd == -1) {
333 err |= ERR_RETRYABLE | ERR_ALERT;
Willy Tarreau36722d22020-09-17 08:32:17 +0200334 memprintf(errmsg, "cannot create receiving socket (%s)", strerror(errno));
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200335 goto bind_return;
336 }
337 }
338
Willy Tarreau145b17f2023-01-11 10:59:52 +0100339 if (ext && fd < global.maxsock && fdtab[fd].owner) {
340 /* This FD was already bound so this means that it was already
341 * known and registered before parsing, hence it's an inherited
342 * FD. The only reason why it's already known here is that it
343 * has been registered multiple times (multiple listeners on the
344 * same, or a "shards" directive on the line). There cannot be
345 * multiple listeners on one FD but at least we can create a
346 * new one from the original one. We won't reconfigure it,
347 * however, as this was already done for the first one.
348 */
349 fd = dup(fd);
350 if (fd == -1) {
351 err |= ERR_RETRYABLE | ERR_ALERT;
352 memprintf(errmsg, "cannot dup() receiving socket (%s)", strerror(errno));
353 goto bind_return;
354 }
355 }
356
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200357 if (fd >= global.maxsock) {
358 err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
359 memprintf(errmsg, "not enough free sockets (raise '-n' parameter)");
360 goto bind_close_return;
361 }
362
Willy Tarreau38247432022-04-26 10:24:14 +0200363 if (fd_set_nonblock(fd) == -1) {
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200364 err |= ERR_FATAL | ERR_ALERT;
365 memprintf(errmsg, "cannot make socket non-blocking");
366 goto bind_close_return;
367 }
368
369 if (!ext && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
370 /* not fatal but should be reported */
371 memprintf(errmsg, "cannot do so_reuseaddr");
372 err |= ERR_ALERT;
373 }
374
375#ifdef SO_REUSEPORT
376 /* OpenBSD and Linux 3.9 support this. As it's present in old libc versions of
377 * Linux, it might return an error that we will silently ignore.
378 */
Willy Tarreau785b89f2023-04-22 15:09:07 +0200379 if (!ext && (rx->proto->flags & PROTO_F_REUSEPORT_SUPPORTED))
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200380 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
381#endif
382
Willy Tarreau9f53b7b2023-04-22 20:12:59 +0200383#ifdef SO_REUSEPORT_LB
384 /* FreeBSD 12 and above use this to load-balance incoming connections.
385 * This is limited to 256 listeners per group however.
386 */
Willy Tarreau785b89f2023-04-22 15:09:07 +0200387 if (!ext && (rx->proto->flags & PROTO_F_REUSEPORT_SUPPORTED))
Willy Tarreau9f53b7b2023-04-22 20:12:59 +0200388 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &one, sizeof(one));
389#endif
390
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200391 if (!ext && (rx->settings->options & RX_O_FOREIGN)) {
392 switch (addr_inet.ss_family) {
393 case AF_INET:
394 if (!sock_inet4_make_foreign(fd)) {
395 memprintf(errmsg, "cannot make receiving socket transparent");
396 err |= ERR_ALERT;
397 }
398 break;
399 case AF_INET6:
400 if (!sock_inet6_make_foreign(fd)) {
401 memprintf(errmsg, "cannot make receiving socket transparent");
402 err |= ERR_ALERT;
403 }
404 break;
405 }
406 }
407
408#ifdef SO_BINDTODEVICE
409 /* Note: this might fail if not CAP_NET_RAW */
410 if (!ext && rx->settings->interface) {
411 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
412 rx->settings->interface,
413 strlen(rx->settings->interface) + 1) == -1) {
Willy Tarreauf78b52e2021-10-14 11:41:19 +0200414 memprintf(errmsg, "cannot bind receiver to device '%s' (%s)", rx->settings->interface, strerror(errno));
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200415 err |= ERR_WARN;
416 }
417 }
418#endif
419
420#if defined(IPV6_V6ONLY)
421 if (addr_inet.ss_family == AF_INET6 && !ext) {
422 /* Prepare to match the v6only option against what we really want. Note
423 * that sadly the two options are not exclusive to each other and that
424 * v6only is stronger than v4v6.
425 */
426 if ((rx->settings->options & RX_O_V6ONLY) ||
427 (sock_inet6_v6only_default && !(rx->settings->options & RX_O_V4V6)))
428 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
429 else
430 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
431 }
432#endif
433
Willy Tarreauf1f66092020-09-04 08:15:31 +0200434 if (!ext && bind(fd, (struct sockaddr *)&addr_inet, rx->proto->fam->sock_addrlen) == -1) {
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200435 err |= ERR_RETRYABLE | ERR_ALERT;
Willy Tarreau36722d22020-09-17 08:32:17 +0200436 memprintf(errmsg, "cannot bind socket (%s)", strerror(errno));
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200437 goto bind_close_return;
438 }
439
440 rx->fd = fd;
441 rx->flags |= RX_F_BOUND;
442
Willy Tarreau9464bb12022-07-05 05:16:13 +0200443 fd_insert(fd, rx->owner, rx->iocb, rx->bind_tgroup, rx->bind_thread);
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200444
445 /* for now, all regularly bound TCP listeners are exportable */
446 if (!(rx->flags & RX_F_INHERITED))
Willy Tarreau9063a662021-04-06 18:09:06 +0200447 HA_ATOMIC_OR(&fdtab[fd].state, FD_EXPORTED);
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200448
449 bind_return:
450 if (errmsg && *errmsg) {
451 char pn[INET6_ADDRSTRLEN];
452
453 addr_to_str(&addr_inet, pn, sizeof(pn));
Willy Tarreau6823a3a2021-10-14 11:59:15 +0200454 memprintf(errmsg, "%s for [%s:%d]", *errmsg, pn, get_host_port(&addr_inet));
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200455 }
Willy Tarreau0e1aaf42023-02-27 16:39:32 +0100456 bind_ret_err:
Willy Tarreaud69ce1f2020-09-01 14:18:04 +0200457 return err;
458
459 bind_close_return:
460 close(fd);
461 goto bind_return;
462}
463
Willy Tarreaud88e8c02020-08-28 16:06:01 +0200464static void sock_inet_prepare()
465{
466 int fd, val;
467 socklen_t len;
468
Willy Tarreaue5bdc512020-08-28 18:03:10 +0200469 fd = socket(AF_INET, SOCK_STREAM, 0);
470 if (fd >= 0) {
471#ifdef TCP_MAXSEG
472 /* retrieve the OS' default mss for TCPv4 */
473 len = sizeof(val);
474 if (getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, &val, &len) == 0)
475 sock_inet_tcp_maxseg_default = val;
476#endif
477 close(fd);
478 }
479
Willy Tarreaud88e8c02020-08-28 16:06:01 +0200480 fd = socket(AF_INET6, SOCK_STREAM, 0);
481 if (fd >= 0) {
482#if defined(IPV6_V6ONLY)
483 /* retrieve the OS' bindv6only value */
484 len = sizeof(val);
485 if (getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, &len) == 0 && val > 0)
486 sock_inet6_v6only_default = 1;
487#endif
Willy Tarreaue5bdc512020-08-28 18:03:10 +0200488
489#ifdef TCP_MAXSEG
490 /* retrieve the OS' default mss for TCPv6 */
491 len = sizeof(val);
492 if (getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, &val, &len) == 0)
493 sock_inet6_tcp_maxseg_default = val;
494#endif
Willy Tarreaud88e8c02020-08-28 16:06:01 +0200495 close(fd);
496 }
497}
498
499INITCALL0(STG_PREPARE, sock_inet_prepare);
Willy Tarreau37bafdc2020-08-28 17:23:40 +0200500
501
502REGISTER_BUILD_OPTS("Built with transparent proxy support using:"
503#if defined(IP_TRANSPARENT)
504 " IP_TRANSPARENT"
505#endif
506#if defined(IPV6_TRANSPARENT)
507 " IPV6_TRANSPARENT"
508#endif
509#if defined(IP_FREEBIND)
510 " IP_FREEBIND"
511#endif
512#if defined(IP_BINDANY)
513 " IP_BINDANY"
514#endif
515#if defined(IPV6_BINDANY)
516 " IPV6_BINDANY"
517#endif
518#if defined(SO_BINDANY)
519 " SO_BINDANY"
520#endif
521 "");