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