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)))
366 char _cleanup_free_ *sfamily = NULL;
368 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
371 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
381 bool socket_address_can_accept(const SocketAddress *a) {
385 a->type == SOCK_STREAM ||
386 a->type == SOCK_SEQPACKET;
389 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
393 /* Invalid addresses are unequal to all */
394 if (socket_address_verify(a) < 0 ||
395 socket_address_verify(b) < 0)
398 if (a->type != b->type)
401 if (a->size != b->size)
404 if (socket_address_family(a) != socket_address_family(b))
407 switch (socket_address_family(a)) {
410 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
413 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
419 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
422 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
429 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
432 if (a->sockaddr.un.sun_path[0]) {
433 if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
436 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
444 if (a->protocol != b->protocol)
447 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
453 /* Cannot compare, so we assume the addresses are different */
460 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
461 struct SocketAddress b;
466 if (socket_address_parse(&b, s) < 0)
471 return socket_address_equal(a, &b);
474 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
475 struct SocketAddress b;
480 if (socket_address_parse_netlink(&b, s) < 0)
483 return socket_address_equal(a, &b);
486 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
489 if (socket_address_family(a) != AF_UNIX)
492 if (a->sockaddr.un.sun_path[0] == 0)
495 return path_startswith(a->sockaddr.un.sun_path, prefix);
498 bool socket_ipv6_is_supported(void) {
502 if (access("/sys/module/ipv6", F_OK) != 0)
505 /* If we can't check "disable" parameter, assume enabled */
506 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
509 /* If module was loaded with disable=1 no IPv6 available */
510 enabled = l[0] == '0';
516 static const char* const netlink_family_table[] = {
517 [NETLINK_ROUTE] = "route",
518 [NETLINK_FIREWALL] = "firewall",
519 [NETLINK_INET_DIAG] = "inet-diag",
520 [NETLINK_NFLOG] = "nflog",
521 [NETLINK_XFRM] = "xfrm",
522 [NETLINK_SELINUX] = "selinux",
523 [NETLINK_ISCSI] = "iscsi",
524 [NETLINK_AUDIT] = "audit",
525 [NETLINK_FIB_LOOKUP] = "fib-lookup",
526 [NETLINK_CONNECTOR] = "connector",
527 [NETLINK_NETFILTER] = "netfilter",
528 [NETLINK_IP6_FW] = "ip6-fw",
529 [NETLINK_DNRTMSG] = "dnrtmsg",
530 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
531 [NETLINK_GENERIC] = "generic",
532 [NETLINK_SCSITRANSPORT] = "scsitransport",
533 [NETLINK_ECRYPTFS] = "ecryptfs"
536 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
538 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
539 [SOCKET_ADDRESS_DEFAULT] = "default",
540 [SOCKET_ADDRESS_BOTH] = "both",
541 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
544 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);