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