]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-util.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / shared / socket-util.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
42f4e3c4 2
a7334b09
LP
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
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
42f4e3c4
LP
22#include <assert.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <arpa/inet.h>
28#include <stdio.h>
542563ba 29#include <net/if.h>
b5a0699f
LP
30#include <sys/types.h>
31#include <sys/stat.h>
0e098b15
LP
32#include <stddef.h>
33#include <sys/ioctl.h>
b31f535c 34#include <netdb.h>
42f4e3c4
LP
35
36#include "macro.h"
37#include "util.h"
49e942b2 38#include "mkdir.h"
9eb977db 39#include "path-util.h"
42f4e3c4 40#include "socket-util.h"
16c42ce1 41#include "missing.h"
a5c32cff 42#include "fileio.h"
42f4e3c4 43
542563ba 44int socket_address_parse(SocketAddress *a, const char *s) {
42f4e3c4
LP
45 char *e, *n;
46 unsigned u;
4d49b48c 47 int r;
42f4e3c4
LP
48
49 assert(a);
50 assert(s);
51
9152c765 52 zero(*a);
542563ba 53 a->type = SOCK_STREAM;
42f4e3c4
LP
54
55 if (*s == '[') {
56 /* IPv6 in [x:.....:z]:p notation */
57
5bfcc1c6
FF
58 if (!socket_ipv6_is_supported()) {
59 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
60 return -EAFNOSUPPORT;
61 }
62
4d49b48c
LP
63 e = strchr(s+1, ']');
64 if (!e)
42f4e3c4
LP
65 return -EINVAL;
66
4d49b48c 67 n = strndupa(s+1, e-s-1);
42f4e3c4
LP
68
69 errno = 0;
4d49b48c 70 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
8333c77e 71 return errno > 0 ? -errno : -EINVAL;
42f4e3c4
LP
72
73 e++;
74 if (*e != ':')
75 return -EINVAL;
76
77 e++;
4d49b48c
LP
78 r = safe_atou(e, &u);
79 if (r < 0)
42f4e3c4
LP
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);
42f4e3c4
LP
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);
0e098b15 100 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
42f4e3c4 101
1c24e7bd 102 } else if (*s == '@') {
42f4e3c4
LP
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);
0e098b15 112 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
42f4e3c4
LP
113
114 } else {
4d49b48c
LP
115 e = strchr(s, ':');
116 if (e) {
117 r = safe_atou(e+1, &u);
118 if (r < 0)
542563ba
LP
119 return r;
120
121 if (u <= 0 || u > 0xFFFF)
122 return -EINVAL;
42f4e3c4 123
4d49b48c 124 n = strndupa(s, e-s);
42f4e3c4 125
542563ba 126 /* IPv4 in w.x.y.z:p notation? */
4d49b48c
LP
127 r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
128 if (r < 0)
542563ba 129 return -errno;
42f4e3c4 130
542563ba
LP
131 if (r > 0) {
132 /* Gotcha, it's a traditional IPv4 address */
4d49b48c
LP
133 a->sockaddr.in.sin_family = AF_INET;
134 a->sockaddr.in.sin_port = htons((uint16_t) u);
542563ba
LP
135 a->size = sizeof(struct sockaddr_in);
136 } else {
137 unsigned idx;
42f4e3c4 138
4d49b48c 139 if (strlen(n) > IF_NAMESIZE-1)
acbb0225 140 return -EINVAL;
acbb0225 141
542563ba
LP
142 /* Uh, our last resort, an interface name */
143 idx = if_nametoindex(n);
83c60c9f 144 if (idx == 0)
542563ba 145 return -EINVAL;
42f4e3c4 146
5bfcc1c6
FF
147 if (!socket_ipv6_is_supported()) {
148 log_warning("Binding to interface is not available since kernel does not support IPv6.");
149 return -EAFNOSUPPORT;
150 }
151
542563ba
LP
152 a->sockaddr.in6.sin6_family = AF_INET6;
153 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
154 a->sockaddr.in6.sin6_scope_id = idx;
83c60c9f 155 a->sockaddr.in6.sin6_addr = in6addr_any;
542563ba
LP
156 a->size = sizeof(struct sockaddr_in6);
157 }
42f4e3c4
LP
158 } else {
159
160 /* Just a port */
5198dabc
LP
161 r = safe_atou(s, &u);
162 if (r < 0)
42f4e3c4
LP
163 return r;
164
165 if (u <= 0 || u > 0xFFFF)
166 return -EINVAL;
167
5bfcc1c6
FF
168 if (socket_ipv6_is_supported()) {
169 a->sockaddr.in6.sin6_family = AF_INET6;
170 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
171 a->sockaddr.in6.sin6_addr = in6addr_any;
172 a->size = sizeof(struct sockaddr_in6);
173 } else {
4d49b48c
LP
174 a->sockaddr.in.sin_family = AF_INET;
175 a->sockaddr.in.sin_port = htons((uint16_t) u);
176 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
5bfcc1c6
FF
177 a->size = sizeof(struct sockaddr_in);
178 }
42f4e3c4
LP
179 }
180 }
181
182 return 0;
183}
184
7a22745a
LP
185int socket_address_parse_netlink(SocketAddress *a, const char *s) {
186 int family;
187 unsigned group = 0;
f8b69d1d 188 _cleanup_free_ char *sfamily = NULL;
7a22745a
LP
189 assert(a);
190 assert(s);
191
192 zero(*a);
193 a->type = SOCK_RAW;
194
195 errno = 0;
196 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
bcb161b0 197 return errno > 0 ? -errno : -EINVAL;
7a22745a 198
f8b69d1d
MS
199 family = netlink_family_from_string(sfamily);
200 if (family < 0)
201 return -EINVAL;
7a22745a
LP
202
203 a->sockaddr.nl.nl_family = AF_NETLINK;
204 a->sockaddr.nl.nl_groups = group;
205
206 a->type = SOCK_RAW;
207 a->size = sizeof(struct sockaddr_nl);
208 a->protocol = family;
209
210 return 0;
211}
212
542563ba 213int socket_address_verify(const SocketAddress *a) {
42f4e3c4
LP
214 assert(a);
215
542563ba 216 switch (socket_address_family(a)) {
42f4e3c4 217
7a22745a
LP
218 case AF_INET:
219 if (a->size != sizeof(struct sockaddr_in))
220 return -EINVAL;
42f4e3c4 221
4d49b48c 222 if (a->sockaddr.in.sin_port == 0)
7a22745a 223 return -EINVAL;
42f4e3c4 224
7a22745a
LP
225 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
226 return -EINVAL;
42f4e3c4 227
7a22745a
LP
228 return 0;
229
230 case AF_INET6:
231 if (a->size != sizeof(struct sockaddr_in6))
232 return -EINVAL;
42f4e3c4 233
7a22745a
LP
234 if (a->sockaddr.in6.sin6_port == 0)
235 return -EINVAL;
42f4e3c4 236
7a22745a
LP
237 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
238 return -EINVAL;
42f4e3c4 239
7a22745a 240 return 0;
42f4e3c4 241
7a22745a
LP
242 case AF_UNIX:
243 if (a->size < offsetof(struct sockaddr_un, sun_path))
244 return -EINVAL;
42f4e3c4 245
7a22745a 246 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 247
7a22745a
LP
248 if (a->sockaddr.un.sun_path[0] != 0) {
249 char *e;
250
251 /* path */
4d49b48c
LP
252 e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
253 if (!e)
7a22745a
LP
254 return -EINVAL;
255
256 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
257 return -EINVAL;
42f4e3c4 258 }
7a22745a 259 }
42f4e3c4 260
5a2b80ce 261 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
7a22745a 262 return -EINVAL;
42f4e3c4 263
7a22745a
LP
264 return 0;
265
266 case AF_NETLINK:
267
268 if (a->size != sizeof(struct sockaddr_nl))
269 return -EINVAL;
270
271 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
272 return -EINVAL;
273
274 return 0;
275
276 default:
277 return -EAFNOSUPPORT;
42f4e3c4
LP
278 }
279}
280
4d49b48c 281int socket_address_print(const SocketAddress *a, char **ret) {
42f4e3c4 282 int r;
4d49b48c 283
42f4e3c4 284 assert(a);
4d49b48c 285 assert(ret);
42f4e3c4 286
4d49b48c
LP
287 r = socket_address_verify(a);
288 if (r < 0)
42f4e3c4
LP
289 return r;
290
4d49b48c 291 if (socket_address_family(a) == AF_NETLINK) {
7fd1b19b 292 _cleanup_free_ char *sfamily = NULL;
7a22745a 293
f8b69d1d 294 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
7a22745a 295 if (r < 0)
f8b69d1d 296 return r;
4d49b48c
LP
297
298 r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
8520cfa5
MS
299 if (r < 0)
300 return -ENOMEM;
7a22745a
LP
301
302 return 0;
303 }
304
4d49b48c 305 return sockaddr_pretty(&a->sockaddr.sa, a->size, false, ret);
42f4e3c4
LP
306}
307
4f2d528d
LP
308bool socket_address_can_accept(const SocketAddress *a) {
309 assert(a);
310
311 return
312 a->type == SOCK_STREAM ||
313 a->type == SOCK_SEQPACKET;
314}
a16e1123
LP
315
316bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
317 assert(a);
318 assert(b);
319
320 /* Invalid addresses are unequal to all */
321 if (socket_address_verify(a) < 0 ||
322 socket_address_verify(b) < 0)
323 return false;
324
325 if (a->type != b->type)
326 return false;
327
328 if (a->size != b->size)
329 return false;
330
331 if (socket_address_family(a) != socket_address_family(b))
332 return false;
333
334 switch (socket_address_family(a)) {
335
336 case AF_INET:
4d49b48c 337 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
a16e1123
LP
338 return false;
339
4d49b48c 340 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
a16e1123
LP
341 return false;
342
343 break;
344
345 case AF_INET6:
346 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
347 return false;
348
349 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
350 return false;
351
352 break;
353
354 case AF_UNIX:
355
356 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
357 return false;
358
359 if (a->sockaddr.un.sun_path[0]) {
641906e9 360 if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
a16e1123
LP
361 return false;
362 } else {
b12c1e7c 363 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
a16e1123
LP
364 return false;
365 }
366
367 break;
368
7a22745a
LP
369 case AF_NETLINK:
370
371 if (a->protocol != b->protocol)
372 return false;
373
374 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
375 return false;
376
377 break;
378
a16e1123
LP
379 default:
380 /* Cannot compare, so we assume the addresses are different */
381 return false;
382 }
383
384 return true;
385}
386
27ca8d7a 387bool socket_address_is(const SocketAddress *a, const char *s, int type) {
a16e1123
LP
388 struct SocketAddress b;
389
390 assert(a);
391 assert(s);
392
393 if (socket_address_parse(&b, s) < 0)
394 return false;
395
27ca8d7a
LP
396 b.type = type;
397
a16e1123 398 return socket_address_equal(a, &b);
6e2ef85b
LP
399}
400
7a22745a
LP
401bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
402 struct SocketAddress b;
403
404 assert(a);
405 assert(s);
406
407 if (socket_address_parse_netlink(&b, s) < 0)
408 return false;
409
410 return socket_address_equal(a, &b);
411}
412
a57f7e2c 413const char* socket_address_get_path(const SocketAddress *a) {
6e2ef85b
LP
414 assert(a);
415
416 if (socket_address_family(a) != AF_UNIX)
a57f7e2c 417 return NULL;
6e2ef85b
LP
418
419 if (a->sockaddr.un.sun_path[0] == 0)
a57f7e2c 420 return NULL;
a16e1123 421
a57f7e2c 422 return a->sockaddr.un.sun_path;
a16e1123 423}
c0120d99 424
5bfcc1c6 425bool socket_ipv6_is_supported(void) {
79a98c60 426 _cleanup_free_ char *l = NULL;
f89f1e8f
AB
427
428 if (access("/sys/module/ipv6", F_OK) != 0)
90ab5042 429 return false;
f89f1e8f
AB
430
431 /* If we can't check "disable" parameter, assume enabled */
432 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
90ab5042 433 return true;
f89f1e8f
AB
434
435 /* If module was loaded with disable=1 no IPv6 available */
79a98c60 436 return l[0] == '0';
5bfcc1c6
FF
437}
438
01e10de3
LP
439bool socket_address_matches_fd(const SocketAddress *a, int fd) {
440 union sockaddr_union sa;
441 socklen_t salen = sizeof(sa), solen;
442 int protocol, type;
443
444 assert(a);
445 assert(fd >= 0);
446
447 if (getsockname(fd, &sa.sa, &salen) < 0)
448 return false;
449
450 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
451 return false;
452
453 solen = sizeof(type);
454 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
455 return false;
456
457 if (type != a->type)
458 return false;
459
460 if (a->protocol != 0) {
461 solen = sizeof(protocol);
462 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
463 return false;
464
465 if (protocol != a->protocol)
466 return false;
467 }
468
469 switch (sa.sa.sa_family) {
470
471 case AF_INET:
4d49b48c
LP
472 return sa.in.sin_port == a->sockaddr.in.sin_port &&
473 sa.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr;
01e10de3
LP
474
475 case AF_INET6:
476 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
477 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
478
479 case AF_UNIX:
480 return salen == a->size &&
481 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
482
483 }
484
485 return false;
486}
487
4d49b48c
LP
488int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) {
489 union sockaddr_union *sa = (union sockaddr_union*) _sa;
8569a776
LP
490 char *p;
491
4d49b48c
LP
492 assert(sa);
493 assert(salen >= sizeof(sa->sa.sa_family));
8569a776 494
4d49b48c 495 switch (sa->sa.sa_family) {
8569a776
LP
496
497 case AF_INET: {
498 uint32_t a;
499
4d49b48c 500 a = ntohl(sa->in.sin_addr.s_addr);
8569a776
LP
501
502 if (asprintf(&p,
503 "%u.%u.%u.%u:%u",
504 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
4d49b48c 505 ntohs(sa->in.sin_port)) < 0)
8569a776
LP
506 return -ENOMEM;
507
508 break;
509 }
510
511 case AF_INET6: {
512 static const unsigned char ipv4_prefix[] = {
513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
514 };
515
4d49b48c
LP
516 if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
517 const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
8569a776
LP
518
519 if (asprintf(&p,
520 "%u.%u.%u.%u:%u",
521 a[0], a[1], a[2], a[3],
4d49b48c 522 ntohs(sa->in6.sin6_port)) < 0)
8569a776
LP
523 return -ENOMEM;
524 } else {
525 char a[INET6_ADDRSTRLEN];
526
527 if (asprintf(&p,
4d49b48c
LP
528 "[%s]:%u",
529 inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)),
530 ntohs(sa->in6.sin6_port)) < 0)
8569a776
LP
531 return -ENOMEM;
532 }
533
534 break;
535 }
536
4d49b48c
LP
537 case AF_UNIX:
538 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
539 p = strdup("<unnamed>");
540 if (!p)
541 return -ENOMEM;
8569a776 542
4d49b48c
LP
543 } else if (sa->un.sun_path[0] == 0) {
544 /* abstract */
8569a776 545
4d49b48c
LP
546 /* FIXME: We assume we can print the
547 * socket path here and that it hasn't
548 * more than one NUL byte. That is
549 * actually an invalid assumption */
550
551 p = new(char, sizeof(sa->un.sun_path)+1);
552 if (!p)
553 return -ENOMEM;
554
555 p[0] = '@';
556 memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
557 p[sizeof(sa->un.sun_path)] = 0;
558
559 } else {
560 p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
561 if (!ret)
562 return -ENOMEM;
563 }
8569a776
LP
564
565 break;
8569a776
LP
566
567 default:
568 return -ENOTSUP;
569 }
570
4d49b48c 571
8569a776
LP
572 *ret = p;
573 return 0;
574}
575
4d49b48c
LP
576int getpeername_pretty(int fd, char **ret) {
577 union sockaddr_union sa;
b31f535c 578 socklen_t salen = sizeof(sa);
eff05270 579 int r;
4d49b48c
LP
580
581 assert(fd >= 0);
582 assert(ret);
583
4d49b48c
LP
584 if (getpeername(fd, &sa.sa, &salen) < 0)
585 return -errno;
586
587 if (sa.sa.sa_family == AF_UNIX) {
39883f62 588 struct ucred ucred = {};
4d49b48c
LP
589
590 /* UNIX connection sockets are anonymous, so let's use
591 * PID/UID as pretty credentials instead */
592
eff05270
LP
593 r = getpeercred(fd, &ucred);
594 if (r < 0)
595 return r;
4d49b48c 596
de0671ee 597 if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
4d49b48c
LP
598 return -ENOMEM;
599
600 return 0;
601 }
602
603 /* For remote sockets we translate IPv6 addresses back to IPv4
604 * if applicable, since that's nicer. */
605
606 return sockaddr_pretty(&sa.sa, salen, true, ret);
607}
608
609int getsockname_pretty(int fd, char **ret) {
610 union sockaddr_union sa;
b31f535c 611 socklen_t salen = sizeof(sa);
4d49b48c
LP
612
613 assert(fd >= 0);
614 assert(ret);
615
4d49b48c
LP
616 if (getsockname(fd, &sa.sa, &salen) < 0)
617 return -errno;
618
619 /* For local sockets we do not translate IPv6 addresses back
620 * to IPv6 if applicable, since this is usually used for
621 * listening sockets where the difference between IPv4 and
622 * IPv6 matters. */
623
624 return sockaddr_pretty(&sa.sa, salen, false, ret);
625}
626
b31f535c
ZJS
627int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
628 int r;
629 char host[NI_MAXHOST], *ret;
630
631 assert(_ret);
632
633 r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
634 NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
635 if (r != 0) {
b31f535c
ZJS
636 int saved_errno = errno;
637
cb651834 638 r = sockaddr_pretty(&sa->sa, salen, true, &ret);
f647962d
MS
639 if (r < 0)
640 return log_error_errno(r, "sockadd_pretty() failed: %m");
b31f535c 641
279d3c9c 642 log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
cb651834
ZJS
643 } else {
644 ret = strdup(host);
645 if (!ret)
646 return log_oom();
647 }
b31f535c
ZJS
648
649 *_ret = ret;
650 return 0;
651}
652
653int getnameinfo_pretty(int fd, char **ret) {
654 union sockaddr_union sa;
655 socklen_t salen = sizeof(sa);
656
657 assert(fd >= 0);
658 assert(ret);
659
660 if (getsockname(fd, &sa.sa, &salen) < 0) {
56f64d95 661 log_error_errno(errno, "getsockname(%d) failed: %m", fd);
b31f535c
ZJS
662 return -errno;
663 }
664
665 return socknameinfo_pretty(&sa, salen, ret);
666}
667
bd1fe7c7
LP
668int socket_address_unlink(SocketAddress *a) {
669 assert(a);
670
671 if (socket_address_family(a) != AF_UNIX)
672 return 0;
673
674 if (a->sockaddr.un.sun_path[0] == 0)
675 return 0;
676
677 if (unlink(a->sockaddr.un.sun_path) < 0)
678 return -errno;
679
680 return 1;
681}
682
7a22745a
LP
683static const char* const netlink_family_table[] = {
684 [NETLINK_ROUTE] = "route",
685 [NETLINK_FIREWALL] = "firewall",
686 [NETLINK_INET_DIAG] = "inet-diag",
687 [NETLINK_NFLOG] = "nflog",
688 [NETLINK_XFRM] = "xfrm",
689 [NETLINK_SELINUX] = "selinux",
690 [NETLINK_ISCSI] = "iscsi",
691 [NETLINK_AUDIT] = "audit",
692 [NETLINK_FIB_LOOKUP] = "fib-lookup",
693 [NETLINK_CONNECTOR] = "connector",
694 [NETLINK_NETFILTER] = "netfilter",
695 [NETLINK_IP6_FW] = "ip6-fw",
696 [NETLINK_DNRTMSG] = "dnrtmsg",
697 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
698 [NETLINK_GENERIC] = "generic",
699 [NETLINK_SCSITRANSPORT] = "scsitransport",
700 [NETLINK_ECRYPTFS] = "ecryptfs"
701};
702
f8b69d1d 703DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
7a22745a 704
c0120d99
LP
705static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
706 [SOCKET_ADDRESS_DEFAULT] = "default",
707 [SOCKET_ADDRESS_BOTH] = "both",
708 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
709};
710
711DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
f01e5736
LP
712
713bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
714 assert(a);
715 assert(b);
716
717 if (a->sa.sa_family != b->sa.sa_family)
718 return false;
719
720 if (a->sa.sa_family == AF_INET)
721 return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
722
723 if (a->sa.sa_family == AF_INET6)
724 return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
725
726 return false;
727}
db73295a
LP
728
729char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
730 assert(addr);
731 assert(buffer);
732
733 /* Like ether_ntoa() but uses %02x instead of %x to print
734 * ethernet addresses, which makes them look less funny. Also,
735 * doesn't use a static buffer. */
736
737 sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
738 addr->ether_addr_octet[0],
739 addr->ether_addr_octet[1],
740 addr->ether_addr_octet[2],
741 addr->ether_addr_octet[3],
742 addr->ether_addr_octet[4],
743 addr->ether_addr_octet[5]);
744
745 return buffer;
746}