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>
38 #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 int socket_address_listen(
388 const SocketAddress
*a
,
390 SocketAddressBindIPv6Only only
,
391 const char *bind_to_device
,
394 mode_t directory_mode
,
403 if ((r
= socket_address_verify(a
)) < 0)
406 if (socket_address_family(a
) == AF_INET6
&& !socket_ipv6_is_supported())
407 return -EAFNOSUPPORT
;
409 r
= label_socket_set(label
);
413 fd
= socket(socket_address_family(a
), a
->type
| SOCK_NONBLOCK
| SOCK_CLOEXEC
, a
->protocol
);
414 r
= fd
< 0 ? -errno
: 0;
416 label_socket_clear();
421 if (socket_address_family(a
) == AF_INET6
&& only
!= SOCKET_ADDRESS_DEFAULT
) {
422 int flag
= only
== SOCKET_ADDRESS_IPV6_ONLY
;
424 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &flag
, sizeof(flag
)) < 0)
428 if (socket_address_family(a
) == AF_INET
|| socket_address_family(a
) == AF_INET6
) {
430 if (setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
, bind_to_device
, strlen(bind_to_device
)+1) < 0)
435 if (setsockopt(fd
, IPPROTO_IP
, IP_FREEBIND
, &one
, sizeof(one
)) < 0)
436 log_warning("IP_FREEBIND failed: %m");
441 if (setsockopt(fd
, IPPROTO_IP
, IP_TRANSPARENT
, &one
, sizeof(one
)) < 0)
442 log_warning("IP_TRANSPARENT failed: %m");
447 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
)) < 0)
450 if (socket_address_family(a
) == AF_UNIX
&& a
->sockaddr
.un
.sun_path
[0] != 0) {
454 mkdir_parents(a
->sockaddr
.un
.sun_path
, directory_mode
);
456 /* Enforce the right access mode for the socket*/
457 old_mask
= umask(~ socket_mode
);
459 /* Include the original umask in our mask */
460 umask(~socket_mode
| old_mask
);
462 r
= label_bind(fd
, &a
->sockaddr
.sa
, a
->size
);
464 if (r
< 0 && errno
== EADDRINUSE
) {
465 /* Unlink and try again */
466 unlink(a
->sockaddr
.un
.sun_path
);
467 r
= bind(fd
, &a
->sockaddr
.sa
, a
->size
);
472 r
= bind(fd
, &a
->sockaddr
.sa
, a
->size
);
477 if (socket_address_can_accept(a
))
478 if (listen(fd
, backlog
) < 0)
486 close_nointr_nofail(fd
);
490 bool socket_address_can_accept(const SocketAddress
*a
) {
494 a
->type
== SOCK_STREAM
||
495 a
->type
== SOCK_SEQPACKET
;
498 bool socket_address_equal(const SocketAddress
*a
, const SocketAddress
*b
) {
502 /* Invalid addresses are unequal to all */
503 if (socket_address_verify(a
) < 0 ||
504 socket_address_verify(b
) < 0)
507 if (a
->type
!= b
->type
)
510 if (a
->size
!= b
->size
)
513 if (socket_address_family(a
) != socket_address_family(b
))
516 switch (socket_address_family(a
)) {
519 if (a
->sockaddr
.in4
.sin_addr
.s_addr
!= b
->sockaddr
.in4
.sin_addr
.s_addr
)
522 if (a
->sockaddr
.in4
.sin_port
!= b
->sockaddr
.in4
.sin_port
)
528 if (memcmp(&a
->sockaddr
.in6
.sin6_addr
, &b
->sockaddr
.in6
.sin6_addr
, sizeof(a
->sockaddr
.in6
.sin6_addr
)) != 0)
531 if (a
->sockaddr
.in6
.sin6_port
!= b
->sockaddr
.in6
.sin6_port
)
538 if ((a
->sockaddr
.un
.sun_path
[0] == 0) != (b
->sockaddr
.un
.sun_path
[0] == 0))
541 if (a
->sockaddr
.un
.sun_path
[0]) {
542 if (strncmp(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
, sizeof(a
->sockaddr
.un
.sun_path
)) != 0)
545 if (memcmp(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
, a
->size
) != 0)
553 if (a
->protocol
!= b
->protocol
)
556 if (a
->sockaddr
.nl
.nl_groups
!= b
->sockaddr
.nl
.nl_groups
)
562 /* Cannot compare, so we assume the addresses are different */
569 bool socket_address_is(const SocketAddress
*a
, const char *s
, int type
) {
570 struct SocketAddress b
;
575 if (socket_address_parse(&b
, s
) < 0)
580 return socket_address_equal(a
, &b
);
583 bool socket_address_is_netlink(const SocketAddress
*a
, const char *s
) {
584 struct SocketAddress b
;
589 if (socket_address_parse_netlink(&b
, s
) < 0)
592 return socket_address_equal(a
, &b
);
595 bool socket_address_needs_mount(const SocketAddress
*a
, const char *prefix
) {
598 if (socket_address_family(a
) != AF_UNIX
)
601 if (a
->sockaddr
.un
.sun_path
[0] == 0)
604 return path_startswith(a
->sockaddr
.un
.sun_path
, prefix
);
607 bool socket_ipv6_is_supported(void) {
611 if (access("/sys/module/ipv6", F_OK
) != 0)
614 /* If we can't check "disable" parameter, assume enabled */
615 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l
) < 0)
618 /* If module was loaded with disable=1 no IPv6 available */
619 enabled
= l
[0] == '0';
625 static const char* const netlink_family_table
[] = {
626 [NETLINK_ROUTE
] = "route",
627 [NETLINK_FIREWALL
] = "firewall",
628 [NETLINK_INET_DIAG
] = "inet-diag",
629 [NETLINK_NFLOG
] = "nflog",
630 [NETLINK_XFRM
] = "xfrm",
631 [NETLINK_SELINUX
] = "selinux",
632 [NETLINK_ISCSI
] = "iscsi",
633 [NETLINK_AUDIT
] = "audit",
634 [NETLINK_FIB_LOOKUP
] = "fib-lookup",
635 [NETLINK_CONNECTOR
] = "connector",
636 [NETLINK_NETFILTER
] = "netfilter",
637 [NETLINK_IP6_FW
] = "ip6-fw",
638 [NETLINK_DNRTMSG
] = "dnrtmsg",
639 [NETLINK_KOBJECT_UEVENT
] = "kobject-uevent",
640 [NETLINK_GENERIC
] = "generic",
641 [NETLINK_SCSITRANSPORT
] = "scsitransport",
642 [NETLINK_ECRYPTFS
] = "ecryptfs"
645 DEFINE_STRING_TABLE_LOOKUP(netlink_family
, int);
647 static const char* const socket_address_bind_ipv6_only_table
[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX
] = {
648 [SOCKET_ADDRESS_DEFAULT
] = "default",
649 [SOCKET_ADDRESS_BOTH
] = "both",
650 [SOCKET_ADDRESS_IPV6_ONLY
] = "ipv6-only"
653 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only
, SocketAddressBindIPv6Only
);