]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-util.c
core, shared: in deserializing, match same files reached via different paths
[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
a16e1123
LP
328 if (socket_address_family(a) != socket_address_family(b))
329 return false;
330
331 switch (socket_address_family(a)) {
332
333 case AF_INET:
4d49b48c 334 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
a16e1123
LP
335 return false;
336
4d49b48c 337 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
a16e1123
LP
338 return false;
339
340 break;
341
342 case AF_INET6:
343 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
344 return false;
345
346 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
347 return false;
348
349 break;
350
351 case AF_UNIX:
a16e1123
LP
352 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
353 return false;
354
355 if (a->sockaddr.un.sun_path[0]) {
c78e47a6 356 if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
a16e1123
LP
357 return false;
358 } else {
c78e47a6
MS
359 if (a->size != b->size)
360 return false;
361
b12c1e7c 362 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
a16e1123
LP
363 return false;
364 }
365
366 break;
367
7a22745a 368 case AF_NETLINK:
7a22745a
LP
369 if (a->protocol != b->protocol)
370 return false;
371
372 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
373 return false;
374
375 break;
376
a16e1123
LP
377 default:
378 /* Cannot compare, so we assume the addresses are different */
379 return false;
380 }
381
382 return true;
383}
384
27ca8d7a 385bool socket_address_is(const SocketAddress *a, const char *s, int type) {
a16e1123
LP
386 struct SocketAddress b;
387
388 assert(a);
389 assert(s);
390
391 if (socket_address_parse(&b, s) < 0)
392 return false;
393
27ca8d7a
LP
394 b.type = type;
395
a16e1123 396 return socket_address_equal(a, &b);
6e2ef85b
LP
397}
398
7a22745a
LP
399bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
400 struct SocketAddress b;
401
402 assert(a);
403 assert(s);
404
405 if (socket_address_parse_netlink(&b, s) < 0)
406 return false;
407
408 return socket_address_equal(a, &b);
409}
410
a57f7e2c 411const char* socket_address_get_path(const SocketAddress *a) {
6e2ef85b
LP
412 assert(a);
413
414 if (socket_address_family(a) != AF_UNIX)
a57f7e2c 415 return NULL;
6e2ef85b
LP
416
417 if (a->sockaddr.un.sun_path[0] == 0)
a57f7e2c 418 return NULL;
a16e1123 419
a57f7e2c 420 return a->sockaddr.un.sun_path;
a16e1123 421}
c0120d99 422
5bfcc1c6 423bool socket_ipv6_is_supported(void) {
79a98c60 424 _cleanup_free_ char *l = NULL;
f89f1e8f
AB
425
426 if (access("/sys/module/ipv6", F_OK) != 0)
90ab5042 427 return false;
f89f1e8f
AB
428
429 /* If we can't check "disable" parameter, assume enabled */
430 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
90ab5042 431 return true;
f89f1e8f
AB
432
433 /* If module was loaded with disable=1 no IPv6 available */
79a98c60 434 return l[0] == '0';
5bfcc1c6
FF
435}
436
01e10de3
LP
437bool socket_address_matches_fd(const SocketAddress *a, int fd) {
438 union sockaddr_union sa;
439 socklen_t salen = sizeof(sa), solen;
440 int protocol, type;
441
442 assert(a);
443 assert(fd >= 0);
444
445 if (getsockname(fd, &sa.sa, &salen) < 0)
446 return false;
447
448 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
449 return false;
450
451 solen = sizeof(type);
452 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
453 return false;
454
455 if (type != a->type)
456 return false;
457
458 if (a->protocol != 0) {
459 solen = sizeof(protocol);
460 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
461 return false;
462
463 if (protocol != a->protocol)
464 return false;
465 }
466
467 switch (sa.sa.sa_family) {
468
469 case AF_INET:
4d49b48c
LP
470 return sa.in.sin_port == a->sockaddr.in.sin_port &&
471 sa.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr;
01e10de3
LP
472
473 case AF_INET6:
474 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
475 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
476
477 case AF_UNIX:
478 return salen == a->size &&
479 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
480
481 }
482
483 return false;
484}
485
4d49b48c
LP
486int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) {
487 union sockaddr_union *sa = (union sockaddr_union*) _sa;
8569a776
LP
488 char *p;
489
4d49b48c
LP
490 assert(sa);
491 assert(salen >= sizeof(sa->sa.sa_family));
8569a776 492
4d49b48c 493 switch (sa->sa.sa_family) {
8569a776
LP
494
495 case AF_INET: {
496 uint32_t a;
497
4d49b48c 498 a = ntohl(sa->in.sin_addr.s_addr);
8569a776
LP
499
500 if (asprintf(&p,
501 "%u.%u.%u.%u:%u",
502 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
4d49b48c 503 ntohs(sa->in.sin_port)) < 0)
8569a776
LP
504 return -ENOMEM;
505
506 break;
507 }
508
509 case AF_INET6: {
510 static const unsigned char ipv4_prefix[] = {
511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
512 };
513
4d49b48c
LP
514 if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
515 const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
8569a776
LP
516
517 if (asprintf(&p,
518 "%u.%u.%u.%u:%u",
519 a[0], a[1], a[2], a[3],
4d49b48c 520 ntohs(sa->in6.sin6_port)) < 0)
8569a776
LP
521 return -ENOMEM;
522 } else {
523 char a[INET6_ADDRSTRLEN];
524
525 if (asprintf(&p,
4d49b48c
LP
526 "[%s]:%u",
527 inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)),
528 ntohs(sa->in6.sin6_port)) < 0)
8569a776
LP
529 return -ENOMEM;
530 }
531
532 break;
533 }
534
4d49b48c
LP
535 case AF_UNIX:
536 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
537 p = strdup("<unnamed>");
538 if (!p)
539 return -ENOMEM;
8569a776 540
4d49b48c
LP
541 } else if (sa->un.sun_path[0] == 0) {
542 /* abstract */
8569a776 543
4d49b48c
LP
544 /* FIXME: We assume we can print the
545 * socket path here and that it hasn't
546 * more than one NUL byte. That is
547 * actually an invalid assumption */
548
549 p = new(char, sizeof(sa->un.sun_path)+1);
550 if (!p)
551 return -ENOMEM;
552
553 p[0] = '@';
554 memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
555 p[sizeof(sa->un.sun_path)] = 0;
556
557 } else {
558 p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
559 if (!ret)
560 return -ENOMEM;
561 }
8569a776
LP
562
563 break;
8569a776
LP
564
565 default:
566 return -ENOTSUP;
567 }
568
4d49b48c 569
8569a776
LP
570 *ret = p;
571 return 0;
572}
573
4d49b48c
LP
574int getpeername_pretty(int fd, char **ret) {
575 union sockaddr_union sa;
b31f535c 576 socklen_t salen = sizeof(sa);
eff05270 577 int r;
4d49b48c
LP
578
579 assert(fd >= 0);
580 assert(ret);
581
4d49b48c
LP
582 if (getpeername(fd, &sa.sa, &salen) < 0)
583 return -errno;
584
585 if (sa.sa.sa_family == AF_UNIX) {
39883f62 586 struct ucred ucred = {};
4d49b48c
LP
587
588 /* UNIX connection sockets are anonymous, so let's use
589 * PID/UID as pretty credentials instead */
590
eff05270
LP
591 r = getpeercred(fd, &ucred);
592 if (r < 0)
593 return r;
4d49b48c 594
de0671ee 595 if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
4d49b48c
LP
596 return -ENOMEM;
597
598 return 0;
599 }
600
601 /* For remote sockets we translate IPv6 addresses back to IPv4
602 * if applicable, since that's nicer. */
603
604 return sockaddr_pretty(&sa.sa, salen, true, ret);
605}
606
607int getsockname_pretty(int fd, char **ret) {
608 union sockaddr_union sa;
b31f535c 609 socklen_t salen = sizeof(sa);
4d49b48c
LP
610
611 assert(fd >= 0);
612 assert(ret);
613
4d49b48c
LP
614 if (getsockname(fd, &sa.sa, &salen) < 0)
615 return -errno;
616
617 /* For local sockets we do not translate IPv6 addresses back
618 * to IPv6 if applicable, since this is usually used for
619 * listening sockets where the difference between IPv4 and
620 * IPv6 matters. */
621
622 return sockaddr_pretty(&sa.sa, salen, false, ret);
623}
624
b31f535c
ZJS
625int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
626 int r;
627 char host[NI_MAXHOST], *ret;
628
629 assert(_ret);
630
631 r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
632 NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
633 if (r != 0) {
b31f535c
ZJS
634 int saved_errno = errno;
635
cb651834 636 r = sockaddr_pretty(&sa->sa, salen, true, &ret);
f647962d
MS
637 if (r < 0)
638 return log_error_errno(r, "sockadd_pretty() failed: %m");
b31f535c 639
279d3c9c 640 log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
cb651834
ZJS
641 } else {
642 ret = strdup(host);
643 if (!ret)
644 return log_oom();
645 }
b31f535c
ZJS
646
647 *_ret = ret;
648 return 0;
649}
650
651int getnameinfo_pretty(int fd, char **ret) {
652 union sockaddr_union sa;
653 socklen_t salen = sizeof(sa);
654
655 assert(fd >= 0);
656 assert(ret);
657
4a62c710
MS
658 if (getsockname(fd, &sa.sa, &salen) < 0)
659 return log_error_errno(errno, "getsockname(%d) failed: %m", fd);
b31f535c
ZJS
660
661 return socknameinfo_pretty(&sa, salen, ret);
662}
663
bd1fe7c7
LP
664int socket_address_unlink(SocketAddress *a) {
665 assert(a);
666
667 if (socket_address_family(a) != AF_UNIX)
668 return 0;
669
670 if (a->sockaddr.un.sun_path[0] == 0)
671 return 0;
672
673 if (unlink(a->sockaddr.un.sun_path) < 0)
674 return -errno;
675
676 return 1;
677}
678
7a22745a
LP
679static const char* const netlink_family_table[] = {
680 [NETLINK_ROUTE] = "route",
681 [NETLINK_FIREWALL] = "firewall",
682 [NETLINK_INET_DIAG] = "inet-diag",
683 [NETLINK_NFLOG] = "nflog",
684 [NETLINK_XFRM] = "xfrm",
685 [NETLINK_SELINUX] = "selinux",
686 [NETLINK_ISCSI] = "iscsi",
687 [NETLINK_AUDIT] = "audit",
688 [NETLINK_FIB_LOOKUP] = "fib-lookup",
689 [NETLINK_CONNECTOR] = "connector",
690 [NETLINK_NETFILTER] = "netfilter",
691 [NETLINK_IP6_FW] = "ip6-fw",
692 [NETLINK_DNRTMSG] = "dnrtmsg",
693 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
694 [NETLINK_GENERIC] = "generic",
695 [NETLINK_SCSITRANSPORT] = "scsitransport",
696 [NETLINK_ECRYPTFS] = "ecryptfs"
697};
698
f8b69d1d 699DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
7a22745a 700
c0120d99
LP
701static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
702 [SOCKET_ADDRESS_DEFAULT] = "default",
703 [SOCKET_ADDRESS_BOTH] = "both",
704 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
705};
706
707DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
f01e5736
LP
708
709bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
710 assert(a);
711 assert(b);
712
713 if (a->sa.sa_family != b->sa.sa_family)
714 return false;
715
716 if (a->sa.sa_family == AF_INET)
717 return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
718
719 if (a->sa.sa_family == AF_INET6)
720 return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
721
722 return false;
723}
db73295a
LP
724
725char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
726 assert(addr);
727 assert(buffer);
728
729 /* Like ether_ntoa() but uses %02x instead of %x to print
730 * ethernet addresses, which makes them look less funny. Also,
731 * doesn't use a static buffer. */
732
733 sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
734 addr->ether_addr_octet[0],
735 addr->ether_addr_octet[1],
736 addr->ether_addr_octet[2],
737 addr->ether_addr_octet[3],
738 addr->ether_addr_octet[4],
739 addr->ether_addr_octet[5]);
740
741 return buffer;
742}