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