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>
33 #include "socket-util.h"
35 int socket_address_parse(SocketAddress
*a
, const char *s
) {
44 a
->type
= SOCK_STREAM
;
47 /* IPv6 in [x:.....:z]:p notation */
49 if (!(e
= strchr(s
+1, ']')))
52 if (!(n
= strndup(s
+1, e
-s
-1)))
56 if (inet_pton(AF_INET6
, n
, &a
->sockaddr
.in6
.sin6_addr
) <= 0) {
58 return errno
!= 0 ? -errno
: -EINVAL
;
68 if ((r
= safe_atou(e
, &u
)) < 0)
71 if (u
<= 0 || u
> 0xFFFF)
74 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
75 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
76 a
->size
= sizeof(struct sockaddr_in6
);
78 } else if (*s
== '/') {
84 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
))
87 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
88 memcpy(a
->sockaddr
.un
.sun_path
, s
, l
);
89 a
->size
= sizeof(sa_family_t
) + l
+ 1;
91 } else if (*s
== '@') {
92 /* Abstract AF_UNIX socket */
96 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
) - 1)
99 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
100 memcpy(a
->sockaddr
.un
.sun_path
+1, s
+1, l
);
101 a
->size
= sizeof(struct sockaddr_un
);
105 if ((e
= strchr(s
, ':'))) {
107 if ((r
= safe_atou(e
+1, &u
)) < 0)
110 if (u
<= 0 || u
> 0xFFFF)
113 if (!(n
= strndup(s
, e
-s
)))
116 /* IPv4 in w.x.y.z:p notation? */
117 if ((r
= inet_pton(AF_INET
, n
, &a
->sockaddr
.in4
.sin_addr
)) < 0) {
123 /* Gotcha, it's a traditional IPv4 address */
126 a
->sockaddr
.in4
.sin_family
= AF_INET
;
127 a
->sockaddr
.in4
.sin_port
= htons((uint16_t) u
);
128 a
->size
= sizeof(struct sockaddr_in
);
132 if (strlen(n
) > IF_NAMESIZE
-1) {
137 /* Uh, our last resort, an interface name */
138 idx
= if_nametoindex(n
);
144 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
145 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
146 a
->sockaddr
.in6
.sin6_scope_id
= idx
;
147 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
148 a
->size
= sizeof(struct sockaddr_in6
);
154 if ((r
= safe_atou(s
, &u
)) < 0)
157 if (u
<= 0 || u
> 0xFFFF)
160 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
161 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
162 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
163 a
->size
= sizeof(struct sockaddr_in6
);
170 int socket_address_verify(const SocketAddress
*a
) {
173 switch (socket_address_family(a
)) {
175 if (a
->size
!= sizeof(struct sockaddr_in
))
178 if (a
->sockaddr
.in4
.sin_port
== 0)
184 if (a
->size
!= sizeof(struct sockaddr_in6
))
187 if (a
->sockaddr
.in6
.sin6_port
== 0)
193 if (a
->size
< sizeof(sa_family_t
))
196 if (a
->size
> sizeof(sa_family_t
)) {
198 if (a
->sockaddr
.un
.sun_path
[0] == 0) {
200 if (a
->size
!= sizeof(struct sockaddr_un
))
206 if (!(e
= memchr(a
->sockaddr
.un
.sun_path
, 0, sizeof(a
->sockaddr
.un
.sun_path
))))
209 if (a
->size
!= sizeof(sa_family_t
) + (e
- a
->sockaddr
.un
.sun_path
) + 1)
217 return -EAFNOSUPPORT
;
221 int socket_address_print(const SocketAddress
*a
, char **p
) {
226 if ((r
= socket_address_verify(a
)) < 0)
229 switch (socket_address_family(a
)) {
233 if (!(ret
= new(char, INET_ADDRSTRLEN
+1+5+1)))
236 if (!inet_ntop(AF_INET
, &a
->sockaddr
.in4
.sin_addr
, ret
, INET_ADDRSTRLEN
)) {
241 sprintf(strchr(ret
, 0), ":%u", ntohs(a
->sockaddr
.in4
.sin_port
));
249 if (!(ret
= new(char, 1+INET6_ADDRSTRLEN
+2+5+1)))
253 if (!inet_ntop(AF_INET6
, &a
->sockaddr
.in6
.sin6_addr
, ret
+1, INET6_ADDRSTRLEN
)) {
258 sprintf(strchr(ret
, 0), "]:%u", ntohs(a
->sockaddr
.in6
.sin6_port
));
266 if (a
->size
<= sizeof(sa_family_t
)) {
268 if (!(ret
= strdup("<unamed>")))
271 } else if (a
->sockaddr
.un
.sun_path
[0] == 0) {
274 /* FIXME: We assume we can print the
275 * socket path here and that it hasn't
276 * more than one NUL byte. That is
277 * actually an invalid assumption */
279 if (!(ret
= new(char, sizeof(a
->sockaddr
.un
.sun_path
)+1)))
283 memcpy(ret
+1, a
->sockaddr
.un
.sun_path
+1, sizeof(a
->sockaddr
.un
.sun_path
)-1);
284 ret
[sizeof(a
->sockaddr
.un
.sun_path
)] = 0;
288 if (!(ret
= strdup(a
->sockaddr
.un
.sun_path
)))
301 int socket_address_listen(const SocketAddress
*a
, int backlog
, SocketAddressBindIPv6Only only
, const char *bind_to_device
, int *ret
) {
306 if ((r
= socket_address_verify(a
)) < 0)
309 if ((fd
= socket(socket_address_family(a
), a
->type
| SOCK_NONBLOCK
| SOCK_CLOEXEC
, 0)) < 0)
312 if (socket_address_family(a
) == AF_INET6
&& only
!= SOCKET_ADDRESS_DEFAULT
) {
313 int flag
= only
== SOCKET_ADDRESS_IPV6_ONLY
;
315 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &flag
, sizeof(flag
)) < 0)
320 if (setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
, bind_to_device
, strlen(bind_to_device
)+1) < 0)
324 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
)) < 0)
327 if (bind(fd
, &a
->sockaddr
.sa
, a
->size
) < 0)
330 if (a
->type
== SOCK_STREAM
)
331 if (listen(fd
, backlog
) < 0)