]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/socket-util.c
update fixme
[thirdparty/systemd.git] / src / 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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
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"
37#include "socket-util.h"
16c42ce1 38#include "missing.h"
e51bc1a2 39#include "label.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
542563ba 192int socket_address_verify(const SocketAddress *a) {
42f4e3c4
LP
193 assert(a);
194
542563ba 195 switch (socket_address_family(a)) {
42f4e3c4
LP
196 case AF_INET:
197 if (a->size != sizeof(struct sockaddr_in))
198 return -EINVAL;
199
200 if (a->sockaddr.in4.sin_port == 0)
201 return -EINVAL;
202
203 return 0;
204
205 case AF_INET6:
206 if (a->size != sizeof(struct sockaddr_in6))
207 return -EINVAL;
208
209 if (a->sockaddr.in6.sin6_port == 0)
210 return -EINVAL;
211
212 return 0;
213
214 case AF_UNIX:
0e098b15 215 if (a->size < offsetof(struct sockaddr_un, sun_path))
42f4e3c4
LP
216 return -EINVAL;
217
0e098b15 218 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4 219
b12c1e7c 220 if (a->sockaddr.un.sun_path[0] != 0) {
42f4e3c4
LP
221 char *e;
222
223 /* path */
224 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
225 return -EINVAL;
226
0e098b15 227 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
42f4e3c4
LP
228 return -EINVAL;
229 }
230 }
231
232 return 0;
233
234 default:
235 return -EAFNOSUPPORT;
236 }
237}
238
542563ba 239int socket_address_print(const SocketAddress *a, char **p) {
42f4e3c4
LP
240 int r;
241 assert(a);
242 assert(p);
243
542563ba 244 if ((r = socket_address_verify(a)) < 0)
42f4e3c4
LP
245 return r;
246
542563ba 247 switch (socket_address_family(a)) {
42f4e3c4
LP
248 case AF_INET: {
249 char *ret;
250
251 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
252 return -ENOMEM;
253
254 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
255 free(ret);
256 return -errno;
257 }
258
259 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
260 *p = ret;
261 return 0;
262 }
263
264 case AF_INET6: {
265 char *ret;
266
267 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
268 return -ENOMEM;
269
270 ret[0] = '[';
271 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
272 free(ret);
273 return -errno;
274 }
275
276 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
277 *p = ret;
278 return 0;
279 }
280
281 case AF_UNIX: {
282 char *ret;
283
0e098b15 284 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
42f4e3c4
LP
285
286 if (!(ret = strdup("<unamed>")))
287 return -ENOMEM;
288
289 } else if (a->sockaddr.un.sun_path[0] == 0) {
290 /* abstract */
291
292 /* FIXME: We assume we can print the
293 * socket path here and that it hasn't
294 * more than one NUL byte. That is
295 * actually an invalid assumption */
296
297 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
298 return -ENOMEM;
299
1c24e7bd 300 ret[0] = '@';
42f4e3c4
LP
301 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
302 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
303
304 } else {
305
306 if (!(ret = strdup(a->sockaddr.un.sun_path)))
307 return -ENOMEM;
308 }
309
310 *p = ret;
311 return 0;
312 }
313
314 default:
315 return -EINVAL;
316 }
317}
318
b5a0699f
LP
319int socket_address_listen(
320 const SocketAddress *a,
321 int backlog,
322 SocketAddressBindIPv6Only only,
323 const char *bind_to_device,
4fd5948e 324 bool free_bind,
b5a0699f
LP
325 mode_t directory_mode,
326 mode_t socket_mode,
56cf987f 327 const char *label,
b5a0699f
LP
328 int *ret) {
329
acbb0225 330 int r, fd, one;
42f4e3c4 331 assert(a);
83c60c9f 332 assert(ret);
42f4e3c4 333
542563ba 334 if ((r = socket_address_verify(a)) < 0)
42f4e3c4
LP
335 return r;
336
5bfcc1c6
FF
337 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
338 return -EAFNOSUPPORT;
339
56cf987f
DW
340 r = label_socket_set(label);
341 if (r < 0)
342 return r;
7a58bfa4
DW
343
344 fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
345 r = fd < 0 ? -errno : 0;
b15bdda8 346
56cf987f 347 label_socket_clear();
7a58bfa4
DW
348
349 if (r < 0)
350 return r;
42f4e3c4 351
542563ba
LP
352 if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
353 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
354
acbb0225
LP
355 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
356 goto fail;
542563ba
LP
357 }
358
acbb0225
LP
359 if (bind_to_device)
360 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
361 goto fail;
362
4fd5948e
LP
363 if (free_bind) {
364 one = 1;
365 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
366 log_warning("IP_FREEBIND failed: %m");
367 }
368
acbb0225
LP
369 one = 1;
370 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
371 goto fail;
372
b5a0699f
LP
373 if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
374 mode_t old_mask;
375
376 /* Create parents */
377 mkdir_parents(a->sockaddr.un.sun_path, directory_mode);
378
379 /* Enforce the right access mode for the socket*/
380 old_mask = umask(~ socket_mode);
381
382 /* Include the original umask in our mask */
383 umask(~socket_mode | old_mask);
384
385 r = bind(fd, &a->sockaddr.sa, a->size);
386
387 if (r < 0 && errno == EADDRINUSE) {
388 /* Unlink and try again */
389 unlink(a->sockaddr.un.sun_path);
390 r = bind(fd, &a->sockaddr.sa, a->size);
391 }
392
393 umask(old_mask);
394 } else
395 r = bind(fd, &a->sockaddr.sa, a->size);
396
397 if (r < 0)
acbb0225 398 goto fail;
42f4e3c4
LP
399
400 if (a->type == SOCK_STREAM)
acbb0225
LP
401 if (listen(fd, backlog) < 0)
402 goto fail;
42f4e3c4 403
83c60c9f 404 *ret = fd;
42f4e3c4 405 return 0;
acbb0225
LP
406
407fail:
408 r = -errno;
a16e1123 409 close_nointr_nofail(fd);
acbb0225 410 return r;
42f4e3c4 411}
4f2d528d
LP
412
413bool socket_address_can_accept(const SocketAddress *a) {
414 assert(a);
415
416 return
417 a->type == SOCK_STREAM ||
418 a->type == SOCK_SEQPACKET;
419}
a16e1123
LP
420
421bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
422 assert(a);
423 assert(b);
424
425 /* Invalid addresses are unequal to all */
426 if (socket_address_verify(a) < 0 ||
427 socket_address_verify(b) < 0)
428 return false;
429
430 if (a->type != b->type)
431 return false;
432
433 if (a->size != b->size)
434 return false;
435
436 if (socket_address_family(a) != socket_address_family(b))
437 return false;
438
439 switch (socket_address_family(a)) {
440
441 case AF_INET:
442 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
443 return false;
444
445 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
446 return false;
447
448 break;
449
450 case AF_INET6:
451 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
452 return false;
453
454 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
455 return false;
456
457 break;
458
459 case AF_UNIX:
460
461 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
462 return false;
463
464 if (a->sockaddr.un.sun_path[0]) {
465 if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
466 return false;
467 } else {
b12c1e7c 468 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
a16e1123
LP
469 return false;
470 }
471
472 break;
473
474 default:
475 /* Cannot compare, so we assume the addresses are different */
476 return false;
477 }
478
479 return true;
480}
481
27ca8d7a 482bool socket_address_is(const SocketAddress *a, const char *s, int type) {
a16e1123
LP
483 struct SocketAddress b;
484
485 assert(a);
486 assert(s);
487
488 if (socket_address_parse(&b, s) < 0)
489 return false;
490
27ca8d7a
LP
491 b.type = type;
492
a16e1123 493 return socket_address_equal(a, &b);
6e2ef85b
LP
494}
495
496bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
497 assert(a);
498
499 if (socket_address_family(a) != AF_UNIX)
500 return false;
501
502 if (a->sockaddr.un.sun_path[0] == 0)
503 return false;
a16e1123 504
6e2ef85b 505 return path_startswith(a->sockaddr.un.sun_path, prefix);
a16e1123 506}
c0120d99 507
5bfcc1c6
FF
508bool socket_ipv6_is_supported(void) {
509 return access("/sys/module/ipv6", F_OK) == 0;
510}
511
c0120d99
LP
512static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
513 [SOCKET_ADDRESS_DEFAULT] = "default",
514 [SOCKET_ADDRESS_BOTH] = "both",
515 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
516};
517
518DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);