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) {
425 _cleanup_free_ char *l = NULL;
427 if (access("/sys/module/ipv6", F_OK) != 0)
430 /* If we can't check "disable" parameter, assume enabled */
431 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
434 /* If module was loaded with disable=1 no IPv6 available */
438 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
439 union sockaddr_union sa;
440 socklen_t salen = sizeof(sa), solen;
446 if (getsockname(fd, &sa.sa, &salen) < 0)
449 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
452 solen = sizeof(type);
453 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
459 if (a->protocol != 0) {
460 solen = sizeof(protocol);
461 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
464 if (protocol != a->protocol)
468 switch (sa.sa.sa_family) {
471 return sa.in.sin_port == a->sockaddr.in.sin_port &&
472 sa.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr;
475 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
476 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
479 return salen == a->size &&
480 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
487 int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) {
488 union sockaddr_union *sa = (union sockaddr_union*) _sa;
492 assert(salen >= sizeof(sa->sa.sa_family));
494 switch (sa->sa.sa_family) {
499 a = ntohl(sa->in.sin_addr.s_addr);
503 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
504 ntohs(sa->in.sin_port)) < 0)
511 static const unsigned char ipv4_prefix[] = {
512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
515 if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
516 const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
520 a[0], a[1], a[2], a[3],
521 ntohs(sa->in6.sin6_port)) < 0)
524 char a[INET6_ADDRSTRLEN];
528 inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)),
529 ntohs(sa->in6.sin6_port)) < 0)
537 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
538 p = strdup("<unnamed>");
542 } else if (sa->un.sun_path[0] == 0) {
545 /* FIXME: We assume we can print the
546 * socket path here and that it hasn't
547 * more than one NUL byte. That is
548 * actually an invalid assumption */
550 p = new(char, sizeof(sa->un.sun_path)+1);
555 memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
556 p[sizeof(sa->un.sun_path)] = 0;
559 p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
575 int getpeername_pretty(int fd, char **ret) {
576 union sockaddr_union sa;
584 if (getpeername(fd, &sa.sa, &salen) < 0)
587 if (sa.sa.sa_family == AF_UNIX) {
590 /* UNIX connection sockets are anonymous, so let's use
591 * PID/UID as pretty credentials instead */
593 r = getpeercred(fd, &ucred);
597 if (asprintf(ret, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.uid) < 0)
603 /* For remote sockets we translate IPv6 addresses back to IPv4
604 * if applicable, since that's nicer. */
606 return sockaddr_pretty(&sa.sa, salen, true, ret);
609 int getsockname_pretty(int fd, char **ret) {
610 union sockaddr_union sa;
617 if (getsockname(fd, &sa.sa, &salen) < 0)
620 /* For local sockets we do not translate IPv6 addresses back
621 * to IPv6 if applicable, since this is usually used for
622 * listening sockets where the difference between IPv4 and
625 return sockaddr_pretty(&sa.sa, salen, false, ret);
628 static const char* const netlink_family_table[] = {
629 [NETLINK_ROUTE] = "route",
630 [NETLINK_FIREWALL] = "firewall",
631 [NETLINK_INET_DIAG] = "inet-diag",
632 [NETLINK_NFLOG] = "nflog",
633 [NETLINK_XFRM] = "xfrm",
634 [NETLINK_SELINUX] = "selinux",
635 [NETLINK_ISCSI] = "iscsi",
636 [NETLINK_AUDIT] = "audit",
637 [NETLINK_FIB_LOOKUP] = "fib-lookup",
638 [NETLINK_CONNECTOR] = "connector",
639 [NETLINK_NETFILTER] = "netfilter",
640 [NETLINK_IP6_FW] = "ip6-fw",
641 [NETLINK_DNRTMSG] = "dnrtmsg",
642 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
643 [NETLINK_GENERIC] = "generic",
644 [NETLINK_SCSITRANSPORT] = "scsitransport",
645 [NETLINK_ECRYPTFS] = "ecryptfs"
648 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
650 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
651 [SOCKET_ADDRESS_DEFAULT] = "default",
652 [SOCKET_ADDRESS_BOTH] = "both",
653 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
656 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);