1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <arpa/inet.h>
26 #include <netinet/ip.h>
35 #include "alloc-util.h"
38 #include "format-util.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "socket-util.h"
45 #include "string-table.h"
46 #include "string-util.h"
48 #include "user-util.h"
53 # define IDN_FLAGS (NI_IDN|NI_IDN_USE_STD3_ASCII_RULES)
58 int socket_address_parse(SocketAddress
*a
, const char *s
) {
67 a
->type
= SOCK_STREAM
;
70 /* IPv6 in [x:.....:z]:p notation */
76 n
= strndupa(s
+1, e
-s
-1);
79 if (inet_pton(AF_INET6
, n
, &a
->sockaddr
.in6
.sin6_addr
) <= 0)
80 return errno
> 0 ? -errno
: -EINVAL
;
91 if (u
<= 0 || u
> 0xFFFF)
94 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
95 a
->sockaddr
.in6
.sin6_port
= htobe16((uint16_t)u
);
96 a
->size
= sizeof(struct sockaddr_in6
);
98 } else if (*s
== '/') {
104 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
))
107 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
108 memcpy(a
->sockaddr
.un
.sun_path
, s
, l
);
109 a
->size
= offsetof(struct sockaddr_un
, sun_path
) + l
+ 1;
111 } else if (*s
== '@') {
112 /* Abstract AF_UNIX socket */
116 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
) - 1)
119 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
120 memcpy(a
->sockaddr
.un
.sun_path
+1, s
+1, l
);
121 a
->size
= offsetof(struct sockaddr_un
, sun_path
) + 1 + l
;
123 } else if (startswith(s
, "vsock:")) {
124 /* AF_VSOCK socket in vsock:cid:port notation */
125 const char *cid_start
= s
+ strlen("vsock:");
127 e
= strchr(cid_start
, ':');
131 r
= safe_atou(e
+1, &u
);
135 n
= strndupa(cid_start
, e
- cid_start
);
137 r
= safe_atou(n
, &a
->sockaddr
.vm
.svm_cid
);
141 a
->sockaddr
.vm
.svm_cid
= VMADDR_CID_ANY
;
143 a
->sockaddr
.vm
.svm_family
= AF_VSOCK
;
144 a
->sockaddr
.vm
.svm_port
= u
;
145 a
->size
= sizeof(struct sockaddr_vm
);
150 r
= safe_atou(e
+1, &u
);
154 if (u
<= 0 || u
> 0xFFFF)
157 n
= strndupa(s
, e
-s
);
159 /* IPv4 in w.x.y.z:p notation? */
160 r
= inet_pton(AF_INET
, n
, &a
->sockaddr
.in
.sin_addr
);
165 /* Gotcha, it's a traditional IPv4 address */
166 a
->sockaddr
.in
.sin_family
= AF_INET
;
167 a
->sockaddr
.in
.sin_port
= htobe16((uint16_t)u
);
168 a
->size
= sizeof(struct sockaddr_in
);
172 if (strlen(n
) > IF_NAMESIZE
-1)
175 /* Uh, our last resort, an interface name */
176 idx
= if_nametoindex(n
);
180 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
181 a
->sockaddr
.in6
.sin6_port
= htobe16((uint16_t)u
);
182 a
->sockaddr
.in6
.sin6_scope_id
= idx
;
183 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
184 a
->size
= sizeof(struct sockaddr_in6
);
189 r
= safe_atou(s
, &u
);
193 if (u
<= 0 || u
> 0xFFFF)
196 if (socket_ipv6_is_supported()) {
197 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
198 a
->sockaddr
.in6
.sin6_port
= htobe16((uint16_t)u
);
199 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
200 a
->size
= sizeof(struct sockaddr_in6
);
202 a
->sockaddr
.in
.sin_family
= AF_INET
;
203 a
->sockaddr
.in
.sin_port
= htobe16((uint16_t)u
);
204 a
->sockaddr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
205 a
->size
= sizeof(struct sockaddr_in
);
213 int socket_address_parse_and_warn(SocketAddress
*a
, const char *s
) {
217 /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
219 r
= socket_address_parse(&b
, s
);
223 if (!socket_ipv6_is_supported() && b
.sockaddr
.sa
.sa_family
== AF_INET6
) {
224 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
225 return -EAFNOSUPPORT
;
232 int socket_address_parse_netlink(SocketAddress
*a
, const char *s
) {
235 _cleanup_free_
char *sfamily
= NULL
;
243 if (sscanf(s
, "%ms %u", &sfamily
, &group
) < 1)
244 return errno
> 0 ? -errno
: -EINVAL
;
246 family
= netlink_family_from_string(sfamily
);
250 a
->sockaddr
.nl
.nl_family
= AF_NETLINK
;
251 a
->sockaddr
.nl
.nl_groups
= group
;
254 a
->size
= sizeof(struct sockaddr_nl
);
255 a
->protocol
= family
;
260 int socket_address_verify(const SocketAddress
*a
) {
263 switch (socket_address_family(a
)) {
266 if (a
->size
!= sizeof(struct sockaddr_in
))
269 if (a
->sockaddr
.in
.sin_port
== 0)
272 if (!IN_SET(a
->type
, SOCK_STREAM
, SOCK_DGRAM
))
278 if (a
->size
!= sizeof(struct sockaddr_in6
))
281 if (a
->sockaddr
.in6
.sin6_port
== 0)
284 if (!IN_SET(a
->type
, SOCK_STREAM
, SOCK_DGRAM
))
290 if (a
->size
< offsetof(struct sockaddr_un
, sun_path
))
293 if (a
->size
> offsetof(struct sockaddr_un
, sun_path
)) {
295 if (a
->sockaddr
.un
.sun_path
[0] != 0) {
299 e
= memchr(a
->sockaddr
.un
.sun_path
, 0, sizeof(a
->sockaddr
.un
.sun_path
));
303 if (a
->size
!= offsetof(struct sockaddr_un
, sun_path
) + (e
- a
->sockaddr
.un
.sun_path
) + 1)
308 if (!IN_SET(a
->type
, SOCK_STREAM
, SOCK_DGRAM
, SOCK_SEQPACKET
))
315 if (a
->size
!= sizeof(struct sockaddr_nl
))
318 if (!IN_SET(a
->type
, SOCK_RAW
, SOCK_DGRAM
))
324 if (a
->size
!= sizeof(struct sockaddr_vm
))
327 if (!IN_SET(a
->type
, SOCK_STREAM
, SOCK_DGRAM
))
333 return -EAFNOSUPPORT
;
337 int socket_address_print(const SocketAddress
*a
, char **ret
) {
343 r
= socket_address_verify(a
);
347 if (socket_address_family(a
) == AF_NETLINK
) {
348 _cleanup_free_
char *sfamily
= NULL
;
350 r
= netlink_family_to_string_alloc(a
->protocol
, &sfamily
);
354 r
= asprintf(ret
, "%s %u", sfamily
, a
->sockaddr
.nl
.nl_groups
);
361 return sockaddr_pretty(&a
->sockaddr
.sa
, a
->size
, false, true, ret
);
364 bool socket_address_can_accept(const SocketAddress
*a
) {
368 IN_SET(a
->type
, SOCK_STREAM
, SOCK_SEQPACKET
);
371 bool socket_address_equal(const SocketAddress
*a
, const SocketAddress
*b
) {
375 /* Invalid addresses are unequal to all */
376 if (socket_address_verify(a
) < 0 ||
377 socket_address_verify(b
) < 0)
380 if (a
->type
!= b
->type
)
383 if (socket_address_family(a
) != socket_address_family(b
))
386 switch (socket_address_family(a
)) {
389 if (a
->sockaddr
.in
.sin_addr
.s_addr
!= b
->sockaddr
.in
.sin_addr
.s_addr
)
392 if (a
->sockaddr
.in
.sin_port
!= b
->sockaddr
.in
.sin_port
)
398 if (memcmp(&a
->sockaddr
.in6
.sin6_addr
, &b
->sockaddr
.in6
.sin6_addr
, sizeof(a
->sockaddr
.in6
.sin6_addr
)) != 0)
401 if (a
->sockaddr
.in6
.sin6_port
!= b
->sockaddr
.in6
.sin6_port
)
407 if (a
->size
<= offsetof(struct sockaddr_un
, sun_path
) ||
408 b
->size
<= offsetof(struct sockaddr_un
, sun_path
))
411 if ((a
->sockaddr
.un
.sun_path
[0] == 0) != (b
->sockaddr
.un
.sun_path
[0] == 0))
414 if (a
->sockaddr
.un
.sun_path
[0]) {
415 if (!path_equal_or_files_same(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
, 0))
418 if (a
->size
!= b
->size
)
421 if (memcmp(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
, a
->size
) != 0)
428 if (a
->protocol
!= b
->protocol
)
431 if (a
->sockaddr
.nl
.nl_groups
!= b
->sockaddr
.nl
.nl_groups
)
437 if (a
->sockaddr
.vm
.svm_cid
!= b
->sockaddr
.vm
.svm_cid
)
440 if (a
->sockaddr
.vm
.svm_port
!= b
->sockaddr
.vm
.svm_port
)
446 /* Cannot compare, so we assume the addresses are different */
453 bool socket_address_is(const SocketAddress
*a
, const char *s
, int type
) {
454 struct SocketAddress b
;
459 if (socket_address_parse(&b
, s
) < 0)
464 return socket_address_equal(a
, &b
);
467 bool socket_address_is_netlink(const SocketAddress
*a
, const char *s
) {
468 struct SocketAddress b
;
473 if (socket_address_parse_netlink(&b
, s
) < 0)
476 return socket_address_equal(a
, &b
);
479 const char* socket_address_get_path(const SocketAddress
*a
) {
482 if (socket_address_family(a
) != AF_UNIX
)
485 if (a
->sockaddr
.un
.sun_path
[0] == 0)
488 return a
->sockaddr
.un
.sun_path
;
491 bool socket_ipv6_is_supported(void) {
492 if (access("/proc/net/if_inet6", F_OK
) != 0)
498 bool socket_address_matches_fd(const SocketAddress
*a
, int fd
) {
505 b
.size
= sizeof(b
.sockaddr
);
506 if (getsockname(fd
, &b
.sockaddr
.sa
, &b
.size
) < 0)
509 if (b
.sockaddr
.sa
.sa_family
!= a
->sockaddr
.sa
.sa_family
)
512 solen
= sizeof(b
.type
);
513 if (getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &b
.type
, &solen
) < 0)
516 if (b
.type
!= a
->type
)
519 if (a
->protocol
!= 0) {
520 solen
= sizeof(b
.protocol
);
521 if (getsockopt(fd
, SOL_SOCKET
, SO_PROTOCOL
, &b
.protocol
, &solen
) < 0)
524 if (b
.protocol
!= a
->protocol
)
528 return socket_address_equal(a
, &b
);
531 int sockaddr_port(const struct sockaddr
*_sa
, unsigned *port
) {
532 union sockaddr_union
*sa
= (union sockaddr_union
*) _sa
;
536 switch (sa
->sa
.sa_family
) {
538 *port
= be16toh(sa
->in
.sin_port
);
542 *port
= be16toh(sa
->in6
.sin6_port
);
546 *port
= sa
->vm
.svm_port
;
550 return -EAFNOSUPPORT
;
554 int sockaddr_pretty(const struct sockaddr
*_sa
, socklen_t salen
, bool translate_ipv6
, bool include_port
, char **ret
) {
555 union sockaddr_union
*sa
= (union sockaddr_union
*) _sa
;
560 assert(salen
>= sizeof(sa
->sa
.sa_family
));
562 switch (sa
->sa
.sa_family
) {
567 a
= be32toh(sa
->in
.sin_addr
.s_addr
);
572 a
>> 24, (a
>> 16) & 0xFF, (a
>> 8) & 0xFF, a
& 0xFF,
573 be16toh(sa
->in
.sin_port
));
577 a
>> 24, (a
>> 16) & 0xFF, (a
>> 8) & 0xFF, a
& 0xFF);
584 static const unsigned char ipv4_prefix
[] = {
585 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
588 if (translate_ipv6
&&
589 memcmp(&sa
->in6
.sin6_addr
, ipv4_prefix
, sizeof(ipv4_prefix
)) == 0) {
590 const uint8_t *a
= sa
->in6
.sin6_addr
.s6_addr
+12;
594 a
[0], a
[1], a
[2], a
[3],
595 be16toh(sa
->in6
.sin6_port
));
599 a
[0], a
[1], a
[2], a
[3]);
603 char a
[INET6_ADDRSTRLEN
];
605 inet_ntop(AF_INET6
, &sa
->in6
.sin6_addr
, a
, sizeof(a
));
611 be16toh(sa
->in6
.sin6_port
));
625 if (salen
<= offsetof(struct sockaddr_un
, sun_path
)) {
626 p
= strdup("<unnamed>");
630 } else if (sa
->un
.sun_path
[0] == 0) {
633 /* FIXME: We assume we can print the
634 * socket path here and that it hasn't
635 * more than one NUL byte. That is
636 * actually an invalid assumption */
638 p
= new(char, sizeof(sa
->un
.sun_path
)+1);
643 memcpy(p
+1, sa
->un
.sun_path
+1, sizeof(sa
->un
.sun_path
)-1);
644 p
[sizeof(sa
->un
.sun_path
)] = 0;
647 p
= strndup(sa
->un
.sun_path
, sizeof(sa
->un
.sun_path
));
661 r
= asprintf(&p
, "vsock:%u", sa
->vm
.svm_cid
);
675 int getpeername_pretty(int fd
, bool include_port
, char **ret
) {
676 union sockaddr_union sa
;
677 socklen_t salen
= sizeof(sa
);
683 if (getpeername(fd
, &sa
.sa
, &salen
) < 0)
686 if (sa
.sa
.sa_family
== AF_UNIX
) {
687 struct ucred ucred
= {};
689 /* UNIX connection sockets are anonymous, so let's use
690 * PID/UID as pretty credentials instead */
692 r
= getpeercred(fd
, &ucred
);
696 if (asprintf(ret
, "PID "PID_FMT
"/UID "UID_FMT
, ucred
.pid
, ucred
.uid
) < 0)
702 /* For remote sockets we translate IPv6 addresses back to IPv4
703 * if applicable, since that's nicer. */
705 return sockaddr_pretty(&sa
.sa
, salen
, true, include_port
, ret
);
708 int getsockname_pretty(int fd
, char **ret
) {
709 union sockaddr_union sa
;
710 socklen_t salen
= sizeof(sa
);
715 if (getsockname(fd
, &sa
.sa
, &salen
) < 0)
718 /* For local sockets we do not translate IPv6 addresses back
719 * to IPv6 if applicable, since this is usually used for
720 * listening sockets where the difference between IPv4 and
723 return sockaddr_pretty(&sa
.sa
, salen
, false, true, ret
);
726 int socknameinfo_pretty(union sockaddr_union
*sa
, socklen_t salen
, char **_ret
) {
728 char host
[NI_MAXHOST
], *ret
;
732 r
= getnameinfo(&sa
->sa
, salen
, host
, sizeof(host
), NULL
, 0, IDN_FLAGS
);
734 int saved_errno
= errno
;
736 r
= sockaddr_pretty(&sa
->sa
, salen
, true, true, &ret
);
740 log_debug_errno(saved_errno
, "getnameinfo(%s) failed: %m", ret
);
751 int getnameinfo_pretty(int fd
, char **ret
) {
752 union sockaddr_union sa
;
753 socklen_t salen
= sizeof(sa
);
758 if (getsockname(fd
, &sa
.sa
, &salen
) < 0)
761 return socknameinfo_pretty(&sa
, salen
, ret
);
764 int socket_address_unlink(SocketAddress
*a
) {
767 if (socket_address_family(a
) != AF_UNIX
)
770 if (a
->sockaddr
.un
.sun_path
[0] == 0)
773 if (unlink(a
->sockaddr
.un
.sun_path
) < 0)
779 static const char* const netlink_family_table
[] = {
780 [NETLINK_ROUTE
] = "route",
781 [NETLINK_FIREWALL
] = "firewall",
782 [NETLINK_INET_DIAG
] = "inet-diag",
783 [NETLINK_NFLOG
] = "nflog",
784 [NETLINK_XFRM
] = "xfrm",
785 [NETLINK_SELINUX
] = "selinux",
786 [NETLINK_ISCSI
] = "iscsi",
787 [NETLINK_AUDIT
] = "audit",
788 [NETLINK_FIB_LOOKUP
] = "fib-lookup",
789 [NETLINK_CONNECTOR
] = "connector",
790 [NETLINK_NETFILTER
] = "netfilter",
791 [NETLINK_IP6_FW
] = "ip6-fw",
792 [NETLINK_DNRTMSG
] = "dnrtmsg",
793 [NETLINK_KOBJECT_UEVENT
] = "kobject-uevent",
794 [NETLINK_GENERIC
] = "generic",
795 [NETLINK_SCSITRANSPORT
] = "scsitransport",
796 [NETLINK_ECRYPTFS
] = "ecryptfs",
797 [NETLINK_RDMA
] = "rdma",
800 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family
, int, INT_MAX
);
802 static const char* const socket_address_bind_ipv6_only_table
[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX
] = {
803 [SOCKET_ADDRESS_DEFAULT
] = "default",
804 [SOCKET_ADDRESS_BOTH
] = "both",
805 [SOCKET_ADDRESS_IPV6_ONLY
] = "ipv6-only"
808 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only
, SocketAddressBindIPv6Only
);
810 bool sockaddr_equal(const union sockaddr_union
*a
, const union sockaddr_union
*b
) {
814 if (a
->sa
.sa_family
!= b
->sa
.sa_family
)
817 if (a
->sa
.sa_family
== AF_INET
)
818 return a
->in
.sin_addr
.s_addr
== b
->in
.sin_addr
.s_addr
;
820 if (a
->sa
.sa_family
== AF_INET6
)
821 return memcmp(&a
->in6
.sin6_addr
, &b
->in6
.sin6_addr
, sizeof(a
->in6
.sin6_addr
)) == 0;
823 if (a
->sa
.sa_family
== AF_VSOCK
)
824 return a
->vm
.svm_cid
== b
->vm
.svm_cid
;
829 int fd_inc_sndbuf(int fd
, size_t n
) {
831 socklen_t l
= sizeof(value
);
833 r
= getsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &value
, &l
);
834 if (r
>= 0 && l
== sizeof(value
) && (size_t) value
>= n
*2)
837 /* If we have the privileges we will ignore the kernel limit. */
840 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUFFORCE
, &value
, sizeof(value
)) < 0)
841 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &value
, sizeof(value
)) < 0)
847 int fd_inc_rcvbuf(int fd
, size_t n
) {
849 socklen_t l
= sizeof(value
);
851 r
= getsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &value
, &l
);
852 if (r
>= 0 && l
== sizeof(value
) && (size_t) value
>= n
*2)
855 /* If we have the privileges we will ignore the kernel limit. */
858 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUFFORCE
, &value
, sizeof(value
)) < 0)
859 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &value
, sizeof(value
)) < 0)
864 static const char* const ip_tos_table
[] = {
865 [IPTOS_LOWDELAY
] = "low-delay",
866 [IPTOS_THROUGHPUT
] = "throughput",
867 [IPTOS_RELIABILITY
] = "reliability",
868 [IPTOS_LOWCOST
] = "low-cost",
871 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos
, int, 0xff);
873 bool ifname_valid(const char *p
) {
876 /* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
877 * but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We
878 * also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
883 if (strlen(p
) >= IFNAMSIZ
)
886 if (dot_or_dot_dot(p
))
890 if ((unsigned char) *p
>= 127U)
893 if ((unsigned char) *p
<= 32U)
896 if (IN_SET(*p
, ':', '/'))
899 numeric
= numeric
&& (*p
>= '0' && *p
<= '9');
909 bool address_label_valid(const char *p
) {
914 if (strlen(p
) >= IFNAMSIZ
)
918 if ((uint8_t) *p
>= 127U)
921 if ((uint8_t) *p
<= 31U)
929 int getpeercred(int fd
, struct ucred
*ucred
) {
930 socklen_t n
= sizeof(struct ucred
);
937 r
= getsockopt(fd
, SOL_SOCKET
, SO_PEERCRED
, &u
, &n
);
941 if (n
!= sizeof(struct ucred
))
944 /* Check if the data is actually useful and not suppressed due
945 * to namespacing issues */
948 if (u
.uid
== UID_INVALID
)
950 if (u
.gid
== GID_INVALID
)
957 int getpeersec(int fd
, char **ret
) {
969 r
= getsockopt(fd
, SOL_SOCKET
, SO_PEERSEC
, s
, &n
);
980 r
= getsockopt(fd
, SOL_SOCKET
, SO_PEERSEC
, s
, &n
);
999 const struct sockaddr
*sa
, socklen_t len
,
1003 struct cmsghdr cmsghdr
;
1004 uint8_t buf
[CMSG_SPACE(sizeof(int))];
1006 struct msghdr mh
= {
1007 .msg_name
= (struct sockaddr
*) sa
,
1009 .msg_control
= &control
,
1010 .msg_controllen
= sizeof(control
),
1012 struct cmsghdr
*cmsg
;
1014 assert(transport_fd
>= 0);
1017 cmsg
= CMSG_FIRSTHDR(&mh
);
1018 cmsg
->cmsg_level
= SOL_SOCKET
;
1019 cmsg
->cmsg_type
= SCM_RIGHTS
;
1020 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
1021 memcpy(CMSG_DATA(cmsg
), &fd
, sizeof(int));
1023 mh
.msg_controllen
= CMSG_SPACE(sizeof(int));
1024 if (sendmsg(transport_fd
, &mh
, MSG_NOSIGNAL
| flags
) < 0)
1030 int receive_one_fd(int transport_fd
, int flags
) {
1032 struct cmsghdr cmsghdr
;
1033 uint8_t buf
[CMSG_SPACE(sizeof(int))];
1035 struct msghdr mh
= {
1036 .msg_control
= &control
,
1037 .msg_controllen
= sizeof(control
),
1039 struct cmsghdr
*cmsg
, *found
= NULL
;
1041 assert(transport_fd
>= 0);
1044 * Receive a single FD via @transport_fd. We don't care for
1045 * the transport-type. We retrieve a single FD at most, so for
1046 * packet-based transports, the caller must ensure to send
1047 * only a single FD per packet. This is best used in
1048 * combination with send_one_fd().
1051 if (recvmsg(transport_fd
, &mh
, MSG_NOSIGNAL
| MSG_CMSG_CLOEXEC
| flags
) < 0)
1054 CMSG_FOREACH(cmsg
, &mh
) {
1055 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
1056 cmsg
->cmsg_type
== SCM_RIGHTS
&&
1057 cmsg
->cmsg_len
== CMSG_LEN(sizeof(int))) {
1065 cmsg_close_all(&mh
);
1069 return *(int*) CMSG_DATA(found
);
1072 ssize_t
next_datagram_size_fd(int fd
) {
1076 /* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will
1077 * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD doesn't
1078 * do. This difference is actually of major importance as we need to be sure that the size returned here
1079 * actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of
1080 * the wrong size. */
1082 l
= recv(fd
, NULL
, 0, MSG_PEEK
|MSG_TRUNC
);
1084 if (IN_SET(errno
, EOPNOTSUPP
, EFAULT
))
1097 /* Some sockets (AF_PACKET) do not support null-sized recv() with MSG_TRUNC set, let's fall back to FIONREAD
1098 * for them. Checksums don't matter for raw sockets anyway, hence this should be fine. */
1100 if (ioctl(fd
, FIONREAD
, &k
) < 0)
1106 int flush_accept(int fd
) {
1108 struct pollfd pollfd
= {
1115 /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */
1120 r
= poll(&pollfd
, 1, 0);
1130 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1135 if (errno
== EAGAIN
)
1145 struct cmsghdr
* cmsg_find(struct msghdr
*mh
, int level
, int type
, socklen_t length
) {
1146 struct cmsghdr
*cmsg
;
1150 CMSG_FOREACH(cmsg
, mh
)
1151 if (cmsg
->cmsg_level
== level
&&
1152 cmsg
->cmsg_type
== type
&&
1153 (length
== (socklen_t
) -1 || length
== cmsg
->cmsg_len
))
1159 int socket_ioctl_fd(void) {
1162 /* Create a socket to invoke the various network interface ioctl()s on. Traditionally only AF_INET was good for
1163 * that. Since kernel 4.6 AF_NETLINK works for this too. We first try to use AF_INET hence, but if that's not
1164 * available (for example, because it is made unavailable via SECCOMP or such), we'll fall back to the more
1165 * generic AF_NETLINK. */
1167 fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
1169 fd
= socket(AF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
, NETLINK_GENERIC
);