]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-netlink.c
cryptenroll: allow to use a public key on a token
[thirdparty/systemd.git] / src / shared / socket-netlink.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
5c3fa98d
ZJS
2
3#include <arpa/inet.h>
4#include <errno.h>
fa2bc6f1 5#include <linux/net_namespace.h>
5c3fa98d
ZJS
6#include <net/if.h>
7#include <string.h>
8
9#include "alloc-util.h"
10#include "errno-util.h"
11#include "extract-word.h"
fa2bc6f1 12#include "fd-util.h"
5c3fa98d
ZJS
13#include "log.h"
14#include "memory-util.h"
fa2bc6f1 15#include "namespace-util.h"
fc2ea97a 16#include "netlink-util.h"
5c3fa98d
ZJS
17#include "parse-util.h"
18#include "socket-netlink.h"
19#include "socket-util.h"
20#include "string-util.h"
21
22int socket_address_parse(SocketAddress *a, const char *s) {
747b5d96 23 uint16_t port;
5c3fa98d
ZJS
24 int r;
25
26 assert(a);
27 assert(s);
28
747b5d96
LB
29 r = socket_address_parse_unix(a, s);
30 if (r == -EPROTO)
31 r = socket_address_parse_vsock(a, s);
32 if (r != -EPROTO)
33 return r;
5c3fa98d 34
747b5d96
LB
35 r = parse_ip_port(s, &port);
36 if (r == -ERANGE)
37 return r; /* Valid port syntax, but the numerical value is wrong for a port. */
38 if (r >= 0) {
39 /* Just a port */
40 if (socket_ipv6_is_supported())
41 *a = (SocketAddress) {
42 .sockaddr.in6 = {
43 .sin6_family = AF_INET6,
44 .sin6_port = htobe16(port),
45 .sin6_addr = in6addr_any,
46 },
47 .size = sizeof(struct sockaddr_in6),
48 };
49 else
50 *a = (SocketAddress) {
51 .sockaddr.in = {
52 .sin_family = AF_INET,
53 .sin_port = htobe16(port),
54 .sin_addr.s_addr = INADDR_ANY,
55 },
56 .size = sizeof(struct sockaddr_in),
57 };
5c3fa98d 58
747b5d96
LB
59 } else {
60 union in_addr_union address;
61 int family, ifindex;
5c3fa98d 62
747b5d96 63 r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL);
5c3fa98d
ZJS
64 if (r < 0)
65 return r;
66
747b5d96
LB
67 if (port == 0) /* No port, no go. */
68 return -EINVAL;
75af1666 69
747b5d96
LB
70 if (family == AF_INET)
71 *a = (SocketAddress) {
72 .sockaddr.in = {
73 .sin_family = AF_INET,
74 .sin_addr = address.in,
75 .sin_port = htobe16(port),
76 },
77 .size = sizeof(struct sockaddr_in),
78 };
79 else if (family == AF_INET6)
80 *a = (SocketAddress) {
81 .sockaddr.in6 = {
82 .sin6_family = AF_INET6,
83 .sin6_addr = address.in6,
84 .sin6_port = htobe16(port),
85 .sin6_scope_id = ifindex,
86 },
87 .size = sizeof(struct sockaddr_in6),
88 };
89 else
90 assert_not_reached();
5c3fa98d
ZJS
91 }
92
93 return 0;
94}
95
96int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
97 SocketAddress b;
98 int r;
99
100 /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
101
102 r = socket_address_parse(&b, s);
103 if (r < 0)
104 return r;
105
106 if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
107 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
108 return -EAFNOSUPPORT;
109 }
110
111 *a = b;
112 return 0;
113}
114
115int socket_address_parse_netlink(SocketAddress *a, const char *s) {
116 _cleanup_free_ char *word = NULL;
117 unsigned group = 0;
118 int family, r;
119
120 assert(a);
121 assert(s);
122
5c3fa98d
ZJS
123 r = extract_first_word(&s, &word, NULL, 0);
124 if (r < 0)
125 return r;
126 if (r == 0)
127 return -EINVAL;
128
129 family = netlink_family_from_string(word);
130 if (family < 0)
131 return -EINVAL;
132
133 if (!isempty(s)) {
134 r = safe_atou(s, &group);
135 if (r < 0)
136 return r;
137 }
138
a73569f1
ZJS
139 *a = (SocketAddress) {
140 .type = SOCK_RAW,
141 .sockaddr.nl.nl_family = AF_NETLINK,
142 .sockaddr.nl.nl_groups = group,
143 .protocol = family,
144 .size = sizeof(struct sockaddr_nl),
145 };
5c3fa98d
ZJS
146
147 return 0;
148}
149
150bool socket_address_is(const SocketAddress *a, const char *s, int type) {
151 struct SocketAddress b;
152
153 assert(a);
154 assert(s);
155
156 if (socket_address_parse(&b, s) < 0)
157 return false;
158
159 b.type = type;
160
161 return socket_address_equal(a, &b);
162}
163
164bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
165 struct SocketAddress b;
166
167 assert(a);
168 assert(s);
169
170 if (socket_address_parse_netlink(&b, s) < 0)
171 return false;
172
173 return socket_address_equal(a, &b);
174}
175
176int make_socket_fd(int log_level, const char* address, int type, int flags) {
177 SocketAddress a;
178 int fd, r;
179
180 r = socket_address_parse(&a, address);
181 if (r < 0)
182 return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
183
184 a.type = type;
185
768fcd77 186 fd = socket_address_listen(&a, type | flags, SOMAXCONN_DELUXE, SOCKET_ADDRESS_DEFAULT,
5c3fa98d
ZJS
187 NULL, false, false, false, 0755, 0644, NULL);
188 if (fd < 0 || log_get_max_level() >= log_level) {
189 _cleanup_free_ char *p = NULL;
190
191 r = socket_address_print(&a, &p);
192 if (r < 0)
193 return log_error_errno(r, "socket_address_print(): %m");
194
195 if (fd < 0)
196 log_error_errno(fd, "Failed to listen on %s: %m", p);
197 else
198 log_full(log_level, "Listening on %s", p);
199 }
200
201 return fd;
202}
203
a723fb85
YW
204int in_addr_port_ifindex_name_from_string_auto(
205 const char *s,
206 int *ret_family,
207 union in_addr_union *ret_address,
208 uint16_t *ret_port,
209 int *ret_ifindex,
210 char **ret_server_name) {
211
212 _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *name = NULL;
213 int family, ifindex = 0, r;
214 union in_addr_union a;
215 uint16_t port = 0;
216 const char *m;
5c3fa98d
ZJS
217
218 assert(s);
5c3fa98d 219
a723fb85
YW
220 /* This accepts the following:
221 * 192.168.0.1:53#example.com
25b2d602
ZJS
222 * [2001:4860:4860::8888]:53%eth0#example.com
223 *
224 * If ret_port is NULL, then the port cannot be specified.
225 * If ret_ifindex is NULL, then the interface index cannot be specified.
226 * If ret_server_name is NULL, then server_name cannot be specified.
227 *
228 * ret_family is always AF_INET or AF_INET6.
229 */
a723fb85
YW
230
231 m = strchr(s, '#');
232 if (m) {
233 if (!ret_server_name)
234 return -EINVAL;
235
236 if (isempty(m + 1))
237 return -EINVAL;
238
239 name = strdup(m + 1);
240 if (!name)
241 return -ENOMEM;
242
243 s = buf1 = strndup(s, m - s);
244 if (!buf1)
245 return -ENOMEM;
246 }
247
248 m = strchr(s, '%');
249 if (m) {
25b2d602
ZJS
250 if (!ret_ifindex)
251 return -EINVAL;
252
a723fb85
YW
253 if (isempty(m + 1))
254 return -EINVAL;
5c3fa98d 255
c1f848d7
ZJS
256 if (!ifname_valid_full(m + 1, IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC))
257 return -EINVAL; /* We want to return -EINVAL for syntactically invalid names,
258 * and -ENODEV for valid but nonexistent interfaces. */
259
f6e49154 260 ifindex = rtnl_resolve_interface(NULL, m + 1);
25b2d602
ZJS
261 if (ifindex < 0)
262 return ifindex;
5c3fa98d 263
a723fb85
YW
264 s = buf2 = strndup(s, m - s);
265 if (!buf2)
5c3fa98d
ZJS
266 return -ENOMEM;
267 }
268
a723fb85
YW
269 m = strrchr(s, ':');
270 if (m) {
271 if (*s == '[') {
272 _cleanup_free_ char *ip_str = NULL;
5c3fa98d 273
a723fb85
YW
274 if (!ret_port)
275 return -EINVAL;
2d95d81f 276
a723fb85
YW
277 if (*(m - 1) != ']')
278 return -EINVAL;
2d95d81f 279
a723fb85 280 family = AF_INET6;
2d95d81f 281
a723fb85
YW
282 r = parse_ip_port(m + 1, &port);
283 if (r < 0)
284 return r;
2d95d81f 285
a723fb85
YW
286 ip_str = strndup(s + 1, m - s - 2);
287 if (!ip_str)
288 return -ENOMEM;
2d95d81f 289
a723fb85
YW
290 r = in_addr_from_string(family, ip_str, &a);
291 if (r < 0)
292 return r;
293 } else {
294 /* First try to parse the string as IPv6 address without port number */
295 r = in_addr_from_string(AF_INET6, s, &a);
296 if (r < 0) {
297 /* Then the input should be IPv4 address with port number */
298 _cleanup_free_ char *ip_str = NULL;
299
300 if (!ret_port)
301 return -EINVAL;
302
303 family = AF_INET;
304
305 ip_str = strndup(s, m - s);
306 if (!ip_str)
307 return -ENOMEM;
308
309 r = in_addr_from_string(family, ip_str, &a);
310 if (r < 0)
311 return r;
312
313 r = parse_ip_port(m + 1, &port);
314 if (r < 0)
315 return r;
316 } else
317 family = AF_INET6;
318 }
319 } else {
320 family = AF_INET;
321 r = in_addr_from_string(family, s, &a);
322 if (r < 0)
323 return r;
2d95d81f
MAL
324 }
325
a723fb85
YW
326 if (ret_family)
327 *ret_family = family;
328 if (ret_address)
329 *ret_address = a;
330 if (ret_port)
331 *ret_port = port;
332 if (ret_ifindex)
333 *ret_ifindex = ifindex;
334 if (ret_server_name)
335 *ret_server_name = TAKE_PTR(name);
2d95d81f
MAL
336
337 return r;
338}
408f8fbc
YW
339
340struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
341 if (!a)
342 return NULL;
343
344 free(a->server_name);
345 free(a->cached_server_string);
346 return mfree(a);
347}
348
ceffbc58
LP
349int in_addr_full_new(
350 int family,
351 const union in_addr_union *a,
352 uint16_t port,
353 int ifindex,
354 const char *server_name,
355 struct in_addr_full **ret) {
356
408f8fbc
YW
357 _cleanup_free_ char *name = NULL;
358 struct in_addr_full *x;
359
360 assert(ret);
361
362 if (!isempty(server_name)) {
363 name = strdup(server_name);
364 if (!name)
365 return -ENOMEM;
366 }
367
368 x = new(struct in_addr_full, 1);
369 if (!x)
370 return -ENOMEM;
371
372 *x = (struct in_addr_full) {
373 .family = family,
374 .address = *a,
375 .port = port,
376 .ifindex = ifindex,
377 .server_name = TAKE_PTR(name),
378 };
379
380 *ret = x;
381 return 0;
382}
383
384int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret) {
385 _cleanup_free_ char *server_name = NULL;
386 int family, ifindex, r;
387 union in_addr_union a;
388 uint16_t port;
389
390 assert(s);
391
392 r = in_addr_port_ifindex_name_from_string_auto(s, &family, &a, &port, &ifindex, &server_name);
393 if (r < 0)
394 return r;
395
396 return in_addr_full_new(family, &a, port, ifindex, server_name, ret);
397}
398
399const char *in_addr_full_to_string(struct in_addr_full *a) {
400 assert(a);
401
402 if (!a->cached_server_string)
403 (void) in_addr_port_ifindex_name_to_string(
404 a->family,
405 &a->address,
406 a->port,
407 a->ifindex,
408 a->server_name,
409 &a->cached_server_string);
410
411 return a->cached_server_string;
412}
fa2bc6f1
LP
413
414int netns_get_nsid(int netnsfd, uint32_t *ret) {
415 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
416 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
417 _cleanup_close_ int _netns_fd = -EBADF;
418 int r;
419
420 if (netnsfd < 0) {
421 r = namespace_open(
422 0,
d2881ef9
YW
423 /* ret_pidns_fd = */ NULL,
424 /* ret_mntns_fd = */ NULL,
fa2bc6f1 425 &_netns_fd,
d2881ef9
YW
426 /* ret_userns_fd = */ NULL,
427 /* ret_root_fd = */ NULL);
fa2bc6f1
LP
428 if (r < 0)
429 return r;
430
431 netnsfd = _netns_fd;
432 }
433
434 r = sd_netlink_open(&rtnl);
435 if (r < 0)
436 return r;
437
438 r = sd_rtnl_message_new_nsid(rtnl, &req, RTM_GETNSID);
439 if (r < 0)
440 return r;
441
442 r = sd_netlink_message_append_s32(req, NETNSA_FD, netnsfd);
443 if (r < 0)
444 return r;
445
446 r = sd_netlink_call(rtnl, req, 0, &reply);
447 if (r < 0)
448 return r;
449
450 for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
451 uint16_t type;
452
453 r = sd_netlink_message_get_errno(m);
454 if (r < 0)
455 return r;
456
457 r = sd_netlink_message_get_type(m, &type);
458 if (r < 0)
459 return r;
460 if (type != RTM_NEWNSID)
461 continue;
462
463 uint32_t u;
464 r = sd_netlink_message_read_u32(m, NETNSA_NSID, &u);
465 if (r < 0)
466 return r;
467
468 if (u == UINT32_MAX) /* no NSID assigned yet */
469 return -ENODATA;
470
471 if (ret)
472 *ret = u;
473
474 return 0;
475 }
476
477 return -ENXIO;
478}