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/>.
27 #include <arpa/inet.h>
30 #include <sys/types.h>
33 #include <sys/ioctl.h>
38 #include "path-util.h"
39 #include "socket-util.h"
43 int socket_address_parse(SocketAddress *a, const char *s) {
52 a->type = SOCK_STREAM;
55 /* IPv6 in [x:.....:z]:p notation */
57 if (!socket_ipv6_is_supported()) {
58 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
66 n = strndupa(s+1, e-s-1);
69 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
70 return errno > 0 ? -errno : -EINVAL;
81 if (u <= 0 || u > 0xFFFF)
84 a->sockaddr.in6.sin6_family = AF_INET6;
85 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
86 a->size = sizeof(struct sockaddr_in6);
88 } else if (*s == '/') {
94 if (l >= sizeof(a->sockaddr.un.sun_path))
97 a->sockaddr.un.sun_family = AF_UNIX;
98 memcpy(a->sockaddr.un.sun_path, s, l);
99 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
101 } else if (*s == '@') {
102 /* Abstract AF_UNIX socket */
106 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
109 a->sockaddr.un.sun_family = AF_UNIX;
110 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
111 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
116 r = safe_atou(e+1, &u);
120 if (u <= 0 || u > 0xFFFF)
123 n = strndupa(s, e-s);
125 /* IPv4 in w.x.y.z:p notation? */
126 r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
131 /* Gotcha, it's a traditional IPv4 address */
132 a->sockaddr.in.sin_family = AF_INET;
133 a->sockaddr.in.sin_port = htons((uint16_t) u);
134 a->size = sizeof(struct sockaddr_in);
138 if (strlen(n) > IF_NAMESIZE-1)
141 /* Uh, our last resort, an interface name */
142 idx = if_nametoindex(n);
146 if (!socket_ipv6_is_supported()) {
147 log_warning("Binding to interface is not available since kernel does not support IPv6.");
148 return -EAFNOSUPPORT;
151 a->sockaddr.in6.sin6_family = AF_INET6;
152 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
153 a->sockaddr.in6.sin6_scope_id = idx;
154 a->sockaddr.in6.sin6_addr = in6addr_any;
155 a->size = sizeof(struct sockaddr_in6);
160 r = safe_atou(s, &u);
164 if (u <= 0 || u > 0xFFFF)
167 if (socket_ipv6_is_supported()) {
168 a->sockaddr.in6.sin6_family = AF_INET6;
169 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
170 a->sockaddr.in6.sin6_addr = in6addr_any;
171 a->size = sizeof(struct sockaddr_in6);
173 a->sockaddr.in.sin_family = AF_INET;
174 a->sockaddr.in.sin_port = htons((uint16_t) u);
175 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
176 a->size = sizeof(struct sockaddr_in);
184 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
187 _cleanup_free_ char *sfamily = NULL;
195 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
196 return errno > 0 ? -errno : -EINVAL;
198 family = netlink_family_from_string(sfamily);
202 a->sockaddr.nl.nl_family = AF_NETLINK;
203 a->sockaddr.nl.nl_groups = group;
206 a->size = sizeof(struct sockaddr_nl);
207 a->protocol = family;
212 int socket_address_verify(const SocketAddress *a) {
215 switch (socket_address_family(a)) {
218 if (a->size != sizeof(struct sockaddr_in))
221 if (a->sockaddr.in.sin_port == 0)
224 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
230 if (a->size != sizeof(struct sockaddr_in6))
233 if (a->sockaddr.in6.sin6_port == 0)
236 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
242 if (a->size < offsetof(struct sockaddr_un, sun_path))
245 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
247 if (a->sockaddr.un.sun_path[0] != 0) {
251 e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
255 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
260 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
267 if (a->size != sizeof(struct sockaddr_nl))
270 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
276 return -EAFNOSUPPORT;
280 int socket_address_print(const SocketAddress *a, char **ret) {
286 r = socket_address_verify(a);
290 if (socket_address_family(a) == AF_NETLINK) {
291 _cleanup_free_ char *sfamily = NULL;
293 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
297 r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
304 return sockaddr_pretty(&a->sockaddr.sa, a->size, false, ret);
307 bool socket_address_can_accept(const SocketAddress *a) {
311 a->type == SOCK_STREAM ||
312 a->type == SOCK_SEQPACKET;
315 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
319 /* Invalid addresses are unequal to all */
320 if (socket_address_verify(a) < 0 ||
321 socket_address_verify(b) < 0)
324 if (a->type != b->type)
327 if (a->size != b->size)
330 if (socket_address_family(a) != socket_address_family(b))
333 switch (socket_address_family(a)) {
336 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
339 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
345 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
348 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
355 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
358 if (a->sockaddr.un.sun_path[0]) {
359 if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
362 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
370 if (a->protocol != b->protocol)
373 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
379 /* Cannot compare, so we assume the addresses are different */
386 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
387 struct SocketAddress b;
392 if (socket_address_parse(&b, s) < 0)
397 return socket_address_equal(a, &b);
400 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
401 struct SocketAddress b;
406 if (socket_address_parse_netlink(&b, s) < 0)
409 return socket_address_equal(a, &b);
412 const char* socket_address_get_path(const SocketAddress *a) {
415 if (socket_address_family(a) != AF_UNIX)
418 if (a->sockaddr.un.sun_path[0] == 0)
421 return a->sockaddr.un.sun_path;
424 bool socket_ipv6_is_supported(void) {
428 if (access("/sys/module/ipv6", F_OK) != 0)
431 /* If we can't check "disable" parameter, assume enabled */
432 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
435 /* If module was loaded with disable=1 no IPv6 available */
436 enabled = l[0] == '0';
442 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
443 union sockaddr_union sa;
444 socklen_t salen = sizeof(sa), solen;
450 if (getsockname(fd, &sa.sa, &salen) < 0)
453 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
456 solen = sizeof(type);
457 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
463 if (a->protocol != 0) {
464 solen = sizeof(protocol);
465 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
468 if (protocol != a->protocol)
472 switch (sa.sa.sa_family) {
475 return sa.in.sin_port == a->sockaddr.in.sin_port &&
476 sa.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr;
479 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
480 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
483 return salen == a->size &&
484 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
491 int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) {
492 union sockaddr_union *sa = (union sockaddr_union*) _sa;
496 assert(salen >= sizeof(sa->sa.sa_family));
498 switch (sa->sa.sa_family) {
503 a = ntohl(sa->in.sin_addr.s_addr);
507 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
508 ntohs(sa->in.sin_port)) < 0)
515 static const unsigned char ipv4_prefix[] = {
516 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
519 if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
520 const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
524 a[0], a[1], a[2], a[3],
525 ntohs(sa->in6.sin6_port)) < 0)
528 char a[INET6_ADDRSTRLEN];
532 inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)),
533 ntohs(sa->in6.sin6_port)) < 0)
541 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
542 p = strdup("<unnamed>");
546 } else if (sa->un.sun_path[0] == 0) {
549 /* FIXME: We assume we can print the
550 * socket path here and that it hasn't
551 * more than one NUL byte. That is
552 * actually an invalid assumption */
554 p = new(char, sizeof(sa->un.sun_path)+1);
559 memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
560 p[sizeof(sa->un.sun_path)] = 0;
563 p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
579 int getpeername_pretty(int fd, char **ret) {
580 union sockaddr_union sa;
587 if (getpeername(fd, &sa.sa, &salen) < 0)
590 if (sa.sa.sa_family == AF_UNIX) {
593 /* UNIX connection sockets are anonymous, so let's use
594 * PID/UID as pretty credentials instead */
596 salen = sizeof(ucred);
597 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &salen) < 0)
600 if (asprintf(ret, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.pid) < 0)
606 /* For remote sockets we translate IPv6 addresses back to IPv4
607 * if applicable, since that's nicer. */
609 return sockaddr_pretty(&sa.sa, salen, true, ret);
612 int getsockname_pretty(int fd, char **ret) {
613 union sockaddr_union sa;
620 if (getsockname(fd, &sa.sa, &salen) < 0)
623 /* For local sockets we do not translate IPv6 addresses back
624 * to IPv6 if applicable, since this is usually used for
625 * listening sockets where the difference between IPv4 and
628 return sockaddr_pretty(&sa.sa, salen, false, ret);
631 static const char* const netlink_family_table[] = {
632 [NETLINK_ROUTE] = "route",
633 [NETLINK_FIREWALL] = "firewall",
634 [NETLINK_INET_DIAG] = "inet-diag",
635 [NETLINK_NFLOG] = "nflog",
636 [NETLINK_XFRM] = "xfrm",
637 [NETLINK_SELINUX] = "selinux",
638 [NETLINK_ISCSI] = "iscsi",
639 [NETLINK_AUDIT] = "audit",
640 [NETLINK_FIB_LOOKUP] = "fib-lookup",
641 [NETLINK_CONNECTOR] = "connector",
642 [NETLINK_NETFILTER] = "netfilter",
643 [NETLINK_IP6_FW] = "ip6-fw",
644 [NETLINK_DNRTMSG] = "dnrtmsg",
645 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
646 [NETLINK_GENERIC] = "generic",
647 [NETLINK_SCSITRANSPORT] = "scsitransport",
648 [NETLINK_ECRYPTFS] = "ecryptfs"
651 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
653 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
654 [SOCKET_ADDRESS_DEFAULT] = "default",
655 [SOCKET_ADDRESS_BOTH] = "both",
656 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
659 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);