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