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