chiark / gitweb /
Prep v228: Add remaining updates from upstream (1/3)
[elogind.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 }