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 char* sfamily = NULL;
205 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
206 return errno ? -errno : -EINVAL;
208 if ((family = netlink_family_from_string(sfamily)) < 0)
209 if (safe_atoi(sfamily, &family) < 0) {
216 a->sockaddr.nl.nl_family = AF_NETLINK;
217 a->sockaddr.nl.nl_groups = group;
220 a->size = sizeof(struct sockaddr_nl);
221 a->protocol = family;
226 int socket_address_verify(const SocketAddress *a) {
229 switch (socket_address_family(a)) {
232 if (a->size != sizeof(struct sockaddr_in))
235 if (a->sockaddr.in4.sin_port == 0)
238 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
244 if (a->size != sizeof(struct sockaddr_in6))
247 if (a->sockaddr.in6.sin6_port == 0)
250 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
256 if (a->size < offsetof(struct sockaddr_un, sun_path))
259 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
261 if (a->sockaddr.un.sun_path[0] != 0) {
265 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
268 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
273 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
280 if (a->size != sizeof(struct sockaddr_nl))
283 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
289 return -EAFNOSUPPORT;
293 int socket_address_print(const SocketAddress *a, char **p) {
298 if ((r = socket_address_verify(a)) < 0)
301 switch (socket_address_family(a)) {
306 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
309 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
314 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
322 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
326 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
331 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
339 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
341 if (!(ret = strdup("<unnamed>")))
344 } else if (a->sockaddr.un.sun_path[0] == 0) {
347 /* FIXME: We assume we can print the
348 * socket path here and that it hasn't
349 * more than one NUL byte. That is
350 * actually an invalid assumption */
352 if (!(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;
361 if (!(ret = strdup(a->sockaddr.un.sun_path)))
372 if ((sfamily = netlink_family_to_string(a->protocol)))
373 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
375 r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups);
388 bool socket_address_can_accept(const SocketAddress *a) {
392 a->type == SOCK_STREAM ||
393 a->type == SOCK_SEQPACKET;
396 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
400 /* Invalid addresses are unequal to all */
401 if (socket_address_verify(a) < 0 ||
402 socket_address_verify(b) < 0)
405 if (a->type != b->type)
408 if (a->size != b->size)
411 if (socket_address_family(a) != socket_address_family(b))
414 switch (socket_address_family(a)) {
417 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
420 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
426 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
429 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
436 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
439 if (a->sockaddr.un.sun_path[0]) {
440 if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
443 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
451 if (a->protocol != b->protocol)
454 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
460 /* Cannot compare, so we assume the addresses are different */
467 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
468 struct SocketAddress b;
473 if (socket_address_parse(&b, s) < 0)
478 return socket_address_equal(a, &b);
481 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
482 struct SocketAddress b;
487 if (socket_address_parse_netlink(&b, s) < 0)
490 return socket_address_equal(a, &b);
493 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
496 if (socket_address_family(a) != AF_UNIX)
499 if (a->sockaddr.un.sun_path[0] == 0)
502 return path_startswith(a->sockaddr.un.sun_path, prefix);
505 bool socket_ipv6_is_supported(void) {
509 if (access("/sys/module/ipv6", F_OK) != 0)
512 /* If we can't check "disable" parameter, assume enabled */
513 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
516 /* If module was loaded with disable=1 no IPv6 available */
517 enabled = l[0] == '0';
523 static const char* const netlink_family_table[] = {
524 [NETLINK_ROUTE] = "route",
525 [NETLINK_FIREWALL] = "firewall",
526 [NETLINK_INET_DIAG] = "inet-diag",
527 [NETLINK_NFLOG] = "nflog",
528 [NETLINK_XFRM] = "xfrm",
529 [NETLINK_SELINUX] = "selinux",
530 [NETLINK_ISCSI] = "iscsi",
531 [NETLINK_AUDIT] = "audit",
532 [NETLINK_FIB_LOOKUP] = "fib-lookup",
533 [NETLINK_CONNECTOR] = "connector",
534 [NETLINK_NETFILTER] = "netfilter",
535 [NETLINK_IP6_FW] = "ip6-fw",
536 [NETLINK_DNRTMSG] = "dnrtmsg",
537 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
538 [NETLINK_GENERIC] = "generic",
539 [NETLINK_SCSITRANSPORT] = "scsitransport",
540 [NETLINK_ECRYPTFS] = "ecryptfs"
543 DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
545 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
546 [SOCKET_ADDRESS_DEFAULT] = "default",
547 [SOCKET_ADDRESS_BOTH] = "both",
548 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
551 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);