]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-util.c
relicense to LGPLv2.1 (with exceptions)
[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"
42f4e3c4 38#include "socket-util.h"
16c42ce1 39#include "missing.h"
42f4e3c4 40
542563ba 41int socket_address_parse(SocketAddress *a, const char *s) {
42f4e3c4
LP
42 int r;
43 char *e, *n;
44 unsigned u;
45
46 assert(a);
47 assert(s);
48
9152c765 49 zero(*a);
542563ba 50 a->type = SOCK_STREAM;
42f4e3c4
LP
51
52 if (*s == '[') {
53 /* IPv6 in [x:.....:z]:p notation */
54
5bfcc1c6
FF
55 if (!socket_ipv6_is_supported()) {
56 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
57 return -EAFNOSUPPORT;
58 }
59
42f4e3c4
LP
60 if (!(e = strchr(s+1, ']')))
61 return -EINVAL;
62
63 if (!(n = strndup(s+1, e-s-1)))
64 return -ENOMEM;
65
66 errno = 0;
67 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
68 free(n);
69 return errno != 0 ? -errno : -EINVAL;
70 }
71
72 free(n);
73
74 e++;
75 if (*e != ':')
76 return -EINVAL;
77
78 e++;
79 if ((r = safe_atou(e, &u)) < 0)
80 return r;
81
82 if (u <= 0 || u > 0xFFFF)
83 return -EINVAL;
84
85 a->sockaddr.in6.sin6_family = AF_INET6;
86 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
87 a->size = sizeof(struct sockaddr_in6);
42f4e3c4
LP
88
89 } else if (*s == '/') {
90 /* AF_UNIX socket */
91
92 size_t l;
93
94 l = strlen(s);
95 if (l >= sizeof(a->sockaddr.un.sun_path))
96 return -EINVAL;
97
98 a->sockaddr.un.sun_family = AF_UNIX;
99 memcpy(a->sockaddr.un.sun_path, s, l);
0e098b15 100 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
42f4e3c4 101
1c24e7bd 102 } else if (*s == '@') {
42f4e3c4
LP
103 /* Abstract AF_UNIX socket */
104 size_t l;
105
106 l = strlen(s+1);
107 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
108 return -EINVAL;
109
110 a->sockaddr.un.sun_family = AF_UNIX;
111 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
0e098b15 112 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
42f4e3c4
LP
113
114 } else {
115
116 if ((e = strchr(s, ':'))) {
542563ba
LP
117
118 if ((r = safe_atou(e+1, &u)) < 0)
119 return r;
120
121 if (u <= 0 || u > 0xFFFF)
122 return -EINVAL;
42f4e3c4 123
42f4e3c4
LP
124 if (!(n = strndup(s, e-s)))
125 return -ENOMEM;
126
542563ba
LP
127 /* IPv4 in w.x.y.z:p notation? */
128 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
42f4e3c4 129 free(n);
542563ba 130 return -errno;
42f4e3c4
LP
131 }
132
542563ba
LP
133 if (r > 0) {
134 /* Gotcha, it's a traditional IPv4 address */
135 free(n);
42f4e3c4 136
542563ba
LP
137 a->sockaddr.in4.sin_family = AF_INET;
138 a->sockaddr.in4.sin_port = htons((uint16_t) u);
139 a->size = sizeof(struct sockaddr_in);
140 } else {
141 unsigned idx;
42f4e3c4 142
acbb0225
LP
143 if (strlen(n) > IF_NAMESIZE-1) {
144 free(n);
145 return -EINVAL;
146 }
147
542563ba
LP
148 /* Uh, our last resort, an interface name */
149 idx = if_nametoindex(n);
150 free(n);
151
83c60c9f 152 if (idx == 0)
542563ba 153 return -EINVAL;
42f4e3c4 154
5bfcc1c6
FF
155 if (!socket_ipv6_is_supported()) {
156 log_warning("Binding to interface is not available since kernel does not support IPv6.");
157 return -EAFNOSUPPORT;
158 }
159
542563ba
LP
160 a->sockaddr.in6.sin6_family = AF_INET6;
161 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
162 a->sockaddr.in6.sin6_scope_id = idx;
83c60c9f 163 a->sockaddr.in6.sin6_addr = in6addr_any;
542563ba
LP
164 a->size = sizeof(struct sockaddr_in6);
165 }
42f4e3c4
LP
166 } else {
167
168 /* Just a port */
169 if ((r = safe_atou(s, &u)) < 0)
170 return r;
171
172 if (u <= 0 || u > 0xFFFF)
173 return -EINVAL;
174
5bfcc1c6
FF
175 if (socket_ipv6_is_supported()) {
176 a->sockaddr.in6.sin6_family = AF_INET6;
177 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
178 a->sockaddr.in6.sin6_addr = in6addr_any;
179 a->size = sizeof(struct sockaddr_in6);
180 } else {
181 a->sockaddr.in4.sin_family = AF_INET;
182 a->sockaddr.in4.sin_port = htons((uint16_t) u);
183 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
184 a->size = sizeof(struct sockaddr_in);
185 }
42f4e3c4
LP
186 }
187 }
188
189 return 0;
190}
191
7a22745a
LP
192int socket_address_parse_netlink(SocketAddress *a, const char *s) {
193 int family;
194 unsigned group = 0;
195 char* sfamily = NULL;
196 assert(a);
197 assert(s);
198
199 zero(*a);
200 a->type = SOCK_RAW;
201
202 errno = 0;
203 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
204 return errno ? -errno : -EINVAL;
205
206 if ((family = netlink_family_from_string(sfamily)) < 0)
207 if (safe_atoi(sfamily, &family) < 0) {
208 free(sfamily);
209 return -EINVAL;
210 }
211
212 free(sfamily);
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
7a22745a
LP
233 if (a->sockaddr.in4.sin_port == 0)
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 */
263 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
264 return -EINVAL;
265
266 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
267 return -EINVAL;
42f4e3c4 268 }
7a22745a 269 }
42f4e3c4 270
5a2b80ce 271 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
7a22745a 272 return -EINVAL;
42f4e3c4 273
7a22745a
LP
274 return 0;
275
276 case AF_NETLINK:
277
278 if (a->size != sizeof(struct sockaddr_nl))
279 return -EINVAL;
280
281 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
282 return -EINVAL;
283
284 return 0;
285
286 default:
287 return -EAFNOSUPPORT;
42f4e3c4
LP
288 }
289}
290
542563ba 291int socket_address_print(const SocketAddress *a, char **p) {
42f4e3c4
LP
292 int r;
293 assert(a);
294 assert(p);
295
542563ba 296 if ((r = socket_address_verify(a)) < 0)
42f4e3c4
LP
297 return r;
298
542563ba 299 switch (socket_address_family(a)) {
42f4e3c4 300
7a22745a
LP
301 case AF_INET: {
302 char *ret;
42f4e3c4 303
7a22745a
LP
304 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
305 return -ENOMEM;
42f4e3c4 306
7a22745a
LP
307 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
308 free(ret);
309 return -errno;
42f4e3c4
LP
310 }
311
7a22745a
LP
312 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
313 *p = ret;
314 return 0;
315 }
42f4e3c4 316
7a22745a
LP
317 case AF_INET6: {
318 char *ret;
42f4e3c4 319
7a22745a
LP
320 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
321 return -ENOMEM;
42f4e3c4 322
7a22745a
LP
323 ret[0] = '[';
324 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
325 free(ret);
326 return -errno;
42f4e3c4
LP
327 }
328
7a22745a
LP
329 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
330 *p = ret;
331 return 0;
332 }
42f4e3c4 333
7a22745a
LP
334 case AF_UNIX: {
335 char *ret;
42f4e3c4 336
7a22745a 337 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 338
7a22745a
LP
339 if (!(ret = strdup("<unnamed>")))
340 return -ENOMEM;
42f4e3c4 341
7a22745a
LP
342 } else if (a->sockaddr.un.sun_path[0] == 0) {
343 /* abstract */
42f4e3c4 344
7a22745a
LP
345 /* FIXME: We assume we can print the
346 * socket path here and that it hasn't
347 * more than one NUL byte. That is
348 * actually an invalid assumption */
42f4e3c4 349
7a22745a
LP
350 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
351 return -ENOMEM;
42f4e3c4 352
7a22745a
LP
353 ret[0] = '@';
354 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
355 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
42f4e3c4 356
7a22745a 357 } else {
42f4e3c4 358
7a22745a
LP
359 if (!(ret = strdup(a->sockaddr.un.sun_path)))
360 return -ENOMEM;
42f4e3c4
LP
361 }
362
7a22745a
LP
363 *p = ret;
364 return 0;
365 }
366
367 case AF_NETLINK: {
368 const char *sfamily;
369
370 if ((sfamily = netlink_family_to_string(a->protocol)))
371 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
372 else
373 r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups);
374
375 if (r < 0)
376 return -ENOMEM;
377
378 return 0;
379 }
380
381 default:
382 return -EINVAL;
42f4e3c4
LP
383 }
384}
385
4f2d528d
LP
386bool socket_address_can_accept(const SocketAddress *a) {
387 assert(a);
388
389 return
390 a->type == SOCK_STREAM ||
391 a->type == SOCK_SEQPACKET;
392}
a16e1123
LP
393
394bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
395 assert(a);
396 assert(b);
397
398 /* Invalid addresses are unequal to all */
399 if (socket_address_verify(a) < 0 ||
400 socket_address_verify(b) < 0)
401 return false;
402
403 if (a->type != b->type)
404 return false;
405
406 if (a->size != b->size)
407 return false;
408
409 if (socket_address_family(a) != socket_address_family(b))
410 return false;
411
412 switch (socket_address_family(a)) {
413
414 case AF_INET:
415 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
416 return false;
417
418 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
419 return false;
420
421 break;
422
423 case AF_INET6:
424 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
425 return false;
426
427 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
428 return false;
429
430 break;
431
432 case AF_UNIX:
433
434 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
435 return false;
436
437 if (a->sockaddr.un.sun_path[0]) {
438 if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
439 return false;
440 } else {
b12c1e7c 441 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
a16e1123
LP
442 return false;
443 }
444
445 break;
446
7a22745a
LP
447 case AF_NETLINK:
448
449 if (a->protocol != b->protocol)
450 return false;
451
452 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
453 return false;
454
455 break;
456
a16e1123
LP
457 default:
458 /* Cannot compare, so we assume the addresses are different */
459 return false;
460 }
461
462 return true;
463}
464
27ca8d7a 465bool socket_address_is(const SocketAddress *a, const char *s, int type) {
a16e1123
LP
466 struct SocketAddress b;
467
468 assert(a);
469 assert(s);
470
471 if (socket_address_parse(&b, s) < 0)
472 return false;
473
27ca8d7a
LP
474 b.type = type;
475
a16e1123 476 return socket_address_equal(a, &b);
6e2ef85b
LP
477}
478
7a22745a
LP
479bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
480 struct SocketAddress b;
481
482 assert(a);
483 assert(s);
484
485 if (socket_address_parse_netlink(&b, s) < 0)
486 return false;
487
488 return socket_address_equal(a, &b);
489}
490
6e2ef85b
LP
491bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
492 assert(a);
493
494 if (socket_address_family(a) != AF_UNIX)
495 return false;
496
497 if (a->sockaddr.un.sun_path[0] == 0)
498 return false;
a16e1123 499
6e2ef85b 500 return path_startswith(a->sockaddr.un.sun_path, prefix);
a16e1123 501}
c0120d99 502
5bfcc1c6 503bool socket_ipv6_is_supported(void) {
f89f1e8f
AB
504 char *l = 0;
505 bool enabled;
506
507 if (access("/sys/module/ipv6", F_OK) != 0)
508 return 0;
509
510 /* If we can't check "disable" parameter, assume enabled */
511 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
512 return 1;
513
514 /* If module was loaded with disable=1 no IPv6 available */
515 enabled = l[0] == '0';
516 free(l);
517
518 return enabled;
5bfcc1c6
FF
519}
520
7a22745a
LP
521static const char* const netlink_family_table[] = {
522 [NETLINK_ROUTE] = "route",
523 [NETLINK_FIREWALL] = "firewall",
524 [NETLINK_INET_DIAG] = "inet-diag",
525 [NETLINK_NFLOG] = "nflog",
526 [NETLINK_XFRM] = "xfrm",
527 [NETLINK_SELINUX] = "selinux",
528 [NETLINK_ISCSI] = "iscsi",
529 [NETLINK_AUDIT] = "audit",
530 [NETLINK_FIB_LOOKUP] = "fib-lookup",
531 [NETLINK_CONNECTOR] = "connector",
532 [NETLINK_NETFILTER] = "netfilter",
533 [NETLINK_IP6_FW] = "ip6-fw",
534 [NETLINK_DNRTMSG] = "dnrtmsg",
535 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
536 [NETLINK_GENERIC] = "generic",
537 [NETLINK_SCSITRANSPORT] = "scsitransport",
538 [NETLINK_ECRYPTFS] = "ecryptfs"
539};
540
541DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
542
c0120d99
LP
543static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
544 [SOCKET_ADDRESS_DEFAULT] = "default",
545 [SOCKET_ADDRESS_BOTH] = "both",
546 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
547};
548
549DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);