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