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 > 0 ? -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 ret = new(char, INET_ADDRSTRLEN+1+5+1);
307 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
312 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
320 ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1);
325 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
330 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
338 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
339 ret = strdup("<unnamed>");
343 } else if (a->sockaddr.un.sun_path[0] == 0) {
346 /* FIXME: We assume we can print the
347 * socket path here and that it hasn't
348 * more than one NUL byte. That is
349 * actually an invalid assumption */
351 ret = new(char, sizeof(a->sockaddr.un.sun_path)+1);
356 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
357 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
360 ret = strdup(a->sockaddr.un.sun_path);
370 _cleanup_free_ char *sfamily = NULL;
372 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
375 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
387 bool socket_address_can_accept(const SocketAddress *a) {
391 a->type == SOCK_STREAM ||
392 a->type == SOCK_SEQPACKET;
395 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
399 /* Invalid addresses are unequal to all */
400 if (socket_address_verify(a) < 0 ||
401 socket_address_verify(b) < 0)
404 if (a->type != b->type)
407 if (a->size != b->size)
410 if (socket_address_family(a) != socket_address_family(b))
413 switch (socket_address_family(a)) {
416 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
419 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
425 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
428 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
435 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
438 if (a->sockaddr.un.sun_path[0]) {
439 if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
442 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
450 if (a->protocol != b->protocol)
453 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
459 /* Cannot compare, so we assume the addresses are different */
466 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
467 struct SocketAddress b;
472 if (socket_address_parse(&b, s) < 0)
477 return socket_address_equal(a, &b);
480 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
481 struct SocketAddress b;
486 if (socket_address_parse_netlink(&b, s) < 0)
489 return socket_address_equal(a, &b);
492 const char* socket_address_get_path(const SocketAddress *a) {
495 if (socket_address_family(a) != AF_UNIX)
498 if (a->sockaddr.un.sun_path[0] == 0)
501 return a->sockaddr.un.sun_path;
504 bool socket_ipv6_is_supported(void) {
508 if (access("/sys/module/ipv6", F_OK) != 0)
511 /* If we can't check "disable" parameter, assume enabled */
512 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
515 /* If module was loaded with disable=1 no IPv6 available */
516 enabled = l[0] == '0';
522 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
523 union sockaddr_union sa;
524 socklen_t salen = sizeof(sa), solen;
530 if (getsockname(fd, &sa.sa, &salen) < 0)
533 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
536 solen = sizeof(type);
537 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
543 if (a->protocol != 0) {
544 solen = sizeof(protocol);
545 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
548 if (protocol != a->protocol)
552 switch (sa.sa.sa_family) {
555 return sa.in4.sin_port == a->sockaddr.in4.sin_port &&
556 sa.in4.sin_addr.s_addr == a->sockaddr.in4.sin_addr.s_addr;
559 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
560 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
563 return salen == a->size &&
564 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
571 int make_socket_fd(const char* address, int flags) {
574 _cleanup_free_ char *p = NULL;
576 r = socket_address_parse(&a, address);
578 log_error("failed to parse socket: %s", strerror(-r));
582 fd = socket(socket_address_family(&a), flags, 0);
584 log_error("socket(): %m");
588 r = socket_address_print(&a, &p);
590 log_error("socket_address_print(): %s", strerror(-r));
593 log_info("Listening on %s", p);
595 r = bind(fd, &a.sockaddr.sa, a.size);
597 log_error("bind to %s: %m", address);
601 r = listen(fd, SOMAXCONN);
603 log_error("listen on %s: %m", address);
610 static const char* const netlink_family_table[] = {
611 [NETLINK_ROUTE] = "route",
612 [NETLINK_FIREWALL] = "firewall",
613 [NETLINK_INET_DIAG] = "inet-diag",
614 [NETLINK_NFLOG] = "nflog",
615 [NETLINK_XFRM] = "xfrm",
616 [NETLINK_SELINUX] = "selinux",
617 [NETLINK_ISCSI] = "iscsi",
618 [NETLINK_AUDIT] = "audit",
619 [NETLINK_FIB_LOOKUP] = "fib-lookup",
620 [NETLINK_CONNECTOR] = "connector",
621 [NETLINK_NETFILTER] = "netfilter",
622 [NETLINK_IP6_FW] = "ip6-fw",
623 [NETLINK_DNRTMSG] = "dnrtmsg",
624 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
625 [NETLINK_GENERIC] = "generic",
626 [NETLINK_SCSITRANSPORT] = "scsitransport",
627 [NETLINK_ECRYPTFS] = "ecryptfs"
630 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
632 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
633 [SOCKET_ADDRESS_DEFAULT] = "default",
634 [SOCKET_ADDRESS_BOTH] = "both",
635 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
638 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);