chiark / gitweb /
554f8ac965a705e5ddfd887fa53b4565eaea4b10
[elogind.git] / src / shared / 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 #include <stddef.h>
33 #include <sys/ioctl.h>
34
35 #include "macro.h"
36 #include "util.h"
37 #include "mkdir.h"
38 #include "socket-util.h"
39 #include "missing.h"
40 #include "label.h"
41
42 int socket_address_parse(SocketAddress *a, const char *s) {
43         int r;
44         char *e, *n;
45         unsigned u;
46
47         assert(a);
48         assert(s);
49
50         zero(*a);
51         a->type = SOCK_STREAM;
52
53         if (*s == '[') {
54                 /* IPv6 in [x:.....:z]:p notation */
55
56                 if (!socket_ipv6_is_supported()) {
57                         log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
58                         return -EAFNOSUPPORT;
59                 }
60
61                 if (!(e = strchr(s+1, ']')))
62                         return -EINVAL;
63
64                 if (!(n = strndup(s+1, e-s-1)))
65                         return -ENOMEM;
66
67                 errno = 0;
68                 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
69                         free(n);
70                         return errno != 0 ? -errno : -EINVAL;
71                 }
72
73                 free(n);
74
75                 e++;
76                 if (*e != ':')
77                         return -EINVAL;
78
79                 e++;
80                 if ((r = safe_atou(e, &u)) < 0)
81                         return r;
82
83                 if (u <= 0 || u > 0xFFFF)
84                         return -EINVAL;
85
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);
89
90         } else if (*s == '/') {
91                 /* AF_UNIX socket */
92
93                 size_t l;
94
95                 l = strlen(s);
96                 if (l >= sizeof(a->sockaddr.un.sun_path))
97                         return -EINVAL;
98
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;
102
103         } else if (*s == '@') {
104                 /* Abstract AF_UNIX socket */
105                 size_t l;
106
107                 l = strlen(s+1);
108                 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
109                         return -EINVAL;
110
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;
114
115         } else {
116
117                 if ((e = strchr(s, ':'))) {
118
119                         if ((r = safe_atou(e+1, &u)) < 0)
120                                 return r;
121
122                         if (u <= 0 || u > 0xFFFF)
123                                 return -EINVAL;
124
125                         if (!(n = strndup(s, e-s)))
126                                 return -ENOMEM;
127
128                         /* IPv4 in w.x.y.z:p notation? */
129                         if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
130                                 free(n);
131                                 return -errno;
132                         }
133
134                         if (r > 0) {
135                                 /* Gotcha, it's a traditional IPv4 address */
136                                 free(n);
137
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);
141                         } else {
142                                 unsigned idx;
143
144                                 if (strlen(n) > IF_NAMESIZE-1) {
145                                         free(n);
146                                         return -EINVAL;
147                                 }
148
149                                 /* Uh, our last resort, an interface name */
150                                 idx = if_nametoindex(n);
151                                 free(n);
152
153                                 if (idx == 0)
154                                         return -EINVAL;
155
156                                 if (!socket_ipv6_is_supported()) {
157                                         log_warning("Binding to interface is not available since kernel does not support IPv6.");
158                                         return -EAFNOSUPPORT;
159                                 }
160
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);
166                         }
167                 } else {
168
169                         /* Just a port */
170                         if ((r = safe_atou(s, &u)) < 0)
171                                 return r;
172
173                         if (u <= 0 || u > 0xFFFF)
174                                 return -EINVAL;
175
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);
181                         } else {
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);
186                         }
187                 }
188         }
189
190         return 0;
191 }
192
193 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
194         int family;
195         unsigned group = 0;
196         char* sfamily = NULL;
197         assert(a);
198         assert(s);
199
200         zero(*a);
201         a->type = SOCK_RAW;
202
203         errno = 0;
204         if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
205                 return errno ? -errno : -EINVAL;
206
207         if ((family = netlink_family_from_string(sfamily)) < 0)
208                 if (safe_atoi(sfamily, &family) < 0) {
209                         free(sfamily);
210                         return -EINVAL;
211                 }
212
213         free(sfamily);
214
215         a->sockaddr.nl.nl_family = AF_NETLINK;
216         a->sockaddr.nl.nl_groups = group;
217
218         a->type = SOCK_RAW;
219         a->size = sizeof(struct sockaddr_nl);
220         a->protocol = family;
221
222         return 0;
223 }
224
225 int socket_address_verify(const SocketAddress *a) {
226         assert(a);
227
228         switch (socket_address_family(a)) {
229
230         case AF_INET:
231                 if (a->size != sizeof(struct sockaddr_in))
232                         return -EINVAL;
233
234                 if (a->sockaddr.in4.sin_port == 0)
235                         return -EINVAL;
236
237                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
238                         return -EINVAL;
239
240                 return 0;
241
242         case AF_INET6:
243                 if (a->size != sizeof(struct sockaddr_in6))
244                         return -EINVAL;
245
246                 if (a->sockaddr.in6.sin6_port == 0)
247                         return -EINVAL;
248
249                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
250                         return -EINVAL;
251
252                 return 0;
253
254         case AF_UNIX:
255                 if (a->size < offsetof(struct sockaddr_un, sun_path))
256                         return -EINVAL;
257
258                 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
259
260                         if (a->sockaddr.un.sun_path[0] != 0) {
261                                 char *e;
262
263                                 /* path */
264                                 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
265                                         return -EINVAL;
266
267                                 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
268                                         return -EINVAL;
269                         }
270                 }
271
272                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
273                         return -EINVAL;
274
275                 return 0;
276
277         case AF_NETLINK:
278
279                 if (a->size != sizeof(struct sockaddr_nl))
280                         return -EINVAL;
281
282                 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
283                         return -EINVAL;
284
285                 return 0;
286
287         default:
288                 return -EAFNOSUPPORT;
289         }
290 }
291
292 int socket_address_print(const SocketAddress *a, char **p) {
293         int r;
294         assert(a);
295         assert(p);
296
297         if ((r = socket_address_verify(a)) < 0)
298                 return r;
299
300         switch (socket_address_family(a)) {
301
302         case AF_INET: {
303                 char *ret;
304
305                 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
306                         return -ENOMEM;
307
308                 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
309                         free(ret);
310                         return -errno;
311                 }
312
313                 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
314                 *p = ret;
315                 return 0;
316         }
317
318         case AF_INET6: {
319                 char *ret;
320
321                 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
322                         return -ENOMEM;
323
324                 ret[0] = '[';
325                 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
326                         free(ret);
327                         return -errno;
328                 }
329
330                 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
331                 *p = ret;
332                 return 0;
333         }
334
335         case AF_UNIX: {
336                 char *ret;
337
338                 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
339
340                         if (!(ret = strdup("<unnamed>")))
341                                 return -ENOMEM;
342
343                 } else if (a->sockaddr.un.sun_path[0] == 0) {
344                         /* abstract */
345
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 */
350
351                         if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
352                                 return -ENOMEM;
353
354                         ret[0] = '@';
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;
357
358                 } else {
359
360                         if (!(ret = strdup(a->sockaddr.un.sun_path)))
361                                 return -ENOMEM;
362                 }
363
364                 *p = ret;
365                 return 0;
366         }
367
368         case AF_NETLINK: {
369                 const char *sfamily;
370
371                 if ((sfamily = netlink_family_to_string(a->protocol)))
372                         r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
373                 else
374                         r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups);
375
376                 if (r < 0)
377                         return -ENOMEM;
378
379                 return 0;
380         }
381
382         default:
383                 return -EINVAL;
384         }
385 }
386
387 int socket_address_listen(
388                 const SocketAddress *a,
389                 int backlog,
390                 SocketAddressBindIPv6Only only,
391                 const char *bind_to_device,
392                 bool free_bind,
393                 bool transparent,
394                 mode_t directory_mode,
395                 mode_t socket_mode,
396                 const char *label,
397                 int *ret) {
398
399         int r, fd, one;
400         assert(a);
401         assert(ret);
402
403         if ((r = socket_address_verify(a)) < 0)
404                 return r;
405
406         if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
407                 return -EAFNOSUPPORT;
408
409         r = label_socket_set(label);
410         if (r < 0)
411                 return r;
412
413         fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, a->protocol);
414         r = fd < 0 ? -errno : 0;
415
416         label_socket_clear();
417
418         if (r < 0)
419                 return r;
420
421         if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
422                 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
423
424                 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
425                         goto fail;
426         }
427
428         if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
429                 if (bind_to_device)
430                         if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
431                                 goto fail;
432
433                 if (free_bind) {
434                         one = 1;
435                         if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
436                                 log_warning("IP_FREEBIND failed: %m");
437                 }
438
439                 if (transparent) {
440                         one = 1;
441                         if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
442                                 log_warning("IP_TRANSPARENT failed: %m");
443                 }
444         }
445
446         one = 1;
447         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
448                 goto fail;
449
450         if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
451                 mode_t old_mask;
452
453                 /* Create parents */
454                 mkdir_parents(a->sockaddr.un.sun_path, directory_mode);
455
456                 /* Enforce the right access mode for the socket*/
457                 old_mask = umask(~ socket_mode);
458
459                 /* Include the original umask in our mask */
460                 umask(~socket_mode | old_mask);
461
462                 r = label_bind(fd, &a->sockaddr.sa, a->size);
463
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);
468                 }
469
470                 umask(old_mask);
471         } else
472                 r = bind(fd, &a->sockaddr.sa, a->size);
473
474         if (r < 0)
475                 goto fail;
476
477         if (socket_address_can_accept(a))
478                 if (listen(fd, backlog) < 0)
479                         goto fail;
480
481         *ret = fd;
482         return 0;
483
484 fail:
485         r = -errno;
486         close_nointr_nofail(fd);
487         return r;
488 }
489
490 bool socket_address_can_accept(const SocketAddress *a) {
491         assert(a);
492
493         return
494                 a->type == SOCK_STREAM ||
495                 a->type == SOCK_SEQPACKET;
496 }
497
498 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
499         assert(a);
500         assert(b);
501
502         /* Invalid addresses are unequal to all */
503         if (socket_address_verify(a) < 0 ||
504             socket_address_verify(b) < 0)
505                 return false;
506
507         if (a->type != b->type)
508                 return false;
509
510         if (a->size != b->size)
511                 return false;
512
513         if (socket_address_family(a) != socket_address_family(b))
514                 return false;
515
516         switch (socket_address_family(a)) {
517
518         case AF_INET:
519                 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
520                         return false;
521
522                 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
523                         return false;
524
525                 break;
526
527         case AF_INET6:
528                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
529                         return false;
530
531                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
532                         return false;
533
534                 break;
535
536         case AF_UNIX:
537
538                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
539                         return false;
540
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)
543                                 return false;
544                 } else {
545                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
546                                 return false;
547                 }
548
549                 break;
550
551         case AF_NETLINK:
552
553                 if (a->protocol != b->protocol)
554                         return false;
555
556                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
557                         return false;
558
559                 break;
560
561         default:
562                 /* Cannot compare, so we assume the addresses are different */
563                 return false;
564         }
565
566         return true;
567 }
568
569 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
570         struct SocketAddress b;
571
572         assert(a);
573         assert(s);
574
575         if (socket_address_parse(&b, s) < 0)
576                 return false;
577
578         b.type = type;
579
580         return socket_address_equal(a, &b);
581 }
582
583 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
584         struct SocketAddress b;
585
586         assert(a);
587         assert(s);
588
589         if (socket_address_parse_netlink(&b, s) < 0)
590                 return false;
591
592         return socket_address_equal(a, &b);
593 }
594
595 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
596         assert(a);
597
598         if (socket_address_family(a) != AF_UNIX)
599                 return false;
600
601         if (a->sockaddr.un.sun_path[0] == 0)
602                 return false;
603
604         return path_startswith(a->sockaddr.un.sun_path, prefix);
605 }
606
607 bool socket_ipv6_is_supported(void) {
608         char *l = 0;
609         bool enabled;
610
611         if (access("/sys/module/ipv6", F_OK) != 0)
612                 return 0;
613
614         /* If we can't check "disable" parameter, assume enabled */
615         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
616                 return 1;
617
618         /* If module was loaded with disable=1 no IPv6 available */
619         enabled = l[0] == '0';
620         free(l);
621
622         return enabled;
623 }
624
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"
643 };
644
645 DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
646
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"
651 };
652
653 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);