chiark / gitweb /
manager: measure startup times
[elogind.git] / src / socket-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <assert.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <arpa/inet.h>
28 #include <stdio.h>
29 #include <net/if.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32
33 #include "macro.h"
34 #include "util.h"
35 #include "socket-util.h"
36 #include "missing.h"
37 #include "label.h"
38 #include <sys/ioctl.h>
39
40 int socket_address_parse(SocketAddress *a, const char *s) {
41         int r;
42         char *e, *n;
43         unsigned u;
44
45         assert(a);
46         assert(s);
47
48         zero(*a);
49         a->type = SOCK_STREAM;
50
51         if (*s == '[') {
52                 /* IPv6 in [x:.....:z]:p notation */
53
54                 if (!socket_ipv6_is_supported()) {
55                         log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
56                         return -EAFNOSUPPORT;
57                 }
58
59                 if (!(e = strchr(s+1, ']')))
60                         return -EINVAL;
61
62                 if (!(n = strndup(s+1, e-s-1)))
63                         return -ENOMEM;
64
65                 errno = 0;
66                 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
67                         free(n);
68                         return errno != 0 ? -errno : -EINVAL;
69                 }
70
71                 free(n);
72
73                 e++;
74                 if (*e != ':')
75                         return -EINVAL;
76
77                 e++;
78                 if ((r = safe_atou(e, &u)) < 0)
79                         return r;
80
81                 if (u <= 0 || u > 0xFFFF)
82                         return -EINVAL;
83
84                 a->sockaddr.in6.sin6_family = AF_INET6;
85                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
86                 a->size = sizeof(struct sockaddr_in6);
87
88         } else if (*s == '/') {
89                 /* AF_UNIX socket */
90
91                 size_t l;
92
93                 l = strlen(s);
94                 if (l >= sizeof(a->sockaddr.un.sun_path))
95                         return -EINVAL;
96
97                 a->sockaddr.un.sun_family = AF_UNIX;
98                 memcpy(a->sockaddr.un.sun_path, s, l);
99                 a->size = sizeof(sa_family_t) + l + 1;
100
101         } else if (*s == '@') {
102                 /* Abstract AF_UNIX socket */
103                 size_t l;
104
105                 l = strlen(s+1);
106                 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
107                         return -EINVAL;
108
109                 a->sockaddr.un.sun_family = AF_UNIX;
110                 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
111                 a->size = sizeof(sa_family_t) + 1 + l;
112
113         } else {
114
115                 if ((e = strchr(s, ':'))) {
116
117                         if ((r = safe_atou(e+1, &u)) < 0)
118                                 return r;
119
120                         if (u <= 0 || u > 0xFFFF)
121                                 return -EINVAL;
122
123                         if (!(n = strndup(s, e-s)))
124                                 return -ENOMEM;
125
126                         /* IPv4 in w.x.y.z:p notation? */
127                         if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
128                                 free(n);
129                                 return -errno;
130                         }
131
132                         if (r > 0) {
133                                 /* Gotcha, it's a traditional IPv4 address */
134                                 free(n);
135
136                                 a->sockaddr.in4.sin_family = AF_INET;
137                                 a->sockaddr.in4.sin_port = htons((uint16_t) u);
138                                 a->size = sizeof(struct sockaddr_in);
139                         } else {
140                                 unsigned idx;
141
142                                 if (strlen(n) > IF_NAMESIZE-1) {
143                                         free(n);
144                                         return -EINVAL;
145                                 }
146
147                                 /* Uh, our last resort, an interface name */
148                                 idx = if_nametoindex(n);
149                                 free(n);
150
151                                 if (idx == 0)
152                                         return -EINVAL;
153
154                                 if (!socket_ipv6_is_supported()) {
155                                         log_warning("Binding to interface is not available since kernel does not support IPv6.");
156                                         return -EAFNOSUPPORT;
157                                 }
158
159                                 a->sockaddr.in6.sin6_family = AF_INET6;
160                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
161                                 a->sockaddr.in6.sin6_scope_id = idx;
162                                 a->sockaddr.in6.sin6_addr = in6addr_any;
163                                 a->size = sizeof(struct sockaddr_in6);
164                         }
165                 } else {
166
167                         /* Just a port */
168                         if ((r = safe_atou(s, &u)) < 0)
169                                 return r;
170
171                         if (u <= 0 || u > 0xFFFF)
172                                 return -EINVAL;
173
174                         if (socket_ipv6_is_supported()) {
175                                 a->sockaddr.in6.sin6_family = AF_INET6;
176                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
177                                 a->sockaddr.in6.sin6_addr = in6addr_any;
178                                 a->size = sizeof(struct sockaddr_in6);
179                         } else {
180                                 a->sockaddr.in4.sin_family = AF_INET;
181                                 a->sockaddr.in4.sin_port = htons((uint16_t) u);
182                                 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
183                                 a->size = sizeof(struct sockaddr_in);
184                         }
185                 }
186         }
187
188         return 0;
189 }
190
191 int socket_address_verify(const SocketAddress *a) {
192         assert(a);
193
194         switch (socket_address_family(a)) {
195                 case AF_INET:
196                         if (a->size != sizeof(struct sockaddr_in))
197                                 return -EINVAL;
198
199                         if (a->sockaddr.in4.sin_port == 0)
200                                 return -EINVAL;
201
202                         return 0;
203
204                 case AF_INET6:
205                         if (a->size != sizeof(struct sockaddr_in6))
206                                 return -EINVAL;
207
208                         if (a->sockaddr.in6.sin6_port == 0)
209                                 return -EINVAL;
210
211                         return 0;
212
213                 case AF_UNIX:
214                         if (a->size < sizeof(sa_family_t))
215                                 return -EINVAL;
216
217                         if (a->size > sizeof(sa_family_t)) {
218
219                                 if (a->sockaddr.un.sun_path[0] != 0) {
220                                         char *e;
221
222                                         /* path */
223                                         if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
224                                                 return -EINVAL;
225
226                                         if (a->size != sizeof(sa_family_t) + (e - a->sockaddr.un.sun_path) + 1)
227                                                 return -EINVAL;
228                                 }
229                         }
230
231                         return 0;
232
233                 default:
234                         return -EAFNOSUPPORT;
235         }
236 }
237
238 int socket_address_print(const SocketAddress *a, char **p) {
239         int r;
240         assert(a);
241         assert(p);
242
243         if ((r = socket_address_verify(a)) < 0)
244                 return r;
245
246         switch (socket_address_family(a)) {
247                 case AF_INET: {
248                         char *ret;
249
250                         if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
251                                 return -ENOMEM;
252
253                         if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
254                                 free(ret);
255                                 return -errno;
256                         }
257
258                         sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
259                         *p = ret;
260                         return 0;
261                 }
262
263                 case AF_INET6: {
264                         char *ret;
265
266                         if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
267                                 return -ENOMEM;
268
269                         ret[0] = '[';
270                         if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
271                                 free(ret);
272                                 return -errno;
273                         }
274
275                         sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
276                         *p = ret;
277                         return 0;
278                 }
279
280                 case AF_UNIX: {
281                         char *ret;
282
283                         if (a->size <= sizeof(sa_family_t)) {
284
285                                 if (!(ret = strdup("<unamed>")))
286                                         return -ENOMEM;
287
288                         } else if (a->sockaddr.un.sun_path[0] == 0) {
289                                 /* abstract */
290
291                                 /* FIXME: We assume we can print the
292                                  * socket path here and that it hasn't
293                                  * more than one NUL byte. That is
294                                  * actually an invalid assumption */
295
296                                 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
297                                         return -ENOMEM;
298
299                                 ret[0] = '@';
300                                 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
301                                 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
302
303                         } else {
304
305                                 if (!(ret = strdup(a->sockaddr.un.sun_path)))
306                                         return -ENOMEM;
307                         }
308
309                         *p = ret;
310                         return 0;
311                 }
312
313                 default:
314                         return -EINVAL;
315         }
316 }
317
318 int socket_address_listen(
319                 const SocketAddress *a,
320                 int backlog,
321                 SocketAddressBindIPv6Only only,
322                 const char *bind_to_device,
323                 bool free_bind,
324                 mode_t directory_mode,
325                 mode_t socket_mode,
326                 const char *label,
327                 int *ret) {
328
329         int r, fd, one;
330         assert(a);
331         assert(ret);
332
333         if ((r = socket_address_verify(a)) < 0)
334                 return r;
335
336         if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
337                 return -EAFNOSUPPORT;
338
339         r = label_socket_set(label);
340         if (r < 0)
341                 return r;
342
343         fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
344         r = fd < 0 ? -errno : 0;
345
346         label_socket_clear();
347
348         if (r < 0)
349                 return r;
350
351         if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
352                 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
353
354                 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
355                         goto fail;
356         }
357
358         if (bind_to_device)
359                 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
360                         goto fail;
361
362         if (free_bind) {
363                 one = 1;
364                 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
365                         log_warning("IP_FREEBIND failed: %m");
366         }
367
368         one = 1;
369         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
370                 goto fail;
371
372         if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
373                 mode_t old_mask;
374
375                 /* Create parents */
376                 mkdir_parents(a->sockaddr.un.sun_path, directory_mode);
377
378                 /* Enforce the right access mode for the socket*/
379                 old_mask = umask(~ socket_mode);
380
381                 /* Include the original umask in our mask */
382                 umask(~socket_mode | old_mask);
383
384                 r = bind(fd, &a->sockaddr.sa, a->size);
385
386                 if (r < 0 && errno == EADDRINUSE) {
387                         /* Unlink and try again */
388                         unlink(a->sockaddr.un.sun_path);
389                         r = bind(fd, &a->sockaddr.sa, a->size);
390                 }
391
392                 umask(old_mask);
393         } else
394                 r = bind(fd, &a->sockaddr.sa, a->size);
395
396         if (r < 0)
397                 goto fail;
398
399         if (a->type == SOCK_STREAM)
400                 if (listen(fd, backlog) < 0)
401                         goto fail;
402
403         *ret = fd;
404         return 0;
405
406 fail:
407         r = -errno;
408         close_nointr_nofail(fd);
409         return r;
410 }
411
412 bool socket_address_can_accept(const SocketAddress *a) {
413         assert(a);
414
415         return
416                 a->type == SOCK_STREAM ||
417                 a->type == SOCK_SEQPACKET;
418 }
419
420 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
421         assert(a);
422         assert(b);
423
424         /* Invalid addresses are unequal to all */
425         if (socket_address_verify(a) < 0 ||
426             socket_address_verify(b) < 0)
427                 return false;
428
429         if (a->type != b->type)
430                 return false;
431
432         if (a->size != b->size)
433                 return false;
434
435         if (socket_address_family(a) != socket_address_family(b))
436                 return false;
437
438         switch (socket_address_family(a)) {
439
440         case AF_INET:
441                 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
442                         return false;
443
444                 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
445                         return false;
446
447                 break;
448
449         case AF_INET6:
450                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
451                         return false;
452
453                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
454                         return false;
455
456                 break;
457
458         case AF_UNIX:
459
460                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
461                         return false;
462
463                 if (a->sockaddr.un.sun_path[0]) {
464                         if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
465                                 return false;
466                 } else {
467                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
468                                 return false;
469                 }
470
471                 break;
472
473         default:
474                 /* Cannot compare, so we assume the addresses are different */
475                 return false;
476         }
477
478         return true;
479 }
480
481 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
482         struct SocketAddress b;
483
484         assert(a);
485         assert(s);
486
487         if (socket_address_parse(&b, s) < 0)
488                 return false;
489
490         b.type = type;
491
492         return socket_address_equal(a, &b);
493 }
494
495 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
496         assert(a);
497
498         if (socket_address_family(a) != AF_UNIX)
499                 return false;
500
501         if (a->sockaddr.un.sun_path[0] == 0)
502                 return false;
503
504         return path_startswith(a->sockaddr.un.sun_path, prefix);
505 }
506
507 bool socket_ipv6_is_supported(void) {
508         return access("/sys/module/ipv6", F_OK) == 0;
509 }
510
511 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
512         [SOCKET_ADDRESS_DEFAULT] = "default",
513         [SOCKET_ADDRESS_BOTH] = "both",
514         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
515 };
516
517 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);