]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/socket-util.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / shared / socket-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
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>
29 #include <net/if.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <stddef.h>
33 #include <sys/ioctl.h>
34
35 #include "macro.h"
36 #include "util.h"
37 #include "mkdir.h"
38 #include "socket-util.h"
39 #include "missing.h"
40
41 int socket_address_parse(SocketAddress *a, const char *s) {
42 int r;
43 char *e, *n;
44 unsigned u;
45
46 assert(a);
47 assert(s);
48
49 zero(*a);
50 a->type = SOCK_STREAM;
51
52 if (*s == '[') {
53 /* IPv6 in [x:.....:z]:p notation */
54
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
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);
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);
100 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
101
102 } else if (*s == '@') {
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);
112 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
113
114 } else {
115
116 if ((e = strchr(s, ':'))) {
117
118 if ((r = safe_atou(e+1, &u)) < 0)
119 return r;
120
121 if (u <= 0 || u > 0xFFFF)
122 return -EINVAL;
123
124 if (!(n = strndup(s, e-s)))
125 return -ENOMEM;
126
127 /* IPv4 in w.x.y.z:p notation? */
128 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
129 free(n);
130 return -errno;
131 }
132
133 if (r > 0) {
134 /* Gotcha, it's a traditional IPv4 address */
135 free(n);
136
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;
142
143 if (strlen(n) > IF_NAMESIZE-1) {
144 free(n);
145 return -EINVAL;
146 }
147
148 /* Uh, our last resort, an interface name */
149 idx = if_nametoindex(n);
150 free(n);
151
152 if (idx == 0)
153 return -EINVAL;
154
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
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;
163 a->sockaddr.in6.sin6_addr = in6addr_any;
164 a->size = sizeof(struct sockaddr_in6);
165 }
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
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 }
186 }
187 }
188
189 return 0;
190 }
191
192 int 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
224 int socket_address_verify(const SocketAddress *a) {
225 assert(a);
226
227 switch (socket_address_family(a)) {
228
229 case AF_INET:
230 if (a->size != sizeof(struct sockaddr_in))
231 return -EINVAL;
232
233 if (a->sockaddr.in4.sin_port == 0)
234 return -EINVAL;
235
236 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
237 return -EINVAL;
238
239 return 0;
240
241 case AF_INET6:
242 if (a->size != sizeof(struct sockaddr_in6))
243 return -EINVAL;
244
245 if (a->sockaddr.in6.sin6_port == 0)
246 return -EINVAL;
247
248 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
249 return -EINVAL;
250
251 return 0;
252
253 case AF_UNIX:
254 if (a->size < offsetof(struct sockaddr_un, sun_path))
255 return -EINVAL;
256
257 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
258
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;
268 }
269 }
270
271 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
272 return -EINVAL;
273
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;
288 }
289 }
290
291 int socket_address_print(const SocketAddress *a, char **p) {
292 int r;
293 assert(a);
294 assert(p);
295
296 if ((r = socket_address_verify(a)) < 0)
297 return r;
298
299 switch (socket_address_family(a)) {
300
301 case AF_INET: {
302 char *ret;
303
304 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
305 return -ENOMEM;
306
307 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
308 free(ret);
309 return -errno;
310 }
311
312 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
313 *p = ret;
314 return 0;
315 }
316
317 case AF_INET6: {
318 char *ret;
319
320 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
321 return -ENOMEM;
322
323 ret[0] = '[';
324 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
325 free(ret);
326 return -errno;
327 }
328
329 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
330 *p = ret;
331 return 0;
332 }
333
334 case AF_UNIX: {
335 char *ret;
336
337 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
338
339 if (!(ret = strdup("<unnamed>")))
340 return -ENOMEM;
341
342 } else if (a->sockaddr.un.sun_path[0] == 0) {
343 /* abstract */
344
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 */
349
350 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
351 return -ENOMEM;
352
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;
356
357 } else {
358
359 if (!(ret = strdup(a->sockaddr.un.sun_path)))
360 return -ENOMEM;
361 }
362
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;
383 }
384 }
385
386 bool socket_address_can_accept(const SocketAddress *a) {
387 assert(a);
388
389 return
390 a->type == SOCK_STREAM ||
391 a->type == SOCK_SEQPACKET;
392 }
393
394 bool 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 {
441 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
442 return false;
443 }
444
445 break;
446
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
457 default:
458 /* Cannot compare, so we assume the addresses are different */
459 return false;
460 }
461
462 return true;
463 }
464
465 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
466 struct SocketAddress b;
467
468 assert(a);
469 assert(s);
470
471 if (socket_address_parse(&b, s) < 0)
472 return false;
473
474 b.type = type;
475
476 return socket_address_equal(a, &b);
477 }
478
479 bool 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
491 bool 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;
499
500 return path_startswith(a->sockaddr.un.sun_path, prefix);
501 }
502
503 bool socket_ipv6_is_supported(void) {
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;
519 }
520
521 static 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
541 DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
542
543 static 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
549 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);