]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/socket-util.c
util-lib: split string parsing related calls from util.[ch] into parse-util.[ch]
[thirdparty/systemd.git] / src / basic / 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 <arpa/inet.h>
23 #include <errno.h>
24 #include <net/if.h>
25 #include <netdb.h>
26 #include <netinet/ip.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32
33 #include "fd-util.h"
34 #include "fileio.h"
35 #include "formats-util.h"
36 #include "macro.h"
37 #include "missing.h"
38 #include "parse-util.h"
39 #include "path-util.h"
40 #include "socket-util.h"
41 #include "string-util.h"
42 #include "util.h"
43
44 int socket_address_parse(SocketAddress *a, const char *s) {
45 char *e, *n;
46 unsigned u;
47 int r;
48
49 assert(a);
50 assert(s);
51
52 zero(*a);
53 a->type = SOCK_STREAM;
54
55 if (*s == '[') {
56 /* IPv6 in [x:.....:z]:p notation */
57
58 e = strchr(s+1, ']');
59 if (!e)
60 return -EINVAL;
61
62 n = strndupa(s+1, e-s-1);
63
64 errno = 0;
65 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
66 return errno > 0 ? -errno : -EINVAL;
67
68 e++;
69 if (*e != ':')
70 return -EINVAL;
71
72 e++;
73 r = safe_atou(e, &u);
74 if (r < 0)
75 return r;
76
77 if (u <= 0 || u > 0xFFFF)
78 return -EINVAL;
79
80 a->sockaddr.in6.sin6_family = AF_INET6;
81 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
82 a->size = sizeof(struct sockaddr_in6);
83
84 } else if (*s == '/') {
85 /* AF_UNIX socket */
86
87 size_t l;
88
89 l = strlen(s);
90 if (l >= sizeof(a->sockaddr.un.sun_path))
91 return -EINVAL;
92
93 a->sockaddr.un.sun_family = AF_UNIX;
94 memcpy(a->sockaddr.un.sun_path, s, l);
95 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
96
97 } else if (*s == '@') {
98 /* Abstract AF_UNIX socket */
99 size_t l;
100
101 l = strlen(s+1);
102 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
103 return -EINVAL;
104
105 a->sockaddr.un.sun_family = AF_UNIX;
106 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
107 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
108
109 } else {
110 e = strchr(s, ':');
111 if (e) {
112 r = safe_atou(e+1, &u);
113 if (r < 0)
114 return r;
115
116 if (u <= 0 || u > 0xFFFF)
117 return -EINVAL;
118
119 n = strndupa(s, e-s);
120
121 /* IPv4 in w.x.y.z:p notation? */
122 r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
123 if (r < 0)
124 return -errno;
125
126 if (r > 0) {
127 /* Gotcha, it's a traditional IPv4 address */
128 a->sockaddr.in.sin_family = AF_INET;
129 a->sockaddr.in.sin_port = htons((uint16_t) u);
130 a->size = sizeof(struct sockaddr_in);
131 } else {
132 unsigned idx;
133
134 if (strlen(n) > IF_NAMESIZE-1)
135 return -EINVAL;
136
137 /* Uh, our last resort, an interface name */
138 idx = if_nametoindex(n);
139 if (idx == 0)
140 return -EINVAL;
141
142 a->sockaddr.in6.sin6_family = AF_INET6;
143 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
144 a->sockaddr.in6.sin6_scope_id = idx;
145 a->sockaddr.in6.sin6_addr = in6addr_any;
146 a->size = sizeof(struct sockaddr_in6);
147 }
148 } else {
149
150 /* Just a port */
151 r = safe_atou(s, &u);
152 if (r < 0)
153 return r;
154
155 if (u <= 0 || u > 0xFFFF)
156 return -EINVAL;
157
158 if (socket_ipv6_is_supported()) {
159 a->sockaddr.in6.sin6_family = AF_INET6;
160 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
161 a->sockaddr.in6.sin6_addr = in6addr_any;
162 a->size = sizeof(struct sockaddr_in6);
163 } else {
164 a->sockaddr.in.sin_family = AF_INET;
165 a->sockaddr.in.sin_port = htons((uint16_t) u);
166 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
167 a->size = sizeof(struct sockaddr_in);
168 }
169 }
170 }
171
172 return 0;
173 }
174
175 int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
176 SocketAddress b;
177 int r;
178
179 /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
180
181 r = socket_address_parse(&b, s);
182 if (r < 0)
183 return r;
184
185 if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
186 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
187 return -EAFNOSUPPORT;
188 }
189
190 *a = b;
191 return 0;
192 }
193
194 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
195 int family;
196 unsigned group = 0;
197 _cleanup_free_ char *sfamily = NULL;
198 assert(a);
199 assert(s);
200
201 zero(*a);
202 a->type = SOCK_RAW;
203
204 errno = 0;
205 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
206 return errno > 0 ? -errno : -EINVAL;
207
208 family = netlink_family_from_string(sfamily);
209 if (family < 0)
210 return -EINVAL;
211
212 a->sockaddr.nl.nl_family = AF_NETLINK;
213 a->sockaddr.nl.nl_groups = group;
214
215 a->type = SOCK_RAW;
216 a->size = sizeof(struct sockaddr_nl);
217 a->protocol = family;
218
219 return 0;
220 }
221
222 int socket_address_verify(const SocketAddress *a) {
223 assert(a);
224
225 switch (socket_address_family(a)) {
226
227 case AF_INET:
228 if (a->size != sizeof(struct sockaddr_in))
229 return -EINVAL;
230
231 if (a->sockaddr.in.sin_port == 0)
232 return -EINVAL;
233
234 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
235 return -EINVAL;
236
237 return 0;
238
239 case AF_INET6:
240 if (a->size != sizeof(struct sockaddr_in6))
241 return -EINVAL;
242
243 if (a->sockaddr.in6.sin6_port == 0)
244 return -EINVAL;
245
246 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
247 return -EINVAL;
248
249 return 0;
250
251 case AF_UNIX:
252 if (a->size < offsetof(struct sockaddr_un, sun_path))
253 return -EINVAL;
254
255 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
256
257 if (a->sockaddr.un.sun_path[0] != 0) {
258 char *e;
259
260 /* path */
261 e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
262 if (!e)
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 **ret) {
291 int r;
292
293 assert(a);
294 assert(ret);
295
296 r = socket_address_verify(a);
297 if (r < 0)
298 return r;
299
300 if (socket_address_family(a) == AF_NETLINK) {
301 _cleanup_free_ char *sfamily = NULL;
302
303 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
304 if (r < 0)
305 return r;
306
307 r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
308 if (r < 0)
309 return -ENOMEM;
310
311 return 0;
312 }
313
314 return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret);
315 }
316
317 bool socket_address_can_accept(const SocketAddress *a) {
318 assert(a);
319
320 return
321 a->type == SOCK_STREAM ||
322 a->type == SOCK_SEQPACKET;
323 }
324
325 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
326 assert(a);
327 assert(b);
328
329 /* Invalid addresses are unequal to all */
330 if (socket_address_verify(a) < 0 ||
331 socket_address_verify(b) < 0)
332 return false;
333
334 if (a->type != b->type)
335 return false;
336
337 if (socket_address_family(a) != socket_address_family(b))
338 return false;
339
340 switch (socket_address_family(a)) {
341
342 case AF_INET:
343 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
344 return false;
345
346 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
347 return false;
348
349 break;
350
351 case AF_INET6:
352 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
353 return false;
354
355 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
356 return false;
357
358 break;
359
360 case AF_UNIX:
361 if (a->size <= offsetof(struct sockaddr_un, sun_path) ||
362 b->size <= offsetof(struct sockaddr_un, sun_path))
363 return false;
364
365 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
366 return false;
367
368 if (a->sockaddr.un.sun_path[0]) {
369 if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
370 return false;
371 } else {
372 if (a->size != b->size)
373 return false;
374
375 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
376 return false;
377 }
378
379 break;
380
381 case AF_NETLINK:
382 if (a->protocol != b->protocol)
383 return false;
384
385 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
386 return false;
387
388 break;
389
390 default:
391 /* Cannot compare, so we assume the addresses are different */
392 return false;
393 }
394
395 return true;
396 }
397
398 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
399 struct SocketAddress b;
400
401 assert(a);
402 assert(s);
403
404 if (socket_address_parse(&b, s) < 0)
405 return false;
406
407 b.type = type;
408
409 return socket_address_equal(a, &b);
410 }
411
412 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
413 struct SocketAddress b;
414
415 assert(a);
416 assert(s);
417
418 if (socket_address_parse_netlink(&b, s) < 0)
419 return false;
420
421 return socket_address_equal(a, &b);
422 }
423
424 const char* socket_address_get_path(const SocketAddress *a) {
425 assert(a);
426
427 if (socket_address_family(a) != AF_UNIX)
428 return NULL;
429
430 if (a->sockaddr.un.sun_path[0] == 0)
431 return NULL;
432
433 return a->sockaddr.un.sun_path;
434 }
435
436 bool socket_ipv6_is_supported(void) {
437 _cleanup_free_ char *l = NULL;
438
439 if (access("/sys/module/ipv6", F_OK) != 0)
440 return false;
441
442 /* If we can't check "disable" parameter, assume enabled */
443 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
444 return true;
445
446 /* If module was loaded with disable=1 no IPv6 available */
447 return l[0] == '0';
448 }
449
450 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
451 SocketAddress b;
452 socklen_t solen;
453
454 assert(a);
455 assert(fd >= 0);
456
457 b.size = sizeof(b.sockaddr);
458 if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
459 return false;
460
461 if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
462 return false;
463
464 solen = sizeof(b.type);
465 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
466 return false;
467
468 if (b.type != a->type)
469 return false;
470
471 if (a->protocol != 0) {
472 solen = sizeof(b.protocol);
473 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
474 return false;
475
476 if (b.protocol != a->protocol)
477 return false;
478 }
479
480 return socket_address_equal(a, &b);
481 }
482
483 int sockaddr_port(const struct sockaddr *_sa) {
484 union sockaddr_union *sa = (union sockaddr_union*) _sa;
485
486 assert(sa);
487
488 if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6))
489 return -EAFNOSUPPORT;
490
491 return ntohs(sa->sa.sa_family == AF_INET6 ?
492 sa->in6.sin6_port :
493 sa->in.sin_port);
494 }
495
496 int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
497 union sockaddr_union *sa = (union sockaddr_union*) _sa;
498 char *p;
499 int r;
500
501 assert(sa);
502 assert(salen >= sizeof(sa->sa.sa_family));
503
504 switch (sa->sa.sa_family) {
505
506 case AF_INET: {
507 uint32_t a;
508
509 a = ntohl(sa->in.sin_addr.s_addr);
510
511 if (include_port)
512 r = asprintf(&p,
513 "%u.%u.%u.%u:%u",
514 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
515 ntohs(sa->in.sin_port));
516 else
517 r = asprintf(&p,
518 "%u.%u.%u.%u",
519 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF);
520 if (r < 0)
521 return -ENOMEM;
522 break;
523 }
524
525 case AF_INET6: {
526 static const unsigned char ipv4_prefix[] = {
527 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
528 };
529
530 if (translate_ipv6 &&
531 memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
532 const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
533 if (include_port)
534 r = asprintf(&p,
535 "%u.%u.%u.%u:%u",
536 a[0], a[1], a[2], a[3],
537 ntohs(sa->in6.sin6_port));
538 else
539 r = asprintf(&p,
540 "%u.%u.%u.%u",
541 a[0], a[1], a[2], a[3]);
542 if (r < 0)
543 return -ENOMEM;
544 } else {
545 char a[INET6_ADDRSTRLEN];
546
547 inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
548
549 if (include_port) {
550 r = asprintf(&p,
551 "[%s]:%u",
552 a,
553 ntohs(sa->in6.sin6_port));
554 if (r < 0)
555 return -ENOMEM;
556 } else {
557 p = strdup(a);
558 if (!p)
559 return -ENOMEM;
560 }
561 }
562
563 break;
564 }
565
566 case AF_UNIX:
567 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
568 p = strdup("<unnamed>");
569 if (!p)
570 return -ENOMEM;
571
572 } else if (sa->un.sun_path[0] == 0) {
573 /* abstract */
574
575 /* FIXME: We assume we can print the
576 * socket path here and that it hasn't
577 * more than one NUL byte. That is
578 * actually an invalid assumption */
579
580 p = new(char, sizeof(sa->un.sun_path)+1);
581 if (!p)
582 return -ENOMEM;
583
584 p[0] = '@';
585 memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
586 p[sizeof(sa->un.sun_path)] = 0;
587
588 } else {
589 p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
590 if (!p)
591 return -ENOMEM;
592 }
593
594 break;
595
596 default:
597 return -EOPNOTSUPP;
598 }
599
600
601 *ret = p;
602 return 0;
603 }
604
605 int getpeername_pretty(int fd, char **ret) {
606 union sockaddr_union sa;
607 socklen_t salen = sizeof(sa);
608 int r;
609
610 assert(fd >= 0);
611 assert(ret);
612
613 if (getpeername(fd, &sa.sa, &salen) < 0)
614 return -errno;
615
616 if (sa.sa.sa_family == AF_UNIX) {
617 struct ucred ucred = {};
618
619 /* UNIX connection sockets are anonymous, so let's use
620 * PID/UID as pretty credentials instead */
621
622 r = getpeercred(fd, &ucred);
623 if (r < 0)
624 return r;
625
626 if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
627 return -ENOMEM;
628
629 return 0;
630 }
631
632 /* For remote sockets we translate IPv6 addresses back to IPv4
633 * if applicable, since that's nicer. */
634
635 return sockaddr_pretty(&sa.sa, salen, true, true, ret);
636 }
637
638 int getsockname_pretty(int fd, char **ret) {
639 union sockaddr_union sa;
640 socklen_t salen = sizeof(sa);
641
642 assert(fd >= 0);
643 assert(ret);
644
645 if (getsockname(fd, &sa.sa, &salen) < 0)
646 return -errno;
647
648 /* For local sockets we do not translate IPv6 addresses back
649 * to IPv6 if applicable, since this is usually used for
650 * listening sockets where the difference between IPv4 and
651 * IPv6 matters. */
652
653 return sockaddr_pretty(&sa.sa, salen, false, true, ret);
654 }
655
656 int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
657 int r;
658 char host[NI_MAXHOST], *ret;
659
660 assert(_ret);
661
662 r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
663 NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
664 if (r != 0) {
665 int saved_errno = errno;
666
667 r = sockaddr_pretty(&sa->sa, salen, true, true, &ret);
668 if (r < 0)
669 return r;
670
671 log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
672 } else {
673 ret = strdup(host);
674 if (!ret)
675 return -ENOMEM;
676 }
677
678 *_ret = ret;
679 return 0;
680 }
681
682 int getnameinfo_pretty(int fd, char **ret) {
683 union sockaddr_union sa;
684 socklen_t salen = sizeof(sa);
685
686 assert(fd >= 0);
687 assert(ret);
688
689 if (getsockname(fd, &sa.sa, &salen) < 0)
690 return -errno;
691
692 return socknameinfo_pretty(&sa, salen, ret);
693 }
694
695 int socket_address_unlink(SocketAddress *a) {
696 assert(a);
697
698 if (socket_address_family(a) != AF_UNIX)
699 return 0;
700
701 if (a->sockaddr.un.sun_path[0] == 0)
702 return 0;
703
704 if (unlink(a->sockaddr.un.sun_path) < 0)
705 return -errno;
706
707 return 1;
708 }
709
710 static const char* const netlink_family_table[] = {
711 [NETLINK_ROUTE] = "route",
712 [NETLINK_FIREWALL] = "firewall",
713 [NETLINK_INET_DIAG] = "inet-diag",
714 [NETLINK_NFLOG] = "nflog",
715 [NETLINK_XFRM] = "xfrm",
716 [NETLINK_SELINUX] = "selinux",
717 [NETLINK_ISCSI] = "iscsi",
718 [NETLINK_AUDIT] = "audit",
719 [NETLINK_FIB_LOOKUP] = "fib-lookup",
720 [NETLINK_CONNECTOR] = "connector",
721 [NETLINK_NETFILTER] = "netfilter",
722 [NETLINK_IP6_FW] = "ip6-fw",
723 [NETLINK_DNRTMSG] = "dnrtmsg",
724 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
725 [NETLINK_GENERIC] = "generic",
726 [NETLINK_SCSITRANSPORT] = "scsitransport",
727 [NETLINK_ECRYPTFS] = "ecryptfs"
728 };
729
730 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
731
732 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
733 [SOCKET_ADDRESS_DEFAULT] = "default",
734 [SOCKET_ADDRESS_BOTH] = "both",
735 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
736 };
737
738 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
739
740 bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
741 assert(a);
742 assert(b);
743
744 if (a->sa.sa_family != b->sa.sa_family)
745 return false;
746
747 if (a->sa.sa_family == AF_INET)
748 return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
749
750 if (a->sa.sa_family == AF_INET6)
751 return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
752
753 return false;
754 }
755
756 int fd_inc_sndbuf(int fd, size_t n) {
757 int r, value;
758 socklen_t l = sizeof(value);
759
760 r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
761 if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
762 return 0;
763
764 /* If we have the privileges we will ignore the kernel limit. */
765
766 value = (int) n;
767 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
768 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
769 return -errno;
770
771 return 1;
772 }
773
774 int fd_inc_rcvbuf(int fd, size_t n) {
775 int r, value;
776 socklen_t l = sizeof(value);
777
778 r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
779 if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
780 return 0;
781
782 /* If we have the privileges we will ignore the kernel limit. */
783
784 value = (int) n;
785 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
786 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
787 return -errno;
788 return 1;
789 }
790
791 static const char* const ip_tos_table[] = {
792 [IPTOS_LOWDELAY] = "low-delay",
793 [IPTOS_THROUGHPUT] = "throughput",
794 [IPTOS_RELIABILITY] = "reliability",
795 [IPTOS_LOWCOST] = "low-cost",
796 };
797
798 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
799
800 int getpeercred(int fd, struct ucred *ucred) {
801 socklen_t n = sizeof(struct ucred);
802 struct ucred u;
803 int r;
804
805 assert(fd >= 0);
806 assert(ucred);
807
808 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
809 if (r < 0)
810 return -errno;
811
812 if (n != sizeof(struct ucred))
813 return -EIO;
814
815 /* Check if the data is actually useful and not suppressed due
816 * to namespacing issues */
817 if (u.pid <= 0)
818 return -ENODATA;
819 if (u.uid == UID_INVALID)
820 return -ENODATA;
821 if (u.gid == GID_INVALID)
822 return -ENODATA;
823
824 *ucred = u;
825 return 0;
826 }
827
828 int getpeersec(int fd, char **ret) {
829 socklen_t n = 64;
830 char *s;
831 int r;
832
833 assert(fd >= 0);
834 assert(ret);
835
836 s = new0(char, n);
837 if (!s)
838 return -ENOMEM;
839
840 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
841 if (r < 0) {
842 free(s);
843
844 if (errno != ERANGE)
845 return -errno;
846
847 s = new0(char, n);
848 if (!s)
849 return -ENOMEM;
850
851 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
852 if (r < 0) {
853 free(s);
854 return -errno;
855 }
856 }
857
858 if (isempty(s)) {
859 free(s);
860 return -EOPNOTSUPP;
861 }
862
863 *ret = s;
864 return 0;
865 }
866
867 int send_one_fd(int transport_fd, int fd, int flags) {
868 union {
869 struct cmsghdr cmsghdr;
870 uint8_t buf[CMSG_SPACE(sizeof(int))];
871 } control = {};
872 struct msghdr mh = {
873 .msg_control = &control,
874 .msg_controllen = sizeof(control),
875 };
876 struct cmsghdr *cmsg;
877
878 assert(transport_fd >= 0);
879 assert(fd >= 0);
880
881 cmsg = CMSG_FIRSTHDR(&mh);
882 cmsg->cmsg_level = SOL_SOCKET;
883 cmsg->cmsg_type = SCM_RIGHTS;
884 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
885 memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
886
887 mh.msg_controllen = CMSG_SPACE(sizeof(int));
888 if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0)
889 return -errno;
890
891 return 0;
892 }
893
894 int receive_one_fd(int transport_fd, int flags) {
895 union {
896 struct cmsghdr cmsghdr;
897 uint8_t buf[CMSG_SPACE(sizeof(int))];
898 } control = {};
899 struct msghdr mh = {
900 .msg_control = &control,
901 .msg_controllen = sizeof(control),
902 };
903 struct cmsghdr *cmsg, *found = NULL;
904
905 assert(transport_fd >= 0);
906
907 /*
908 * Receive a single FD via @transport_fd. We don't care for
909 * the transport-type. We retrieve a single FD at most, so for
910 * packet-based transports, the caller must ensure to send
911 * only a single FD per packet. This is best used in
912 * combination with send_one_fd().
913 */
914
915 if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0)
916 return -errno;
917
918 CMSG_FOREACH(cmsg, &mh) {
919 if (cmsg->cmsg_level == SOL_SOCKET &&
920 cmsg->cmsg_type == SCM_RIGHTS &&
921 cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
922 assert(!found);
923 found = cmsg;
924 break;
925 }
926 }
927
928 if (!found) {
929 cmsg_close_all(&mh);
930 return -EIO;
931 }
932
933 return *(int*) CMSG_DATA(found);
934 }