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