]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-util.c
udev: move man pages to udev section
[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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
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"
37#include "socket-util.h"
16c42ce1 38#include "missing.h"
e51bc1a2 39#include "label.h"
42f4e3c4 40
542563ba 41int socket_address_parse(SocketAddress *a, const char *s) {
42f4e3c4
LP
42 int r;
43 char *e, *n;
44 unsigned u;
45
46 assert(a);
47 assert(s);
48
9152c765 49 zero(*a);
542563ba 50 a->type = SOCK_STREAM;
42f4e3c4
LP
51
52 if (*s == '[') {
53 /* IPv6 in [x:.....:z]:p notation */
54
5bfcc1c6
FF
55 if (!socket_ipv6_is_supported()) {
56 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
57 return -EAFNOSUPPORT;
58 }
59
42f4e3c4
LP
60 if (!(e = strchr(s+1, ']')))
61 return -EINVAL;
62
63 if (!(n = strndup(s+1, e-s-1)))
64 return -ENOMEM;
65
66 errno = 0;
67 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
68 free(n);
69 return errno != 0 ? -errno : -EINVAL;
70 }
71
72 free(n);
73
74 e++;
75 if (*e != ':')
76 return -EINVAL;
77
78 e++;
79 if ((r = safe_atou(e, &u)) < 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);
42f4e3c4
LP
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);
0e098b15 100 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
42f4e3c4 101
1c24e7bd 102 } else if (*s == '@') {
42f4e3c4
LP
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);
0e098b15 112 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
42f4e3c4
LP
113
114 } else {
115
116 if ((e = strchr(s, ':'))) {
542563ba
LP
117
118 if ((r = safe_atou(e+1, &u)) < 0)
119 return r;
120
121 if (u <= 0 || u > 0xFFFF)
122 return -EINVAL;
42f4e3c4 123
42f4e3c4
LP
124 if (!(n = strndup(s, e-s)))
125 return -ENOMEM;
126
542563ba
LP
127 /* IPv4 in w.x.y.z:p notation? */
128 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
42f4e3c4 129 free(n);
542563ba 130 return -errno;
42f4e3c4
LP
131 }
132
542563ba
LP
133 if (r > 0) {
134 /* Gotcha, it's a traditional IPv4 address */
135 free(n);
42f4e3c4 136
542563ba
LP
137 a->sockaddr.in4.sin_family = AF_INET;
138 a->sockaddr.in4.sin_port = htons((uint16_t) u);
139 a->size = sizeof(struct sockaddr_in);
140 } else {
141 unsigned idx;
42f4e3c4 142
acbb0225
LP
143 if (strlen(n) > IF_NAMESIZE-1) {
144 free(n);
145 return -EINVAL;
146 }
147
542563ba
LP
148 /* Uh, our last resort, an interface name */
149 idx = if_nametoindex(n);
150 free(n);
151
83c60c9f 152 if (idx == 0)
542563ba 153 return -EINVAL;
42f4e3c4 154
5bfcc1c6
FF
155 if (!socket_ipv6_is_supported()) {
156 log_warning("Binding to interface is not available since kernel does not support IPv6.");
157 return -EAFNOSUPPORT;
158 }
159
542563ba
LP
160 a->sockaddr.in6.sin6_family = AF_INET6;
161 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
162 a->sockaddr.in6.sin6_scope_id = idx;
83c60c9f 163 a->sockaddr.in6.sin6_addr = in6addr_any;
542563ba
LP
164 a->size = sizeof(struct sockaddr_in6);
165 }
42f4e3c4
LP
166 } else {
167
168 /* Just a port */
169 if ((r = safe_atou(s, &u)) < 0)
170 return r;
171
172 if (u <= 0 || u > 0xFFFF)
173 return -EINVAL;
174
5bfcc1c6
FF
175 if (socket_ipv6_is_supported()) {
176 a->sockaddr.in6.sin6_family = AF_INET6;
177 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
178 a->sockaddr.in6.sin6_addr = in6addr_any;
179 a->size = sizeof(struct sockaddr_in6);
180 } else {
181 a->sockaddr.in4.sin_family = AF_INET;
182 a->sockaddr.in4.sin_port = htons((uint16_t) u);
183 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
184 a->size = sizeof(struct sockaddr_in);
185 }
42f4e3c4
LP
186 }
187 }
188
189 return 0;
190}
191
7a22745a
LP
192int socket_address_parse_netlink(SocketAddress *a, const char *s) {
193 int family;
194 unsigned group = 0;
195 char* sfamily = NULL;
196 assert(a);
197 assert(s);
198
199 zero(*a);
200 a->type = SOCK_RAW;
201
202 errno = 0;
203 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
204 return errno ? -errno : -EINVAL;
205
206 if ((family = netlink_family_from_string(sfamily)) < 0)
207 if (safe_atoi(sfamily, &family) < 0) {
208 free(sfamily);
209 return -EINVAL;
210 }
211
212 free(sfamily);
213
214 a->sockaddr.nl.nl_family = AF_NETLINK;
215 a->sockaddr.nl.nl_groups = group;
216
217 a->type = SOCK_RAW;
218 a->size = sizeof(struct sockaddr_nl);
219 a->protocol = family;
220
221 return 0;
222}
223
542563ba 224int socket_address_verify(const SocketAddress *a) {
42f4e3c4
LP
225 assert(a);
226
542563ba 227 switch (socket_address_family(a)) {
42f4e3c4 228
7a22745a
LP
229 case AF_INET:
230 if (a->size != sizeof(struct sockaddr_in))
231 return -EINVAL;
42f4e3c4 232
7a22745a
LP
233 if (a->sockaddr.in4.sin_port == 0)
234 return -EINVAL;
42f4e3c4 235
7a22745a
LP
236 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
237 return -EINVAL;
42f4e3c4 238
7a22745a
LP
239 return 0;
240
241 case AF_INET6:
242 if (a->size != sizeof(struct sockaddr_in6))
243 return -EINVAL;
42f4e3c4 244
7a22745a
LP
245 if (a->sockaddr.in6.sin6_port == 0)
246 return -EINVAL;
42f4e3c4 247
7a22745a
LP
248 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
249 return -EINVAL;
42f4e3c4 250
7a22745a 251 return 0;
42f4e3c4 252
7a22745a
LP
253 case AF_UNIX:
254 if (a->size < offsetof(struct sockaddr_un, sun_path))
255 return -EINVAL;
42f4e3c4 256
7a22745a 257 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 258
7a22745a
LP
259 if (a->sockaddr.un.sun_path[0] != 0) {
260 char *e;
261
262 /* path */
263 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
264 return -EINVAL;
265
266 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
267 return -EINVAL;
42f4e3c4 268 }
7a22745a 269 }
42f4e3c4 270
5a2b80ce 271 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
7a22745a 272 return -EINVAL;
42f4e3c4 273
7a22745a
LP
274 return 0;
275
276 case AF_NETLINK:
277
278 if (a->size != sizeof(struct sockaddr_nl))
279 return -EINVAL;
280
281 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
282 return -EINVAL;
283
284 return 0;
285
286 default:
287 return -EAFNOSUPPORT;
42f4e3c4
LP
288 }
289}
290
542563ba 291int socket_address_print(const SocketAddress *a, char **p) {
42f4e3c4
LP
292 int r;
293 assert(a);
294 assert(p);
295
542563ba 296 if ((r = socket_address_verify(a)) < 0)
42f4e3c4
LP
297 return r;
298
542563ba 299 switch (socket_address_family(a)) {
42f4e3c4 300
7a22745a
LP
301 case AF_INET: {
302 char *ret;
42f4e3c4 303
7a22745a
LP
304 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
305 return -ENOMEM;
42f4e3c4 306
7a22745a
LP
307 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
308 free(ret);
309 return -errno;
42f4e3c4
LP
310 }
311
7a22745a
LP
312 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
313 *p = ret;
314 return 0;
315 }
42f4e3c4 316
7a22745a
LP
317 case AF_INET6: {
318 char *ret;
42f4e3c4 319
7a22745a
LP
320 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
321 return -ENOMEM;
42f4e3c4 322
7a22745a
LP
323 ret[0] = '[';
324 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
325 free(ret);
326 return -errno;
42f4e3c4
LP
327 }
328
7a22745a
LP
329 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
330 *p = ret;
331 return 0;
332 }
42f4e3c4 333
7a22745a
LP
334 case AF_UNIX: {
335 char *ret;
42f4e3c4 336
7a22745a 337 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 338
7a22745a
LP
339 if (!(ret = strdup("<unnamed>")))
340 return -ENOMEM;
42f4e3c4 341
7a22745a
LP
342 } else if (a->sockaddr.un.sun_path[0] == 0) {
343 /* abstract */
42f4e3c4 344
7a22745a
LP
345 /* FIXME: We assume we can print the
346 * socket path here and that it hasn't
347 * more than one NUL byte. That is
348 * actually an invalid assumption */
42f4e3c4 349
7a22745a
LP
350 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
351 return -ENOMEM;
42f4e3c4 352
7a22745a
LP
353 ret[0] = '@';
354 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
355 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
42f4e3c4 356
7a22745a 357 } else {
42f4e3c4 358
7a22745a
LP
359 if (!(ret = strdup(a->sockaddr.un.sun_path)))
360 return -ENOMEM;
42f4e3c4
LP
361 }
362
7a22745a
LP
363 *p = ret;
364 return 0;
365 }
366
367 case AF_NETLINK: {
368 const char *sfamily;
369
370 if ((sfamily = netlink_family_to_string(a->protocol)))
371 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
372 else
373 r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups);
374
375 if (r < 0)
376 return -ENOMEM;
377
378 return 0;
379 }
380
381 default:
382 return -EINVAL;
42f4e3c4
LP
383 }
384}
385
b5a0699f
LP
386int socket_address_listen(
387 const SocketAddress *a,
388 int backlog,
389 SocketAddressBindIPv6Only only,
390 const char *bind_to_device,
4fd5948e 391 bool free_bind,
6b6d2dee 392 bool transparent,
b5a0699f
LP
393 mode_t directory_mode,
394 mode_t socket_mode,
56cf987f 395 const char *label,
b5a0699f
LP
396 int *ret) {
397
acbb0225 398 int r, fd, one;
42f4e3c4 399 assert(a);
83c60c9f 400 assert(ret);
42f4e3c4 401
542563ba 402 if ((r = socket_address_verify(a)) < 0)
42f4e3c4
LP
403 return r;
404
5bfcc1c6
FF
405 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
406 return -EAFNOSUPPORT;
407
56cf987f
DW
408 r = label_socket_set(label);
409 if (r < 0)
410 return r;
7a58bfa4 411
7a22745a 412 fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, a->protocol);
7a58bfa4 413 r = fd < 0 ? -errno : 0;
b15bdda8 414
56cf987f 415 label_socket_clear();
7a58bfa4
DW
416
417 if (r < 0)
418 return r;
42f4e3c4 419
542563ba
LP
420 if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
421 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
422
acbb0225
LP
423 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
424 goto fail;
542563ba
LP
425 }
426
7a22745a
LP
427 if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
428 if (bind_to_device)
429 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
430 goto fail;
acbb0225 431
7a22745a
LP
432 if (free_bind) {
433 one = 1;
434 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
435 log_warning("IP_FREEBIND failed: %m");
436 }
6b6d2dee
LP
437
438 if (transparent) {
439 one = 1;
440 if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
441 log_warning("IP_TRANSPARENT failed: %m");
442 }
4fd5948e
LP
443 }
444
acbb0225
LP
445 one = 1;
446 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
447 goto fail;
448
b5a0699f
LP
449 if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
450 mode_t old_mask;
451
452 /* Create parents */
453 mkdir_parents(a->sockaddr.un.sun_path, directory_mode);
454
455 /* Enforce the right access mode for the socket*/
456 old_mask = umask(~ socket_mode);
457
458 /* Include the original umask in our mask */
459 umask(~socket_mode | old_mask);
460
f13e30d2 461 r = label_bind(fd, &a->sockaddr.sa, a->size);
b5a0699f
LP
462
463 if (r < 0 && errno == EADDRINUSE) {
464 /* Unlink and try again */
465 unlink(a->sockaddr.un.sun_path);
466 r = bind(fd, &a->sockaddr.sa, a->size);
467 }
468
469 umask(old_mask);
470 } else
471 r = bind(fd, &a->sockaddr.sa, a->size);
472
473 if (r < 0)
acbb0225 474 goto fail;
42f4e3c4 475
7a22745a 476 if (socket_address_can_accept(a))
acbb0225
LP
477 if (listen(fd, backlog) < 0)
478 goto fail;
42f4e3c4 479
83c60c9f 480 *ret = fd;
42f4e3c4 481 return 0;
acbb0225
LP
482
483fail:
484 r = -errno;
a16e1123 485 close_nointr_nofail(fd);
acbb0225 486 return r;
42f4e3c4 487}
4f2d528d
LP
488
489bool socket_address_can_accept(const SocketAddress *a) {
490 assert(a);
491
492 return
493 a->type == SOCK_STREAM ||
494 a->type == SOCK_SEQPACKET;
495}
a16e1123
LP
496
497bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
498 assert(a);
499 assert(b);
500
501 /* Invalid addresses are unequal to all */
502 if (socket_address_verify(a) < 0 ||
503 socket_address_verify(b) < 0)
504 return false;
505
506 if (a->type != b->type)
507 return false;
508
509 if (a->size != b->size)
510 return false;
511
512 if (socket_address_family(a) != socket_address_family(b))
513 return false;
514
515 switch (socket_address_family(a)) {
516
517 case AF_INET:
518 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
519 return false;
520
521 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
522 return false;
523
524 break;
525
526 case AF_INET6:
527 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
528 return false;
529
530 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
531 return false;
532
533 break;
534
535 case AF_UNIX:
536
537 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
538 return false;
539
540 if (a->sockaddr.un.sun_path[0]) {
541 if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
542 return false;
543 } else {
b12c1e7c 544 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
a16e1123
LP
545 return false;
546 }
547
548 break;
549
7a22745a
LP
550 case AF_NETLINK:
551
552 if (a->protocol != b->protocol)
553 return false;
554
555 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
556 return false;
557
558 break;
559
a16e1123
LP
560 default:
561 /* Cannot compare, so we assume the addresses are different */
562 return false;
563 }
564
565 return true;
566}
567
27ca8d7a 568bool socket_address_is(const SocketAddress *a, const char *s, int type) {
a16e1123
LP
569 struct SocketAddress b;
570
571 assert(a);
572 assert(s);
573
574 if (socket_address_parse(&b, s) < 0)
575 return false;
576
27ca8d7a
LP
577 b.type = type;
578
a16e1123 579 return socket_address_equal(a, &b);
6e2ef85b
LP
580}
581
7a22745a
LP
582bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
583 struct SocketAddress b;
584
585 assert(a);
586 assert(s);
587
588 if (socket_address_parse_netlink(&b, s) < 0)
589 return false;
590
591 return socket_address_equal(a, &b);
592}
593
6e2ef85b
LP
594bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
595 assert(a);
596
597 if (socket_address_family(a) != AF_UNIX)
598 return false;
599
600 if (a->sockaddr.un.sun_path[0] == 0)
601 return false;
a16e1123 602
6e2ef85b 603 return path_startswith(a->sockaddr.un.sun_path, prefix);
a16e1123 604}
c0120d99 605
5bfcc1c6 606bool socket_ipv6_is_supported(void) {
f89f1e8f
AB
607 char *l = 0;
608 bool enabled;
609
610 if (access("/sys/module/ipv6", F_OK) != 0)
611 return 0;
612
613 /* If we can't check "disable" parameter, assume enabled */
614 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
615 return 1;
616
617 /* If module was loaded with disable=1 no IPv6 available */
618 enabled = l[0] == '0';
619 free(l);
620
621 return enabled;
5bfcc1c6
FF
622}
623
7a22745a
LP
624static const char* const netlink_family_table[] = {
625 [NETLINK_ROUTE] = "route",
626 [NETLINK_FIREWALL] = "firewall",
627 [NETLINK_INET_DIAG] = "inet-diag",
628 [NETLINK_NFLOG] = "nflog",
629 [NETLINK_XFRM] = "xfrm",
630 [NETLINK_SELINUX] = "selinux",
631 [NETLINK_ISCSI] = "iscsi",
632 [NETLINK_AUDIT] = "audit",
633 [NETLINK_FIB_LOOKUP] = "fib-lookup",
634 [NETLINK_CONNECTOR] = "connector",
635 [NETLINK_NETFILTER] = "netfilter",
636 [NETLINK_IP6_FW] = "ip6-fw",
637 [NETLINK_DNRTMSG] = "dnrtmsg",
638 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
639 [NETLINK_GENERIC] = "generic",
640 [NETLINK_SCSITRANSPORT] = "scsitransport",
641 [NETLINK_ECRYPTFS] = "ecryptfs"
642};
643
644DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
645
c0120d99
LP
646static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
647 [SOCKET_ADDRESS_DEFAULT] = "default",
648 [SOCKET_ADDRESS_BOTH] = "both",
649 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
650};
651
652DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);