]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/socket-util.c
core, shared: in deserializing, match same files reached via different paths
[thirdparty/systemd.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 #include <netdb.h>
35
36 #include "macro.h"
37 #include "util.h"
38 #include "mkdir.h"
39 #include "path-util.h"
40 #include "socket-util.h"
41 #include "missing.h"
42 #include "fileio.h"
43
44 int socket_address_parse(SocketAddress *a, const char *s) {
45 char *e, *n;
46 unsigned u;
47 int r;
48
49 assert(a);
50 assert(s);
51
52 zero(*a);
53 a->type = SOCK_STREAM;
54
55 if (*s == '[') {
56 /* IPv6 in [x:.....:z]:p notation */
57
58 if (!socket_ipv6_is_supported()) {
59 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
60 return -EAFNOSUPPORT;
61 }
62
63 e = strchr(s+1, ']');
64 if (!e)
65 return -EINVAL;
66
67 n = strndupa(s+1, e-s-1);
68
69 errno = 0;
70 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
71 return errno > 0 ? -errno : -EINVAL;
72
73 e++;
74 if (*e != ':')
75 return -EINVAL;
76
77 e++;
78 r = safe_atou(e, &u);
79 if (r < 0)
80 return r;
81
82 if (u <= 0 || u > 0xFFFF)
83 return -EINVAL;
84
85 a->sockaddr.in6.sin6_family = AF_INET6;
86 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
87 a->size = sizeof(struct sockaddr_in6);
88
89 } else if (*s == '/') {
90 /* AF_UNIX socket */
91
92 size_t l;
93
94 l = strlen(s);
95 if (l >= sizeof(a->sockaddr.un.sun_path))
96 return -EINVAL;
97
98 a->sockaddr.un.sun_family = AF_UNIX;
99 memcpy(a->sockaddr.un.sun_path, s, l);
100 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
101
102 } else if (*s == '@') {
103 /* Abstract AF_UNIX socket */
104 size_t l;
105
106 l = strlen(s+1);
107 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
108 return -EINVAL;
109
110 a->sockaddr.un.sun_family = AF_UNIX;
111 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
112 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
113
114 } else {
115 e = strchr(s, ':');
116 if (e) {
117 r = safe_atou(e+1, &u);
118 if (r < 0)
119 return r;
120
121 if (u <= 0 || u > 0xFFFF)
122 return -EINVAL;
123
124 n = strndupa(s, e-s);
125
126 /* IPv4 in w.x.y.z:p notation? */
127 r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
128 if (r < 0)
129 return -errno;
130
131 if (r > 0) {
132 /* Gotcha, it's a traditional IPv4 address */
133 a->sockaddr.in.sin_family = AF_INET;
134 a->sockaddr.in.sin_port = htons((uint16_t) u);
135 a->size = sizeof(struct sockaddr_in);
136 } else {
137 unsigned idx;
138
139 if (strlen(n) > IF_NAMESIZE-1)
140 return -EINVAL;
141
142 /* Uh, our last resort, an interface name */
143 idx = if_nametoindex(n);
144 if (idx == 0)
145 return -EINVAL;
146
147 if (!socket_ipv6_is_supported()) {
148 log_warning("Binding to interface is not available since kernel does not support IPv6.");
149 return -EAFNOSUPPORT;
150 }
151
152 a->sockaddr.in6.sin6_family = AF_INET6;
153 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
154 a->sockaddr.in6.sin6_scope_id = idx;
155 a->sockaddr.in6.sin6_addr = in6addr_any;
156 a->size = sizeof(struct sockaddr_in6);
157 }
158 } else {
159
160 /* Just a port */
161 r = safe_atou(s, &u);
162 if (r < 0)
163 return r;
164
165 if (u <= 0 || u > 0xFFFF)
166 return -EINVAL;
167
168 if (socket_ipv6_is_supported()) {
169 a->sockaddr.in6.sin6_family = AF_INET6;
170 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
171 a->sockaddr.in6.sin6_addr = in6addr_any;
172 a->size = sizeof(struct sockaddr_in6);
173 } else {
174 a->sockaddr.in.sin_family = AF_INET;
175 a->sockaddr.in.sin_port = htons((uint16_t) u);
176 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
177 a->size = sizeof(struct sockaddr_in);
178 }
179 }
180 }
181
182 return 0;
183 }
184
185 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
186 int family;
187 unsigned group = 0;
188 _cleanup_free_ char *sfamily = NULL;
189 assert(a);
190 assert(s);
191
192 zero(*a);
193 a->type = SOCK_RAW;
194
195 errno = 0;
196 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
197 return errno > 0 ? -errno : -EINVAL;
198
199 family = netlink_family_from_string(sfamily);
200 if (family < 0)
201 return -EINVAL;
202
203 a->sockaddr.nl.nl_family = AF_NETLINK;
204 a->sockaddr.nl.nl_groups = group;
205
206 a->type = SOCK_RAW;
207 a->size = sizeof(struct sockaddr_nl);
208 a->protocol = family;
209
210 return 0;
211 }
212
213 int socket_address_verify(const SocketAddress *a) {
214 assert(a);
215
216 switch (socket_address_family(a)) {
217
218 case AF_INET:
219 if (a->size != sizeof(struct sockaddr_in))
220 return -EINVAL;
221
222 if (a->sockaddr.in.sin_port == 0)
223 return -EINVAL;
224
225 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
226 return -EINVAL;
227
228 return 0;
229
230 case AF_INET6:
231 if (a->size != sizeof(struct sockaddr_in6))
232 return -EINVAL;
233
234 if (a->sockaddr.in6.sin6_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_UNIX:
243 if (a->size < offsetof(struct sockaddr_un, sun_path))
244 return -EINVAL;
245
246 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
247
248 if (a->sockaddr.un.sun_path[0] != 0) {
249 char *e;
250
251 /* path */
252 e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
253 if (!e)
254 return -EINVAL;
255
256 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
257 return -EINVAL;
258 }
259 }
260
261 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
262 return -EINVAL;
263
264 return 0;
265
266 case AF_NETLINK:
267
268 if (a->size != sizeof(struct sockaddr_nl))
269 return -EINVAL;
270
271 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
272 return -EINVAL;
273
274 return 0;
275
276 default:
277 return -EAFNOSUPPORT;
278 }
279 }
280
281 int socket_address_print(const SocketAddress *a, char **ret) {
282 int r;
283
284 assert(a);
285 assert(ret);
286
287 r = socket_address_verify(a);
288 if (r < 0)
289 return r;
290
291 if (socket_address_family(a) == AF_NETLINK) {
292 _cleanup_free_ char *sfamily = NULL;
293
294 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
295 if (r < 0)
296 return r;
297
298 r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
299 if (r < 0)
300 return -ENOMEM;
301
302 return 0;
303 }
304
305 return sockaddr_pretty(&a->sockaddr.sa, a->size, false, ret);
306 }
307
308 bool socket_address_can_accept(const SocketAddress *a) {
309 assert(a);
310
311 return
312 a->type == SOCK_STREAM ||
313 a->type == SOCK_SEQPACKET;
314 }
315
316 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
317 assert(a);
318 assert(b);
319
320 /* Invalid addresses are unequal to all */
321 if (socket_address_verify(a) < 0 ||
322 socket_address_verify(b) < 0)
323 return false;
324
325 if (a->type != b->type)
326 return false;
327
328 if (socket_address_family(a) != socket_address_family(b))
329 return false;
330
331 switch (socket_address_family(a)) {
332
333 case AF_INET:
334 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
335 return false;
336
337 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
338 return false;
339
340 break;
341
342 case AF_INET6:
343 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
344 return false;
345
346 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
347 return false;
348
349 break;
350
351 case AF_UNIX:
352 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
353 return false;
354
355 if (a->sockaddr.un.sun_path[0]) {
356 if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
357 return false;
358 } else {
359 if (a->size != b->size)
360 return false;
361
362 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
363 return false;
364 }
365
366 break;
367
368 case AF_NETLINK:
369 if (a->protocol != b->protocol)
370 return false;
371
372 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
373 return false;
374
375 break;
376
377 default:
378 /* Cannot compare, so we assume the addresses are different */
379 return false;
380 }
381
382 return true;
383 }
384
385 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
386 struct SocketAddress b;
387
388 assert(a);
389 assert(s);
390
391 if (socket_address_parse(&b, s) < 0)
392 return false;
393
394 b.type = type;
395
396 return socket_address_equal(a, &b);
397 }
398
399 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
400 struct SocketAddress b;
401
402 assert(a);
403 assert(s);
404
405 if (socket_address_parse_netlink(&b, s) < 0)
406 return false;
407
408 return socket_address_equal(a, &b);
409 }
410
411 const char* socket_address_get_path(const SocketAddress *a) {
412 assert(a);
413
414 if (socket_address_family(a) != AF_UNIX)
415 return NULL;
416
417 if (a->sockaddr.un.sun_path[0] == 0)
418 return NULL;
419
420 return a->sockaddr.un.sun_path;
421 }
422
423 bool socket_ipv6_is_supported(void) {
424 _cleanup_free_ char *l = NULL;
425
426 if (access("/sys/module/ipv6", F_OK) != 0)
427 return false;
428
429 /* If we can't check "disable" parameter, assume enabled */
430 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
431 return true;
432
433 /* If module was loaded with disable=1 no IPv6 available */
434 return l[0] == '0';
435 }
436
437 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
438 union sockaddr_union sa;
439 socklen_t salen = sizeof(sa), solen;
440 int protocol, type;
441
442 assert(a);
443 assert(fd >= 0);
444
445 if (getsockname(fd, &sa.sa, &salen) < 0)
446 return false;
447
448 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
449 return false;
450
451 solen = sizeof(type);
452 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
453 return false;
454
455 if (type != a->type)
456 return false;
457
458 if (a->protocol != 0) {
459 solen = sizeof(protocol);
460 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
461 return false;
462
463 if (protocol != a->protocol)
464 return false;
465 }
466
467 switch (sa.sa.sa_family) {
468
469 case AF_INET:
470 return sa.in.sin_port == a->sockaddr.in.sin_port &&
471 sa.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr;
472
473 case AF_INET6:
474 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
475 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
476
477 case AF_UNIX:
478 return salen == a->size &&
479 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
480
481 }
482
483 return false;
484 }
485
486 int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) {
487 union sockaddr_union *sa = (union sockaddr_union*) _sa;
488 char *p;
489
490 assert(sa);
491 assert(salen >= sizeof(sa->sa.sa_family));
492
493 switch (sa->sa.sa_family) {
494
495 case AF_INET: {
496 uint32_t a;
497
498 a = ntohl(sa->in.sin_addr.s_addr);
499
500 if (asprintf(&p,
501 "%u.%u.%u.%u:%u",
502 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
503 ntohs(sa->in.sin_port)) < 0)
504 return -ENOMEM;
505
506 break;
507 }
508
509 case AF_INET6: {
510 static const unsigned char ipv4_prefix[] = {
511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
512 };
513
514 if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
515 const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
516
517 if (asprintf(&p,
518 "%u.%u.%u.%u:%u",
519 a[0], a[1], a[2], a[3],
520 ntohs(sa->in6.sin6_port)) < 0)
521 return -ENOMEM;
522 } else {
523 char a[INET6_ADDRSTRLEN];
524
525 if (asprintf(&p,
526 "[%s]:%u",
527 inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)),
528 ntohs(sa->in6.sin6_port)) < 0)
529 return -ENOMEM;
530 }
531
532 break;
533 }
534
535 case AF_UNIX:
536 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
537 p = strdup("<unnamed>");
538 if (!p)
539 return -ENOMEM;
540
541 } else if (sa->un.sun_path[0] == 0) {
542 /* abstract */
543
544 /* FIXME: We assume we can print the
545 * socket path here and that it hasn't
546 * more than one NUL byte. That is
547 * actually an invalid assumption */
548
549 p = new(char, sizeof(sa->un.sun_path)+1);
550 if (!p)
551 return -ENOMEM;
552
553 p[0] = '@';
554 memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
555 p[sizeof(sa->un.sun_path)] = 0;
556
557 } else {
558 p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
559 if (!ret)
560 return -ENOMEM;
561 }
562
563 break;
564
565 default:
566 return -ENOTSUP;
567 }
568
569
570 *ret = p;
571 return 0;
572 }
573
574 int getpeername_pretty(int fd, char **ret) {
575 union sockaddr_union sa;
576 socklen_t salen = sizeof(sa);
577 int r;
578
579 assert(fd >= 0);
580 assert(ret);
581
582 if (getpeername(fd, &sa.sa, &salen) < 0)
583 return -errno;
584
585 if (sa.sa.sa_family == AF_UNIX) {
586 struct ucred ucred = {};
587
588 /* UNIX connection sockets are anonymous, so let's use
589 * PID/UID as pretty credentials instead */
590
591 r = getpeercred(fd, &ucred);
592 if (r < 0)
593 return r;
594
595 if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
596 return -ENOMEM;
597
598 return 0;
599 }
600
601 /* For remote sockets we translate IPv6 addresses back to IPv4
602 * if applicable, since that's nicer. */
603
604 return sockaddr_pretty(&sa.sa, salen, true, ret);
605 }
606
607 int getsockname_pretty(int fd, char **ret) {
608 union sockaddr_union sa;
609 socklen_t salen = sizeof(sa);
610
611 assert(fd >= 0);
612 assert(ret);
613
614 if (getsockname(fd, &sa.sa, &salen) < 0)
615 return -errno;
616
617 /* For local sockets we do not translate IPv6 addresses back
618 * to IPv6 if applicable, since this is usually used for
619 * listening sockets where the difference between IPv4 and
620 * IPv6 matters. */
621
622 return sockaddr_pretty(&sa.sa, salen, false, ret);
623 }
624
625 int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
626 int r;
627 char host[NI_MAXHOST], *ret;
628
629 assert(_ret);
630
631 r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
632 NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
633 if (r != 0) {
634 int saved_errno = errno;
635
636 r = sockaddr_pretty(&sa->sa, salen, true, &ret);
637 if (r < 0)
638 return log_error_errno(r, "sockadd_pretty() failed: %m");
639
640 log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
641 } else {
642 ret = strdup(host);
643 if (!ret)
644 return log_oom();
645 }
646
647 *_ret = ret;
648 return 0;
649 }
650
651 int getnameinfo_pretty(int fd, char **ret) {
652 union sockaddr_union sa;
653 socklen_t salen = sizeof(sa);
654
655 assert(fd >= 0);
656 assert(ret);
657
658 if (getsockname(fd, &sa.sa, &salen) < 0)
659 return log_error_errno(errno, "getsockname(%d) failed: %m", fd);
660
661 return socknameinfo_pretty(&sa, salen, ret);
662 }
663
664 int socket_address_unlink(SocketAddress *a) {
665 assert(a);
666
667 if (socket_address_family(a) != AF_UNIX)
668 return 0;
669
670 if (a->sockaddr.un.sun_path[0] == 0)
671 return 0;
672
673 if (unlink(a->sockaddr.un.sun_path) < 0)
674 return -errno;
675
676 return 1;
677 }
678
679 static const char* const netlink_family_table[] = {
680 [NETLINK_ROUTE] = "route",
681 [NETLINK_FIREWALL] = "firewall",
682 [NETLINK_INET_DIAG] = "inet-diag",
683 [NETLINK_NFLOG] = "nflog",
684 [NETLINK_XFRM] = "xfrm",
685 [NETLINK_SELINUX] = "selinux",
686 [NETLINK_ISCSI] = "iscsi",
687 [NETLINK_AUDIT] = "audit",
688 [NETLINK_FIB_LOOKUP] = "fib-lookup",
689 [NETLINK_CONNECTOR] = "connector",
690 [NETLINK_NETFILTER] = "netfilter",
691 [NETLINK_IP6_FW] = "ip6-fw",
692 [NETLINK_DNRTMSG] = "dnrtmsg",
693 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
694 [NETLINK_GENERIC] = "generic",
695 [NETLINK_SCSITRANSPORT] = "scsitransport",
696 [NETLINK_ECRYPTFS] = "ecryptfs"
697 };
698
699 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
700
701 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
702 [SOCKET_ADDRESS_DEFAULT] = "default",
703 [SOCKET_ADDRESS_BOTH] = "both",
704 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
705 };
706
707 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
708
709 bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
710 assert(a);
711 assert(b);
712
713 if (a->sa.sa_family != b->sa.sa_family)
714 return false;
715
716 if (a->sa.sa_family == AF_INET)
717 return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
718
719 if (a->sa.sa_family == AF_INET6)
720 return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
721
722 return false;
723 }
724
725 char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
726 assert(addr);
727 assert(buffer);
728
729 /* Like ether_ntoa() but uses %02x instead of %x to print
730 * ethernet addresses, which makes them look less funny. Also,
731 * doesn't use a static buffer. */
732
733 sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
734 addr->ether_addr_octet[0],
735 addr->ether_addr_octet[1],
736 addr->ether_addr_octet[2],
737 addr->ether_addr_octet[3],
738 addr->ether_addr_octet[4],
739 addr->ether_addr_octet[5]);
740
741 return buffer;
742 }