]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-util.c
util: split-out path-util.[ch]
[thirdparty/systemd.git] / src / shared / socket-util.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
42f4e3c4 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
42f4e3c4
LP
22#include <assert.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <arpa/inet.h>
28#include <stdio.h>
542563ba 29#include <net/if.h>
b5a0699f
LP
30#include <sys/types.h>
31#include <sys/stat.h>
0e098b15
LP
32#include <stddef.h>
33#include <sys/ioctl.h>
42f4e3c4
LP
34
35#include "macro.h"
36#include "util.h"
49e942b2 37#include "mkdir.h"
9eb977db 38#include "path-util.h"
42f4e3c4 39#include "socket-util.h"
16c42ce1 40#include "missing.h"
42f4e3c4 41
542563ba 42int socket_address_parse(SocketAddress *a, const char *s) {
42f4e3c4
LP
43 int r;
44 char *e, *n;
45 unsigned u;
46
47 assert(a);
48 assert(s);
49
9152c765 50 zero(*a);
542563ba 51 a->type = SOCK_STREAM;
42f4e3c4
LP
52
53 if (*s == '[') {
54 /* IPv6 in [x:.....:z]:p notation */
55
5bfcc1c6
FF
56 if (!socket_ipv6_is_supported()) {
57 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
58 return -EAFNOSUPPORT;
59 }
60
42f4e3c4
LP
61 if (!(e = strchr(s+1, ']')))
62 return -EINVAL;
63
64 if (!(n = strndup(s+1, e-s-1)))
65 return -ENOMEM;
66
67 errno = 0;
68 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
69 free(n);
70 return errno != 0 ? -errno : -EINVAL;
71 }
72
73 free(n);
74
75 e++;
76 if (*e != ':')
77 return -EINVAL;
78
79 e++;
80 if ((r = safe_atou(e, &u)) < 0)
81 return r;
82
83 if (u <= 0 || u > 0xFFFF)
84 return -EINVAL;
85
86 a->sockaddr.in6.sin6_family = AF_INET6;
87 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
88 a->size = sizeof(struct sockaddr_in6);
42f4e3c4
LP
89
90 } else if (*s == '/') {
91 /* AF_UNIX socket */
92
93 size_t l;
94
95 l = strlen(s);
96 if (l >= sizeof(a->sockaddr.un.sun_path))
97 return -EINVAL;
98
99 a->sockaddr.un.sun_family = AF_UNIX;
100 memcpy(a->sockaddr.un.sun_path, s, l);
0e098b15 101 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
42f4e3c4 102
1c24e7bd 103 } else if (*s == '@') {
42f4e3c4
LP
104 /* Abstract AF_UNIX socket */
105 size_t l;
106
107 l = strlen(s+1);
108 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
109 return -EINVAL;
110
111 a->sockaddr.un.sun_family = AF_UNIX;
112 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
0e098b15 113 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
42f4e3c4
LP
114
115 } else {
116
117 if ((e = strchr(s, ':'))) {
542563ba
LP
118
119 if ((r = safe_atou(e+1, &u)) < 0)
120 return r;
121
122 if (u <= 0 || u > 0xFFFF)
123 return -EINVAL;
42f4e3c4 124
42f4e3c4
LP
125 if (!(n = strndup(s, e-s)))
126 return -ENOMEM;
127
542563ba
LP
128 /* IPv4 in w.x.y.z:p notation? */
129 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
42f4e3c4 130 free(n);
542563ba 131 return -errno;
42f4e3c4
LP
132 }
133
542563ba
LP
134 if (r > 0) {
135 /* Gotcha, it's a traditional IPv4 address */
136 free(n);
42f4e3c4 137
542563ba
LP
138 a->sockaddr.in4.sin_family = AF_INET;
139 a->sockaddr.in4.sin_port = htons((uint16_t) u);
140 a->size = sizeof(struct sockaddr_in);
141 } else {
142 unsigned idx;
42f4e3c4 143
acbb0225
LP
144 if (strlen(n) > IF_NAMESIZE-1) {
145 free(n);
146 return -EINVAL;
147 }
148
542563ba
LP
149 /* Uh, our last resort, an interface name */
150 idx = if_nametoindex(n);
151 free(n);
152
83c60c9f 153 if (idx == 0)
542563ba 154 return -EINVAL;
42f4e3c4 155
5bfcc1c6
FF
156 if (!socket_ipv6_is_supported()) {
157 log_warning("Binding to interface is not available since kernel does not support IPv6.");
158 return -EAFNOSUPPORT;
159 }
160
542563ba
LP
161 a->sockaddr.in6.sin6_family = AF_INET6;
162 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
163 a->sockaddr.in6.sin6_scope_id = idx;
83c60c9f 164 a->sockaddr.in6.sin6_addr = in6addr_any;
542563ba
LP
165 a->size = sizeof(struct sockaddr_in6);
166 }
42f4e3c4
LP
167 } else {
168
169 /* Just a port */
170 if ((r = safe_atou(s, &u)) < 0)
171 return r;
172
173 if (u <= 0 || u > 0xFFFF)
174 return -EINVAL;
175
5bfcc1c6
FF
176 if (socket_ipv6_is_supported()) {
177 a->sockaddr.in6.sin6_family = AF_INET6;
178 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
179 a->sockaddr.in6.sin6_addr = in6addr_any;
180 a->size = sizeof(struct sockaddr_in6);
181 } else {
182 a->sockaddr.in4.sin_family = AF_INET;
183 a->sockaddr.in4.sin_port = htons((uint16_t) u);
184 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
185 a->size = sizeof(struct sockaddr_in);
186 }
42f4e3c4
LP
187 }
188 }
189
190 return 0;
191}
192
7a22745a
LP
193int socket_address_parse_netlink(SocketAddress *a, const char *s) {
194 int family;
195 unsigned group = 0;
196 char* sfamily = NULL;
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)
205 return errno ? -errno : -EINVAL;
206
207 if ((family = netlink_family_from_string(sfamily)) < 0)
208 if (safe_atoi(sfamily, &family) < 0) {
209 free(sfamily);
210 return -EINVAL;
211 }
212
213 free(sfamily);
214
215 a->sockaddr.nl.nl_family = AF_NETLINK;
216 a->sockaddr.nl.nl_groups = group;
217
218 a->type = SOCK_RAW;
219 a->size = sizeof(struct sockaddr_nl);
220 a->protocol = family;
221
222 return 0;
223}
224
542563ba 225int socket_address_verify(const SocketAddress *a) {
42f4e3c4
LP
226 assert(a);
227
542563ba 228 switch (socket_address_family(a)) {
42f4e3c4 229
7a22745a
LP
230 case AF_INET:
231 if (a->size != sizeof(struct sockaddr_in))
232 return -EINVAL;
42f4e3c4 233
7a22745a
LP
234 if (a->sockaddr.in4.sin_port == 0)
235 return -EINVAL;
42f4e3c4 236
7a22745a
LP
237 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
238 return -EINVAL;
42f4e3c4 239
7a22745a
LP
240 return 0;
241
242 case AF_INET6:
243 if (a->size != sizeof(struct sockaddr_in6))
244 return -EINVAL;
42f4e3c4 245
7a22745a
LP
246 if (a->sockaddr.in6.sin6_port == 0)
247 return -EINVAL;
42f4e3c4 248
7a22745a
LP
249 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
250 return -EINVAL;
42f4e3c4 251
7a22745a 252 return 0;
42f4e3c4 253
7a22745a
LP
254 case AF_UNIX:
255 if (a->size < offsetof(struct sockaddr_un, sun_path))
256 return -EINVAL;
42f4e3c4 257
7a22745a 258 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 259
7a22745a
LP
260 if (a->sockaddr.un.sun_path[0] != 0) {
261 char *e;
262
263 /* path */
264 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
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
542563ba 292int socket_address_print(const SocketAddress *a, char **p) {
42f4e3c4
LP
293 int r;
294 assert(a);
295 assert(p);
296
542563ba 297 if ((r = socket_address_verify(a)) < 0)
42f4e3c4
LP
298 return r;
299
542563ba 300 switch (socket_address_family(a)) {
42f4e3c4 301
7a22745a
LP
302 case AF_INET: {
303 char *ret;
42f4e3c4 304
7a22745a
LP
305 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
306 return -ENOMEM;
42f4e3c4 307
7a22745a
LP
308 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
309 free(ret);
310 return -errno;
42f4e3c4
LP
311 }
312
7a22745a
LP
313 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
314 *p = ret;
315 return 0;
316 }
42f4e3c4 317
7a22745a
LP
318 case AF_INET6: {
319 char *ret;
42f4e3c4 320
7a22745a
LP
321 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
322 return -ENOMEM;
42f4e3c4 323
7a22745a
LP
324 ret[0] = '[';
325 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
326 free(ret);
327 return -errno;
42f4e3c4
LP
328 }
329
7a22745a
LP
330 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
331 *p = ret;
332 return 0;
333 }
42f4e3c4 334
7a22745a
LP
335 case AF_UNIX: {
336 char *ret;
42f4e3c4 337
7a22745a 338 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 339
7a22745a
LP
340 if (!(ret = strdup("<unnamed>")))
341 return -ENOMEM;
42f4e3c4 342
7a22745a
LP
343 } else if (a->sockaddr.un.sun_path[0] == 0) {
344 /* abstract */
42f4e3c4 345
7a22745a
LP
346 /* FIXME: We assume we can print the
347 * socket path here and that it hasn't
348 * more than one NUL byte. That is
349 * actually an invalid assumption */
42f4e3c4 350
7a22745a
LP
351 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
352 return -ENOMEM;
42f4e3c4 353
7a22745a
LP
354 ret[0] = '@';
355 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
356 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
42f4e3c4 357
7a22745a 358 } else {
42f4e3c4 359
7a22745a
LP
360 if (!(ret = strdup(a->sockaddr.un.sun_path)))
361 return -ENOMEM;
42f4e3c4
LP
362 }
363
7a22745a
LP
364 *p = ret;
365 return 0;
366 }
367
368 case AF_NETLINK: {
369 const char *sfamily;
370
371 if ((sfamily = netlink_family_to_string(a->protocol)))
372 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
373 else
374 r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups);
375
376 if (r < 0)
377 return -ENOMEM;
378
379 return 0;
380 }
381
382 default:
383 return -EINVAL;
42f4e3c4
LP
384 }
385}
386
4f2d528d
LP
387bool socket_address_can_accept(const SocketAddress *a) {
388 assert(a);
389
390 return
391 a->type == SOCK_STREAM ||
392 a->type == SOCK_SEQPACKET;
393}
a16e1123
LP
394
395bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
396 assert(a);
397 assert(b);
398
399 /* Invalid addresses are unequal to all */
400 if (socket_address_verify(a) < 0 ||
401 socket_address_verify(b) < 0)
402 return false;
403
404 if (a->type != b->type)
405 return false;
406
407 if (a->size != b->size)
408 return false;
409
410 if (socket_address_family(a) != socket_address_family(b))
411 return false;
412
413 switch (socket_address_family(a)) {
414
415 case AF_INET:
416 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
417 return false;
418
419 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
420 return false;
421
422 break;
423
424 case AF_INET6:
425 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
426 return false;
427
428 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
429 return false;
430
431 break;
432
433 case AF_UNIX:
434
435 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
436 return false;
437
438 if (a->sockaddr.un.sun_path[0]) {
439 if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
440 return false;
441 } else {
b12c1e7c 442 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
a16e1123
LP
443 return false;
444 }
445
446 break;
447
7a22745a
LP
448 case AF_NETLINK:
449
450 if (a->protocol != b->protocol)
451 return false;
452
453 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
454 return false;
455
456 break;
457
a16e1123
LP
458 default:
459 /* Cannot compare, so we assume the addresses are different */
460 return false;
461 }
462
463 return true;
464}
465
27ca8d7a 466bool socket_address_is(const SocketAddress *a, const char *s, int type) {
a16e1123
LP
467 struct SocketAddress b;
468
469 assert(a);
470 assert(s);
471
472 if (socket_address_parse(&b, s) < 0)
473 return false;
474
27ca8d7a
LP
475 b.type = type;
476
a16e1123 477 return socket_address_equal(a, &b);
6e2ef85b
LP
478}
479
7a22745a
LP
480bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
481 struct SocketAddress b;
482
483 assert(a);
484 assert(s);
485
486 if (socket_address_parse_netlink(&b, s) < 0)
487 return false;
488
489 return socket_address_equal(a, &b);
490}
491
6e2ef85b
LP
492bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
493 assert(a);
494
495 if (socket_address_family(a) != AF_UNIX)
496 return false;
497
498 if (a->sockaddr.un.sun_path[0] == 0)
499 return false;
a16e1123 500
6e2ef85b 501 return path_startswith(a->sockaddr.un.sun_path, prefix);
a16e1123 502}
c0120d99 503
5bfcc1c6 504bool socket_ipv6_is_supported(void) {
f89f1e8f
AB
505 char *l = 0;
506 bool enabled;
507
508 if (access("/sys/module/ipv6", F_OK) != 0)
509 return 0;
510
511 /* If we can't check "disable" parameter, assume enabled */
512 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
513 return 1;
514
515 /* If module was loaded with disable=1 no IPv6 available */
516 enabled = l[0] == '0';
517 free(l);
518
519 return enabled;
5bfcc1c6
FF
520}
521
7a22745a
LP
522static const char* const netlink_family_table[] = {
523 [NETLINK_ROUTE] = "route",
524 [NETLINK_FIREWALL] = "firewall",
525 [NETLINK_INET_DIAG] = "inet-diag",
526 [NETLINK_NFLOG] = "nflog",
527 [NETLINK_XFRM] = "xfrm",
528 [NETLINK_SELINUX] = "selinux",
529 [NETLINK_ISCSI] = "iscsi",
530 [NETLINK_AUDIT] = "audit",
531 [NETLINK_FIB_LOOKUP] = "fib-lookup",
532 [NETLINK_CONNECTOR] = "connector",
533 [NETLINK_NETFILTER] = "netfilter",
534 [NETLINK_IP6_FW] = "ip6-fw",
535 [NETLINK_DNRTMSG] = "dnrtmsg",
536 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
537 [NETLINK_GENERIC] = "generic",
538 [NETLINK_SCSITRANSPORT] = "scsitransport",
539 [NETLINK_ECRYPTFS] = "ecryptfs"
540};
541
542DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
543
c0120d99
LP
544static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
545 [SOCKET_ADDRESS_DEFAULT] = "default",
546 [SOCKET_ADDRESS_BOTH] = "both",
547 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
548};
549
550DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);