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.");
62 if (!(e = strchr(s+1, ']')))
65 if (!(n = strndup(s+1, e-s-1)))
69 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
71 return errno != 0 ? -errno : -EINVAL;
81 if ((r = safe_atou(e, &u)) < 0)
84 if (u <= 0 || u > 0xFFFF)
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);
91 } else if (*s == '/') {
97 if (l >= sizeof(a->sockaddr.un.sun_path))
100 a->sockaddr.un.sun_family = AF_UNIX;
101 memcpy(a->sockaddr.un.sun_path, s, l);
102 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
104 } else if (*s == '@') {
105 /* Abstract AF_UNIX socket */
109 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
112 a->sockaddr.un.sun_family = AF_UNIX;
113 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
114 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
118 if ((e = strchr(s, ':'))) {
120 if ((r = safe_atou(e+1, &u)) < 0)
123 if (u <= 0 || u > 0xFFFF)
126 if (!(n = strndup(s, e-s)))
129 /* IPv4 in w.x.y.z:p notation? */
130 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
136 /* Gotcha, it's a traditional IPv4 address */
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);
145 if (strlen(n) > IF_NAMESIZE-1) {
150 /* Uh, our last resort, an interface name */
151 idx = if_nametoindex(n);
157 if (!socket_ipv6_is_supported()) {
158 log_warning("Binding to interface is not available since kernel does not support IPv6.");
159 return -EAFNOSUPPORT;
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;
165 a->sockaddr.in6.sin6_addr = in6addr_any;
166 a->size = sizeof(struct sockaddr_in6);
171 r = safe_atou(s, &u);
175 if (u <= 0 || u > 0xFFFF)
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);
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);
195 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
198 _cleanup_free_ char *sfamily = NULL;
206 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
207 return errno ? -errno : -EINVAL;
209 family = netlink_family_from_string(sfamily);
213 a->sockaddr.nl.nl_family = AF_NETLINK;
214 a->sockaddr.nl.nl_groups = group;
217 a->size = sizeof(struct sockaddr_nl);
218 a->protocol = family;
223 int socket_address_verify(const SocketAddress *a) {
226 switch (socket_address_family(a)) {
229 if (a->size != sizeof(struct sockaddr_in))
232 if (a->sockaddr.in4.sin_port == 0)
235 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
241 if (a->size != sizeof(struct sockaddr_in6))
244 if (a->sockaddr.in6.sin6_port == 0)
247 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
253 if (a->size < offsetof(struct sockaddr_un, sun_path))
256 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
258 if (a->sockaddr.un.sun_path[0] != 0) {
262 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
265 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
270 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
277 if (a->size != sizeof(struct sockaddr_nl))
280 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
286 return -EAFNOSUPPORT;
290 int socket_address_print(const SocketAddress *a, char **p) {
295 if ((r = socket_address_verify(a)) < 0)
298 switch (socket_address_family(a)) {
303 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
306 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
311 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
319 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
323 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
328 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
336 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
338 if (!(ret = strdup("<unnamed>")))
341 } else if (a->sockaddr.un.sun_path[0] == 0) {
344 /* FIXME: We assume we can print the
345 * socket path here and that it hasn't
346 * more than one NUL byte. That is
347 * actually an invalid assumption */
349 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
353 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
354 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
358 if (!(ret = strdup(a->sockaddr.un.sun_path)))
367 char _cleanup_free_ *sfamily = NULL;
369 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
372 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
384 bool socket_address_can_accept(const SocketAddress *a) {
388 a->type == SOCK_STREAM ||
389 a->type == SOCK_SEQPACKET;
392 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
396 /* Invalid addresses are unequal to all */
397 if (socket_address_verify(a) < 0 ||
398 socket_address_verify(b) < 0)
401 if (a->type != b->type)
404 if (a->size != b->size)
407 if (socket_address_family(a) != socket_address_family(b))
410 switch (socket_address_family(a)) {
413 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
416 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
422 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
425 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
432 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
435 if (a->sockaddr.un.sun_path[0]) {
436 if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
439 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
447 if (a->protocol != b->protocol)
450 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
456 /* Cannot compare, so we assume the addresses are different */
463 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
464 struct SocketAddress b;
469 if (socket_address_parse(&b, s) < 0)
474 return socket_address_equal(a, &b);
477 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
478 struct SocketAddress b;
483 if (socket_address_parse_netlink(&b, s) < 0)
486 return socket_address_equal(a, &b);
489 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
492 if (socket_address_family(a) != AF_UNIX)
495 if (a->sockaddr.un.sun_path[0] == 0)
498 return path_startswith(a->sockaddr.un.sun_path, prefix);
501 bool socket_ipv6_is_supported(void) {
505 if (access("/sys/module/ipv6", F_OK) != 0)
508 /* If we can't check "disable" parameter, assume enabled */
509 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
512 /* If module was loaded with disable=1 no IPv6 available */
513 enabled = l[0] == '0';
519 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
520 union sockaddr_union sa;
521 socklen_t salen = sizeof(sa), solen;
527 if (getsockname(fd, &sa.sa, &salen) < 0)
530 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
533 solen = sizeof(type);
534 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
540 if (a->protocol != 0) {
541 solen = sizeof(protocol);
542 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
545 if (protocol != a->protocol)
549 switch (sa.sa.sa_family) {
552 return sa.in4.sin_port == a->sockaddr.in4.sin_port &&
553 sa.in4.sin_addr.s_addr == a->sockaddr.in4.sin_addr.s_addr;
556 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
557 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
560 return salen == a->size &&
561 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
568 int make_socket_fd(const char* address, int flags) {
571 char _cleanup_free_ *p = NULL;
573 r = socket_address_parse(&a, address);
575 log_error("failed to parse socket: %s", strerror(-r));
579 fd = socket(socket_address_family(&a), flags, 0);
581 log_error("socket(): %m");
585 r = socket_address_print(&a, &p);
587 log_error("socket_address_print(): %s", strerror(-r));
590 log_info("Listening on %s", p);
592 r = bind(fd, &a.sockaddr.sa, a.size);
594 log_error("bind to %s: %m", address);
598 r = listen(fd, SOMAXCONN);
600 log_error("listen on %s: %m", address);
607 static const char* const netlink_family_table[] = {
608 [NETLINK_ROUTE] = "route",
609 [NETLINK_FIREWALL] = "firewall",
610 [NETLINK_INET_DIAG] = "inet-diag",
611 [NETLINK_NFLOG] = "nflog",
612 [NETLINK_XFRM] = "xfrm",
613 [NETLINK_SELINUX] = "selinux",
614 [NETLINK_ISCSI] = "iscsi",
615 [NETLINK_AUDIT] = "audit",
616 [NETLINK_FIB_LOOKUP] = "fib-lookup",
617 [NETLINK_CONNECTOR] = "connector",
618 [NETLINK_NETFILTER] = "netfilter",
619 [NETLINK_IP6_FW] = "ip6-fw",
620 [NETLINK_DNRTMSG] = "dnrtmsg",
621 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
622 [NETLINK_GENERIC] = "generic",
623 [NETLINK_SCSITRANSPORT] = "scsitransport",
624 [NETLINK_ECRYPTFS] = "ecryptfs"
627 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
629 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
630 [SOCKET_ADDRESS_DEFAULT] = "default",
631 [SOCKET_ADDRESS_BOTH] = "both",
632 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
635 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);