]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-util.c
core: fix explanation of associativity
[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
3b1c5241 300 return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, 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
3b1c5241
SL
469int sockaddr_port(const struct sockaddr *_sa) {
470 union sockaddr_union *sa = (union sockaddr_union*) _sa;
471
472 assert(sa);
473
474 if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6))
475 return -EAFNOSUPPORT;
476
477 return ntohs(sa->sa.sa_family == AF_INET6 ?
478 sa->in6.sin6_port :
479 sa->in.sin_port);
480}
481
482int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
4d49b48c 483 union sockaddr_union *sa = (union sockaddr_union*) _sa;
8569a776
LP
484 char *p;
485
4d49b48c
LP
486 assert(sa);
487 assert(salen >= sizeof(sa->sa.sa_family));
8569a776 488
4d49b48c 489 switch (sa->sa.sa_family) {
8569a776
LP
490
491 case AF_INET: {
492 uint32_t a;
493
4d49b48c 494 a = ntohl(sa->in.sin_addr.s_addr);
8569a776 495
3b1c5241
SL
496 if (include_port) {
497 if (asprintf(&p,
498 "%u.%u.%u.%u:%u",
499 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
500 ntohs(sa->in.sin_port)) < 0)
501 return -ENOMEM;
502 } else {
503 if (asprintf(&p,
504 "%u.%u.%u.%u",
505 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF) < 0)
506 return -ENOMEM;
507 }
8569a776
LP
508
509 break;
510 }
511
512 case AF_INET6: {
513 static const unsigned char ipv4_prefix[] = {
514 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
515 };
516
4d49b48c
LP
517 if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
518 const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
3b1c5241
SL
519 if (include_port) {
520 if (asprintf(&p,
521 "%u.%u.%u.%u:%u",
522 a[0], a[1], a[2], a[3],
523 ntohs(sa->in6.sin6_port)) < 0)
524 return -ENOMEM;
525 } else {
526 if (asprintf(&p,
527 "%u.%u.%u.%u",
528 a[0], a[1], a[2], a[3]) < 0)
529 return -ENOMEM;
530 }
8569a776
LP
531 } else {
532 char a[INET6_ADDRSTRLEN];
533
3b1c5241
SL
534 inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
535
536 if (include_port) {
537 if (asprintf(&p,
538 "[%s]:%u",
539 a,
540 ntohs(sa->in6.sin6_port)) < 0)
541 return -ENOMEM;
542 } else {
543 p = strdup(a);
544 if (!p)
545 return -ENOMEM;
546 }
8569a776
LP
547 }
548
549 break;
550 }
551
4d49b48c
LP
552 case AF_UNIX:
553 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
554 p = strdup("<unnamed>");
555 if (!p)
556 return -ENOMEM;
8569a776 557
4d49b48c
LP
558 } else if (sa->un.sun_path[0] == 0) {
559 /* abstract */
8569a776 560
4d49b48c
LP
561 /* FIXME: We assume we can print the
562 * socket path here and that it hasn't
563 * more than one NUL byte. That is
564 * actually an invalid assumption */
565
566 p = new(char, sizeof(sa->un.sun_path)+1);
567 if (!p)
568 return -ENOMEM;
569
570 p[0] = '@';
571 memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
572 p[sizeof(sa->un.sun_path)] = 0;
573
574 } else {
575 p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
576 if (!ret)
577 return -ENOMEM;
578 }
8569a776
LP
579
580 break;
8569a776
LP
581
582 default:
583 return -ENOTSUP;
584 }
585
4d49b48c 586
8569a776
LP
587 *ret = p;
588 return 0;
589}
590
4d49b48c
LP
591int getpeername_pretty(int fd, char **ret) {
592 union sockaddr_union sa;
b31f535c 593 socklen_t salen = sizeof(sa);
eff05270 594 int r;
4d49b48c
LP
595
596 assert(fd >= 0);
597 assert(ret);
598
4d49b48c
LP
599 if (getpeername(fd, &sa.sa, &salen) < 0)
600 return -errno;
601
602 if (sa.sa.sa_family == AF_UNIX) {
39883f62 603 struct ucred ucred = {};
4d49b48c
LP
604
605 /* UNIX connection sockets are anonymous, so let's use
606 * PID/UID as pretty credentials instead */
607
eff05270
LP
608 r = getpeercred(fd, &ucred);
609 if (r < 0)
610 return r;
4d49b48c 611
de0671ee 612 if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
4d49b48c
LP
613 return -ENOMEM;
614
615 return 0;
616 }
617
618 /* For remote sockets we translate IPv6 addresses back to IPv4
619 * if applicable, since that's nicer. */
620
3b1c5241 621 return sockaddr_pretty(&sa.sa, salen, true, true, ret);
4d49b48c
LP
622}
623
624int getsockname_pretty(int fd, char **ret) {
625 union sockaddr_union sa;
b31f535c 626 socklen_t salen = sizeof(sa);
4d49b48c
LP
627
628 assert(fd >= 0);
629 assert(ret);
630
4d49b48c
LP
631 if (getsockname(fd, &sa.sa, &salen) < 0)
632 return -errno;
633
634 /* For local sockets we do not translate IPv6 addresses back
635 * to IPv6 if applicable, since this is usually used for
636 * listening sockets where the difference between IPv4 and
637 * IPv6 matters. */
638
3b1c5241 639 return sockaddr_pretty(&sa.sa, salen, false, true, ret);
4d49b48c
LP
640}
641
b31f535c
ZJS
642int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
643 int r;
644 char host[NI_MAXHOST], *ret;
645
646 assert(_ret);
647
648 r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
649 NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
650 if (r != 0) {
b31f535c
ZJS
651 int saved_errno = errno;
652
3b1c5241 653 r = sockaddr_pretty(&sa->sa, salen, true, true, &ret);
f647962d
MS
654 if (r < 0)
655 return log_error_errno(r, "sockadd_pretty() failed: %m");
b31f535c 656
279d3c9c 657 log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
cb651834
ZJS
658 } else {
659 ret = strdup(host);
660 if (!ret)
661 return log_oom();
662 }
b31f535c
ZJS
663
664 *_ret = ret;
665 return 0;
666}
667
668int getnameinfo_pretty(int fd, char **ret) {
669 union sockaddr_union sa;
670 socklen_t salen = sizeof(sa);
671
672 assert(fd >= 0);
673 assert(ret);
674
4a62c710
MS
675 if (getsockname(fd, &sa.sa, &salen) < 0)
676 return log_error_errno(errno, "getsockname(%d) failed: %m", fd);
b31f535c
ZJS
677
678 return socknameinfo_pretty(&sa, salen, ret);
679}
680
bd1fe7c7
LP
681int socket_address_unlink(SocketAddress *a) {
682 assert(a);
683
684 if (socket_address_family(a) != AF_UNIX)
685 return 0;
686
687 if (a->sockaddr.un.sun_path[0] == 0)
688 return 0;
689
690 if (unlink(a->sockaddr.un.sun_path) < 0)
691 return -errno;
692
693 return 1;
694}
695
7a22745a
LP
696static const char* const netlink_family_table[] = {
697 [NETLINK_ROUTE] = "route",
698 [NETLINK_FIREWALL] = "firewall",
699 [NETLINK_INET_DIAG] = "inet-diag",
700 [NETLINK_NFLOG] = "nflog",
701 [NETLINK_XFRM] = "xfrm",
702 [NETLINK_SELINUX] = "selinux",
703 [NETLINK_ISCSI] = "iscsi",
704 [NETLINK_AUDIT] = "audit",
705 [NETLINK_FIB_LOOKUP] = "fib-lookup",
706 [NETLINK_CONNECTOR] = "connector",
707 [NETLINK_NETFILTER] = "netfilter",
708 [NETLINK_IP6_FW] = "ip6-fw",
709 [NETLINK_DNRTMSG] = "dnrtmsg",
710 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
711 [NETLINK_GENERIC] = "generic",
712 [NETLINK_SCSITRANSPORT] = "scsitransport",
713 [NETLINK_ECRYPTFS] = "ecryptfs"
714};
715
f8b69d1d 716DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
7a22745a 717
c0120d99
LP
718static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
719 [SOCKET_ADDRESS_DEFAULT] = "default",
720 [SOCKET_ADDRESS_BOTH] = "both",
721 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
722};
723
724DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
f01e5736
LP
725
726bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
727 assert(a);
728 assert(b);
729
730 if (a->sa.sa_family != b->sa.sa_family)
731 return false;
732
733 if (a->sa.sa_family == AF_INET)
734 return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
735
736 if (a->sa.sa_family == AF_INET6)
737 return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
738
739 return false;
740}
db73295a
LP
741
742char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
743 assert(addr);
744 assert(buffer);
745
746 /* Like ether_ntoa() but uses %02x instead of %x to print
747 * ethernet addresses, which makes them look less funny. Also,
748 * doesn't use a static buffer. */
749
750 sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
751 addr->ether_addr_octet[0],
752 addr->ether_addr_octet[1],
753 addr->ether_addr_octet[2],
754 addr->ether_addr_octet[3],
755 addr->ether_addr_octet[4],
756 addr->ether_addr_octet[5]);
757
758 return buffer;
759}