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 "socket-util.h"
41 int socket_address_parse(SocketAddress *a, const char *s) {
50 a->type = SOCK_STREAM;
53 /* IPv6 in [x:.....:z]:p notation */
55 if (!socket_ipv6_is_supported()) {
56 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
60 if (!(e = strchr(s+1, ']')))
63 if (!(n = strndup(s+1, e-s-1)))
67 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
69 return errno != 0 ? -errno : -EINVAL;
79 if ((r = safe_atou(e, &u)) < 0)
82 if (u <= 0 || u > 0xFFFF)
85 a->sockaddr.in6.sin6_family = AF_INET6;
86 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
87 a->size = sizeof(struct sockaddr_in6);
89 } else if (*s == '/') {
95 if (l >= sizeof(a->sockaddr.un.sun_path))
98 a->sockaddr.un.sun_family = AF_UNIX;
99 memcpy(a->sockaddr.un.sun_path, s, l);
100 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
102 } else if (*s == '@') {
103 /* Abstract AF_UNIX socket */
107 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
110 a->sockaddr.un.sun_family = AF_UNIX;
111 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
112 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
116 if ((e = strchr(s, ':'))) {
118 if ((r = safe_atou(e+1, &u)) < 0)
121 if (u <= 0 || u > 0xFFFF)
124 if (!(n = strndup(s, e-s)))
127 /* IPv4 in w.x.y.z:p notation? */
128 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
134 /* Gotcha, it's a traditional IPv4 address */
137 a->sockaddr.in4.sin_family = AF_INET;
138 a->sockaddr.in4.sin_port = htons((uint16_t) u);
139 a->size = sizeof(struct sockaddr_in);
143 if (strlen(n) > IF_NAMESIZE-1) {
148 /* Uh, our last resort, an interface name */
149 idx = if_nametoindex(n);
155 if (!socket_ipv6_is_supported()) {
156 log_warning("Binding to interface is not available since kernel does not support IPv6.");
157 return -EAFNOSUPPORT;
160 a->sockaddr.in6.sin6_family = AF_INET6;
161 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
162 a->sockaddr.in6.sin6_scope_id = idx;
163 a->sockaddr.in6.sin6_addr = in6addr_any;
164 a->size = sizeof(struct sockaddr_in6);
169 if ((r = safe_atou(s, &u)) < 0)
172 if (u <= 0 || u > 0xFFFF)
175 if (socket_ipv6_is_supported()) {
176 a->sockaddr.in6.sin6_family = AF_INET6;
177 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
178 a->sockaddr.in6.sin6_addr = in6addr_any;
179 a->size = sizeof(struct sockaddr_in6);
181 a->sockaddr.in4.sin_family = AF_INET;
182 a->sockaddr.in4.sin_port = htons((uint16_t) u);
183 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
184 a->size = sizeof(struct sockaddr_in);
192 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
195 char* sfamily = NULL;
203 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
204 return errno ? -errno : -EINVAL;
206 if ((family = netlink_family_from_string(sfamily)) < 0)
207 if (safe_atoi(sfamily, &family) < 0) {
214 a->sockaddr.nl.nl_family = AF_NETLINK;
215 a->sockaddr.nl.nl_groups = group;
218 a->size = sizeof(struct sockaddr_nl);
219 a->protocol = family;
224 int socket_address_verify(const SocketAddress *a) {
227 switch (socket_address_family(a)) {
230 if (a->size != sizeof(struct sockaddr_in))
233 if (a->sockaddr.in4.sin_port == 0)
236 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
242 if (a->size != sizeof(struct sockaddr_in6))
245 if (a->sockaddr.in6.sin6_port == 0)
248 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
254 if (a->size < offsetof(struct sockaddr_un, sun_path))
257 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
259 if (a->sockaddr.un.sun_path[0] != 0) {
263 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
266 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
271 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
278 if (a->size != sizeof(struct sockaddr_nl))
281 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
287 return -EAFNOSUPPORT;
291 int socket_address_print(const SocketAddress *a, char **p) {
296 if ((r = socket_address_verify(a)) < 0)
299 switch (socket_address_family(a)) {
304 if (!(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 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
324 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
329 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
337 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
339 if (!(ret = strdup("<unnamed>")))
342 } else if (a->sockaddr.un.sun_path[0] == 0) {
345 /* FIXME: We assume we can print the
346 * socket path here and that it hasn't
347 * more than one NUL byte. That is
348 * actually an invalid assumption */
350 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
354 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
355 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
359 if (!(ret = strdup(a->sockaddr.un.sun_path)))
370 if ((sfamily = netlink_family_to_string(a->protocol)))
371 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
373 r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups);
386 bool socket_address_can_accept(const SocketAddress *a) {
390 a->type == SOCK_STREAM ||
391 a->type == SOCK_SEQPACKET;
394 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
398 /* Invalid addresses are unequal to all */
399 if (socket_address_verify(a) < 0 ||
400 socket_address_verify(b) < 0)
403 if (a->type != b->type)
406 if (a->size != b->size)
409 if (socket_address_family(a) != socket_address_family(b))
412 switch (socket_address_family(a)) {
415 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
418 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
424 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
427 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
434 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
437 if (a->sockaddr.un.sun_path[0]) {
438 if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
441 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
449 if (a->protocol != b->protocol)
452 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
458 /* Cannot compare, so we assume the addresses are different */
465 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
466 struct SocketAddress b;
471 if (socket_address_parse(&b, s) < 0)
476 return socket_address_equal(a, &b);
479 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
480 struct SocketAddress b;
485 if (socket_address_parse_netlink(&b, s) < 0)
488 return socket_address_equal(a, &b);
491 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
494 if (socket_address_family(a) != AF_UNIX)
497 if (a->sockaddr.un.sun_path[0] == 0)
500 return path_startswith(a->sockaddr.un.sun_path, prefix);
503 bool socket_ipv6_is_supported(void) {
507 if (access("/sys/module/ipv6", F_OK) != 0)
510 /* If we can't check "disable" parameter, assume enabled */
511 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
514 /* If module was loaded with disable=1 no IPv6 available */
515 enabled = l[0] == '0';
521 static const char* const netlink_family_table[] = {
522 [NETLINK_ROUTE] = "route",
523 [NETLINK_FIREWALL] = "firewall",
524 [NETLINK_INET_DIAG] = "inet-diag",
525 [NETLINK_NFLOG] = "nflog",
526 [NETLINK_XFRM] = "xfrm",
527 [NETLINK_SELINUX] = "selinux",
528 [NETLINK_ISCSI] = "iscsi",
529 [NETLINK_AUDIT] = "audit",
530 [NETLINK_FIB_LOOKUP] = "fib-lookup",
531 [NETLINK_CONNECTOR] = "connector",
532 [NETLINK_NETFILTER] = "netfilter",
533 [NETLINK_IP6_FW] = "ip6-fw",
534 [NETLINK_DNRTMSG] = "dnrtmsg",
535 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
536 [NETLINK_GENERIC] = "generic",
537 [NETLINK_SCSITRANSPORT] = "scsitransport",
538 [NETLINK_ECRYPTFS] = "ecryptfs"
541 DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
543 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
544 [SOCKET_ADDRESS_DEFAULT] = "default",
545 [SOCKET_ADDRESS_BOTH] = "both",
546 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
549 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);