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 if ((r = safe_atou(s, &u)) < 0)
173 if (u <= 0 || u > 0xFFFF)
176 if (socket_ipv6_is_supported()) {
177 a->sockaddr.in6.sin6_family = AF_INET6;
178 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
179 a->sockaddr.in6.sin6_addr = in6addr_any;
180 a->size = sizeof(struct sockaddr_in6);
182 a->sockaddr.in4.sin_family = AF_INET;
183 a->sockaddr.in4.sin_port = htons((uint16_t) u);
184 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
185 a->size = sizeof(struct sockaddr_in);
193 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
196 char* sfamily = NULL;
204 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
205 return errno ? -errno : -EINVAL;
207 if ((family = netlink_family_from_string(sfamily)) < 0)
208 if (safe_atoi(sfamily, &family) < 0) {
215 a->sockaddr.nl.nl_family = AF_NETLINK;
216 a->sockaddr.nl.nl_groups = group;
219 a->size = sizeof(struct sockaddr_nl);
220 a->protocol = family;
225 int socket_address_verify(const SocketAddress *a) {
228 switch (socket_address_family(a)) {
231 if (a->size != sizeof(struct sockaddr_in))
234 if (a->sockaddr.in4.sin_port == 0)
237 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
243 if (a->size != sizeof(struct sockaddr_in6))
246 if (a->sockaddr.in6.sin6_port == 0)
249 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
255 if (a->size < offsetof(struct sockaddr_un, sun_path))
258 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
260 if (a->sockaddr.un.sun_path[0] != 0) {
264 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
267 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
272 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
279 if (a->size != sizeof(struct sockaddr_nl))
282 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
288 return -EAFNOSUPPORT;
292 int socket_address_print(const SocketAddress *a, char **p) {
297 if ((r = socket_address_verify(a)) < 0)
300 switch (socket_address_family(a)) {
305 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
308 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
313 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
321 if (!(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)) {
340 if (!(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 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
355 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
356 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
360 if (!(ret = strdup(a->sockaddr.un.sun_path)))
371 if ((sfamily = netlink_family_to_string(a->protocol)))
372 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
374 r = asprintf(p, "%i %u", a->protocol, 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 (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
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 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
495 if (socket_address_family(a) != AF_UNIX)
498 if (a->sockaddr.un.sun_path[0] == 0)
501 return path_startswith(a->sockaddr.un.sun_path, prefix);
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 static const char* const netlink_family_table[] = {
523 [NETLINK_ROUTE] = "route",
524 [NETLINK_FIREWALL] = "firewall",
525 [NETLINK_INET_DIAG] = "inet-diag",
526 [NETLINK_NFLOG] = "nflog",
527 [NETLINK_XFRM] = "xfrm",
528 [NETLINK_SELINUX] = "selinux",
529 [NETLINK_ISCSI] = "iscsi",
530 [NETLINK_AUDIT] = "audit",
531 [NETLINK_FIB_LOOKUP] = "fib-lookup",
532 [NETLINK_CONNECTOR] = "connector",
533 [NETLINK_NETFILTER] = "netfilter",
534 [NETLINK_IP6_FW] = "ip6-fw",
535 [NETLINK_DNRTMSG] = "dnrtmsg",
536 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
537 [NETLINK_GENERIC] = "generic",
538 [NETLINK_SCSITRANSPORT] = "scsitransport",
539 [NETLINK_ECRYPTFS] = "ecryptfs"
542 DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
544 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
545 [SOCKET_ADDRESS_DEFAULT] = "default",
546 [SOCKET_ADDRESS_BOTH] = "both",
547 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
550 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);