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