]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/shared/socket-util.c
event: make sure we keep a reference to all events we dispatch while we do so.
[thirdparty/systemd.git] / src / shared / socket-util.c
... / ...
CommitLineData
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#include "fileio.h"
42
43int socket_address_parse(SocketAddress *a, const char *s) {
44 int r;
45 char *e, *n;
46 unsigned u;
47
48 assert(a);
49 assert(s);
50
51 zero(*a);
52 a->type = SOCK_STREAM;
53
54 if (*s == '[') {
55 /* IPv6 in [x:.....:z]:p notation */
56
57 if (!socket_ipv6_is_supported()) {
58 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
59 return -EAFNOSUPPORT;
60 }
61
62 if (!(e = strchr(s+1, ']')))
63 return -EINVAL;
64
65 if (!(n = strndup(s+1, e-s-1)))
66 return -ENOMEM;
67
68 errno = 0;
69 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
70 free(n);
71 return errno > 0 ? -errno : -EINVAL;
72 }
73
74 free(n);
75
76 e++;
77 if (*e != ':')
78 return -EINVAL;
79
80 e++;
81 if ((r = safe_atou(e, &u)) < 0)
82 return r;
83
84 if (u <= 0 || u > 0xFFFF)
85 return -EINVAL;
86
87 a->sockaddr.in6.sin6_family = AF_INET6;
88 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
89 a->size = sizeof(struct sockaddr_in6);
90
91 } else if (*s == '/') {
92 /* AF_UNIX socket */
93
94 size_t l;
95
96 l = strlen(s);
97 if (l >= sizeof(a->sockaddr.un.sun_path))
98 return -EINVAL;
99
100 a->sockaddr.un.sun_family = AF_UNIX;
101 memcpy(a->sockaddr.un.sun_path, s, l);
102 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
103
104 } else if (*s == '@') {
105 /* Abstract AF_UNIX socket */
106 size_t l;
107
108 l = strlen(s+1);
109 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
110 return -EINVAL;
111
112 a->sockaddr.un.sun_family = AF_UNIX;
113 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
114 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
115
116 } else {
117
118 if ((e = strchr(s, ':'))) {
119
120 if ((r = safe_atou(e+1, &u)) < 0)
121 return r;
122
123 if (u <= 0 || u > 0xFFFF)
124 return -EINVAL;
125
126 if (!(n = strndup(s, e-s)))
127 return -ENOMEM;
128
129 /* IPv4 in w.x.y.z:p notation? */
130 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
131 free(n);
132 return -errno;
133 }
134
135 if (r > 0) {
136 /* Gotcha, it's a traditional IPv4 address */
137 free(n);
138
139 a->sockaddr.in4.sin_family = AF_INET;
140 a->sockaddr.in4.sin_port = htons((uint16_t) u);
141 a->size = sizeof(struct sockaddr_in);
142 } else {
143 unsigned idx;
144
145 if (strlen(n) > IF_NAMESIZE-1) {
146 free(n);
147 return -EINVAL;
148 }
149
150 /* Uh, our last resort, an interface name */
151 idx = if_nametoindex(n);
152 free(n);
153
154 if (idx == 0)
155 return -EINVAL;
156
157 if (!socket_ipv6_is_supported()) {
158 log_warning("Binding to interface is not available since kernel does not support IPv6.");
159 return -EAFNOSUPPORT;
160 }
161
162 a->sockaddr.in6.sin6_family = AF_INET6;
163 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
164 a->sockaddr.in6.sin6_scope_id = idx;
165 a->sockaddr.in6.sin6_addr = in6addr_any;
166 a->size = sizeof(struct sockaddr_in6);
167 }
168 } else {
169
170 /* Just a port */
171 r = safe_atou(s, &u);
172 if (r < 0)
173 return r;
174
175 if (u <= 0 || u > 0xFFFF)
176 return -EINVAL;
177
178 if (socket_ipv6_is_supported()) {
179 a->sockaddr.in6.sin6_family = AF_INET6;
180 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
181 a->sockaddr.in6.sin6_addr = in6addr_any;
182 a->size = sizeof(struct sockaddr_in6);
183 } else {
184 a->sockaddr.in4.sin_family = AF_INET;
185 a->sockaddr.in4.sin_port = htons((uint16_t) u);
186 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
187 a->size = sizeof(struct sockaddr_in);
188 }
189 }
190 }
191
192 return 0;
193}
194
195int socket_address_parse_netlink(SocketAddress *a, const char *s) {
196 int family;
197 unsigned group = 0;
198 _cleanup_free_ char *sfamily = NULL;
199 assert(a);
200 assert(s);
201
202 zero(*a);
203 a->type = SOCK_RAW;
204
205 errno = 0;
206 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
207 return errno > 0 ? -errno : -EINVAL;
208
209 family = netlink_family_from_string(sfamily);
210 if (family < 0)
211 return -EINVAL;
212
213 a->sockaddr.nl.nl_family = AF_NETLINK;
214 a->sockaddr.nl.nl_groups = group;
215
216 a->type = SOCK_RAW;
217 a->size = sizeof(struct sockaddr_nl);
218 a->protocol = family;
219
220 return 0;
221}
222
223int socket_address_verify(const SocketAddress *a) {
224 assert(a);
225
226 switch (socket_address_family(a)) {
227
228 case AF_INET:
229 if (a->size != sizeof(struct sockaddr_in))
230 return -EINVAL;
231
232 if (a->sockaddr.in4.sin_port == 0)
233 return -EINVAL;
234
235 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
236 return -EINVAL;
237
238 return 0;
239
240 case AF_INET6:
241 if (a->size != sizeof(struct sockaddr_in6))
242 return -EINVAL;
243
244 if (a->sockaddr.in6.sin6_port == 0)
245 return -EINVAL;
246
247 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
248 return -EINVAL;
249
250 return 0;
251
252 case AF_UNIX:
253 if (a->size < offsetof(struct sockaddr_un, sun_path))
254 return -EINVAL;
255
256 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
257
258 if (a->sockaddr.un.sun_path[0] != 0) {
259 char *e;
260
261 /* path */
262 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
263 return -EINVAL;
264
265 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
266 return -EINVAL;
267 }
268 }
269
270 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
271 return -EINVAL;
272
273 return 0;
274
275 case AF_NETLINK:
276
277 if (a->size != sizeof(struct sockaddr_nl))
278 return -EINVAL;
279
280 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
281 return -EINVAL;
282
283 return 0;
284
285 default:
286 return -EAFNOSUPPORT;
287 }
288}
289
290int socket_address_print(const SocketAddress *a, char **p) {
291 int r;
292 assert(a);
293 assert(p);
294
295 if ((r = socket_address_verify(a)) < 0)
296 return r;
297
298 switch (socket_address_family(a)) {
299
300 case AF_INET: {
301 char *ret;
302
303 ret = new(char, INET_ADDRSTRLEN+1+5+1);
304 if (!ret)
305 return -ENOMEM;
306
307 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
308 free(ret);
309 return -errno;
310 }
311
312 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
313 *p = ret;
314 return 0;
315 }
316
317 case AF_INET6: {
318 char *ret;
319
320 ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1);
321 if (!ret)
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 ret = strdup("<unnamed>");
340 if (!ret)
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 ret = new(char, sizeof(a->sockaddr.un.sun_path)+1);
352 if (!ret)
353 return -ENOMEM;
354
355 ret[0] = '@';
356 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
357 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
358
359 } else {
360 ret = strdup(a->sockaddr.un.sun_path);
361 if (!ret)
362 return -ENOMEM;
363 }
364
365 *p = ret;
366 return 0;
367 }
368
369 case AF_NETLINK: {
370 _cleanup_free_ char *sfamily = NULL;
371
372 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
373 if (r < 0)
374 return r;
375 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
376 if (r < 0)
377 return -ENOMEM;
378
379 return 0;
380 }
381
382 default:
383 return -EINVAL;
384 }
385}
386
387bool socket_address_can_accept(const SocketAddress *a) {
388 assert(a);
389
390 return
391 a->type == SOCK_STREAM ||
392 a->type == SOCK_SEQPACKET;
393}
394
395bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
396 assert(a);
397 assert(b);
398
399 /* Invalid addresses are unequal to all */
400 if (socket_address_verify(a) < 0 ||
401 socket_address_verify(b) < 0)
402 return false;
403
404 if (a->type != b->type)
405 return false;
406
407 if (a->size != b->size)
408 return false;
409
410 if (socket_address_family(a) != socket_address_family(b))
411 return false;
412
413 switch (socket_address_family(a)) {
414
415 case AF_INET:
416 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
417 return false;
418
419 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
420 return false;
421
422 break;
423
424 case AF_INET6:
425 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
426 return false;
427
428 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
429 return false;
430
431 break;
432
433 case AF_UNIX:
434
435 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
436 return false;
437
438 if (a->sockaddr.un.sun_path[0]) {
439 if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
440 return false;
441 } else {
442 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
443 return false;
444 }
445
446 break;
447
448 case AF_NETLINK:
449
450 if (a->protocol != b->protocol)
451 return false;
452
453 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
454 return false;
455
456 break;
457
458 default:
459 /* Cannot compare, so we assume the addresses are different */
460 return false;
461 }
462
463 return true;
464}
465
466bool socket_address_is(const SocketAddress *a, const char *s, int type) {
467 struct SocketAddress b;
468
469 assert(a);
470 assert(s);
471
472 if (socket_address_parse(&b, s) < 0)
473 return false;
474
475 b.type = type;
476
477 return socket_address_equal(a, &b);
478}
479
480bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
481 struct SocketAddress b;
482
483 assert(a);
484 assert(s);
485
486 if (socket_address_parse_netlink(&b, s) < 0)
487 return false;
488
489 return socket_address_equal(a, &b);
490}
491
492const char* socket_address_get_path(const SocketAddress *a) {
493 assert(a);
494
495 if (socket_address_family(a) != AF_UNIX)
496 return NULL;
497
498 if (a->sockaddr.un.sun_path[0] == 0)
499 return NULL;
500
501 return a->sockaddr.un.sun_path;
502}
503
504bool socket_ipv6_is_supported(void) {
505 char *l = 0;
506 bool enabled;
507
508 if (access("/sys/module/ipv6", F_OK) != 0)
509 return 0;
510
511 /* If we can't check "disable" parameter, assume enabled */
512 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
513 return 1;
514
515 /* If module was loaded with disable=1 no IPv6 available */
516 enabled = l[0] == '0';
517 free(l);
518
519 return enabled;
520}
521
522bool socket_address_matches_fd(const SocketAddress *a, int fd) {
523 union sockaddr_union sa;
524 socklen_t salen = sizeof(sa), solen;
525 int protocol, type;
526
527 assert(a);
528 assert(fd >= 0);
529
530 if (getsockname(fd, &sa.sa, &salen) < 0)
531 return false;
532
533 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
534 return false;
535
536 solen = sizeof(type);
537 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
538 return false;
539
540 if (type != a->type)
541 return false;
542
543 if (a->protocol != 0) {
544 solen = sizeof(protocol);
545 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
546 return false;
547
548 if (protocol != a->protocol)
549 return false;
550 }
551
552 switch (sa.sa.sa_family) {
553
554 case AF_INET:
555 return sa.in4.sin_port == a->sockaddr.in4.sin_port &&
556 sa.in4.sin_addr.s_addr == a->sockaddr.in4.sin_addr.s_addr;
557
558 case AF_INET6:
559 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
560 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
561
562 case AF_UNIX:
563 return salen == a->size &&
564 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
565
566 }
567
568 return false;
569}
570
571int getpeername_pretty(int fd, char **ret) {
572
573 union {
574 struct sockaddr sa;
575 struct sockaddr_un un;
576 struct sockaddr_in in;
577 struct sockaddr_in6 in6;
578 struct sockaddr_storage storage;
579 } sa;
580
581 socklen_t salen;
582 char *p;
583
584 assert(fd >= 0);
585 assert(ret);
586
587 salen = sizeof(sa);
588 if (getpeername(fd, &sa.sa, &salen) < 0)
589 return -errno;
590
591 switch (sa.sa.sa_family) {
592
593 case AF_INET: {
594 uint32_t a;
595
596 a = ntohl(sa.in.sin_addr.s_addr);
597
598 if (asprintf(&p,
599 "%u.%u.%u.%u:%u",
600 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
601 ntohs(sa.in.sin_port)) < 0)
602 return -ENOMEM;
603
604 break;
605 }
606
607 case AF_INET6: {
608 static const unsigned char ipv4_prefix[] = {
609 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
610 };
611
612 if (memcmp(&sa.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
613 const uint8_t *a = sa.in6.sin6_addr.s6_addr+12;
614
615 if (asprintf(&p,
616 "%u.%u.%u.%u:%u",
617 a[0], a[1], a[2], a[3],
618 ntohs(sa.in6.sin6_port)) < 0)
619 return -ENOMEM;
620 } else {
621 char a[INET6_ADDRSTRLEN];
622
623 if (asprintf(&p,
624 "%s:%u",
625 inet_ntop(AF_INET6, &sa.in6.sin6_addr, a, sizeof(a)),
626 ntohs(sa.in6.sin6_port)) < 0)
627 return -ENOMEM;
628 }
629
630 break;
631 }
632
633 case AF_UNIX: {
634 struct ucred ucred;
635
636 salen = sizeof(ucred);
637 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &salen) < 0)
638 return -errno;
639
640 if (asprintf(&p, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.pid) < 0)
641 return -ENOMEM;
642
643 break;
644 }
645
646 default:
647 return -ENOTSUP;
648 }
649
650 *ret = p;
651 return 0;
652}
653
654static const char* const netlink_family_table[] = {
655 [NETLINK_ROUTE] = "route",
656 [NETLINK_FIREWALL] = "firewall",
657 [NETLINK_INET_DIAG] = "inet-diag",
658 [NETLINK_NFLOG] = "nflog",
659 [NETLINK_XFRM] = "xfrm",
660 [NETLINK_SELINUX] = "selinux",
661 [NETLINK_ISCSI] = "iscsi",
662 [NETLINK_AUDIT] = "audit",
663 [NETLINK_FIB_LOOKUP] = "fib-lookup",
664 [NETLINK_CONNECTOR] = "connector",
665 [NETLINK_NETFILTER] = "netfilter",
666 [NETLINK_IP6_FW] = "ip6-fw",
667 [NETLINK_DNRTMSG] = "dnrtmsg",
668 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
669 [NETLINK_GENERIC] = "generic",
670 [NETLINK_SCSITRANSPORT] = "scsitransport",
671 [NETLINK_ECRYPTFS] = "ecryptfs"
672};
673
674DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
675
676static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
677 [SOCKET_ADDRESS_DEFAULT] = "default",
678 [SOCKET_ADDRESS_BOTH] = "both",
679 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
680};
681
682DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);