1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
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>
35 #include "socket-util.h"
37 int socket_address_parse(SocketAddress
*a
, const char *s
) {
46 a
->type
= SOCK_STREAM
;
49 /* IPv6 in [x:.....:z]:p notation */
51 if (!(e
= strchr(s
+1, ']')))
54 if (!(n
= strndup(s
+1, e
-s
-1)))
58 if (inet_pton(AF_INET6
, n
, &a
->sockaddr
.in6
.sin6_addr
) <= 0) {
60 return errno
!= 0 ? -errno
: -EINVAL
;
70 if ((r
= safe_atou(e
, &u
)) < 0)
73 if (u
<= 0 || u
> 0xFFFF)
76 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
77 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
78 a
->size
= sizeof(struct sockaddr_in6
);
80 } else if (*s
== '/') {
86 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
))
89 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
90 memcpy(a
->sockaddr
.un
.sun_path
, s
, l
);
91 a
->size
= sizeof(sa_family_t
) + l
+ 1;
93 } else if (*s
== '@') {
94 /* Abstract AF_UNIX socket */
98 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
) - 1)
101 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
102 memcpy(a
->sockaddr
.un
.sun_path
+1, s
+1, l
);
103 a
->size
= sizeof(struct sockaddr_un
);
107 if ((e
= strchr(s
, ':'))) {
109 if ((r
= safe_atou(e
+1, &u
)) < 0)
112 if (u
<= 0 || u
> 0xFFFF)
115 if (!(n
= strndup(s
, e
-s
)))
118 /* IPv4 in w.x.y.z:p notation? */
119 if ((r
= inet_pton(AF_INET
, n
, &a
->sockaddr
.in4
.sin_addr
)) < 0) {
125 /* Gotcha, it's a traditional IPv4 address */
128 a
->sockaddr
.in4
.sin_family
= AF_INET
;
129 a
->sockaddr
.in4
.sin_port
= htons((uint16_t) u
);
130 a
->size
= sizeof(struct sockaddr_in
);
134 if (strlen(n
) > IF_NAMESIZE
-1) {
139 /* Uh, our last resort, an interface name */
140 idx
= if_nametoindex(n
);
146 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
147 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
148 a
->sockaddr
.in6
.sin6_scope_id
= idx
;
149 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
150 a
->size
= sizeof(struct sockaddr_in6
);
156 if ((r
= safe_atou(s
, &u
)) < 0)
159 if (u
<= 0 || u
> 0xFFFF)
162 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
163 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
164 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
165 a
->size
= sizeof(struct sockaddr_in6
);
172 int socket_address_verify(const SocketAddress
*a
) {
175 switch (socket_address_family(a
)) {
177 if (a
->size
!= sizeof(struct sockaddr_in
))
180 if (a
->sockaddr
.in4
.sin_port
== 0)
186 if (a
->size
!= sizeof(struct sockaddr_in6
))
189 if (a
->sockaddr
.in6
.sin6_port
== 0)
195 if (a
->size
< sizeof(sa_family_t
))
198 if (a
->size
> sizeof(sa_family_t
)) {
200 if (a
->sockaddr
.un
.sun_path
[0] == 0) {
202 if (a
->size
!= sizeof(struct sockaddr_un
))
208 if (!(e
= memchr(a
->sockaddr
.un
.sun_path
, 0, sizeof(a
->sockaddr
.un
.sun_path
))))
211 if (a
->size
!= sizeof(sa_family_t
) + (e
- a
->sockaddr
.un
.sun_path
) + 1)
219 return -EAFNOSUPPORT
;
223 int socket_address_print(const SocketAddress
*a
, char **p
) {
228 if ((r
= socket_address_verify(a
)) < 0)
231 switch (socket_address_family(a
)) {
235 if (!(ret
= new(char, INET_ADDRSTRLEN
+1+5+1)))
238 if (!inet_ntop(AF_INET
, &a
->sockaddr
.in4
.sin_addr
, ret
, INET_ADDRSTRLEN
)) {
243 sprintf(strchr(ret
, 0), ":%u", ntohs(a
->sockaddr
.in4
.sin_port
));
251 if (!(ret
= new(char, 1+INET6_ADDRSTRLEN
+2+5+1)))
255 if (!inet_ntop(AF_INET6
, &a
->sockaddr
.in6
.sin6_addr
, ret
+1, INET6_ADDRSTRLEN
)) {
260 sprintf(strchr(ret
, 0), "]:%u", ntohs(a
->sockaddr
.in6
.sin6_port
));
268 if (a
->size
<= sizeof(sa_family_t
)) {
270 if (!(ret
= strdup("<unamed>")))
273 } else if (a
->sockaddr
.un
.sun_path
[0] == 0) {
276 /* FIXME: We assume we can print the
277 * socket path here and that it hasn't
278 * more than one NUL byte. That is
279 * actually an invalid assumption */
281 if (!(ret
= new(char, sizeof(a
->sockaddr
.un
.sun_path
)+1)))
285 memcpy(ret
+1, a
->sockaddr
.un
.sun_path
+1, sizeof(a
->sockaddr
.un
.sun_path
)-1);
286 ret
[sizeof(a
->sockaddr
.un
.sun_path
)] = 0;
290 if (!(ret
= strdup(a
->sockaddr
.un
.sun_path
)))
303 int socket_address_listen(
304 const SocketAddress
*a
,
306 SocketAddressBindIPv6Only only
,
307 const char *bind_to_device
,
308 mode_t directory_mode
,
316 if ((r
= socket_address_verify(a
)) < 0)
319 if ((fd
= socket(socket_address_family(a
), a
->type
| SOCK_NONBLOCK
| SOCK_CLOEXEC
, 0)) < 0)
322 if (socket_address_family(a
) == AF_INET6
&& only
!= SOCKET_ADDRESS_DEFAULT
) {
323 int flag
= only
== SOCKET_ADDRESS_IPV6_ONLY
;
325 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &flag
, sizeof(flag
)) < 0)
330 if (setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
, bind_to_device
, strlen(bind_to_device
)+1) < 0)
334 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
)) < 0)
337 if (socket_address_family(a
) == AF_UNIX
&& a
->sockaddr
.un
.sun_path
[0] != 0) {
341 mkdir_parents(a
->sockaddr
.un
.sun_path
, directory_mode
);
343 /* Enforce the right access mode for the socket*/
344 old_mask
= umask(~ socket_mode
);
346 /* Include the original umask in our mask */
347 umask(~socket_mode
| old_mask
);
349 r
= bind(fd
, &a
->sockaddr
.sa
, a
->size
);
351 if (r
< 0 && errno
== EADDRINUSE
) {
352 /* Unlink and try again */
353 unlink(a
->sockaddr
.un
.sun_path
);
354 r
= bind(fd
, &a
->sockaddr
.sa
, a
->size
);
359 r
= bind(fd
, &a
->sockaddr
.sa
, a
->size
);
364 if (a
->type
== SOCK_STREAM
)
365 if (listen(fd
, backlog
) < 0)
373 close_nointr_nofail(fd
);
377 bool socket_address_can_accept(const SocketAddress
*a
) {
381 a
->type
== SOCK_STREAM
||
382 a
->type
== SOCK_SEQPACKET
;
385 bool socket_address_equal(const SocketAddress
*a
, const SocketAddress
*b
) {
389 /* Invalid addresses are unequal to all */
390 if (socket_address_verify(a
) < 0 ||
391 socket_address_verify(b
) < 0)
394 if (a
->type
!= b
->type
)
397 if (a
->size
!= b
->size
)
400 if (socket_address_family(a
) != socket_address_family(b
))
403 switch (socket_address_family(a
)) {
406 if (a
->sockaddr
.in4
.sin_addr
.s_addr
!= b
->sockaddr
.in4
.sin_addr
.s_addr
)
409 if (a
->sockaddr
.in4
.sin_port
!= b
->sockaddr
.in4
.sin_port
)
415 if (memcmp(&a
->sockaddr
.in6
.sin6_addr
, &b
->sockaddr
.in6
.sin6_addr
, sizeof(a
->sockaddr
.in6
.sin6_addr
)) != 0)
418 if (a
->sockaddr
.in6
.sin6_port
!= b
->sockaddr
.in6
.sin6_port
)
425 if ((a
->sockaddr
.un
.sun_path
[0] == 0) != (b
->sockaddr
.un
.sun_path
[0] == 0))
428 if (a
->sockaddr
.un
.sun_path
[0]) {
429 if (strncmp(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
, sizeof(a
->sockaddr
.un
.sun_path
)) != 0)
432 if (memcmp(a
->sockaddr
.un
.sun_path
, b
->sockaddr
.un
.sun_path
, sizeof(a
->sockaddr
.un
.sun_path
)) != 0)
439 /* Cannot compare, so we assume the addresses are different */
446 bool socket_address_is(const SocketAddress
*a
, const char *s
) {
447 struct SocketAddress b
;
452 if (socket_address_parse(&b
, s
) < 0)
455 return socket_address_equal(a
, &b
);