]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-util.c
event: make sure we keep a reference to all events we dispatch while we do so.
[thirdparty/systemd.git] / src / shared / socket-util.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
42f4e3c4 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
42f4e3c4
LP
22#include <assert.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <arpa/inet.h>
28#include <stdio.h>
542563ba 29#include <net/if.h>
b5a0699f
LP
30#include <sys/types.h>
31#include <sys/stat.h>
0e098b15
LP
32#include <stddef.h>
33#include <sys/ioctl.h>
42f4e3c4
LP
34
35#include "macro.h"
36#include "util.h"
49e942b2 37#include "mkdir.h"
9eb977db 38#include "path-util.h"
42f4e3c4 39#include "socket-util.h"
16c42ce1 40#include "missing.h"
a5c32cff 41#include "fileio.h"
42f4e3c4 42
542563ba 43int socket_address_parse(SocketAddress *a, const char *s) {
42f4e3c4
LP
44 int r;
45 char *e, *n;
46 unsigned u;
47
48 assert(a);
49 assert(s);
50
9152c765 51 zero(*a);
542563ba 52 a->type = SOCK_STREAM;
42f4e3c4
LP
53
54 if (*s == '[') {
55 /* IPv6 in [x:.....:z]:p notation */
56
5bfcc1c6
FF
57 if (!socket_ipv6_is_supported()) {
58 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
59 return -EAFNOSUPPORT;
60 }
61
42f4e3c4
LP
62 if (!(e = strchr(s+1, ']')))
63 return -EINVAL;
64
65 if (!(n = strndup(s+1, e-s-1)))
66 return -ENOMEM;
67
68 errno = 0;
69 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
70 free(n);
8333c77e 71 return errno > 0 ? -errno : -EINVAL;
42f4e3c4
LP
72 }
73
74 free(n);
75
76 e++;
77 if (*e != ':')
78 return -EINVAL;
79
80 e++;
81 if ((r = safe_atou(e, &u)) < 0)
82 return r;
83
84 if (u <= 0 || u > 0xFFFF)
85 return -EINVAL;
86
87 a->sockaddr.in6.sin6_family = AF_INET6;
88 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
89 a->size = sizeof(struct sockaddr_in6);
42f4e3c4
LP
90
91 } else if (*s == '/') {
92 /* AF_UNIX socket */
93
94 size_t l;
95
96 l = strlen(s);
97 if (l >= sizeof(a->sockaddr.un.sun_path))
98 return -EINVAL;
99
100 a->sockaddr.un.sun_family = AF_UNIX;
101 memcpy(a->sockaddr.un.sun_path, s, l);
0e098b15 102 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
42f4e3c4 103
1c24e7bd 104 } else if (*s == '@') {
42f4e3c4
LP
105 /* Abstract AF_UNIX socket */
106 size_t l;
107
108 l = strlen(s+1);
109 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
110 return -EINVAL;
111
112 a->sockaddr.un.sun_family = AF_UNIX;
113 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
0e098b15 114 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
42f4e3c4
LP
115
116 } else {
117
118 if ((e = strchr(s, ':'))) {
542563ba
LP
119
120 if ((r = safe_atou(e+1, &u)) < 0)
121 return r;
122
123 if (u <= 0 || u > 0xFFFF)
124 return -EINVAL;
42f4e3c4 125
42f4e3c4
LP
126 if (!(n = strndup(s, e-s)))
127 return -ENOMEM;
128
542563ba
LP
129 /* IPv4 in w.x.y.z:p notation? */
130 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
42f4e3c4 131 free(n);
542563ba 132 return -errno;
42f4e3c4
LP
133 }
134
542563ba
LP
135 if (r > 0) {
136 /* Gotcha, it's a traditional IPv4 address */
137 free(n);
42f4e3c4 138
542563ba
LP
139 a->sockaddr.in4.sin_family = AF_INET;
140 a->sockaddr.in4.sin_port = htons((uint16_t) u);
141 a->size = sizeof(struct sockaddr_in);
142 } else {
143 unsigned idx;
42f4e3c4 144
acbb0225
LP
145 if (strlen(n) > IF_NAMESIZE-1) {
146 free(n);
147 return -EINVAL;
148 }
149
542563ba
LP
150 /* Uh, our last resort, an interface name */
151 idx = if_nametoindex(n);
152 free(n);
153
83c60c9f 154 if (idx == 0)
542563ba 155 return -EINVAL;
42f4e3c4 156
5bfcc1c6
FF
157 if (!socket_ipv6_is_supported()) {
158 log_warning("Binding to interface is not available since kernel does not support IPv6.");
159 return -EAFNOSUPPORT;
160 }
161
542563ba
LP
162 a->sockaddr.in6.sin6_family = AF_INET6;
163 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
164 a->sockaddr.in6.sin6_scope_id = idx;
83c60c9f 165 a->sockaddr.in6.sin6_addr = in6addr_any;
542563ba
LP
166 a->size = sizeof(struct sockaddr_in6);
167 }
42f4e3c4
LP
168 } else {
169
170 /* Just a port */
5198dabc
LP
171 r = safe_atou(s, &u);
172 if (r < 0)
42f4e3c4
LP
173 return r;
174
175 if (u <= 0 || u > 0xFFFF)
176 return -EINVAL;
177
5bfcc1c6
FF
178 if (socket_ipv6_is_supported()) {
179 a->sockaddr.in6.sin6_family = AF_INET6;
180 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
181 a->sockaddr.in6.sin6_addr = in6addr_any;
182 a->size = sizeof(struct sockaddr_in6);
183 } else {
184 a->sockaddr.in4.sin_family = AF_INET;
185 a->sockaddr.in4.sin_port = htons((uint16_t) u);
186 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
187 a->size = sizeof(struct sockaddr_in);
188 }
42f4e3c4
LP
189 }
190 }
191
192 return 0;
193}
194
7a22745a
LP
195int socket_address_parse_netlink(SocketAddress *a, const char *s) {
196 int family;
197 unsigned group = 0;
f8b69d1d 198 _cleanup_free_ char *sfamily = NULL;
7a22745a
LP
199 assert(a);
200 assert(s);
201
202 zero(*a);
203 a->type = SOCK_RAW;
204
205 errno = 0;
206 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
bcb161b0 207 return errno > 0 ? -errno : -EINVAL;
7a22745a 208
f8b69d1d
MS
209 family = netlink_family_from_string(sfamily);
210 if (family < 0)
211 return -EINVAL;
7a22745a
LP
212
213 a->sockaddr.nl.nl_family = AF_NETLINK;
214 a->sockaddr.nl.nl_groups = group;
215
216 a->type = SOCK_RAW;
217 a->size = sizeof(struct sockaddr_nl);
218 a->protocol = family;
219
220 return 0;
221}
222
542563ba 223int socket_address_verify(const SocketAddress *a) {
42f4e3c4
LP
224 assert(a);
225
542563ba 226 switch (socket_address_family(a)) {
42f4e3c4 227
7a22745a
LP
228 case AF_INET:
229 if (a->size != sizeof(struct sockaddr_in))
230 return -EINVAL;
42f4e3c4 231
7a22745a
LP
232 if (a->sockaddr.in4.sin_port == 0)
233 return -EINVAL;
42f4e3c4 234
7a22745a
LP
235 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
236 return -EINVAL;
42f4e3c4 237
7a22745a
LP
238 return 0;
239
240 case AF_INET6:
241 if (a->size != sizeof(struct sockaddr_in6))
242 return -EINVAL;
42f4e3c4 243
7a22745a
LP
244 if (a->sockaddr.in6.sin6_port == 0)
245 return -EINVAL;
42f4e3c4 246
7a22745a
LP
247 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
248 return -EINVAL;
42f4e3c4 249
7a22745a 250 return 0;
42f4e3c4 251
7a22745a
LP
252 case AF_UNIX:
253 if (a->size < offsetof(struct sockaddr_un, sun_path))
254 return -EINVAL;
42f4e3c4 255
7a22745a 256 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 257
7a22745a
LP
258 if (a->sockaddr.un.sun_path[0] != 0) {
259 char *e;
260
261 /* path */
262 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
263 return -EINVAL;
264
265 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
266 return -EINVAL;
42f4e3c4 267 }
7a22745a 268 }
42f4e3c4 269
5a2b80ce 270 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
7a22745a 271 return -EINVAL;
42f4e3c4 272
7a22745a
LP
273 return 0;
274
275 case AF_NETLINK:
276
277 if (a->size != sizeof(struct sockaddr_nl))
278 return -EINVAL;
279
280 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
281 return -EINVAL;
282
283 return 0;
284
285 default:
286 return -EAFNOSUPPORT;
42f4e3c4
LP
287 }
288}
289
542563ba 290int socket_address_print(const SocketAddress *a, char **p) {
42f4e3c4
LP
291 int r;
292 assert(a);
293 assert(p);
294
542563ba 295 if ((r = socket_address_verify(a)) < 0)
42f4e3c4
LP
296 return r;
297
542563ba 298 switch (socket_address_family(a)) {
42f4e3c4 299
7a22745a
LP
300 case AF_INET: {
301 char *ret;
42f4e3c4 302
b47d419c
ZJS
303 ret = new(char, INET_ADDRSTRLEN+1+5+1);
304 if (!ret)
7a22745a 305 return -ENOMEM;
42f4e3c4 306
7a22745a
LP
307 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
308 free(ret);
309 return -errno;
42f4e3c4
LP
310 }
311
7a22745a
LP
312 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
313 *p = ret;
314 return 0;
315 }
42f4e3c4 316
7a22745a
LP
317 case AF_INET6: {
318 char *ret;
42f4e3c4 319
b47d419c
ZJS
320 ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1);
321 if (!ret)
7a22745a 322 return -ENOMEM;
42f4e3c4 323
7a22745a
LP
324 ret[0] = '[';
325 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
326 free(ret);
327 return -errno;
42f4e3c4
LP
328 }
329
7a22745a
LP
330 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
331 *p = ret;
332 return 0;
333 }
42f4e3c4 334
7a22745a
LP
335 case AF_UNIX: {
336 char *ret;
42f4e3c4 337
7a22745a 338 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
b47d419c
ZJS
339 ret = strdup("<unnamed>");
340 if (!ret)
7a22745a 341 return -ENOMEM;
42f4e3c4 342
7a22745a
LP
343 } else if (a->sockaddr.un.sun_path[0] == 0) {
344 /* abstract */
42f4e3c4 345
7a22745a
LP
346 /* FIXME: We assume we can print the
347 * socket path here and that it hasn't
348 * more than one NUL byte. That is
349 * actually an invalid assumption */
42f4e3c4 350
b47d419c
ZJS
351 ret = new(char, sizeof(a->sockaddr.un.sun_path)+1);
352 if (!ret)
7a22745a 353 return -ENOMEM;
42f4e3c4 354
7a22745a
LP
355 ret[0] = '@';
356 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
357 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
42f4e3c4 358
7a22745a 359 } else {
b47d419c
ZJS
360 ret = strdup(a->sockaddr.un.sun_path);
361 if (!ret)
7a22745a 362 return -ENOMEM;
42f4e3c4
LP
363 }
364
7a22745a
LP
365 *p = ret;
366 return 0;
367 }
368
369 case AF_NETLINK: {
7fd1b19b 370 _cleanup_free_ char *sfamily = NULL;
7a22745a 371
f8b69d1d 372 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
7a22745a 373 if (r < 0)
f8b69d1d
MS
374 return r;
375 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
8520cfa5
MS
376 if (r < 0)
377 return -ENOMEM;
7a22745a
LP
378
379 return 0;
380 }
381
382 default:
383 return -EINVAL;
42f4e3c4
LP
384 }
385}
386
4f2d528d
LP
387bool socket_address_can_accept(const SocketAddress *a) {
388 assert(a);
389
390 return
391 a->type == SOCK_STREAM ||
392 a->type == SOCK_SEQPACKET;
393}
a16e1123
LP
394
395bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
396 assert(a);
397 assert(b);
398
399 /* Invalid addresses are unequal to all */
400 if (socket_address_verify(a) < 0 ||
401 socket_address_verify(b) < 0)
402 return false;
403
404 if (a->type != b->type)
405 return false;
406
407 if (a->size != b->size)
408 return false;
409
410 if (socket_address_family(a) != socket_address_family(b))
411 return false;
412
413 switch (socket_address_family(a)) {
414
415 case AF_INET:
416 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
417 return false;
418
419 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
420 return false;
421
422 break;
423
424 case AF_INET6:
425 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
426 return false;
427
428 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
429 return false;
430
431 break;
432
433 case AF_UNIX:
434
435 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
436 return false;
437
438 if (a->sockaddr.un.sun_path[0]) {
641906e9 439 if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
a16e1123
LP
440 return false;
441 } else {
b12c1e7c 442 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
a16e1123
LP
443 return false;
444 }
445
446 break;
447
7a22745a
LP
448 case AF_NETLINK:
449
450 if (a->protocol != b->protocol)
451 return false;
452
453 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
454 return false;
455
456 break;
457
a16e1123
LP
458 default:
459 /* Cannot compare, so we assume the addresses are different */
460 return false;
461 }
462
463 return true;
464}
465
27ca8d7a 466bool socket_address_is(const SocketAddress *a, const char *s, int type) {
a16e1123
LP
467 struct SocketAddress b;
468
469 assert(a);
470 assert(s);
471
472 if (socket_address_parse(&b, s) < 0)
473 return false;
474
27ca8d7a
LP
475 b.type = type;
476
a16e1123 477 return socket_address_equal(a, &b);
6e2ef85b
LP
478}
479
7a22745a
LP
480bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
481 struct SocketAddress b;
482
483 assert(a);
484 assert(s);
485
486 if (socket_address_parse_netlink(&b, s) < 0)
487 return false;
488
489 return socket_address_equal(a, &b);
490}
491
a57f7e2c 492const char* socket_address_get_path(const SocketAddress *a) {
6e2ef85b
LP
493 assert(a);
494
495 if (socket_address_family(a) != AF_UNIX)
a57f7e2c 496 return NULL;
6e2ef85b
LP
497
498 if (a->sockaddr.un.sun_path[0] == 0)
a57f7e2c 499 return NULL;
a16e1123 500
a57f7e2c 501 return a->sockaddr.un.sun_path;
a16e1123 502}
c0120d99 503
5bfcc1c6 504bool socket_ipv6_is_supported(void) {
f89f1e8f
AB
505 char *l = 0;
506 bool enabled;
507
508 if (access("/sys/module/ipv6", F_OK) != 0)
509 return 0;
510
511 /* If we can't check "disable" parameter, assume enabled */
512 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
513 return 1;
514
515 /* If module was loaded with disable=1 no IPv6 available */
516 enabled = l[0] == '0';
517 free(l);
518
519 return enabled;
5bfcc1c6
FF
520}
521
01e10de3
LP
522bool socket_address_matches_fd(const SocketAddress *a, int fd) {
523 union sockaddr_union sa;
524 socklen_t salen = sizeof(sa), solen;
525 int protocol, type;
526
527 assert(a);
528 assert(fd >= 0);
529
530 if (getsockname(fd, &sa.sa, &salen) < 0)
531 return false;
532
533 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
534 return false;
535
536 solen = sizeof(type);
537 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
538 return false;
539
540 if (type != a->type)
541 return false;
542
543 if (a->protocol != 0) {
544 solen = sizeof(protocol);
545 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
546 return false;
547
548 if (protocol != a->protocol)
549 return false;
550 }
551
552 switch (sa.sa.sa_family) {
553
554 case AF_INET:
555 return sa.in4.sin_port == a->sockaddr.in4.sin_port &&
556 sa.in4.sin_addr.s_addr == a->sockaddr.in4.sin_addr.s_addr;
557
558 case AF_INET6:
559 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
560 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
561
562 case AF_UNIX:
563 return salen == a->size &&
564 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
565
566 }
567
568 return false;
569}
570
8569a776
LP
571int getpeername_pretty(int fd, char **ret) {
572
573 union {
574 struct sockaddr sa;
575 struct sockaddr_un un;
576 struct sockaddr_in in;
577 struct sockaddr_in6 in6;
578 struct sockaddr_storage storage;
579 } sa;
580
581 socklen_t salen;
582 char *p;
583
584 assert(fd >= 0);
585 assert(ret);
586
587 salen = sizeof(sa);
588 if (getpeername(fd, &sa.sa, &salen) < 0)
589 return -errno;
590
591 switch (sa.sa.sa_family) {
592
593 case AF_INET: {
594 uint32_t a;
595
596 a = ntohl(sa.in.sin_addr.s_addr);
597
598 if (asprintf(&p,
599 "%u.%u.%u.%u:%u",
600 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
601 ntohs(sa.in.sin_port)) < 0)
602 return -ENOMEM;
603
604 break;
605 }
606
607 case AF_INET6: {
608 static const unsigned char ipv4_prefix[] = {
609 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
610 };
611
612 if (memcmp(&sa.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
613 const uint8_t *a = sa.in6.sin6_addr.s6_addr+12;
614
615 if (asprintf(&p,
616 "%u.%u.%u.%u:%u",
617 a[0], a[1], a[2], a[3],
618 ntohs(sa.in6.sin6_port)) < 0)
619 return -ENOMEM;
620 } else {
621 char a[INET6_ADDRSTRLEN];
622
623 if (asprintf(&p,
624 "%s:%u",
625 inet_ntop(AF_INET6, &sa.in6.sin6_addr, a, sizeof(a)),
626 ntohs(sa.in6.sin6_port)) < 0)
627 return -ENOMEM;
628 }
629
630 break;
631 }
632
633 case AF_UNIX: {
634 struct ucred ucred;
635
636 salen = sizeof(ucred);
637 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &salen) < 0)
638 return -errno;
639
640 if (asprintf(&p, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.pid) < 0)
641 return -ENOMEM;
642
643 break;
644 }
645
646 default:
647 return -ENOTSUP;
648 }
649
650 *ret = p;
651 return 0;
652}
653
7a22745a
LP
654static const char* const netlink_family_table[] = {
655 [NETLINK_ROUTE] = "route",
656 [NETLINK_FIREWALL] = "firewall",
657 [NETLINK_INET_DIAG] = "inet-diag",
658 [NETLINK_NFLOG] = "nflog",
659 [NETLINK_XFRM] = "xfrm",
660 [NETLINK_SELINUX] = "selinux",
661 [NETLINK_ISCSI] = "iscsi",
662 [NETLINK_AUDIT] = "audit",
663 [NETLINK_FIB_LOOKUP] = "fib-lookup",
664 [NETLINK_CONNECTOR] = "connector",
665 [NETLINK_NETFILTER] = "netfilter",
666 [NETLINK_IP6_FW] = "ip6-fw",
667 [NETLINK_DNRTMSG] = "dnrtmsg",
668 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
669 [NETLINK_GENERIC] = "generic",
670 [NETLINK_SCSITRANSPORT] = "scsitransport",
671 [NETLINK_ECRYPTFS] = "ecryptfs"
672};
673
f8b69d1d 674DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
7a22745a 675
c0120d99
LP
676static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
677 [SOCKET_ADDRESS_DEFAULT] = "default",
678 [SOCKET_ADDRESS_BOTH] = "both",
679 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
680};
681
682DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);