]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-util.c
unit-name: when escaping a path consider the empty path identical to the root dir
[thirdparty/systemd.git] / src / shared / socket-util.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
42f4e3c4 2
a7334b09
LP
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
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
42f4e3c4
LP
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>
542563ba 29#include <net/if.h>
b5a0699f
LP
30#include <sys/types.h>
31#include <sys/stat.h>
0e098b15
LP
32#include <stddef.h>
33#include <sys/ioctl.h>
42f4e3c4
LP
34
35#include "macro.h"
36#include "util.h"
49e942b2 37#include "mkdir.h"
9eb977db 38#include "path-util.h"
42f4e3c4 39#include "socket-util.h"
16c42ce1 40#include "missing.h"
a5c32cff 41#include "fileio.h"
42f4e3c4 42
542563ba 43int socket_address_parse(SocketAddress *a, const char *s) {
42f4e3c4
LP
44 int r;
45 char *e, *n;
46 unsigned u;
47
48 assert(a);
49 assert(s);
50
9152c765 51 zero(*a);
542563ba 52 a->type = SOCK_STREAM;
42f4e3c4
LP
53
54 if (*s == '[') {
55 /* IPv6 in [x:.....:z]:p notation */
56
5bfcc1c6
FF
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
42f4e3c4
LP
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);
8333c77e 71 return errno > 0 ? -errno : -EINVAL;
42f4e3c4
LP
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);
42f4e3c4
LP
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);
0e098b15 102 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
42f4e3c4 103
1c24e7bd 104 } else if (*s == '@') {
42f4e3c4
LP
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);
0e098b15 114 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
42f4e3c4
LP
115
116 } else {
117
118 if ((e = strchr(s, ':'))) {
542563ba
LP
119
120 if ((r = safe_atou(e+1, &u)) < 0)
121 return r;
122
123 if (u <= 0 || u > 0xFFFF)
124 return -EINVAL;
42f4e3c4 125
42f4e3c4
LP
126 if (!(n = strndup(s, e-s)))
127 return -ENOMEM;
128
542563ba
LP
129 /* IPv4 in w.x.y.z:p notation? */
130 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
42f4e3c4 131 free(n);
542563ba 132 return -errno;
42f4e3c4
LP
133 }
134
542563ba
LP
135 if (r > 0) {
136 /* Gotcha, it's a traditional IPv4 address */
137 free(n);
42f4e3c4 138
542563ba
LP
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;
42f4e3c4 144
acbb0225
LP
145 if (strlen(n) > IF_NAMESIZE-1) {
146 free(n);
147 return -EINVAL;
148 }
149
542563ba
LP
150 /* Uh, our last resort, an interface name */
151 idx = if_nametoindex(n);
152 free(n);
153
83c60c9f 154 if (idx == 0)
542563ba 155 return -EINVAL;
42f4e3c4 156
5bfcc1c6
FF
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
542563ba
LP
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;
83c60c9f 165 a->sockaddr.in6.sin6_addr = in6addr_any;
542563ba
LP
166 a->size = sizeof(struct sockaddr_in6);
167 }
42f4e3c4
LP
168 } else {
169
170 /* Just a port */
5198dabc
LP
171 r = safe_atou(s, &u);
172 if (r < 0)
42f4e3c4
LP
173 return r;
174
175 if (u <= 0 || u > 0xFFFF)
176 return -EINVAL;
177
5bfcc1c6
FF
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 }
42f4e3c4
LP
189 }
190 }
191
192 return 0;
193}
194
7a22745a
LP
195int socket_address_parse_netlink(SocketAddress *a, const char *s) {
196 int family;
197 unsigned group = 0;
f8b69d1d 198 _cleanup_free_ char *sfamily = NULL;
7a22745a
LP
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)
bcb161b0 207 return errno > 0 ? -errno : -EINVAL;
7a22745a 208
f8b69d1d
MS
209 family = netlink_family_from_string(sfamily);
210 if (family < 0)
211 return -EINVAL;
7a22745a
LP
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
542563ba 223int socket_address_verify(const SocketAddress *a) {
42f4e3c4
LP
224 assert(a);
225
542563ba 226 switch (socket_address_family(a)) {
42f4e3c4 227
7a22745a
LP
228 case AF_INET:
229 if (a->size != sizeof(struct sockaddr_in))
230 return -EINVAL;
42f4e3c4 231
7a22745a
LP
232 if (a->sockaddr.in4.sin_port == 0)
233 return -EINVAL;
42f4e3c4 234
7a22745a
LP
235 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
236 return -EINVAL;
42f4e3c4 237
7a22745a
LP
238 return 0;
239
240 case AF_INET6:
241 if (a->size != sizeof(struct sockaddr_in6))
242 return -EINVAL;
42f4e3c4 243
7a22745a
LP
244 if (a->sockaddr.in6.sin6_port == 0)
245 return -EINVAL;
42f4e3c4 246
7a22745a
LP
247 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
248 return -EINVAL;
42f4e3c4 249
7a22745a 250 return 0;
42f4e3c4 251
7a22745a
LP
252 case AF_UNIX:
253 if (a->size < offsetof(struct sockaddr_un, sun_path))
254 return -EINVAL;
42f4e3c4 255
7a22745a 256 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 257
7a22745a
LP
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;
42f4e3c4 267 }
7a22745a 268 }
42f4e3c4 269
5a2b80ce 270 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
7a22745a 271 return -EINVAL;
42f4e3c4 272
7a22745a
LP
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;
42f4e3c4
LP
287 }
288}
289
542563ba 290int socket_address_print(const SocketAddress *a, char **p) {
42f4e3c4
LP
291 int r;
292 assert(a);
293 assert(p);
294
542563ba 295 if ((r = socket_address_verify(a)) < 0)
42f4e3c4
LP
296 return r;
297
542563ba 298 switch (socket_address_family(a)) {
42f4e3c4 299
7a22745a
LP
300 case AF_INET: {
301 char *ret;
42f4e3c4 302
7a22745a
LP
303 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
304 return -ENOMEM;
42f4e3c4 305
7a22745a
LP
306 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
307 free(ret);
308 return -errno;
42f4e3c4
LP
309 }
310
7a22745a
LP
311 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
312 *p = ret;
313 return 0;
314 }
42f4e3c4 315
7a22745a
LP
316 case AF_INET6: {
317 char *ret;
42f4e3c4 318
7a22745a
LP
319 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
320 return -ENOMEM;
42f4e3c4 321
7a22745a
LP
322 ret[0] = '[';
323 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
324 free(ret);
325 return -errno;
42f4e3c4
LP
326 }
327
7a22745a
LP
328 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
329 *p = ret;
330 return 0;
331 }
42f4e3c4 332
7a22745a
LP
333 case AF_UNIX: {
334 char *ret;
42f4e3c4 335
7a22745a 336 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 337
7a22745a
LP
338 if (!(ret = strdup("<unnamed>")))
339 return -ENOMEM;
42f4e3c4 340
7a22745a
LP
341 } else if (a->sockaddr.un.sun_path[0] == 0) {
342 /* abstract */
42f4e3c4 343
7a22745a
LP
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 */
42f4e3c4 348
7a22745a
LP
349 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
350 return -ENOMEM;
42f4e3c4 351
7a22745a
LP
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;
42f4e3c4 355
7a22745a 356 } else {
42f4e3c4 357
7a22745a
LP
358 if (!(ret = strdup(a->sockaddr.un.sun_path)))
359 return -ENOMEM;
42f4e3c4
LP
360 }
361
7a22745a
LP
362 *p = ret;
363 return 0;
364 }
365
366 case AF_NETLINK: {
7fd1b19b 367 _cleanup_free_ char *sfamily = NULL;
7a22745a 368
f8b69d1d 369 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
7a22745a 370 if (r < 0)
f8b69d1d
MS
371 return r;
372 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
8520cfa5
MS
373 if (r < 0)
374 return -ENOMEM;
7a22745a
LP
375
376 return 0;
377 }
378
379 default:
380 return -EINVAL;
42f4e3c4
LP
381 }
382}
383
4f2d528d
LP
384bool socket_address_can_accept(const SocketAddress *a) {
385 assert(a);
386
387 return
388 a->type == SOCK_STREAM ||
389 a->type == SOCK_SEQPACKET;
390}
a16e1123
LP
391
392bool 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]) {
641906e9 436 if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
a16e1123
LP
437 return false;
438 } else {
b12c1e7c 439 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
a16e1123
LP
440 return false;
441 }
442
443 break;
444
7a22745a
LP
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
a16e1123
LP
455 default:
456 /* Cannot compare, so we assume the addresses are different */
457 return false;
458 }
459
460 return true;
461}
462
27ca8d7a 463bool socket_address_is(const SocketAddress *a, const char *s, int type) {
a16e1123
LP
464 struct SocketAddress b;
465
466 assert(a);
467 assert(s);
468
469 if (socket_address_parse(&b, s) < 0)
470 return false;
471
27ca8d7a
LP
472 b.type = type;
473
a16e1123 474 return socket_address_equal(a, &b);
6e2ef85b
LP
475}
476
7a22745a
LP
477bool 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
6e2ef85b
LP
489bool 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;
a16e1123 497
6e2ef85b 498 return path_startswith(a->sockaddr.un.sun_path, prefix);
a16e1123 499}
c0120d99 500
5bfcc1c6 501bool socket_ipv6_is_supported(void) {
f89f1e8f
AB
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;
5bfcc1c6
FF
517}
518
01e10de3
LP
519bool 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
2ca0435b
ZJS
568int make_socket_fd(const char* address, int flags) {
569 SocketAddress a;
570 int fd, r;
7fd1b19b 571 _cleanup_free_ char *p = NULL;
2ca0435b
ZJS
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
7a22745a
LP
607static 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
f8b69d1d 627DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
7a22745a 628
c0120d99
LP
629static 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
635DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);