]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/socket-netlink.c
catalog: update Polish translation
[thirdparty/systemd.git] / src / shared / socket-netlink.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <arpa/inet.h>
4 #include <errno.h>
5 #include <net/if.h>
6 #include <string.h>
7
8 #include "alloc-util.h"
9 #include "errno-util.h"
10 #include "extract-word.h"
11 #include "log.h"
12 #include "memory-util.h"
13 #include "netlink-util.h"
14 #include "parse-util.h"
15 #include "socket-netlink.h"
16 #include "socket-util.h"
17 #include "string-util.h"
18
19 int resolve_ifname(sd_netlink **rtnl, const char *name) {
20 int r;
21
22 /* Like if_nametoindex, but resolves "alternative names" too. */
23
24 assert(name);
25
26 r = if_nametoindex(name);
27 if (r > 0)
28 return r;
29
30 return rtnl_resolve_link_alternative_name(rtnl, name);
31 }
32
33 int resolve_interface(sd_netlink **rtnl, const char *name) {
34 int r;
35
36 /* Like resolve_ifname, but resolves interface numbers too. */
37
38 assert(name);
39
40 r = parse_ifindex(name);
41 if (r > 0)
42 return r;
43 assert(r < 0);
44
45 return resolve_ifname(rtnl, name);
46 }
47
48 int resolve_interface_or_warn(sd_netlink **rtnl, const char *name) {
49 int r;
50
51 r = resolve_interface(rtnl, name);
52 if (r < 0)
53 return log_error_errno(r, "Failed to resolve interface \"%s\": %m", name);
54 return r;
55 }
56
57 int socket_address_parse(SocketAddress *a, const char *s) {
58 _cleanup_free_ char *n = NULL;
59 char *e;
60 int r;
61
62 assert(a);
63 assert(s);
64
65 *a = (SocketAddress) {
66 .type = SOCK_STREAM,
67 };
68
69 if (*s == '[') {
70 uint16_t port;
71
72 /* IPv6 in [x:.....:z]:p notation */
73
74 e = strchr(s+1, ']');
75 if (!e)
76 return -EINVAL;
77
78 n = strndup(s+1, e-s-1);
79 if (!n)
80 return -ENOMEM;
81
82 errno = 0;
83 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
84 return errno_or_else(EINVAL);
85
86 e++;
87 if (*e != ':')
88 return -EINVAL;
89
90 e++;
91 r = parse_ip_port(e, &port);
92 if (r < 0)
93 return r;
94
95 a->sockaddr.in6.sin6_family = AF_INET6;
96 a->sockaddr.in6.sin6_port = htobe16(port);
97 a->size = sizeof(struct sockaddr_in6);
98
99 } else if (*s == '/') {
100 /* AF_UNIX socket */
101
102 size_t l;
103
104 l = strlen(s);
105 if (l >= sizeof(a->sockaddr.un.sun_path)) /* Note that we refuse non-NUL-terminated sockets when
106 * parsing (the kernel itself is less strict here in what it
107 * accepts) */
108 return -EINVAL;
109
110 a->sockaddr.un.sun_family = AF_UNIX;
111 memcpy(a->sockaddr.un.sun_path, s, l);
112 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
113
114 } else if (*s == '@') {
115 /* Abstract AF_UNIX socket */
116 size_t l;
117
118 l = strlen(s+1);
119 if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminated sockets here
120 * when parsing, even though abstract namespace sockets
121 * explicitly allow embedded NUL bytes and don't consider
122 * them special. But it's simply annoying to debug such
123 * sockets. */
124 return -EINVAL;
125
126 a->sockaddr.un.sun_family = AF_UNIX;
127 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
128 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
129
130 } else if (startswith(s, "vsock:")) {
131 /* AF_VSOCK socket in vsock:cid:port notation */
132 const char *cid_start = s + STRLEN("vsock:");
133 unsigned port;
134
135 e = strchr(cid_start, ':');
136 if (!e)
137 return -EINVAL;
138
139 r = safe_atou(e+1, &port);
140 if (r < 0)
141 return r;
142
143 n = strndup(cid_start, e - cid_start);
144 if (!n)
145 return -ENOMEM;
146
147 if (!isempty(n)) {
148 r = safe_atou(n, &a->sockaddr.vm.svm_cid);
149 if (r < 0)
150 return r;
151 } else
152 a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
153
154 a->sockaddr.vm.svm_family = AF_VSOCK;
155 a->sockaddr.vm.svm_port = port;
156 a->size = sizeof(struct sockaddr_vm);
157
158 } else {
159 uint16_t port;
160
161 e = strchr(s, ':');
162 if (e) {
163 r = parse_ip_port(e + 1, &port);
164 if (r < 0)
165 return r;
166
167 n = strndup(s, e-s);
168 if (!n)
169 return -ENOMEM;
170
171 /* IPv4 in w.x.y.z:p notation? */
172 r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
173 if (r < 0)
174 return -errno;
175
176 if (r > 0) {
177 /* Gotcha, it's a traditional IPv4 address */
178 a->sockaddr.in.sin_family = AF_INET;
179 a->sockaddr.in.sin_port = htobe16(port);
180 a->size = sizeof(struct sockaddr_in);
181 } else {
182 int idx;
183
184 /* Uh, our last resort, an interface name */
185 idx = resolve_ifname(NULL, n);
186 if (idx < 0)
187 return idx;
188
189 a->sockaddr.in6.sin6_family = AF_INET6;
190 a->sockaddr.in6.sin6_port = htobe16(port);
191 a->sockaddr.in6.sin6_scope_id = idx;
192 a->sockaddr.in6.sin6_addr = in6addr_any;
193 a->size = sizeof(struct sockaddr_in6);
194 }
195 } else {
196
197 /* Just a port */
198 r = parse_ip_port(s, &port);
199 if (r < 0)
200 return r;
201
202 if (socket_ipv6_is_supported()) {
203 a->sockaddr.in6.sin6_family = AF_INET6;
204 a->sockaddr.in6.sin6_port = htobe16(port);
205 a->sockaddr.in6.sin6_addr = in6addr_any;
206 a->size = sizeof(struct sockaddr_in6);
207 } else {
208 a->sockaddr.in.sin_family = AF_INET;
209 a->sockaddr.in.sin_port = htobe16(port);
210 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
211 a->size = sizeof(struct sockaddr_in);
212 }
213 }
214 }
215
216 return 0;
217 }
218
219 int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
220 SocketAddress b;
221 int r;
222
223 /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
224
225 r = socket_address_parse(&b, s);
226 if (r < 0)
227 return r;
228
229 if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
230 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
231 return -EAFNOSUPPORT;
232 }
233
234 *a = b;
235 return 0;
236 }
237
238 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
239 _cleanup_free_ char *word = NULL;
240 unsigned group = 0;
241 int family, r;
242
243 assert(a);
244 assert(s);
245
246 *a = (SocketAddress) {
247 .type = SOCK_RAW,
248 };
249
250 r = extract_first_word(&s, &word, NULL, 0);
251 if (r < 0)
252 return r;
253 if (r == 0)
254 return -EINVAL;
255
256 family = netlink_family_from_string(word);
257 if (family < 0)
258 return -EINVAL;
259
260 if (!isempty(s)) {
261 r = safe_atou(s, &group);
262 if (r < 0)
263 return r;
264 }
265
266 a->sockaddr.nl.nl_family = AF_NETLINK;
267 a->sockaddr.nl.nl_groups = group;
268
269 a->type = SOCK_RAW;
270 a->size = sizeof(struct sockaddr_nl);
271 a->protocol = family;
272
273 return 0;
274 }
275
276 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
277 struct SocketAddress b;
278
279 assert(a);
280 assert(s);
281
282 if (socket_address_parse(&b, s) < 0)
283 return false;
284
285 b.type = type;
286
287 return socket_address_equal(a, &b);
288 }
289
290 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
291 struct SocketAddress b;
292
293 assert(a);
294 assert(s);
295
296 if (socket_address_parse_netlink(&b, s) < 0)
297 return false;
298
299 return socket_address_equal(a, &b);
300 }
301
302 int make_socket_fd(int log_level, const char* address, int type, int flags) {
303 SocketAddress a;
304 int fd, r;
305
306 r = socket_address_parse(&a, address);
307 if (r < 0)
308 return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
309
310 a.type = type;
311
312 fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
313 NULL, false, false, false, 0755, 0644, NULL);
314 if (fd < 0 || log_get_max_level() >= log_level) {
315 _cleanup_free_ char *p = NULL;
316
317 r = socket_address_print(&a, &p);
318 if (r < 0)
319 return log_error_errno(r, "socket_address_print(): %m");
320
321 if (fd < 0)
322 log_error_errno(fd, "Failed to listen on %s: %m", p);
323 else
324 log_full(log_level, "Listening on %s", p);
325 }
326
327 return fd;
328 }
329
330 int in_addr_port_ifindex_name_from_string_auto(
331 const char *s,
332 int *ret_family,
333 union in_addr_union *ret_address,
334 uint16_t *ret_port,
335 int *ret_ifindex,
336 char **ret_server_name) {
337
338 _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *name = NULL;
339 int family, ifindex = 0, r;
340 union in_addr_union a;
341 uint16_t port = 0;
342 const char *m;
343
344 assert(s);
345
346 /* This accepts the following:
347 * 192.168.0.1:53#example.com
348 * [2001:4860:4860::8888]:53%eth0#example.com */
349
350 /* if ret_port is NULL, then strings with port cannot be specified.
351 * Also, if ret_server_name is NULL, then server_name cannot be specified. */
352
353 m = strchr(s, '#');
354 if (m) {
355 if (!ret_server_name)
356 return -EINVAL;
357
358 if (isempty(m + 1))
359 return -EINVAL;
360
361 name = strdup(m + 1);
362 if (!name)
363 return -ENOMEM;
364
365 s = buf1 = strndup(s, m - s);
366 if (!buf1)
367 return -ENOMEM;
368 }
369
370 m = strchr(s, '%');
371 if (m) {
372 if (isempty(m + 1))
373 return -EINVAL;
374
375 if (ret_ifindex) {
376 /* If we shall return the interface index, try to parse it */
377 ifindex = resolve_interface(NULL, m + 1);
378 if (ifindex < 0)
379 return ifindex;
380 }
381
382 s = buf2 = strndup(s, m - s);
383 if (!buf2)
384 return -ENOMEM;
385 }
386
387 m = strrchr(s, ':');
388 if (m) {
389 if (*s == '[') {
390 _cleanup_free_ char *ip_str = NULL;
391
392 if (!ret_port)
393 return -EINVAL;
394
395 if (*(m - 1) != ']')
396 return -EINVAL;
397
398 family = AF_INET6;
399
400 r = parse_ip_port(m + 1, &port);
401 if (r < 0)
402 return r;
403
404 ip_str = strndup(s + 1, m - s - 2);
405 if (!ip_str)
406 return -ENOMEM;
407
408 r = in_addr_from_string(family, ip_str, &a);
409 if (r < 0)
410 return r;
411 } else {
412 /* First try to parse the string as IPv6 address without port number */
413 r = in_addr_from_string(AF_INET6, s, &a);
414 if (r < 0) {
415 /* Then the input should be IPv4 address with port number */
416 _cleanup_free_ char *ip_str = NULL;
417
418 if (!ret_port)
419 return -EINVAL;
420
421 family = AF_INET;
422
423 ip_str = strndup(s, m - s);
424 if (!ip_str)
425 return -ENOMEM;
426
427 r = in_addr_from_string(family, ip_str, &a);
428 if (r < 0)
429 return r;
430
431 r = parse_ip_port(m + 1, &port);
432 if (r < 0)
433 return r;
434 } else
435 family = AF_INET6;
436 }
437 } else {
438 family = AF_INET;
439 r = in_addr_from_string(family, s, &a);
440 if (r < 0)
441 return r;
442 }
443
444 if (ret_family)
445 *ret_family = family;
446 if (ret_address)
447 *ret_address = a;
448 if (ret_port)
449 *ret_port = port;
450 if (ret_ifindex)
451 *ret_ifindex = ifindex;
452 if (ret_server_name)
453 *ret_server_name = TAKE_PTR(name);
454
455 return r;
456 }
457
458 struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
459 if (!a)
460 return NULL;
461
462 free(a->server_name);
463 free(a->cached_server_string);
464 return mfree(a);
465 }
466
467 int in_addr_full_new(int family, union in_addr_union *a, uint16_t port, int ifindex, const char *server_name, struct in_addr_full **ret) {
468 _cleanup_free_ char *name = NULL;
469 struct in_addr_full *x;
470
471 assert(ret);
472
473 if (!isempty(server_name)) {
474 name = strdup(server_name);
475 if (!name)
476 return -ENOMEM;
477 }
478
479 x = new(struct in_addr_full, 1);
480 if (!x)
481 return -ENOMEM;
482
483 *x = (struct in_addr_full) {
484 .family = family,
485 .address = *a,
486 .port = port,
487 .ifindex = ifindex,
488 .server_name = TAKE_PTR(name),
489 };
490
491 *ret = x;
492 return 0;
493 }
494
495 int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret) {
496 _cleanup_free_ char *server_name = NULL;
497 int family, ifindex, r;
498 union in_addr_union a;
499 uint16_t port;
500
501 assert(s);
502
503 r = in_addr_port_ifindex_name_from_string_auto(s, &family, &a, &port, &ifindex, &server_name);
504 if (r < 0)
505 return r;
506
507 return in_addr_full_new(family, &a, port, ifindex, server_name, ret);
508 }
509
510 const char *in_addr_full_to_string(struct in_addr_full *a) {
511 assert(a);
512
513 if (!a->cached_server_string)
514 (void) in_addr_port_ifindex_name_to_string(
515 a->family,
516 &a->address,
517 a->port,
518 a->ifindex,
519 a->server_name,
520 &a->cached_server_string);
521
522 return a->cached_server_string;
523 }