]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-util.c
path-util: set pointer to null after calling free()
[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 */
5198dabc
LP
170 r = safe_atou(s, &u);
171 if (r < 0)
42f4e3c4
LP
172 return r;
173
174 if (u <= 0 || u > 0xFFFF)
175 return -EINVAL;
176
5bfcc1c6
FF
177 if (socket_ipv6_is_supported()) {
178 a->sockaddr.in6.sin6_family = AF_INET6;
179 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
180 a->sockaddr.in6.sin6_addr = in6addr_any;
181 a->size = sizeof(struct sockaddr_in6);
182 } else {
183 a->sockaddr.in4.sin_family = AF_INET;
184 a->sockaddr.in4.sin_port = htons((uint16_t) u);
185 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
186 a->size = sizeof(struct sockaddr_in);
187 }
42f4e3c4
LP
188 }
189 }
190
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)
206 return errno ? -errno : -EINVAL;
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
7a22745a
LP
231 if (a->sockaddr.in4.sin_port == 0)
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 */
261 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
262 return -EINVAL;
263
264 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
265 return -EINVAL;
42f4e3c4 266 }
7a22745a 267 }
42f4e3c4 268
5a2b80ce 269 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
7a22745a 270 return -EINVAL;
42f4e3c4 271
7a22745a
LP
272 return 0;
273
274 case AF_NETLINK:
275
276 if (a->size != sizeof(struct sockaddr_nl))
277 return -EINVAL;
278
279 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
280 return -EINVAL;
281
282 return 0;
283
284 default:
285 return -EAFNOSUPPORT;
42f4e3c4
LP
286 }
287}
288
542563ba 289int socket_address_print(const SocketAddress *a, char **p) {
42f4e3c4
LP
290 int r;
291 assert(a);
292 assert(p);
293
542563ba 294 if ((r = socket_address_verify(a)) < 0)
42f4e3c4
LP
295 return r;
296
542563ba 297 switch (socket_address_family(a)) {
42f4e3c4 298
7a22745a
LP
299 case AF_INET: {
300 char *ret;
42f4e3c4 301
7a22745a
LP
302 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
303 return -ENOMEM;
42f4e3c4 304
7a22745a
LP
305 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
306 free(ret);
307 return -errno;
42f4e3c4
LP
308 }
309
7a22745a
LP
310 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
311 *p = ret;
312 return 0;
313 }
42f4e3c4 314
7a22745a
LP
315 case AF_INET6: {
316 char *ret;
42f4e3c4 317
7a22745a
LP
318 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
319 return -ENOMEM;
42f4e3c4 320
7a22745a
LP
321 ret[0] = '[';
322 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
323 free(ret);
324 return -errno;
42f4e3c4
LP
325 }
326
7a22745a
LP
327 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
328 *p = ret;
329 return 0;
330 }
42f4e3c4 331
7a22745a
LP
332 case AF_UNIX: {
333 char *ret;
42f4e3c4 334
7a22745a 335 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 336
7a22745a
LP
337 if (!(ret = strdup("<unnamed>")))
338 return -ENOMEM;
42f4e3c4 339
7a22745a
LP
340 } else if (a->sockaddr.un.sun_path[0] == 0) {
341 /* abstract */
42f4e3c4 342
7a22745a
LP
343 /* FIXME: We assume we can print the
344 * socket path here and that it hasn't
345 * more than one NUL byte. That is
346 * actually an invalid assumption */
42f4e3c4 347
7a22745a
LP
348 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
349 return -ENOMEM;
42f4e3c4 350
7a22745a
LP
351 ret[0] = '@';
352 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
353 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
42f4e3c4 354
7a22745a 355 } else {
42f4e3c4 356
7a22745a
LP
357 if (!(ret = strdup(a->sockaddr.un.sun_path)))
358 return -ENOMEM;
42f4e3c4
LP
359 }
360
7a22745a
LP
361 *p = ret;
362 return 0;
363 }
364
365 case AF_NETLINK: {
6b6ed3e3 366 char _cleanup_free_ *sfamily = NULL;
7a22745a 367
f8b69d1d 368 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
7a22745a 369 if (r < 0)
f8b69d1d
MS
370 return r;
371 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
7a22745a
LP
372
373 return 0;
374 }
375
376 default:
377 return -EINVAL;
42f4e3c4
LP
378 }
379}
380
4f2d528d
LP
381bool socket_address_can_accept(const SocketAddress *a) {
382 assert(a);
383
384 return
385 a->type == SOCK_STREAM ||
386 a->type == SOCK_SEQPACKET;
387}
a16e1123
LP
388
389bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
390 assert(a);
391 assert(b);
392
393 /* Invalid addresses are unequal to all */
394 if (socket_address_verify(a) < 0 ||
395 socket_address_verify(b) < 0)
396 return false;
397
398 if (a->type != b->type)
399 return false;
400
401 if (a->size != b->size)
402 return false;
403
404 if (socket_address_family(a) != socket_address_family(b))
405 return false;
406
407 switch (socket_address_family(a)) {
408
409 case AF_INET:
410 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
411 return false;
412
413 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
414 return false;
415
416 break;
417
418 case AF_INET6:
419 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
420 return false;
421
422 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
423 return false;
424
425 break;
426
427 case AF_UNIX:
428
429 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
430 return false;
431
432 if (a->sockaddr.un.sun_path[0]) {
433 if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
434 return false;
435 } else {
b12c1e7c 436 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
a16e1123
LP
437 return false;
438 }
439
440 break;
441
7a22745a
LP
442 case AF_NETLINK:
443
444 if (a->protocol != b->protocol)
445 return false;
446
447 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
448 return false;
449
450 break;
451
a16e1123
LP
452 default:
453 /* Cannot compare, so we assume the addresses are different */
454 return false;
455 }
456
457 return true;
458}
459
27ca8d7a 460bool socket_address_is(const SocketAddress *a, const char *s, int type) {
a16e1123
LP
461 struct SocketAddress b;
462
463 assert(a);
464 assert(s);
465
466 if (socket_address_parse(&b, s) < 0)
467 return false;
468
27ca8d7a
LP
469 b.type = type;
470
a16e1123 471 return socket_address_equal(a, &b);
6e2ef85b
LP
472}
473
7a22745a
LP
474bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
475 struct SocketAddress b;
476
477 assert(a);
478 assert(s);
479
480 if (socket_address_parse_netlink(&b, s) < 0)
481 return false;
482
483 return socket_address_equal(a, &b);
484}
485
6e2ef85b
LP
486bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
487 assert(a);
488
489 if (socket_address_family(a) != AF_UNIX)
490 return false;
491
492 if (a->sockaddr.un.sun_path[0] == 0)
493 return false;
a16e1123 494
6e2ef85b 495 return path_startswith(a->sockaddr.un.sun_path, prefix);
a16e1123 496}
c0120d99 497
5bfcc1c6 498bool socket_ipv6_is_supported(void) {
f89f1e8f
AB
499 char *l = 0;
500 bool enabled;
501
502 if (access("/sys/module/ipv6", F_OK) != 0)
503 return 0;
504
505 /* If we can't check "disable" parameter, assume enabled */
506 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
507 return 1;
508
509 /* If module was loaded with disable=1 no IPv6 available */
510 enabled = l[0] == '0';
511 free(l);
512
513 return enabled;
5bfcc1c6
FF
514}
515
7a22745a
LP
516static const char* const netlink_family_table[] = {
517 [NETLINK_ROUTE] = "route",
518 [NETLINK_FIREWALL] = "firewall",
519 [NETLINK_INET_DIAG] = "inet-diag",
520 [NETLINK_NFLOG] = "nflog",
521 [NETLINK_XFRM] = "xfrm",
522 [NETLINK_SELINUX] = "selinux",
523 [NETLINK_ISCSI] = "iscsi",
524 [NETLINK_AUDIT] = "audit",
525 [NETLINK_FIB_LOOKUP] = "fib-lookup",
526 [NETLINK_CONNECTOR] = "connector",
527 [NETLINK_NETFILTER] = "netfilter",
528 [NETLINK_IP6_FW] = "ip6-fw",
529 [NETLINK_DNRTMSG] = "dnrtmsg",
530 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
531 [NETLINK_GENERIC] = "generic",
532 [NETLINK_SCSITRANSPORT] = "scsitransport",
533 [NETLINK_ECRYPTFS] = "ecryptfs"
534};
535
f8b69d1d 536DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
7a22745a 537
c0120d99
LP
538static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
539 [SOCKET_ADDRESS_DEFAULT] = "default",
540 [SOCKET_ADDRESS_BOTH] = "both",
541 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
542};
543
544DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);