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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
18 You should have received a copy of the GNU 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>
37 #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 int socket_address_listen(
387 const SocketAddress
*a
,
389 SocketAddressBindIPv6Only only
,
390 const char *bind_to_device
,
393 mode_t directory_mode
,
402 if ((r
= socket_address_verify(a
)) < 0)
405 if (socket_address_family(a
) == AF_INET6
&& !socket_ipv6_is_supported())
406 return -EAFNOSUPPORT
;
408 r
= label_socket_set(label
);
412 fd
= socket(socket_address_family(a
), a
->type
| SOCK_NONBLOCK
| SOCK_CLOEXEC
, a
->protocol
);
413 r
= fd
< 0 ? -errno
: 0;
415 label_socket_clear();
420 if (socket_address_family(a
) == AF_INET6
&& only
!= SOCKET_ADDRESS_DEFAULT
) {
421 int flag
= only
== SOCKET_ADDRESS_IPV6_ONLY
;
423 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &flag
, sizeof(flag
)) < 0)
427 if (socket_address_family(a
) == AF_INET
|| socket_address_family(a
) == AF_INET6
) {
429 if (setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
, bind_to_device
, strlen(bind_to_device
)+1) < 0)
434 if (setsockopt(fd
, IPPROTO_IP
, IP_FREEBIND
, &one
, sizeof(one
)) < 0)
435 log_warning("IP_FREEBIND failed: %m");
440 if (setsockopt(fd
, IPPROTO_IP
, IP_TRANSPARENT
, &one
, sizeof(one
)) < 0)
441 log_warning("IP_TRANSPARENT failed: %m");
446 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
)) < 0)
449 if (socket_address_family(a
) == AF_UNIX
&& a
->sockaddr
.un
.sun_path
[0] != 0) {
453 mkdir_parents(a
->sockaddr
.un
.sun_path
, directory_mode
);
455 /* Enforce the right access mode for the socket*/
456 old_mask
= umask(~ socket_mode
);
458 /* Include the original umask in our mask */
459 umask(~socket_mode
| old_mask
);
461 r
= label_bind(fd
, &a
->sockaddr
.sa
, a
->size
);
463 if (r
< 0 && errno
== EADDRINUSE
) {
464 /* Unlink and try again */
465 unlink(a
->sockaddr
.un
.sun_path
);
466 r
= bind(fd
, &a
->sockaddr
.sa
, a
->size
);
471 r
= bind(fd
, &a
->sockaddr
.sa
, a
->size
);
476 if (socket_address_can_accept(a
))
477 if (listen(fd
, backlog
) < 0)
485 close_nointr_nofail(fd
);
489 bool socket_address_can_accept(const SocketAddress
*a
) {
493 a
->type
== SOCK_STREAM
||
494 a
->type
== SOCK_SEQPACKET
;
497 bool socket_address_equal(const SocketAddress
*a
, const SocketAddress
*b
) {
501 /* Invalid addresses are unequal to all */
502 if (socket_address_verify(a
) < 0 ||
503 socket_address_verify(b
) < 0)
506 if (a
->type
!= b
->type
)
509 if (a
->size
!= b
->size
)
512 if (socket_address_family(a
) != socket_address_family(b
))
515 switch (socket_address_family(a
)) {
518 if (a
->sockaddr
.in4
.sin_addr
.s_addr
!= b
->sockaddr
.in4
.sin_addr
.s_addr
)
521 if (a
->sockaddr
.in4
.sin_port
!= b
->sockaddr
.in4
.sin_port
)
527 if (memcmp(&a
->sockaddr
.in6
.sin6_addr
, &b
->sockaddr
.in6
.sin6_addr
, sizeof(a
->sockaddr
.in6
.sin6_addr
)) != 0)
530 if (a
->sockaddr
.in6
.sin6_port
!= b
->sockaddr
.in6
.sin6_port
)
537 if ((a
->sockaddr
.un
.sun_path
[0] == 0) != (b
->sockaddr
.un
.sun_path
[0] == 0))
540 if (a
->sockaddr
.un
.sun_path
[0]) {
541 if (strncmp(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
, sizeof(a
->sockaddr
.un
.sun_path
)) != 0)
544 if (memcmp(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
, a
->size
) != 0)
552 if (a
->protocol
!= b
->protocol
)
555 if (a
->sockaddr
.nl
.nl_groups
!= b
->sockaddr
.nl
.nl_groups
)
561 /* Cannot compare, so we assume the addresses are different */
568 bool socket_address_is(const SocketAddress
*a
, const char *s
, int type
) {
569 struct SocketAddress b
;
574 if (socket_address_parse(&b
, s
) < 0)
579 return socket_address_equal(a
, &b
);
582 bool socket_address_is_netlink(const SocketAddress
*a
, const char *s
) {
583 struct SocketAddress b
;
588 if (socket_address_parse_netlink(&b
, s
) < 0)
591 return socket_address_equal(a
, &b
);
594 bool socket_address_needs_mount(const SocketAddress
*a
, const char *prefix
) {
597 if (socket_address_family(a
) != AF_UNIX
)
600 if (a
->sockaddr
.un
.sun_path
[0] == 0)
603 return path_startswith(a
->sockaddr
.un
.sun_path
, prefix
);
606 bool socket_ipv6_is_supported(void) {
610 if (access("/sys/module/ipv6", F_OK
) != 0)
613 /* If we can't check "disable" parameter, assume enabled */
614 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l
) < 0)
617 /* If module was loaded with disable=1 no IPv6 available */
618 enabled
= l
[0] == '0';
624 static const char* const netlink_family_table
[] = {
625 [NETLINK_ROUTE
] = "route",
626 [NETLINK_FIREWALL
] = "firewall",
627 [NETLINK_INET_DIAG
] = "inet-diag",
628 [NETLINK_NFLOG
] = "nflog",
629 [NETLINK_XFRM
] = "xfrm",
630 [NETLINK_SELINUX
] = "selinux",
631 [NETLINK_ISCSI
] = "iscsi",
632 [NETLINK_AUDIT
] = "audit",
633 [NETLINK_FIB_LOOKUP
] = "fib-lookup",
634 [NETLINK_CONNECTOR
] = "connector",
635 [NETLINK_NETFILTER
] = "netfilter",
636 [NETLINK_IP6_FW
] = "ip6-fw",
637 [NETLINK_DNRTMSG
] = "dnrtmsg",
638 [NETLINK_KOBJECT_UEVENT
] = "kobject-uevent",
639 [NETLINK_GENERIC
] = "generic",
640 [NETLINK_SCSITRANSPORT
] = "scsitransport",
641 [NETLINK_ECRYPTFS
] = "ecryptfs"
644 DEFINE_STRING_TABLE_LOOKUP(netlink_family
, int);
646 static const char* const socket_address_bind_ipv6_only_table
[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX
] = {
647 [SOCKET_ADDRESS_DEFAULT
] = "default",
648 [SOCKET_ADDRESS_BOTH
] = "both",
649 [SOCKET_ADDRESS_IPV6_ONLY
] = "ipv6-only"
652 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only
, SocketAddressBindIPv6Only
);