chiark / gitweb /
socket: support socket activation of containers
[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 Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 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   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser 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 "path-util.h"
39 #include "socket-util.h"
40 #include "missing.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                         r = safe_atou(s, &u);
171                         if (r < 0)
172                                 return r;
173
174                         if (u <= 0 || u > 0xFFFF)
175                                 return -EINVAL;
176
177                         if (socket_ipv6_is_supported()) {
178                                 a->sockaddr.in6.sin6_family = AF_INET6;
179                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
180                                 a->sockaddr.in6.sin6_addr = in6addr_any;
181                                 a->size = sizeof(struct sockaddr_in6);
182                         } else {
183                                 a->sockaddr.in4.sin_family = AF_INET;
184                                 a->sockaddr.in4.sin_port = htons((uint16_t) u);
185                                 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
186                                 a->size = sizeof(struct sockaddr_in);
187                         }
188                 }
189         }
190
191         return 0;
192 }
193
194 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
195         int family;
196         unsigned group = 0;
197         _cleanup_free_ char *sfamily = NULL;
198         assert(a);
199         assert(s);
200
201         zero(*a);
202         a->type = SOCK_RAW;
203
204         errno = 0;
205         if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
206                 return errno ? -errno : -EINVAL;
207
208         family = netlink_family_from_string(sfamily);
209         if (family < 0)
210                 return -EINVAL;
211
212         a->sockaddr.nl.nl_family = AF_NETLINK;
213         a->sockaddr.nl.nl_groups = group;
214
215         a->type = SOCK_RAW;
216         a->size = sizeof(struct sockaddr_nl);
217         a->protocol = family;
218
219         return 0;
220 }
221
222 int socket_address_verify(const SocketAddress *a) {
223         assert(a);
224
225         switch (socket_address_family(a)) {
226
227         case AF_INET:
228                 if (a->size != sizeof(struct sockaddr_in))
229                         return -EINVAL;
230
231                 if (a->sockaddr.in4.sin_port == 0)
232                         return -EINVAL;
233
234                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
235                         return -EINVAL;
236
237                 return 0;
238
239         case AF_INET6:
240                 if (a->size != sizeof(struct sockaddr_in6))
241                         return -EINVAL;
242
243                 if (a->sockaddr.in6.sin6_port == 0)
244                         return -EINVAL;
245
246                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
247                         return -EINVAL;
248
249                 return 0;
250
251         case AF_UNIX:
252                 if (a->size < offsetof(struct sockaddr_un, sun_path))
253                         return -EINVAL;
254
255                 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
256
257                         if (a->sockaddr.un.sun_path[0] != 0) {
258                                 char *e;
259
260                                 /* path */
261                                 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
262                                         return -EINVAL;
263
264                                 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
265                                         return -EINVAL;
266                         }
267                 }
268
269                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
270                         return -EINVAL;
271
272                 return 0;
273
274         case AF_NETLINK:
275
276                 if (a->size != sizeof(struct sockaddr_nl))
277                         return -EINVAL;
278
279                 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
280                         return -EINVAL;
281
282                 return 0;
283
284         default:
285                 return -EAFNOSUPPORT;
286         }
287 }
288
289 int socket_address_print(const SocketAddress *a, char **p) {
290         int r;
291         assert(a);
292         assert(p);
293
294         if ((r = socket_address_verify(a)) < 0)
295                 return r;
296
297         switch (socket_address_family(a)) {
298
299         case AF_INET: {
300                 char *ret;
301
302                 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
303                         return -ENOMEM;
304
305                 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
306                         free(ret);
307                         return -errno;
308                 }
309
310                 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
311                 *p = ret;
312                 return 0;
313         }
314
315         case AF_INET6: {
316                 char *ret;
317
318                 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
319                         return -ENOMEM;
320
321                 ret[0] = '[';
322                 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
323                         free(ret);
324                         return -errno;
325                 }
326
327                 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
328                 *p = ret;
329                 return 0;
330         }
331
332         case AF_UNIX: {
333                 char *ret;
334
335                 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
336
337                         if (!(ret = strdup("<unnamed>")))
338                                 return -ENOMEM;
339
340                 } else if (a->sockaddr.un.sun_path[0] == 0) {
341                         /* abstract */
342
343                         /* FIXME: We assume we can print the
344                          * socket path here and that it hasn't
345                          * more than one NUL byte. That is
346                          * actually an invalid assumption */
347
348                         if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
349                                 return -ENOMEM;
350
351                         ret[0] = '@';
352                         memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
353                         ret[sizeof(a->sockaddr.un.sun_path)] = 0;
354
355                 } else {
356
357                         if (!(ret = strdup(a->sockaddr.un.sun_path)))
358                                 return -ENOMEM;
359                 }
360
361                 *p = ret;
362                 return 0;
363         }
364
365         case AF_NETLINK: {
366                 char _cleanup_free_ *sfamily = NULL;
367
368                 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
369                 if (r < 0)
370                         return r;
371                 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
372                 if (r < 0)
373                         return -ENOMEM;
374
375                 return 0;
376         }
377
378         default:
379                 return -EINVAL;
380         }
381 }
382
383 bool socket_address_can_accept(const SocketAddress *a) {
384         assert(a);
385
386         return
387                 a->type == SOCK_STREAM ||
388                 a->type == SOCK_SEQPACKET;
389 }
390
391 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
392         assert(a);
393         assert(b);
394
395         /* Invalid addresses are unequal to all */
396         if (socket_address_verify(a) < 0 ||
397             socket_address_verify(b) < 0)
398                 return false;
399
400         if (a->type != b->type)
401                 return false;
402
403         if (a->size != b->size)
404                 return false;
405
406         if (socket_address_family(a) != socket_address_family(b))
407                 return false;
408
409         switch (socket_address_family(a)) {
410
411         case AF_INET:
412                 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
413                         return false;
414
415                 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
416                         return false;
417
418                 break;
419
420         case AF_INET6:
421                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
422                         return false;
423
424                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
425                         return false;
426
427                 break;
428
429         case AF_UNIX:
430
431                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
432                         return false;
433
434                 if (a->sockaddr.un.sun_path[0]) {
435                         if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
436                                 return false;
437                 } else {
438                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
439                                 return false;
440                 }
441
442                 break;
443
444         case AF_NETLINK:
445
446                 if (a->protocol != b->protocol)
447                         return false;
448
449                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
450                         return false;
451
452                 break;
453
454         default:
455                 /* Cannot compare, so we assume the addresses are different */
456                 return false;
457         }
458
459         return true;
460 }
461
462 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
463         struct SocketAddress b;
464
465         assert(a);
466         assert(s);
467
468         if (socket_address_parse(&b, s) < 0)
469                 return false;
470
471         b.type = type;
472
473         return socket_address_equal(a, &b);
474 }
475
476 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
477         struct SocketAddress b;
478
479         assert(a);
480         assert(s);
481
482         if (socket_address_parse_netlink(&b, s) < 0)
483                 return false;
484
485         return socket_address_equal(a, &b);
486 }
487
488 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
489         assert(a);
490
491         if (socket_address_family(a) != AF_UNIX)
492                 return false;
493
494         if (a->sockaddr.un.sun_path[0] == 0)
495                 return false;
496
497         return path_startswith(a->sockaddr.un.sun_path, prefix);
498 }
499
500 bool socket_ipv6_is_supported(void) {
501         char *l = 0;
502         bool enabled;
503
504         if (access("/sys/module/ipv6", F_OK) != 0)
505                 return 0;
506
507         /* If we can't check "disable" parameter, assume enabled */
508         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
509                 return 1;
510
511         /* If module was loaded with disable=1 no IPv6 available */
512         enabled = l[0] == '0';
513         free(l);
514
515         return enabled;
516 }
517
518 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
519         union sockaddr_union sa;
520         socklen_t salen = sizeof(sa), solen;
521         int protocol, type;
522
523         assert(a);
524         assert(fd >= 0);
525
526         if (getsockname(fd, &sa.sa, &salen) < 0)
527                 return false;
528
529         if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
530                 return false;
531
532         solen = sizeof(type);
533         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
534                 return false;
535
536         if (type != a->type)
537                 return false;
538
539         if (a->protocol != 0)  {
540                 solen = sizeof(protocol);
541                 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
542                         return false;
543
544                 if (protocol != a->protocol)
545                         return false;
546         }
547
548         switch (sa.sa.sa_family) {
549
550         case AF_INET:
551                 return sa.in4.sin_port == a->sockaddr.in4.sin_port &&
552                         sa.in4.sin_addr.s_addr == a->sockaddr.in4.sin_addr.s_addr;
553
554         case AF_INET6:
555                 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
556                         memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
557
558         case AF_UNIX:
559                 return salen == a->size &&
560                         memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
561
562         }
563
564         return false;
565 }
566
567 static const char* const netlink_family_table[] = {
568         [NETLINK_ROUTE] = "route",
569         [NETLINK_FIREWALL] = "firewall",
570         [NETLINK_INET_DIAG] = "inet-diag",
571         [NETLINK_NFLOG] = "nflog",
572         [NETLINK_XFRM] = "xfrm",
573         [NETLINK_SELINUX] = "selinux",
574         [NETLINK_ISCSI] = "iscsi",
575         [NETLINK_AUDIT] = "audit",
576         [NETLINK_FIB_LOOKUP] = "fib-lookup",
577         [NETLINK_CONNECTOR] = "connector",
578         [NETLINK_NETFILTER] = "netfilter",
579         [NETLINK_IP6_FW] = "ip6-fw",
580         [NETLINK_DNRTMSG] = "dnrtmsg",
581         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
582         [NETLINK_GENERIC] = "generic",
583         [NETLINK_SCSITRANSPORT] = "scsitransport",
584         [NETLINK_ECRYPTFS] = "ecryptfs"
585 };
586
587 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
588
589 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
590         [SOCKET_ADDRESS_DEFAULT] = "default",
591         [SOCKET_ADDRESS_BOTH] = "both",
592         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
593 };
594
595 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);