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