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