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