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