chiark / gitweb /
shared: handle unnamed sockets in socket_address_equal()
[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 #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->size <= offsetof(struct sockaddr_un, sun_path) ||
353                     b->size <= offsetof(struct sockaddr_un, sun_path))
354                         return false;
355
356                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
357                         return false;
358
359                 if (a->sockaddr.un.sun_path[0]) {
360                         if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
361                                 return false;
362                 } else {
363                         if (a->size != b->size)
364                                 return false;
365
366                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
367                                 return false;
368                 }
369
370                 break;
371
372         case AF_NETLINK:
373                 if (a->protocol != b->protocol)
374                         return false;
375
376                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
377                         return false;
378
379                 break;
380
381         default:
382                 /* Cannot compare, so we assume the addresses are different */
383                 return false;
384         }
385
386         return true;
387 }
388
389 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
390         struct SocketAddress b;
391
392         assert(a);
393         assert(s);
394
395         if (socket_address_parse(&b, s) < 0)
396                 return false;
397
398         b.type = type;
399
400         return socket_address_equal(a, &b);
401 }
402
403 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
404         struct SocketAddress b;
405
406         assert(a);
407         assert(s);
408
409         if (socket_address_parse_netlink(&b, s) < 0)
410                 return false;
411
412         return socket_address_equal(a, &b);
413 }
414
415 const char* socket_address_get_path(const SocketAddress *a) {
416         assert(a);
417
418         if (socket_address_family(a) != AF_UNIX)
419                 return NULL;
420
421         if (a->sockaddr.un.sun_path[0] == 0)
422                 return NULL;
423
424         return a->sockaddr.un.sun_path;
425 }
426
427 bool socket_ipv6_is_supported(void) {
428         _cleanup_free_ char *l = NULL;
429
430         if (access("/sys/module/ipv6", F_OK) != 0)
431                 return false;
432
433         /* If we can't check "disable" parameter, assume enabled */
434         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
435                 return true;
436
437         /* If module was loaded with disable=1 no IPv6 available */
438         return l[0] == '0';
439 }
440
441 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
442         SocketAddress b;
443         socklen_t solen;
444
445         assert(a);
446         assert(fd >= 0);
447
448         b.size = sizeof(b.sockaddr);
449         if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
450                 return false;
451
452         if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
453                 return false;
454
455         solen = sizeof(b.type);
456         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
457                 return false;
458
459         if (b.type != a->type)
460                 return false;
461
462         if (a->protocol != 0)  {
463                 solen = sizeof(b.protocol);
464                 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
465                         return false;
466
467                 if (b.protocol != a->protocol)
468                         return false;
469         }
470
471         return socket_address_equal(a, &b);
472 }
473
474 int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) {
475         union sockaddr_union *sa = (union sockaddr_union*) _sa;
476         char *p;
477
478         assert(sa);
479         assert(salen >= sizeof(sa->sa.sa_family));
480
481         switch (sa->sa.sa_family) {
482
483         case AF_INET: {
484                 uint32_t a;
485
486                 a = ntohl(sa->in.sin_addr.s_addr);
487
488                 if (asprintf(&p,
489                              "%u.%u.%u.%u:%u",
490                              a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
491                              ntohs(sa->in.sin_port)) < 0)
492                         return -ENOMEM;
493
494                 break;
495         }
496
497         case AF_INET6: {
498                 static const unsigned char ipv4_prefix[] = {
499                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
500                 };
501
502                 if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
503                         const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
504
505                         if (asprintf(&p,
506                                      "%u.%u.%u.%u:%u",
507                                      a[0], a[1], a[2], a[3],
508                                      ntohs(sa->in6.sin6_port)) < 0)
509                                 return -ENOMEM;
510                 } else {
511                         char a[INET6_ADDRSTRLEN];
512
513                         if (asprintf(&p,
514                                      "[%s]:%u",
515                                      inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)),
516                                      ntohs(sa->in6.sin6_port)) < 0)
517                                 return -ENOMEM;
518                 }
519
520                 break;
521         }
522
523         case AF_UNIX:
524                 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
525                         p = strdup("<unnamed>");
526                         if (!p)
527                                 return -ENOMEM;
528
529                 } else if (sa->un.sun_path[0] == 0) {
530                         /* abstract */
531
532                         /* FIXME: We assume we can print the
533                          * socket path here and that it hasn't
534                          * more than one NUL byte. That is
535                          * actually an invalid assumption */
536
537                         p = new(char, sizeof(sa->un.sun_path)+1);
538                         if (!p)
539                                 return -ENOMEM;
540
541                         p[0] = '@';
542                         memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
543                         p[sizeof(sa->un.sun_path)] = 0;
544
545                 } else {
546                         p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
547                         if (!ret)
548                                 return -ENOMEM;
549                 }
550
551                 break;
552
553         default:
554                 return -ENOTSUP;
555         }
556
557
558         *ret = p;
559         return 0;
560 }
561
562 int getpeername_pretty(int fd, char **ret) {
563         union sockaddr_union sa;
564         socklen_t salen = sizeof(sa);
565         int r;
566
567         assert(fd >= 0);
568         assert(ret);
569
570         if (getpeername(fd, &sa.sa, &salen) < 0)
571                 return -errno;
572
573         if (sa.sa.sa_family == AF_UNIX) {
574                 struct ucred ucred = {};
575
576                 /* UNIX connection sockets are anonymous, so let's use
577                  * PID/UID as pretty credentials instead */
578
579                 r = getpeercred(fd, &ucred);
580                 if (r < 0)
581                         return r;
582
583                 if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
584                         return -ENOMEM;
585
586                 return 0;
587         }
588
589         /* For remote sockets we translate IPv6 addresses back to IPv4
590          * if applicable, since that's nicer. */
591
592         return sockaddr_pretty(&sa.sa, salen, true, ret);
593 }
594
595 int getsockname_pretty(int fd, char **ret) {
596         union sockaddr_union sa;
597         socklen_t salen = sizeof(sa);
598
599         assert(fd >= 0);
600         assert(ret);
601
602         if (getsockname(fd, &sa.sa, &salen) < 0)
603                 return -errno;
604
605         /* For local sockets we do not translate IPv6 addresses back
606          * to IPv6 if applicable, since this is usually used for
607          * listening sockets where the difference between IPv4 and
608          * IPv6 matters. */
609
610         return sockaddr_pretty(&sa.sa, salen, false, ret);
611 }
612
613 int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
614         int r;
615         char host[NI_MAXHOST], *ret;
616
617         assert(_ret);
618
619         r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
620                         NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
621         if (r != 0) {
622                 int saved_errno = errno;
623
624                 r = sockaddr_pretty(&sa->sa, salen, true, &ret);
625                 if (r < 0)
626                         return log_error_errno(r, "sockadd_pretty() failed: %m");
627
628                 log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
629         } else {
630                 ret = strdup(host);
631                 if (!ret)
632                         return log_oom();
633         }
634
635         *_ret = ret;
636         return 0;
637 }
638
639 int getnameinfo_pretty(int fd, char **ret) {
640         union sockaddr_union sa;
641         socklen_t salen = sizeof(sa);
642
643         assert(fd >= 0);
644         assert(ret);
645
646         if (getsockname(fd, &sa.sa, &salen) < 0)
647                 return log_error_errno(errno, "getsockname(%d) failed: %m", fd);
648
649         return socknameinfo_pretty(&sa, salen, ret);
650 }
651
652 int socket_address_unlink(SocketAddress *a) {
653         assert(a);
654
655         if (socket_address_family(a) != AF_UNIX)
656                 return 0;
657
658         if (a->sockaddr.un.sun_path[0] == 0)
659                 return 0;
660
661         if (unlink(a->sockaddr.un.sun_path) < 0)
662                 return -errno;
663
664         return 1;
665 }
666
667 static const char* const netlink_family_table[] = {
668         [NETLINK_ROUTE] = "route",
669         [NETLINK_FIREWALL] = "firewall",
670         [NETLINK_INET_DIAG] = "inet-diag",
671         [NETLINK_NFLOG] = "nflog",
672         [NETLINK_XFRM] = "xfrm",
673         [NETLINK_SELINUX] = "selinux",
674         [NETLINK_ISCSI] = "iscsi",
675         [NETLINK_AUDIT] = "audit",
676         [NETLINK_FIB_LOOKUP] = "fib-lookup",
677         [NETLINK_CONNECTOR] = "connector",
678         [NETLINK_NETFILTER] = "netfilter",
679         [NETLINK_IP6_FW] = "ip6-fw",
680         [NETLINK_DNRTMSG] = "dnrtmsg",
681         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
682         [NETLINK_GENERIC] = "generic",
683         [NETLINK_SCSITRANSPORT] = "scsitransport",
684         [NETLINK_ECRYPTFS] = "ecryptfs"
685 };
686
687 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
688
689 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
690         [SOCKET_ADDRESS_DEFAULT] = "default",
691         [SOCKET_ADDRESS_BOTH] = "both",
692         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
693 };
694
695 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
696
697 bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
698         assert(a);
699         assert(b);
700
701         if (a->sa.sa_family != b->sa.sa_family)
702                 return false;
703
704         if (a->sa.sa_family == AF_INET)
705                 return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
706
707         if (a->sa.sa_family == AF_INET6)
708                 return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
709
710         return false;
711 }
712
713 char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
714         assert(addr);
715         assert(buffer);
716
717         /* Like ether_ntoa() but uses %02x instead of %x to print
718          * ethernet addresses, which makes them look less funny. Also,
719          * doesn't use a static buffer. */
720
721         sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
722                 addr->ether_addr_octet[0],
723                 addr->ether_addr_octet[1],
724                 addr->ether_addr_octet[2],
725                 addr->ether_addr_octet[3],
726                 addr->ether_addr_octet[4],
727                 addr->ether_addr_octet[5]);
728
729         return buffer;
730 }