chiark / gitweb /
errno is positive
[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                 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
304                         return -ENOMEM;
305
306                 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
307                         free(ret);
308                         return -errno;
309                 }
310
311                 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
312                 *p = ret;
313                 return 0;
314         }
315
316         case AF_INET6: {
317                 char *ret;
318
319                 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
320                         return -ENOMEM;
321
322                 ret[0] = '[';
323                 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
324                         free(ret);
325                         return -errno;
326                 }
327
328                 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
329                 *p = ret;
330                 return 0;
331         }
332
333         case AF_UNIX: {
334                 char *ret;
335
336                 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
337
338                         if (!(ret = strdup("<unnamed>")))
339                                 return -ENOMEM;
340
341                 } else if (a->sockaddr.un.sun_path[0] == 0) {
342                         /* abstract */
343
344                         /* FIXME: We assume we can print the
345                          * socket path here and that it hasn't
346                          * more than one NUL byte. That is
347                          * actually an invalid assumption */
348
349                         if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
350                                 return -ENOMEM;
351
352                         ret[0] = '@';
353                         memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
354                         ret[sizeof(a->sockaddr.un.sun_path)] = 0;
355
356                 } else {
357
358                         if (!(ret = strdup(a->sockaddr.un.sun_path)))
359                                 return -ENOMEM;
360                 }
361
362                 *p = ret;
363                 return 0;
364         }
365
366         case AF_NETLINK: {
367                 char _cleanup_free_ *sfamily = NULL;
368
369                 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
370                 if (r < 0)
371                         return r;
372                 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
373                 if (r < 0)
374                         return -ENOMEM;
375
376                 return 0;
377         }
378
379         default:
380                 return -EINVAL;
381         }
382 }
383
384 bool socket_address_can_accept(const SocketAddress *a) {
385         assert(a);
386
387         return
388                 a->type == SOCK_STREAM ||
389                 a->type == SOCK_SEQPACKET;
390 }
391
392 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
393         assert(a);
394         assert(b);
395
396         /* Invalid addresses are unequal to all */
397         if (socket_address_verify(a) < 0 ||
398             socket_address_verify(b) < 0)
399                 return false;
400
401         if (a->type != b->type)
402                 return false;
403
404         if (a->size != b->size)
405                 return false;
406
407         if (socket_address_family(a) != socket_address_family(b))
408                 return false;
409
410         switch (socket_address_family(a)) {
411
412         case AF_INET:
413                 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
414                         return false;
415
416                 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
417                         return false;
418
419                 break;
420
421         case AF_INET6:
422                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
423                         return false;
424
425                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
426                         return false;
427
428                 break;
429
430         case AF_UNIX:
431
432                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
433                         return false;
434
435                 if (a->sockaddr.un.sun_path[0]) {
436                         if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
437                                 return false;
438                 } else {
439                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
440                                 return false;
441                 }
442
443                 break;
444
445         case AF_NETLINK:
446
447                 if (a->protocol != b->protocol)
448                         return false;
449
450                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
451                         return false;
452
453                 break;
454
455         default:
456                 /* Cannot compare, so we assume the addresses are different */
457                 return false;
458         }
459
460         return true;
461 }
462
463 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
464         struct SocketAddress b;
465
466         assert(a);
467         assert(s);
468
469         if (socket_address_parse(&b, s) < 0)
470                 return false;
471
472         b.type = type;
473
474         return socket_address_equal(a, &b);
475 }
476
477 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
478         struct SocketAddress b;
479
480         assert(a);
481         assert(s);
482
483         if (socket_address_parse_netlink(&b, s) < 0)
484                 return false;
485
486         return socket_address_equal(a, &b);
487 }
488
489 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
490         assert(a);
491
492         if (socket_address_family(a) != AF_UNIX)
493                 return false;
494
495         if (a->sockaddr.un.sun_path[0] == 0)
496                 return false;
497
498         return path_startswith(a->sockaddr.un.sun_path, prefix);
499 }
500
501 bool socket_ipv6_is_supported(void) {
502         char *l = 0;
503         bool enabled;
504
505         if (access("/sys/module/ipv6", F_OK) != 0)
506                 return 0;
507
508         /* If we can't check "disable" parameter, assume enabled */
509         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
510                 return 1;
511
512         /* If module was loaded with disable=1 no IPv6 available */
513         enabled = l[0] == '0';
514         free(l);
515
516         return enabled;
517 }
518
519 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
520         union sockaddr_union sa;
521         socklen_t salen = sizeof(sa), solen;
522         int protocol, type;
523
524         assert(a);
525         assert(fd >= 0);
526
527         if (getsockname(fd, &sa.sa, &salen) < 0)
528                 return false;
529
530         if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
531                 return false;
532
533         solen = sizeof(type);
534         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
535                 return false;
536
537         if (type != a->type)
538                 return false;
539
540         if (a->protocol != 0)  {
541                 solen = sizeof(protocol);
542                 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
543                         return false;
544
545                 if (protocol != a->protocol)
546                         return false;
547         }
548
549         switch (sa.sa.sa_family) {
550
551         case AF_INET:
552                 return sa.in4.sin_port == a->sockaddr.in4.sin_port &&
553                         sa.in4.sin_addr.s_addr == a->sockaddr.in4.sin_addr.s_addr;
554
555         case AF_INET6:
556                 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
557                         memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
558
559         case AF_UNIX:
560                 return salen == a->size &&
561                         memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
562
563         }
564
565         return false;
566 }
567
568 int make_socket_fd(const char* address, int flags) {
569         SocketAddress a;
570         int fd, r;
571         char _cleanup_free_ *p = NULL;
572
573         r = socket_address_parse(&a, address);
574         if (r < 0) {
575                 log_error("failed to parse socket: %s", strerror(-r));
576                 return r;
577         }
578
579         fd = socket(socket_address_family(&a), flags, 0);
580         if (fd < 0) {
581                 log_error("socket(): %m");
582                 return -errno;
583         }
584
585         r = socket_address_print(&a, &p);
586         if (r < 0) {
587                 log_error("socket_address_print(): %s", strerror(-r));
588                 return r;
589         }
590         log_info("Listening on %s", p);
591
592         r = bind(fd, &a.sockaddr.sa, a.size);
593         if (r < 0) {
594                 log_error("bind to %s: %m", address);
595                 return -errno;
596         }
597
598         r = listen(fd, SOMAXCONN);
599         if (r < 0) {
600                 log_error("listen on %s: %m", address);
601                 return -errno;
602         }
603
604         return fd;
605 }
606
607 static const char* const netlink_family_table[] = {
608         [NETLINK_ROUTE] = "route",
609         [NETLINK_FIREWALL] = "firewall",
610         [NETLINK_INET_DIAG] = "inet-diag",
611         [NETLINK_NFLOG] = "nflog",
612         [NETLINK_XFRM] = "xfrm",
613         [NETLINK_SELINUX] = "selinux",
614         [NETLINK_ISCSI] = "iscsi",
615         [NETLINK_AUDIT] = "audit",
616         [NETLINK_FIB_LOOKUP] = "fib-lookup",
617         [NETLINK_CONNECTOR] = "connector",
618         [NETLINK_NETFILTER] = "netfilter",
619         [NETLINK_IP6_FW] = "ip6-fw",
620         [NETLINK_DNRTMSG] = "dnrtmsg",
621         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
622         [NETLINK_GENERIC] = "generic",
623         [NETLINK_SCSITRANSPORT] = "scsitransport",
624         [NETLINK_ECRYPTFS] = "ecryptfs"
625 };
626
627 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
628
629 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
630         [SOCKET_ADDRESS_DEFAULT] = "default",
631         [SOCKET_ADDRESS_BOTH] = "both",
632         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
633 };
634
635 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);