chiark / gitweb /
0097f011bb1332741b20490c6ef6be102f2df9f0
[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 #include "fileio.h"
42
43 int 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
195 int 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
223 int 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
290 int 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
387 bool 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
395 bool 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
466 bool 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
480 bool 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
492 const 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
504 bool 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
522 bool 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
571 int 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
654 static 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
674 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
675
676 static 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
682 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);