chiark / gitweb /
563c7db607dbde64f2eba4e5591a654a427ab884
[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 #if 0 /// UNNEEDED by elogind
48 int socket_address_parse(SocketAddress *a, const char *s) {
49         char *e, *n;
50         unsigned u;
51         int r;
52
53         assert(a);
54         assert(s);
55
56         zero(*a);
57         a->type = SOCK_STREAM;
58
59         if (*s == '[') {
60                 /* IPv6 in [x:.....:z]:p notation */
61
62                 e = strchr(s+1, ']');
63                 if (!e)
64                         return -EINVAL;
65
66                 n = strndupa(s+1, e-s-1);
67
68                 errno = 0;
69                 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
70                         return errno > 0 ? -errno : -EINVAL;
71
72                 e++;
73                 if (*e != ':')
74                         return -EINVAL;
75
76                 e++;
77                 r = safe_atou(e, &u);
78                 if (r < 0)
79                         return r;
80
81                 if (u <= 0 || u > 0xFFFF)
82                         return -EINVAL;
83
84                 a->sockaddr.in6.sin6_family = AF_INET6;
85                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
86                 a->size = sizeof(struct sockaddr_in6);
87
88         } else if (*s == '/') {
89                 /* AF_UNIX socket */
90
91                 size_t l;
92
93                 l = strlen(s);
94                 if (l >= sizeof(a->sockaddr.un.sun_path))
95                         return -EINVAL;
96
97                 a->sockaddr.un.sun_family = AF_UNIX;
98                 memcpy(a->sockaddr.un.sun_path, s, l);
99                 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
100
101         } else if (*s == '@') {
102                 /* Abstract AF_UNIX socket */
103                 size_t l;
104
105                 l = strlen(s+1);
106                 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
107                         return -EINVAL;
108
109                 a->sockaddr.un.sun_family = AF_UNIX;
110                 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
111                 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
112
113         } else {
114                 e = strchr(s, ':');
115                 if (e) {
116                         r = safe_atou(e+1, &u);
117                         if (r < 0)
118                                 return r;
119
120                         if (u <= 0 || u > 0xFFFF)
121                                 return -EINVAL;
122
123                         n = strndupa(s, e-s);
124
125                         /* IPv4 in w.x.y.z:p notation? */
126                         r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
127                         if (r < 0)
128                                 return -errno;
129
130                         if (r > 0) {
131                                 /* Gotcha, it's a traditional IPv4 address */
132                                 a->sockaddr.in.sin_family = AF_INET;
133                                 a->sockaddr.in.sin_port = htons((uint16_t) u);
134                                 a->size = sizeof(struct sockaddr_in);
135                         } else {
136                                 unsigned idx;
137
138                                 if (strlen(n) > IF_NAMESIZE-1)
139                                         return -EINVAL;
140
141                                 /* Uh, our last resort, an interface name */
142                                 idx = if_nametoindex(n);
143                                 if (idx == 0)
144                                         return -EINVAL;
145
146                                 a->sockaddr.in6.sin6_family = AF_INET6;
147                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
148                                 a->sockaddr.in6.sin6_scope_id = idx;
149                                 a->sockaddr.in6.sin6_addr = in6addr_any;
150                                 a->size = sizeof(struct sockaddr_in6);
151                         }
152                 } else {
153
154                         /* Just a port */
155                         r = safe_atou(s, &u);
156                         if (r < 0)
157                                 return r;
158
159                         if (u <= 0 || u > 0xFFFF)
160                                 return -EINVAL;
161
162                         if (socket_ipv6_is_supported()) {
163                                 a->sockaddr.in6.sin6_family = AF_INET6;
164                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
165                                 a->sockaddr.in6.sin6_addr = in6addr_any;
166                                 a->size = sizeof(struct sockaddr_in6);
167                         } else {
168                                 a->sockaddr.in.sin_family = AF_INET;
169                                 a->sockaddr.in.sin_port = htons((uint16_t) u);
170                                 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
171                                 a->size = sizeof(struct sockaddr_in);
172                         }
173                 }
174         }
175
176         return 0;
177 }
178
179 int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
180         SocketAddress b;
181         int r;
182
183         /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
184
185         r = socket_address_parse(&b, s);
186         if (r < 0)
187                 return r;
188
189         if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
190                 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
191                 return -EAFNOSUPPORT;
192         }
193
194         *a = b;
195         return 0;
196 }
197
198 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
199         int family;
200         unsigned group = 0;
201         _cleanup_free_ char *sfamily = NULL;
202         assert(a);
203         assert(s);
204
205         zero(*a);
206         a->type = SOCK_RAW;
207
208         errno = 0;
209         if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
210                 return errno > 0 ? -errno : -EINVAL;
211
212         family = netlink_family_from_string(sfamily);
213         if (family < 0)
214                 return -EINVAL;
215
216         a->sockaddr.nl.nl_family = AF_NETLINK;
217         a->sockaddr.nl.nl_groups = group;
218
219         a->type = SOCK_RAW;
220         a->size = sizeof(struct sockaddr_nl);
221         a->protocol = family;
222
223         return 0;
224 }
225
226 int socket_address_verify(const SocketAddress *a) {
227         assert(a);
228
229         switch (socket_address_family(a)) {
230
231         case AF_INET:
232                 if (a->size != sizeof(struct sockaddr_in))
233                         return -EINVAL;
234
235                 if (a->sockaddr.in.sin_port == 0)
236                         return -EINVAL;
237
238                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
239                         return -EINVAL;
240
241                 return 0;
242
243         case AF_INET6:
244                 if (a->size != sizeof(struct sockaddr_in6))
245                         return -EINVAL;
246
247                 if (a->sockaddr.in6.sin6_port == 0)
248                         return -EINVAL;
249
250                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
251                         return -EINVAL;
252
253                 return 0;
254
255         case AF_UNIX:
256                 if (a->size < offsetof(struct sockaddr_un, sun_path))
257                         return -EINVAL;
258
259                 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
260
261                         if (a->sockaddr.un.sun_path[0] != 0) {
262                                 char *e;
263
264                                 /* path */
265                                 e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
266                                 if (!e)
267                                         return -EINVAL;
268
269                                 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
270                                         return -EINVAL;
271                         }
272                 }
273
274                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
275                         return -EINVAL;
276
277                 return 0;
278
279         case AF_NETLINK:
280
281                 if (a->size != sizeof(struct sockaddr_nl))
282                         return -EINVAL;
283
284                 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
285                         return -EINVAL;
286
287                 return 0;
288
289         default:
290                 return -EAFNOSUPPORT;
291         }
292 }
293
294 int socket_address_print(const SocketAddress *a, char **ret) {
295         int r;
296
297         assert(a);
298         assert(ret);
299
300         r = socket_address_verify(a);
301         if (r < 0)
302                 return r;
303
304         if (socket_address_family(a) == AF_NETLINK) {
305                 _cleanup_free_ char *sfamily = NULL;
306
307                 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
308                 if (r < 0)
309                         return r;
310
311                 r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
312                 if (r < 0)
313                         return -ENOMEM;
314
315                 return 0;
316         }
317
318         return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret);
319 }
320
321 bool socket_address_can_accept(const SocketAddress *a) {
322         assert(a);
323
324         return
325                 a->type == SOCK_STREAM ||
326                 a->type == SOCK_SEQPACKET;
327 }
328
329 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
330         assert(a);
331         assert(b);
332
333         /* Invalid addresses are unequal to all */
334         if (socket_address_verify(a) < 0 ||
335             socket_address_verify(b) < 0)
336                 return false;
337
338         if (a->type != b->type)
339                 return false;
340
341         if (socket_address_family(a) != socket_address_family(b))
342                 return false;
343
344         switch (socket_address_family(a)) {
345
346         case AF_INET:
347                 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
348                         return false;
349
350                 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
351                         return false;
352
353                 break;
354
355         case AF_INET6:
356                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
357                         return false;
358
359                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
360                         return false;
361
362                 break;
363
364         case AF_UNIX:
365                 if (a->size <= offsetof(struct sockaddr_un, sun_path) ||
366                     b->size <= offsetof(struct sockaddr_un, sun_path))
367                         return false;
368
369                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
370                         return false;
371
372                 if (a->sockaddr.un.sun_path[0]) {
373                         if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
374                                 return false;
375                 } else {
376                         if (a->size != b->size)
377                                 return false;
378
379                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
380                                 return false;
381                 }
382
383                 break;
384
385         case AF_NETLINK:
386                 if (a->protocol != b->protocol)
387                         return false;
388
389                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
390                         return false;
391
392                 break;
393
394         default:
395                 /* Cannot compare, so we assume the addresses are different */
396                 return false;
397         }
398
399         return true;
400 }
401
402 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
403         struct SocketAddress b;
404
405         assert(a);
406         assert(s);
407
408         if (socket_address_parse(&b, s) < 0)
409                 return false;
410
411         b.type = type;
412
413         return socket_address_equal(a, &b);
414 }
415
416 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
417         struct SocketAddress b;
418
419         assert(a);
420         assert(s);
421
422         if (socket_address_parse_netlink(&b, s) < 0)
423                 return false;
424
425         return socket_address_equal(a, &b);
426 }
427
428 const char* socket_address_get_path(const SocketAddress *a) {
429         assert(a);
430
431         if (socket_address_family(a) != AF_UNIX)
432                 return NULL;
433
434         if (a->sockaddr.un.sun_path[0] == 0)
435                 return NULL;
436
437         return a->sockaddr.un.sun_path;
438 }
439 #endif // 0
440
441 bool socket_ipv6_is_supported(void) {
442         _cleanup_free_ char *l = NULL;
443
444         if (access("/sys/module/ipv6", F_OK) != 0)
445                 return false;
446
447         /* If we can't check "disable" parameter, assume enabled */
448         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
449                 return true;
450
451         /* If module was loaded with disable=1 no IPv6 available */
452         return l[0] == '0';
453 }
454
455 #if 0 /// UNNEEDED by elogind
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 #endif // 0
762
763 int fd_inc_sndbuf(int fd, size_t n) {
764         int r, value;
765         socklen_t l = sizeof(value);
766
767         r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
768         if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
769                 return 0;
770
771         /* If we have the privileges we will ignore the kernel limit. */
772
773         value = (int) n;
774         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
775                 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
776                         return -errno;
777
778         return 1;
779 }
780
781 int fd_inc_rcvbuf(int fd, size_t n) {
782         int r, value;
783         socklen_t l = sizeof(value);
784
785         r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
786         if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
787                 return 0;
788
789         /* If we have the privileges we will ignore the kernel limit. */
790
791         value = (int) n;
792         if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
793                 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
794                         return -errno;
795         return 1;
796 }
797
798 #if 0 /// UNNEEDED by elogind
799 static const char* const ip_tos_table[] = {
800         [IPTOS_LOWDELAY] = "low-delay",
801         [IPTOS_THROUGHPUT] = "throughput",
802         [IPTOS_RELIABILITY] = "reliability",
803         [IPTOS_LOWCOST] = "low-cost",
804 };
805
806 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
807 #endif // 0
808
809 int getpeercred(int fd, struct ucred *ucred) {
810         socklen_t n = sizeof(struct ucred);
811         struct ucred u;
812         int r;
813
814         assert(fd >= 0);
815         assert(ucred);
816
817         r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
818         if (r < 0)
819                 return -errno;
820
821         if (n != sizeof(struct ucred))
822                 return -EIO;
823
824         /* Check if the data is actually useful and not suppressed due
825          * to namespacing issues */
826         if (u.pid <= 0)
827                 return -ENODATA;
828         if (u.uid == UID_INVALID)
829                 return -ENODATA;
830         if (u.gid == GID_INVALID)
831                 return -ENODATA;
832
833         *ucred = u;
834         return 0;
835 }
836
837 int getpeersec(int fd, char **ret) {
838         socklen_t n = 64;
839         char *s;
840         int r;
841
842         assert(fd >= 0);
843         assert(ret);
844
845         s = new0(char, n);
846         if (!s)
847                 return -ENOMEM;
848
849         r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
850         if (r < 0) {
851                 free(s);
852
853                 if (errno != ERANGE)
854                         return -errno;
855
856                 s = new0(char, n);
857                 if (!s)
858                         return -ENOMEM;
859
860                 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
861                 if (r < 0) {
862                         free(s);
863                         return -errno;
864                 }
865         }
866
867         if (isempty(s)) {
868                 free(s);
869                 return -EOPNOTSUPP;
870         }
871
872         *ret = s;
873         return 0;
874 }
875
876 int send_one_fd(int transport_fd, int fd, int flags) {
877         union {
878                 struct cmsghdr cmsghdr;
879                 uint8_t buf[CMSG_SPACE(sizeof(int))];
880         } control = {};
881         struct msghdr mh = {
882                 .msg_control = &control,
883                 .msg_controllen = sizeof(control),
884         };
885         struct cmsghdr *cmsg;
886
887         assert(transport_fd >= 0);
888         assert(fd >= 0);
889
890         cmsg = CMSG_FIRSTHDR(&mh);
891         cmsg->cmsg_level = SOL_SOCKET;
892         cmsg->cmsg_type = SCM_RIGHTS;
893         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
894         memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
895
896         mh.msg_controllen = CMSG_SPACE(sizeof(int));
897         if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0)
898                 return -errno;
899
900         return 0;
901 }
902
903 #if 0 /// UNNEEDED by elogind
904 int receive_one_fd(int transport_fd, int flags) {
905         union {
906                 struct cmsghdr cmsghdr;
907                 uint8_t buf[CMSG_SPACE(sizeof(int))];
908         } control = {};
909         struct msghdr mh = {
910                 .msg_control = &control,
911                 .msg_controllen = sizeof(control),
912         };
913         struct cmsghdr *cmsg, *found = NULL;
914
915         assert(transport_fd >= 0);
916
917         /*
918          * Receive a single FD via @transport_fd. We don't care for
919          * the transport-type. We retrieve a single FD at most, so for
920          * packet-based transports, the caller must ensure to send
921          * only a single FD per packet.  This is best used in
922          * combination with send_one_fd().
923          */
924
925         if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0)
926                 return -errno;
927
928         CMSG_FOREACH(cmsg, &mh) {
929                 if (cmsg->cmsg_level == SOL_SOCKET &&
930                     cmsg->cmsg_type == SCM_RIGHTS &&
931                     cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
932                         assert(!found);
933                         found = cmsg;
934                         break;
935                 }
936         }
937
938         if (!found) {
939                 cmsg_close_all(&mh);
940                 return -EIO;
941         }
942
943         return *(int*) CMSG_DATA(found);
944 }
945 #endif // 0