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