1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
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
11 (at your option) any later version.
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
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <arpa/inet.h>
27 #include <netinet/ip.h>
35 #include "alloc-util.h"
38 #include "formats-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"
47 #include "user-util.h"
50 int socket_address_parse(SocketAddress
*a
, const char *s
) {
59 a
->type
= SOCK_STREAM
;
62 /* IPv6 in [x:.....:z]:p notation */
68 n
= strndupa(s
+1, e
-s
-1);
71 if (inet_pton(AF_INET6
, n
, &a
->sockaddr
.in6
.sin6_addr
) <= 0)
72 return errno
> 0 ? -errno
: -EINVAL
;
83 if (u
<= 0 || u
> 0xFFFF)
86 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
87 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
88 a
->size
= sizeof(struct sockaddr_in6
);
90 } else if (*s
== '/') {
96 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
))
99 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
100 memcpy(a
->sockaddr
.un
.sun_path
, s
, l
);
101 a
->size
= offsetof(struct sockaddr_un
, sun_path
) + l
+ 1;
103 } else if (*s
== '@') {
104 /* Abstract AF_UNIX socket */
108 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
) - 1)
111 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
112 memcpy(a
->sockaddr
.un
.sun_path
+1, s
+1, l
);
113 a
->size
= offsetof(struct sockaddr_un
, sun_path
) + 1 + l
;
118 r
= safe_atou(e
+1, &u
);
122 if (u
<= 0 || u
> 0xFFFF)
125 n
= strndupa(s
, e
-s
);
127 /* IPv4 in w.x.y.z:p notation? */
128 r
= inet_pton(AF_INET
, n
, &a
->sockaddr
.in
.sin_addr
);
133 /* Gotcha, it's a traditional IPv4 address */
134 a
->sockaddr
.in
.sin_family
= AF_INET
;
135 a
->sockaddr
.in
.sin_port
= htons((uint16_t) u
);
136 a
->size
= sizeof(struct sockaddr_in
);
140 if (strlen(n
) > IF_NAMESIZE
-1)
143 /* Uh, our last resort, an interface name */
144 idx
= if_nametoindex(n
);
148 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
149 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
150 a
->sockaddr
.in6
.sin6_scope_id
= idx
;
151 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
152 a
->size
= sizeof(struct sockaddr_in6
);
157 r
= safe_atou(s
, &u
);
161 if (u
<= 0 || u
> 0xFFFF)
164 if (socket_ipv6_is_supported()) {
165 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
166 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
167 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
168 a
->size
= sizeof(struct sockaddr_in6
);
170 a
->sockaddr
.in
.sin_family
= AF_INET
;
171 a
->sockaddr
.in
.sin_port
= htons((uint16_t) u
);
172 a
->sockaddr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
173 a
->size
= sizeof(struct sockaddr_in
);
181 int socket_address_parse_and_warn(SocketAddress
*a
, const char *s
) {
185 /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
187 r
= socket_address_parse(&b
, s
);
191 if (!socket_ipv6_is_supported() && b
.sockaddr
.sa
.sa_family
== AF_INET6
) {
192 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
193 return -EAFNOSUPPORT
;
200 int socket_address_parse_netlink(SocketAddress
*a
, const char *s
) {
203 _cleanup_free_
char *sfamily
= NULL
;
211 if (sscanf(s
, "%ms %u", &sfamily
, &group
) < 1)
212 return errno
> 0 ? -errno
: -EINVAL
;
214 family
= netlink_family_from_string(sfamily
);
218 a
->sockaddr
.nl
.nl_family
= AF_NETLINK
;
219 a
->sockaddr
.nl
.nl_groups
= group
;
222 a
->size
= sizeof(struct sockaddr_nl
);
223 a
->protocol
= family
;
228 int socket_address_verify(const SocketAddress
*a
) {
231 switch (socket_address_family(a
)) {
234 if (a
->size
!= sizeof(struct sockaddr_in
))
237 if (a
->sockaddr
.in
.sin_port
== 0)
240 if (a
->type
!= SOCK_STREAM
&& a
->type
!= SOCK_DGRAM
)
246 if (a
->size
!= sizeof(struct sockaddr_in6
))
249 if (a
->sockaddr
.in6
.sin6_port
== 0)
252 if (a
->type
!= SOCK_STREAM
&& a
->type
!= SOCK_DGRAM
)
258 if (a
->size
< offsetof(struct sockaddr_un
, sun_path
))
261 if (a
->size
> offsetof(struct sockaddr_un
, sun_path
)) {
263 if (a
->sockaddr
.un
.sun_path
[0] != 0) {
267 e
= memchr(a
->sockaddr
.un
.sun_path
, 0, sizeof(a
->sockaddr
.un
.sun_path
));
271 if (a
->size
!= offsetof(struct sockaddr_un
, sun_path
) + (e
- a
->sockaddr
.un
.sun_path
) + 1)
276 if (a
->type
!= SOCK_STREAM
&& a
->type
!= SOCK_DGRAM
&& a
->type
!= SOCK_SEQPACKET
)
283 if (a
->size
!= sizeof(struct sockaddr_nl
))
286 if (a
->type
!= SOCK_RAW
&& a
->type
!= SOCK_DGRAM
)
292 return -EAFNOSUPPORT
;
296 int socket_address_print(const SocketAddress
*a
, char **ret
) {
302 r
= socket_address_verify(a
);
306 if (socket_address_family(a
) == AF_NETLINK
) {
307 _cleanup_free_
char *sfamily
= NULL
;
309 r
= netlink_family_to_string_alloc(a
->protocol
, &sfamily
);
313 r
= asprintf(ret
, "%s %u", sfamily
, a
->sockaddr
.nl
.nl_groups
);
320 return sockaddr_pretty(&a
->sockaddr
.sa
, a
->size
, false, true, ret
);
323 bool socket_address_can_accept(const SocketAddress
*a
) {
327 a
->type
== SOCK_STREAM
||
328 a
->type
== SOCK_SEQPACKET
;
331 bool socket_address_equal(const SocketAddress
*a
, const SocketAddress
*b
) {
335 /* Invalid addresses are unequal to all */
336 if (socket_address_verify(a
) < 0 ||
337 socket_address_verify(b
) < 0)
340 if (a
->type
!= b
->type
)
343 if (socket_address_family(a
) != socket_address_family(b
))
346 switch (socket_address_family(a
)) {
349 if (a
->sockaddr
.in
.sin_addr
.s_addr
!= b
->sockaddr
.in
.sin_addr
.s_addr
)
352 if (a
->sockaddr
.in
.sin_port
!= b
->sockaddr
.in
.sin_port
)
358 if (memcmp(&a
->sockaddr
.in6
.sin6_addr
, &b
->sockaddr
.in6
.sin6_addr
, sizeof(a
->sockaddr
.in6
.sin6_addr
)) != 0)
361 if (a
->sockaddr
.in6
.sin6_port
!= b
->sockaddr
.in6
.sin6_port
)
367 if (a
->size
<= offsetof(struct sockaddr_un
, sun_path
) ||
368 b
->size
<= offsetof(struct sockaddr_un
, sun_path
))
371 if ((a
->sockaddr
.un
.sun_path
[0] == 0) != (b
->sockaddr
.un
.sun_path
[0] == 0))
374 if (a
->sockaddr
.un
.sun_path
[0]) {
375 if (!path_equal_or_files_same(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
))
378 if (a
->size
!= b
->size
)
381 if (memcmp(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
, a
->size
) != 0)
388 if (a
->protocol
!= b
->protocol
)
391 if (a
->sockaddr
.nl
.nl_groups
!= b
->sockaddr
.nl
.nl_groups
)
397 /* Cannot compare, so we assume the addresses are different */
404 bool socket_address_is(const SocketAddress
*a
, const char *s
, int type
) {
405 struct SocketAddress b
;
410 if (socket_address_parse(&b
, s
) < 0)
415 return socket_address_equal(a
, &b
);
418 bool socket_address_is_netlink(const SocketAddress
*a
, const char *s
) {
419 struct SocketAddress b
;
424 if (socket_address_parse_netlink(&b
, s
) < 0)
427 return socket_address_equal(a
, &b
);
430 const char* socket_address_get_path(const SocketAddress
*a
) {
433 if (socket_address_family(a
) != AF_UNIX
)
436 if (a
->sockaddr
.un
.sun_path
[0] == 0)
439 return a
->sockaddr
.un
.sun_path
;
442 bool socket_ipv6_is_supported(void) {
443 if (access("/proc/net/sockstat6", F_OK
) != 0)
449 bool socket_address_matches_fd(const SocketAddress
*a
, int fd
) {
456 b
.size
= sizeof(b
.sockaddr
);
457 if (getsockname(fd
, &b
.sockaddr
.sa
, &b
.size
) < 0)
460 if (b
.sockaddr
.sa
.sa_family
!= a
->sockaddr
.sa
.sa_family
)
463 solen
= sizeof(b
.type
);
464 if (getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &b
.type
, &solen
) < 0)
467 if (b
.type
!= a
->type
)
470 if (a
->protocol
!= 0) {
471 solen
= sizeof(b
.protocol
);
472 if (getsockopt(fd
, SOL_SOCKET
, SO_PROTOCOL
, &b
.protocol
, &solen
) < 0)
475 if (b
.protocol
!= a
->protocol
)
479 return socket_address_equal(a
, &b
);
482 int sockaddr_port(const struct sockaddr
*_sa
) {
483 union sockaddr_union
*sa
= (union sockaddr_union
*) _sa
;
487 if (!IN_SET(sa
->sa
.sa_family
, AF_INET
, AF_INET6
))
488 return -EAFNOSUPPORT
;
490 return ntohs(sa
->sa
.sa_family
== AF_INET6
?
495 int sockaddr_pretty(const struct sockaddr
*_sa
, socklen_t salen
, bool translate_ipv6
, bool include_port
, char **ret
) {
496 union sockaddr_union
*sa
= (union sockaddr_union
*) _sa
;
501 assert(salen
>= sizeof(sa
->sa
.sa_family
));
503 switch (sa
->sa
.sa_family
) {
508 a
= ntohl(sa
->in
.sin_addr
.s_addr
);
513 a
>> 24, (a
>> 16) & 0xFF, (a
>> 8) & 0xFF, a
& 0xFF,
514 ntohs(sa
->in
.sin_port
));
518 a
>> 24, (a
>> 16) & 0xFF, (a
>> 8) & 0xFF, a
& 0xFF);
525 static const unsigned char ipv4_prefix
[] = {
526 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
529 if (translate_ipv6
&&
530 memcmp(&sa
->in6
.sin6_addr
, ipv4_prefix
, sizeof(ipv4_prefix
)) == 0) {
531 const uint8_t *a
= sa
->in6
.sin6_addr
.s6_addr
+12;
535 a
[0], a
[1], a
[2], a
[3],
536 ntohs(sa
->in6
.sin6_port
));
540 a
[0], a
[1], a
[2], a
[3]);
544 char a
[INET6_ADDRSTRLEN
];
546 inet_ntop(AF_INET6
, &sa
->in6
.sin6_addr
, a
, sizeof(a
));
552 ntohs(sa
->in6
.sin6_port
));
566 if (salen
<= offsetof(struct sockaddr_un
, sun_path
)) {
567 p
= strdup("<unnamed>");
571 } else if (sa
->un
.sun_path
[0] == 0) {
574 /* FIXME: We assume we can print the
575 * socket path here and that it hasn't
576 * more than one NUL byte. That is
577 * actually an invalid assumption */
579 p
= new(char, sizeof(sa
->un
.sun_path
)+1);
584 memcpy(p
+1, sa
->un
.sun_path
+1, sizeof(sa
->un
.sun_path
)-1);
585 p
[sizeof(sa
->un
.sun_path
)] = 0;
588 p
= strndup(sa
->un
.sun_path
, sizeof(sa
->un
.sun_path
));
604 int getpeername_pretty(int fd
, char **ret
) {
605 union sockaddr_union sa
;
606 socklen_t salen
= sizeof(sa
);
612 if (getpeername(fd
, &sa
.sa
, &salen
) < 0)
615 if (sa
.sa
.sa_family
== AF_UNIX
) {
616 struct ucred ucred
= {};
618 /* UNIX connection sockets are anonymous, so let's use
619 * PID/UID as pretty credentials instead */
621 r
= getpeercred(fd
, &ucred
);
625 if (asprintf(ret
, "PID "PID_FMT
"/UID "UID_FMT
, ucred
.pid
, ucred
.uid
) < 0)
631 /* For remote sockets we translate IPv6 addresses back to IPv4
632 * if applicable, since that's nicer. */
634 return sockaddr_pretty(&sa
.sa
, salen
, true, true, ret
);
637 int getsockname_pretty(int fd
, char **ret
) {
638 union sockaddr_union sa
;
639 socklen_t salen
= sizeof(sa
);
644 if (getsockname(fd
, &sa
.sa
, &salen
) < 0)
647 /* For local sockets we do not translate IPv6 addresses back
648 * to IPv6 if applicable, since this is usually used for
649 * listening sockets where the difference between IPv4 and
652 return sockaddr_pretty(&sa
.sa
, salen
, false, true, ret
);
655 int socknameinfo_pretty(union sockaddr_union
*sa
, socklen_t salen
, char **_ret
) {
657 char host
[NI_MAXHOST
], *ret
;
661 r
= getnameinfo(&sa
->sa
, salen
, host
, sizeof(host
), NULL
, 0,
662 NI_IDN
|NI_IDN_USE_STD3_ASCII_RULES
);
664 int saved_errno
= errno
;
666 r
= sockaddr_pretty(&sa
->sa
, salen
, true, true, &ret
);
670 log_debug_errno(saved_errno
, "getnameinfo(%s) failed: %m", ret
);
681 int getnameinfo_pretty(int fd
, char **ret
) {
682 union sockaddr_union sa
;
683 socklen_t salen
= sizeof(sa
);
688 if (getsockname(fd
, &sa
.sa
, &salen
) < 0)
691 return socknameinfo_pretty(&sa
, salen
, ret
);
694 int socket_address_unlink(SocketAddress
*a
) {
697 if (socket_address_family(a
) != AF_UNIX
)
700 if (a
->sockaddr
.un
.sun_path
[0] == 0)
703 if (unlink(a
->sockaddr
.un
.sun_path
) < 0)
709 static const char* const netlink_family_table
[] = {
710 [NETLINK_ROUTE
] = "route",
711 [NETLINK_FIREWALL
] = "firewall",
712 [NETLINK_INET_DIAG
] = "inet-diag",
713 [NETLINK_NFLOG
] = "nflog",
714 [NETLINK_XFRM
] = "xfrm",
715 [NETLINK_SELINUX
] = "selinux",
716 [NETLINK_ISCSI
] = "iscsi",
717 [NETLINK_AUDIT
] = "audit",
718 [NETLINK_FIB_LOOKUP
] = "fib-lookup",
719 [NETLINK_CONNECTOR
] = "connector",
720 [NETLINK_NETFILTER
] = "netfilter",
721 [NETLINK_IP6_FW
] = "ip6-fw",
722 [NETLINK_DNRTMSG
] = "dnrtmsg",
723 [NETLINK_KOBJECT_UEVENT
] = "kobject-uevent",
724 [NETLINK_GENERIC
] = "generic",
725 [NETLINK_SCSITRANSPORT
] = "scsitransport",
726 [NETLINK_ECRYPTFS
] = "ecryptfs"
729 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family
, int, INT_MAX
);
731 static const char* const socket_address_bind_ipv6_only_table
[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX
] = {
732 [SOCKET_ADDRESS_DEFAULT
] = "default",
733 [SOCKET_ADDRESS_BOTH
] = "both",
734 [SOCKET_ADDRESS_IPV6_ONLY
] = "ipv6-only"
737 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only
, SocketAddressBindIPv6Only
);
739 bool sockaddr_equal(const union sockaddr_union
*a
, const union sockaddr_union
*b
) {
743 if (a
->sa
.sa_family
!= b
->sa
.sa_family
)
746 if (a
->sa
.sa_family
== AF_INET
)
747 return a
->in
.sin_addr
.s_addr
== b
->in
.sin_addr
.s_addr
;
749 if (a
->sa
.sa_family
== AF_INET6
)
750 return memcmp(&a
->in6
.sin6_addr
, &b
->in6
.sin6_addr
, sizeof(a
->in6
.sin6_addr
)) == 0;
755 int fd_inc_sndbuf(int fd
, size_t n
) {
757 socklen_t l
= sizeof(value
);
759 r
= getsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &value
, &l
);
760 if (r
>= 0 && l
== sizeof(value
) && (size_t) value
>= n
*2)
763 /* If we have the privileges we will ignore the kernel limit. */
766 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUFFORCE
, &value
, sizeof(value
)) < 0)
767 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &value
, sizeof(value
)) < 0)
773 int fd_inc_rcvbuf(int fd
, size_t n
) {
775 socklen_t l
= sizeof(value
);
777 r
= getsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &value
, &l
);
778 if (r
>= 0 && l
== sizeof(value
) && (size_t) value
>= n
*2)
781 /* If we have the privileges we will ignore the kernel limit. */
784 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUFFORCE
, &value
, sizeof(value
)) < 0)
785 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &value
, sizeof(value
)) < 0)
790 static const char* const ip_tos_table
[] = {
791 [IPTOS_LOWDELAY
] = "low-delay",
792 [IPTOS_THROUGHPUT
] = "throughput",
793 [IPTOS_RELIABILITY
] = "reliability",
794 [IPTOS_LOWCOST
] = "low-cost",
797 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos
, int, 0xff);
799 int getpeercred(int fd
, struct ucred
*ucred
) {
800 socklen_t n
= sizeof(struct ucred
);
807 r
= getsockopt(fd
, SOL_SOCKET
, SO_PEERCRED
, &u
, &n
);
811 if (n
!= sizeof(struct ucred
))
814 /* Check if the data is actually useful and not suppressed due
815 * to namespacing issues */
818 if (u
.uid
== UID_INVALID
)
820 if (u
.gid
== GID_INVALID
)
827 int getpeersec(int fd
, char **ret
) {
839 r
= getsockopt(fd
, SOL_SOCKET
, SO_PEERSEC
, s
, &n
);
850 r
= getsockopt(fd
, SOL_SOCKET
, SO_PEERSEC
, s
, &n
);
869 const struct sockaddr
*sa
, socklen_t len
,
873 struct cmsghdr cmsghdr
;
874 uint8_t buf
[CMSG_SPACE(sizeof(int))];
876 struct cmsghdr
*cmsg
;
879 .msg_name
= (struct sockaddr
*) sa
,
881 .msg_control
= &control
,
882 .msg_controllen
= sizeof(control
),
885 assert(transport_fd
>= 0);
888 cmsg
= CMSG_FIRSTHDR(&mh
);
889 cmsg
->cmsg_level
= SOL_SOCKET
;
890 cmsg
->cmsg_type
= SCM_RIGHTS
;
891 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
892 memcpy(CMSG_DATA(cmsg
), &fd
, sizeof(int));
894 mh
.msg_controllen
= CMSG_SPACE(sizeof(int));
895 if (sendmsg(transport_fd
, &mh
, MSG_NOSIGNAL
| flags
) < 0)
901 int receive_one_fd(int transport_fd
, int flags
) {
903 struct cmsghdr cmsghdr
;
904 uint8_t buf
[CMSG_SPACE(sizeof(int))];
907 .msg_control
= &control
,
908 .msg_controllen
= sizeof(control
),
910 struct cmsghdr
*cmsg
, *found
= NULL
;
912 assert(transport_fd
>= 0);
915 * Receive a single FD via @transport_fd. We don't care for
916 * the transport-type. We retrieve a single FD at most, so for
917 * packet-based transports, the caller must ensure to send
918 * only a single FD per packet. This is best used in
919 * combination with send_one_fd().
922 if (recvmsg(transport_fd
, &mh
, MSG_NOSIGNAL
| MSG_CMSG_CLOEXEC
| flags
) < 0)
925 CMSG_FOREACH(cmsg
, &mh
) {
926 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
927 cmsg
->cmsg_type
== SCM_RIGHTS
&&
928 cmsg
->cmsg_len
== CMSG_LEN(sizeof(int))) {
940 return *(int*) CMSG_DATA(found
);