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"
42 int socket_address_parse(SocketAddress *a, const char *s) {
51 a->type = SOCK_STREAM;
54 /* IPv6 in [x:.....:z]:p notation */
56 if (!socket_ipv6_is_supported()) {
57 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
61 if (!(e = strchr(s+1, ']')))
64 if (!(n = strndup(s+1, e-s-1)))
68 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
70 return errno != 0 ? -errno : -EINVAL;
80 if ((r = safe_atou(e, &u)) < 0)
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;
117 if ((e = strchr(s, ':'))) {
119 if ((r = safe_atou(e+1, &u)) < 0)
122 if (u <= 0 || u > 0xFFFF)
125 if (!(n = strndup(s, e-s)))
128 /* IPv4 in w.x.y.z:p notation? */
129 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
135 /* Gotcha, it's a traditional IPv4 address */
138 a->sockaddr.in4.sin_family = AF_INET;
139 a->sockaddr.in4.sin_port = htons((uint16_t) u);
140 a->size = sizeof(struct sockaddr_in);
144 if (strlen(n) > IF_NAMESIZE-1) {
149 /* Uh, our last resort, an interface name */
150 idx = if_nametoindex(n);
156 if (!socket_ipv6_is_supported()) {
157 log_warning("Binding to interface is not available since kernel does not support IPv6.");
158 return -EAFNOSUPPORT;
161 a->sockaddr.in6.sin6_family = AF_INET6;
162 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
163 a->sockaddr.in6.sin6_scope_id = idx;
164 a->sockaddr.in6.sin6_addr = in6addr_any;
165 a->size = sizeof(struct sockaddr_in6);
170 r = safe_atou(s, &u);
174 if (u <= 0 || u > 0xFFFF)
177 if (socket_ipv6_is_supported()) {
178 a->sockaddr.in6.sin6_family = AF_INET6;
179 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
180 a->sockaddr.in6.sin6_addr = in6addr_any;
181 a->size = sizeof(struct sockaddr_in6);
183 a->sockaddr.in4.sin_family = AF_INET;
184 a->sockaddr.in4.sin_port = htons((uint16_t) u);
185 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
186 a->size = sizeof(struct sockaddr_in);
194 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
197 _cleanup_free_ char *sfamily = NULL;
205 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
206 return errno ? -errno : -EINVAL;
208 family = netlink_family_from_string(sfamily);
212 a->sockaddr.nl.nl_family = AF_NETLINK;
213 a->sockaddr.nl.nl_groups = group;
216 a->size = sizeof(struct sockaddr_nl);
217 a->protocol = family;
222 int socket_address_verify(const SocketAddress *a) {
225 switch (socket_address_family(a)) {
228 if (a->size != sizeof(struct sockaddr_in))
231 if (a->sockaddr.in4.sin_port == 0)
234 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
240 if (a->size != sizeof(struct sockaddr_in6))
243 if (a->sockaddr.in6.sin6_port == 0)
246 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
252 if (a->size < offsetof(struct sockaddr_un, sun_path))
255 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
257 if (a->sockaddr.un.sun_path[0] != 0) {
261 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
264 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
269 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
276 if (a->size != sizeof(struct sockaddr_nl))
279 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
285 return -EAFNOSUPPORT;
289 int socket_address_print(const SocketAddress *a, char **p) {
294 if ((r = socket_address_verify(a)) < 0)
297 switch (socket_address_family(a)) {
302 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
305 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
310 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
318 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
322 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
327 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
335 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
337 if (!(ret = strdup("<unnamed>")))
340 } else if (a->sockaddr.un.sun_path[0] == 0) {
343 /* FIXME: We assume we can print the
344 * socket path here and that it hasn't
345 * more than one NUL byte. That is
346 * actually an invalid assumption */
348 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
352 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
353 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
357 if (!(ret = strdup(a->sockaddr.un.sun_path)))
368 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
371 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
382 bool socket_address_can_accept(const SocketAddress *a) {
386 a->type == SOCK_STREAM ||
387 a->type == SOCK_SEQPACKET;
390 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
394 /* Invalid addresses are unequal to all */
395 if (socket_address_verify(a) < 0 ||
396 socket_address_verify(b) < 0)
399 if (a->type != b->type)
402 if (a->size != b->size)
405 if (socket_address_family(a) != socket_address_family(b))
408 switch (socket_address_family(a)) {
411 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
414 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
420 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
423 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
430 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
433 if (a->sockaddr.un.sun_path[0]) {
434 if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
437 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
445 if (a->protocol != b->protocol)
448 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
454 /* Cannot compare, so we assume the addresses are different */
461 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
462 struct SocketAddress b;
467 if (socket_address_parse(&b, s) < 0)
472 return socket_address_equal(a, &b);
475 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
476 struct SocketAddress b;
481 if (socket_address_parse_netlink(&b, s) < 0)
484 return socket_address_equal(a, &b);
487 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
490 if (socket_address_family(a) != AF_UNIX)
493 if (a->sockaddr.un.sun_path[0] == 0)
496 return path_startswith(a->sockaddr.un.sun_path, prefix);
499 bool socket_ipv6_is_supported(void) {
503 if (access("/sys/module/ipv6", F_OK) != 0)
506 /* If we can't check "disable" parameter, assume enabled */
507 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
510 /* If module was loaded with disable=1 no IPv6 available */
511 enabled = l[0] == '0';
517 static const char* const netlink_family_table[] = {
518 [NETLINK_ROUTE] = "route",
519 [NETLINK_FIREWALL] = "firewall",
520 [NETLINK_INET_DIAG] = "inet-diag",
521 [NETLINK_NFLOG] = "nflog",
522 [NETLINK_XFRM] = "xfrm",
523 [NETLINK_SELINUX] = "selinux",
524 [NETLINK_ISCSI] = "iscsi",
525 [NETLINK_AUDIT] = "audit",
526 [NETLINK_FIB_LOOKUP] = "fib-lookup",
527 [NETLINK_CONNECTOR] = "connector",
528 [NETLINK_NETFILTER] = "netfilter",
529 [NETLINK_IP6_FW] = "ip6-fw",
530 [NETLINK_DNRTMSG] = "dnrtmsg",
531 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
532 [NETLINK_GENERIC] = "generic",
533 [NETLINK_SCSITRANSPORT] = "scsitransport",
534 [NETLINK_ECRYPTFS] = "ecryptfs"
537 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
539 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
540 [SOCKET_ADDRESS_DEFAULT] = "default",
541 [SOCKET_ADDRESS_BOTH] = "both",
542 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
545 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);