Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
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
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
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
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public License
19 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 : ***/
21 :
22 : #include <string.h>
23 : #include <unistd.h>
24 : #include <errno.h>
25 : #include <arpa/inet.h>
26 : #include <stdio.h>
27 : #include <net/if.h>
28 : #include <sys/types.h>
29 : #include <stddef.h>
30 : #include <netdb.h>
31 :
32 : #include "macro.h"
33 : #include "path-util.h"
34 : #include "util.h"
35 : #include "socket-util.h"
36 : #include "missing.h"
37 : #include "fileio.h"
38 : #include "formats-util.h"
39 :
40 45 : int socket_address_parse(SocketAddress *a, const char *s) {
41 : char *e, *n;
42 : unsigned u;
43 : int r;
44 :
45 45 : assert(a);
46 45 : assert(s);
47 :
48 45 : zero(*a);
49 45 : a->type = SOCK_STREAM;
50 :
51 45 : if (*s == '[') {
52 : /* IPv6 in [x:.....:z]:p notation */
53 :
54 10 : e = strchr(s+1, ']');
55 10 : if (!e)
56 0 : return -EINVAL;
57 :
58 10 : n = strndupa(s+1, e-s-1);
59 :
60 10 : errno = 0;
61 10 : if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
62 1 : return errno > 0 ? -errno : -EINVAL;
63 :
64 9 : e++;
65 9 : if (*e != ':')
66 2 : return -EINVAL;
67 :
68 7 : e++;
69 7 : r = safe_atou(e, &u);
70 7 : if (r < 0)
71 0 : return r;
72 :
73 7 : if (u <= 0 || u > 0xFFFF)
74 2 : return -EINVAL;
75 :
76 5 : a->sockaddr.in6.sin6_family = AF_INET6;
77 5 : a->sockaddr.in6.sin6_port = htons((uint16_t) u);
78 5 : a->size = sizeof(struct sockaddr_in6);
79 :
80 35 : } else if (*s == '/') {
81 : /* AF_UNIX socket */
82 :
83 : size_t l;
84 :
85 5 : l = strlen(s);
86 5 : if (l >= sizeof(a->sockaddr.un.sun_path))
87 0 : return -EINVAL;
88 :
89 5 : a->sockaddr.un.sun_family = AF_UNIX;
90 5 : memcpy(a->sockaddr.un.sun_path, s, l);
91 5 : a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
92 :
93 30 : } else if (*s == '@') {
94 : /* Abstract AF_UNIX socket */
95 : size_t l;
96 :
97 4 : l = strlen(s+1);
98 4 : if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
99 0 : return -EINVAL;
100 :
101 4 : a->sockaddr.un.sun_family = AF_UNIX;
102 4 : memcpy(a->sockaddr.un.sun_path+1, s+1, l);
103 4 : a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
104 :
105 : } else {
106 26 : e = strchr(s, ':');
107 26 : if (e) {
108 16 : r = safe_atou(e+1, &u);
109 16 : if (r < 0)
110 1 : return r;
111 :
112 15 : if (u <= 0 || u > 0xFFFF)
113 2 : return -EINVAL;
114 :
115 13 : n = strndupa(s, e-s);
116 :
117 : /* IPv4 in w.x.y.z:p notation? */
118 13 : r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
119 13 : if (r < 0)
120 0 : return -errno;
121 :
122 13 : if (r > 0) {
123 : /* Gotcha, it's a traditional IPv4 address */
124 13 : a->sockaddr.in.sin_family = AF_INET;
125 13 : a->sockaddr.in.sin_port = htons((uint16_t) u);
126 13 : a->size = sizeof(struct sockaddr_in);
127 : } else {
128 : unsigned idx;
129 :
130 0 : if (strlen(n) > IF_NAMESIZE-1)
131 0 : return -EINVAL;
132 :
133 : /* Uh, our last resort, an interface name */
134 0 : idx = if_nametoindex(n);
135 0 : if (idx == 0)
136 0 : return -EINVAL;
137 :
138 0 : a->sockaddr.in6.sin6_family = AF_INET6;
139 0 : a->sockaddr.in6.sin6_port = htons((uint16_t) u);
140 0 : a->sockaddr.in6.sin6_scope_id = idx;
141 0 : a->sockaddr.in6.sin6_addr = in6addr_any;
142 0 : a->size = sizeof(struct sockaddr_in6);
143 : }
144 : } else {
145 :
146 : /* Just a port */
147 10 : r = safe_atou(s, &u);
148 10 : if (r < 0)
149 5 : return r;
150 :
151 5 : if (u <= 0 || u > 0xFFFF)
152 2 : return -EINVAL;
153 :
154 3 : if (socket_ipv6_is_supported()) {
155 3 : a->sockaddr.in6.sin6_family = AF_INET6;
156 3 : a->sockaddr.in6.sin6_port = htons((uint16_t) u);
157 3 : a->sockaddr.in6.sin6_addr = in6addr_any;
158 3 : a->size = sizeof(struct sockaddr_in6);
159 : } else {
160 0 : a->sockaddr.in.sin_family = AF_INET;
161 0 : a->sockaddr.in.sin_port = htons((uint16_t) u);
162 0 : a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
163 0 : a->size = sizeof(struct sockaddr_in);
164 : }
165 : }
166 : }
167 :
168 30 : return 0;
169 : }
170 :
171 0 : int 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 0 : r = socket_address_parse(&b, s);
178 0 : if (r < 0)
179 0 : return r;
180 :
181 0 : if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
182 0 : log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
183 0 : return -EAFNOSUPPORT;
184 : }
185 :
186 0 : *a = b;
187 0 : return 0;
188 : }
189 :
190 10 : int socket_address_parse_netlink(SocketAddress *a, const char *s) {
191 : int family;
192 10 : unsigned group = 0;
193 20 : _cleanup_free_ char *sfamily = NULL;
194 10 : assert(a);
195 10 : assert(s);
196 :
197 10 : zero(*a);
198 10 : a->type = SOCK_RAW;
199 :
200 10 : errno = 0;
201 10 : if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
202 1 : return errno > 0 ? -errno : -EINVAL;
203 :
204 9 : family = netlink_family_from_string(sfamily);
205 9 : if (family < 0)
206 2 : return -EINVAL;
207 :
208 7 : a->sockaddr.nl.nl_family = AF_NETLINK;
209 7 : a->sockaddr.nl.nl_groups = group;
210 :
211 7 : a->type = SOCK_RAW;
212 7 : a->size = sizeof(struct sockaddr_nl);
213 7 : a->protocol = family;
214 :
215 7 : return 0;
216 : }
217 :
218 26 : int socket_address_verify(const SocketAddress *a) {
219 26 : assert(a);
220 :
221 26 : switch (socket_address_family(a)) {
222 :
223 : case AF_INET:
224 12 : if (a->size != sizeof(struct sockaddr_in))
225 0 : return -EINVAL;
226 :
227 12 : if (a->sockaddr.in.sin_port == 0)
228 0 : return -EINVAL;
229 :
230 12 : if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
231 1 : return -EINVAL;
232 :
233 11 : return 0;
234 :
235 : case AF_INET6:
236 3 : if (a->size != sizeof(struct sockaddr_in6))
237 0 : return -EINVAL;
238 :
239 3 : if (a->sockaddr.in6.sin6_port == 0)
240 0 : return -EINVAL;
241 :
242 3 : if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
243 0 : return -EINVAL;
244 :
245 3 : return 0;
246 :
247 : case AF_UNIX:
248 5 : if (a->size < offsetof(struct sockaddr_un, sun_path))
249 0 : return -EINVAL;
250 :
251 5 : if (a->size > offsetof(struct sockaddr_un, sun_path)) {
252 :
253 5 : if (a->sockaddr.un.sun_path[0] != 0) {
254 : char *e;
255 :
256 : /* path */
257 3 : e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
258 3 : if (!e)
259 0 : return -EINVAL;
260 :
261 3 : if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
262 0 : return -EINVAL;
263 : }
264 : }
265 :
266 5 : if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
267 0 : return -EINVAL;
268 :
269 5 : return 0;
270 :
271 : case AF_NETLINK:
272 :
273 6 : if (a->size != sizeof(struct sockaddr_nl))
274 0 : return -EINVAL;
275 :
276 6 : if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
277 0 : return -EINVAL;
278 :
279 6 : return 0;
280 :
281 : default:
282 0 : return -EAFNOSUPPORT;
283 : }
284 : }
285 :
286 0 : int socket_address_print(const SocketAddress *a, char **ret) {
287 : int r;
288 :
289 0 : assert(a);
290 0 : assert(ret);
291 :
292 0 : r = socket_address_verify(a);
293 0 : if (r < 0)
294 0 : return r;
295 :
296 0 : if (socket_address_family(a) == AF_NETLINK) {
297 0 : _cleanup_free_ char *sfamily = NULL;
298 :
299 0 : r = netlink_family_to_string_alloc(a->protocol, &sfamily);
300 0 : if (r < 0)
301 0 : return r;
302 :
303 0 : r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
304 0 : if (r < 0)
305 0 : return -ENOMEM;
306 :
307 0 : return 0;
308 : }
309 :
310 0 : return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret);
311 : }
312 :
313 0 : bool socket_address_can_accept(const SocketAddress *a) {
314 0 : assert(a);
315 :
316 : return
317 0 : a->type == SOCK_STREAM ||
318 0 : a->type == SOCK_SEQPACKET;
319 : }
320 :
321 13 : bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
322 13 : assert(a);
323 13 : assert(b);
324 :
325 : /* Invalid addresses are unequal to all */
326 26 : if (socket_address_verify(a) < 0 ||
327 13 : socket_address_verify(b) < 0)
328 1 : return false;
329 :
330 12 : if (a->type != b->type)
331 0 : return false;
332 :
333 12 : if (socket_address_family(a) != socket_address_family(b))
334 2 : return false;
335 :
336 10 : switch (socket_address_family(a)) {
337 :
338 : case AF_INET:
339 4 : if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
340 1 : return false;
341 :
342 3 : if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
343 1 : return false;
344 :
345 2 : break;
346 :
347 : case AF_INET6:
348 1 : if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
349 0 : return false;
350 :
351 1 : if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
352 0 : return false;
353 :
354 1 : break;
355 :
356 : case AF_UNIX:
357 4 : if (a->size <= offsetof(struct sockaddr_un, sun_path) ||
358 2 : b->size <= offsetof(struct sockaddr_un, sun_path))
359 0 : return false;
360 :
361 2 : if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
362 0 : return false;
363 :
364 2 : if (a->sockaddr.un.sun_path[0]) {
365 1 : if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
366 0 : return false;
367 : } else {
368 1 : if (a->size != b->size)
369 0 : return false;
370 :
371 1 : if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
372 0 : return false;
373 : }
374 :
375 2 : break;
376 :
377 : case AF_NETLINK:
378 3 : if (a->protocol != b->protocol)
379 0 : return false;
380 :
381 3 : if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
382 1 : return false;
383 :
384 2 : break;
385 :
386 : default:
387 : /* Cannot compare, so we assume the addresses are different */
388 0 : return false;
389 : }
390 :
391 7 : return true;
392 : }
393 :
394 3 : bool socket_address_is(const SocketAddress *a, const char *s, int type) {
395 : struct SocketAddress b;
396 :
397 3 : assert(a);
398 3 : assert(s);
399 :
400 3 : if (socket_address_parse(&b, s) < 0)
401 1 : return false;
402 :
403 2 : b.type = type;
404 :
405 2 : return socket_address_equal(a, &b);
406 : }
407 :
408 3 : bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
409 : struct SocketAddress b;
410 :
411 3 : assert(a);
412 3 : assert(s);
413 :
414 3 : if (socket_address_parse_netlink(&b, s) < 0)
415 1 : return false;
416 :
417 2 : return socket_address_equal(a, &b);
418 : }
419 :
420 4 : const char* socket_address_get_path(const SocketAddress *a) {
421 4 : assert(a);
422 :
423 4 : if (socket_address_family(a) != AF_UNIX)
424 2 : return NULL;
425 :
426 2 : if (a->sockaddr.un.sun_path[0] == 0)
427 1 : return NULL;
428 :
429 1 : return a->sockaddr.un.sun_path;
430 : }
431 :
432 4 : bool socket_ipv6_is_supported(void) {
433 8 : _cleanup_free_ char *l = NULL;
434 :
435 4 : if (access("/sys/module/ipv6", F_OK) != 0)
436 0 : return false;
437 :
438 : /* If we can't check "disable" parameter, assume enabled */
439 4 : if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
440 0 : return true;
441 :
442 : /* If module was loaded with disable=1 no IPv6 available */
443 4 : return l[0] == '0';
444 : }
445 :
446 0 : bool socket_address_matches_fd(const SocketAddress *a, int fd) {
447 : SocketAddress b;
448 : socklen_t solen;
449 :
450 0 : assert(a);
451 0 : assert(fd >= 0);
452 :
453 0 : b.size = sizeof(b.sockaddr);
454 0 : if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
455 0 : return false;
456 :
457 0 : if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
458 0 : return false;
459 :
460 0 : solen = sizeof(b.type);
461 0 : if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
462 0 : return false;
463 :
464 0 : if (b.type != a->type)
465 0 : return false;
466 :
467 0 : if (a->protocol != 0) {
468 0 : solen = sizeof(b.protocol);
469 0 : if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
470 0 : return false;
471 :
472 0 : if (b.protocol != a->protocol)
473 0 : return false;
474 : }
475 :
476 0 : return socket_address_equal(a, &b);
477 : }
478 :
479 0 : int sockaddr_port(const struct sockaddr *_sa) {
480 0 : union sockaddr_union *sa = (union sockaddr_union*) _sa;
481 :
482 0 : assert(sa);
483 :
484 0 : if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6))
485 0 : return -EAFNOSUPPORT;
486 :
487 0 : return ntohs(sa->sa.sa_family == AF_INET6 ?
488 0 : sa->in6.sin6_port :
489 0 : sa->in.sin_port);
490 : }
491 :
492 2 : int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
493 2 : union sockaddr_union *sa = (union sockaddr_union*) _sa;
494 : char *p;
495 : int r;
496 :
497 2 : assert(sa);
498 2 : assert(salen >= sizeof(sa->sa.sa_family));
499 :
500 2 : switch (sa->sa.sa_family) {
501 :
502 : case AF_INET: {
503 : uint32_t a;
504 :
505 1 : a = ntohl(sa->in.sin_addr.s_addr);
506 :
507 1 : if (include_port)
508 3 : r = asprintf(&p,
509 : "%u.%u.%u.%u:%u",
510 2 : a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
511 1 : ntohs(sa->in.sin_port));
512 : else
513 0 : r = asprintf(&p,
514 : "%u.%u.%u.%u",
515 0 : a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF);
516 1 : if (r < 0)
517 0 : return -ENOMEM;
518 1 : 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 :
526 1 : if (translate_ipv6 &&
527 0 : memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
528 0 : const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
529 0 : if (include_port)
530 0 : r = asprintf(&p,
531 : "%u.%u.%u.%u:%u",
532 0 : a[0], a[1], a[2], a[3],
533 0 : ntohs(sa->in6.sin6_port));
534 : else
535 0 : r = asprintf(&p,
536 : "%u.%u.%u.%u",
537 0 : a[0], a[1], a[2], a[3]);
538 0 : if (r < 0)
539 0 : return -ENOMEM;
540 : } else {
541 : char a[INET6_ADDRSTRLEN];
542 :
543 1 : inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
544 :
545 1 : if (include_port) {
546 1 : r = asprintf(&p,
547 : "[%s]:%u",
548 : a,
549 1 : ntohs(sa->in6.sin6_port));
550 1 : if (r < 0)
551 0 : return -ENOMEM;
552 : } else {
553 0 : p = strdup(a);
554 0 : if (!p)
555 0 : return -ENOMEM;
556 : }
557 : }
558 :
559 1 : break;
560 : }
561 :
562 : case AF_UNIX:
563 0 : if (salen <= offsetof(struct sockaddr_un, sun_path)) {
564 0 : p = strdup("<unnamed>");
565 0 : if (!p)
566 0 : return -ENOMEM;
567 :
568 0 : } else if (sa->un.sun_path[0] == 0) {
569 : /* abstract */
570 :
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 0 : p = new(char, sizeof(sa->un.sun_path)+1);
577 0 : if (!p)
578 0 : return -ENOMEM;
579 :
580 0 : p[0] = '@';
581 0 : memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
582 0 : p[sizeof(sa->un.sun_path)] = 0;
583 :
584 : } else {
585 0 : p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
586 0 : if (!ret)
587 0 : return -ENOMEM;
588 : }
589 :
590 0 : break;
591 :
592 : default:
593 0 : return -EOPNOTSUPP;
594 : }
595 :
596 :
597 2 : *ret = p;
598 2 : return 0;
599 : }
600 :
601 0 : int getpeername_pretty(int fd, char **ret) {
602 : union sockaddr_union sa;
603 0 : socklen_t salen = sizeof(sa);
604 : int r;
605 :
606 0 : assert(fd >= 0);
607 0 : assert(ret);
608 :
609 0 : if (getpeername(fd, &sa.sa, &salen) < 0)
610 0 : return -errno;
611 :
612 0 : if (sa.sa.sa_family == AF_UNIX) {
613 0 : struct ucred ucred = {};
614 :
615 : /* UNIX connection sockets are anonymous, so let's use
616 : * PID/UID as pretty credentials instead */
617 :
618 0 : r = getpeercred(fd, &ucred);
619 0 : if (r < 0)
620 0 : return r;
621 :
622 0 : if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
623 0 : return -ENOMEM;
624 :
625 0 : return 0;
626 : }
627 :
628 : /* For remote sockets we translate IPv6 addresses back to IPv4
629 : * if applicable, since that's nicer. */
630 :
631 0 : return sockaddr_pretty(&sa.sa, salen, true, true, ret);
632 : }
633 :
634 0 : int getsockname_pretty(int fd, char **ret) {
635 : union sockaddr_union sa;
636 0 : socklen_t salen = sizeof(sa);
637 :
638 0 : assert(fd >= 0);
639 0 : assert(ret);
640 :
641 0 : if (getsockname(fd, &sa.sa, &salen) < 0)
642 0 : 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 :
649 0 : return sockaddr_pretty(&sa.sa, salen, false, true, ret);
650 : }
651 :
652 1 : int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
653 : int r;
654 : char host[NI_MAXHOST], *ret;
655 :
656 1 : assert(_ret);
657 :
658 1 : r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
659 : NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
660 1 : if (r != 0) {
661 0 : int saved_errno = errno;
662 :
663 0 : r = sockaddr_pretty(&sa->sa, salen, true, true, &ret);
664 0 : if (r < 0)
665 0 : return log_error_errno(r, "sockadd_pretty() failed: %m");
666 :
667 0 : log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
668 : } else {
669 1 : ret = strdup(host);
670 1 : if (!ret)
671 0 : return log_oom();
672 : }
673 :
674 1 : *_ret = ret;
675 1 : return 0;
676 : }
677 :
678 2 : int getnameinfo_pretty(int fd, char **ret) {
679 : union sockaddr_union sa;
680 2 : socklen_t salen = sizeof(sa);
681 :
682 2 : assert(fd >= 0);
683 2 : assert(ret);
684 :
685 2 : if (getsockname(fd, &sa.sa, &salen) < 0)
686 1 : return log_error_errno(errno, "getsockname(%d) failed: %m", fd);
687 :
688 1 : return socknameinfo_pretty(&sa, salen, ret);
689 : }
690 :
691 0 : int socket_address_unlink(SocketAddress *a) {
692 0 : assert(a);
693 :
694 0 : if (socket_address_family(a) != AF_UNIX)
695 0 : return 0;
696 :
697 0 : if (a->sockaddr.un.sun_path[0] == 0)
698 0 : return 0;
699 :
700 0 : if (unlink(a->sockaddr.un.sun_path) < 0)
701 0 : return -errno;
702 :
703 0 : return 1;
704 : }
705 :
706 : static 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 :
726 9 : DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
727 :
728 : static 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 :
734 10 : DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
735 :
736 5 : bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
737 5 : assert(a);
738 5 : assert(b);
739 :
740 5 : if (a->sa.sa_family != b->sa.sa_family)
741 0 : return false;
742 :
743 5 : if (a->sa.sa_family == AF_INET)
744 4 : return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
745 :
746 1 : if (a->sa.sa_family == AF_INET6)
747 1 : return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
748 :
749 0 : return false;
750 : }
751 :
752 1 : char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
753 1 : assert(addr);
754 1 : 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 6 : sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
761 1 : addr->ether_addr_octet[0],
762 1 : addr->ether_addr_octet[1],
763 1 : addr->ether_addr_octet[2],
764 1 : addr->ether_addr_octet[3],
765 1 : addr->ether_addr_octet[4],
766 1 : addr->ether_addr_octet[5]);
767 :
768 1 : return buffer;
769 : }
|