]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/network-internal.c
alloc-util: whenever any of our alloca() wrappers is used to allocate overly large...
[thirdparty/systemd.git] / src / libsystemd-network / network-internal.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
5fde13d7 2
f5284182 3#include <arpa/inet.h>
07630cea
LP
4#include <linux/if.h>
5#include <netinet/ether.h>
5fde13d7 6
dccca82b 7#include "sd-id128.h"
07630cea
LP
8#include "sd-ndisc.h"
9
b5efdb8a 10#include "alloc-util.h"
07630cea
LP
11#include "condition.h"
12#include "conf-parser.h"
e1ea665e 13#include "dhcp-lease-internal.h"
aa31ce18 14#include "ether-addr-util.h"
cf0fbc49 15#include "hexdecoct.h"
be32eb9b 16#include "log.h"
6bedfcbb
LP
17#include "network-internal.h"
18#include "parse-util.h"
07630cea 19#include "siphash24.h"
d31645ad 20#include "socket-util.h"
07630cea
LP
21#include "string-util.h"
22#include "strv.h"
5fde13d7 23#include "utf8.h"
a12fa420 24#include "util.h"
5fde13d7 25
51517f9e 26const char *net_get_name(sd_device *device) {
44e7b949 27 const char *name, *field;
fc541430
TG
28
29 assert(device);
b5db00e5
UTL
30
31 /* fetch some persistent data unique (on this machine) to this device */
51517f9e
YW
32 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC")
33 if (sd_device_get_property_value(device, field, &name) >= 0)
44e7b949 34 return name;
b5db00e5 35
44e7b949 36 return NULL;
fc541430
TG
37}
38
39#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
40
51517f9e 41int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
fc541430
TG
42 size_t l, sz = 0;
43 const char *name = NULL;
44 int r;
45 uint8_t *v;
46
47 assert(device);
48
49 name = net_get_name(device);
b5db00e5
UTL
50 if (!name)
51 return -ENOENT;
52
53 l = strlen(name);
54 sz = sizeof(sd_id128_t) + l;
55 v = alloca(sz);
56
57 /* fetch some persistent data unique to this machine */
58 r = sd_id128_get_machine((sd_id128_t*) v);
59 if (r < 0)
60 return r;
61 memcpy(v + sizeof(sd_id128_t), name, l);
62
63 /* Let's hash the machine ID plus the device name. We
64 * use a fixed, but originally randomly created hash
65 * key here. */
933f9cae 66 *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
b5db00e5
UTL
67
68 return 0;
69}
70
1aa68db1
DM
71static bool net_condition_test_strv(char * const *raw_patterns,
72 const char *string) {
618b196e
DM
73 if (strv_isempty(raw_patterns))
74 return true;
75
76 /* If the patterns begin with "!", edit it out and negate the test. */
77 if (raw_patterns[0][0] == '!') {
78 char **patterns;
da6053d0 79 size_t i, length;
618b196e
DM
80
81 length = strv_length(raw_patterns) + 1; /* Include the NULL. */
82 patterns = newa(char*, length);
83 patterns[0] = raw_patterns[0] + 1; /* Skip the "!". */
84 for (i = 1; i < length; i++)
85 patterns[i] = raw_patterns[i];
86
87 return !string || !strv_fnmatch(patterns, string, 0);
88 }
89
90 return string && strv_fnmatch(raw_patterns, string, 0);
91}
92
e90d0374 93bool net_match_config(Set *match_mac,
5256e00e
TG
94 char * const *match_paths,
95 char * const *match_drivers,
96 char * const *match_types,
97 char * const *match_names,
2cc412b5
TG
98 Condition *match_host,
99 Condition *match_virt,
5022f08a
LP
100 Condition *match_kernel_cmdline,
101 Condition *match_kernel_version,
edbb03e9 102 Condition *match_arch,
505f8da7 103 const struct ether_addr *dev_mac,
b3e01314 104 const char *dev_path,
bf175aaf 105 const char *dev_parent_driver,
b3e01314
TG
106 const char *dev_driver,
107 const char *dev_type,
32bc8adc 108 const char *dev_name) {
be32eb9b 109
2cb62395 110 if (match_host && condition_test(match_host) <= 0)
7eb08da4 111 return false;
2cc412b5 112
2cb62395 113 if (match_virt && condition_test(match_virt) <= 0)
7eb08da4 114 return false;
2cc412b5 115
5022f08a
LP
116 if (match_kernel_cmdline && condition_test(match_kernel_cmdline) <= 0)
117 return false;
118
119 if (match_kernel_version && condition_test(match_kernel_version) <= 0)
7eb08da4 120 return false;
2cc412b5 121
2cb62395 122 if (match_arch && condition_test(match_arch) <= 0)
7eb08da4 123 return false;
edbb03e9 124
25ea58d3 125 if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
7eb08da4 126 return false;
be32eb9b 127
618b196e 128 if (!net_condition_test_strv(match_paths, dev_path))
ee5de57b 129 return false;
5256e00e 130
618b196e 131 if (!net_condition_test_strv(match_drivers, dev_driver))
ee5de57b 132 return false;
5256e00e 133
618b196e 134 if (!net_condition_test_strv(match_types, dev_type))
ee5de57b 135 return false;
5256e00e 136
618b196e 137 if (!net_condition_test_strv(match_names, dev_name))
ee5de57b 138 return false;
5256e00e 139
7eb08da4 140 return true;
be32eb9b 141}
5fde13d7 142
2cc412b5
TG
143int config_parse_net_condition(const char *unit,
144 const char *filename,
145 unsigned line,
146 const char *section,
147 unsigned section_line,
148 const char *lvalue,
149 int ltype,
150 const char *rvalue,
151 void *data,
152 void *userdata) {
153
154 ConditionType cond = ltype;
155 Condition **ret = data;
156 bool negate;
157 Condition *c;
158 _cleanup_free_ char *s = NULL;
159
160 assert(filename);
161 assert(lvalue);
162 assert(rvalue);
163 assert(data);
164
165 negate = rvalue[0] == '!';
166 if (negate)
167 rvalue++;
168
169 s = strdup(rvalue);
170 if (!s)
171 return log_oom();
172
173 c = condition_new(cond, s, false, negate);
174 if (!c)
175 return log_oom();
176
177 if (*ret)
178 condition_free(*ret);
179
180 *ret = c;
181 return 0;
182}
183
d31645ad
LP
184int config_parse_ifnames(
185 const char *unit,
186 const char *filename,
187 unsigned line,
188 const char *section,
189 unsigned section_line,
190 const char *lvalue,
191 int ltype,
192 const char *rvalue,
193 void *data,
194 void *userdata) {
5256e00e
TG
195
196 char ***sv = data;
5256e00e
TG
197 int r;
198
199 assert(filename);
200 assert(lvalue);
201 assert(rvalue);
202 assert(data);
203
93e28226
SS
204 for (;;) {
205 _cleanup_free_ char *word = NULL;
5256e00e 206
93e28226 207 r = extract_first_word(&rvalue, &word, NULL, 0);
a9dd908d
LP
208 if (r < 0) {
209 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue);
210 return 0;
211 }
93e28226
SS
212 if (r == 0)
213 break;
5256e00e 214
d31645ad
LP
215 if (!ifname_valid(word)) {
216 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
5256e00e
TG
217 return 0;
218 }
219
93e28226 220 r = strv_push(sv, word);
5256e00e
TG
221 if (r < 0)
222 return log_oom();
93e28226
SS
223
224 word = NULL;
5256e00e
TG
225 }
226
227 return 0;
228}
229
d2df0d0e
TG
230int config_parse_ifalias(const char *unit,
231 const char *filename,
232 unsigned line,
233 const char *section,
71a61510 234 unsigned section_line,
d2df0d0e
TG
235 const char *lvalue,
236 int ltype,
237 const char *rvalue,
238 void *data,
239 void *userdata) {
240
241 char **s = data;
9c39eb5c 242 _cleanup_free_ char *n = NULL;
d2df0d0e
TG
243
244 assert(filename);
245 assert(lvalue);
246 assert(rvalue);
247 assert(data);
248
249 n = strdup(rvalue);
250 if (!n)
251 return log_oom();
252
253 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
12ca818f 254 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
d2df0d0e
TG
255 return 0;
256 }
257
44386b44
YW
258 if (isempty(n))
259 *s = mfree(*s);
ae2a15bc 260 else
44386b44 261 free_and_replace(*s, n);
d2df0d0e
TG
262
263 return 0;
264}
265
5fde13d7
TG
266int config_parse_hwaddr(const char *unit,
267 const char *filename,
268 unsigned line,
269 const char *section,
71a61510 270 unsigned section_line,
5fde13d7
TG
271 const char *lvalue,
272 int ltype,
273 const char *rvalue,
274 void *data,
275 void *userdata) {
e5c1be89
YW
276
277 _cleanup_free_ struct ether_addr *n = NULL;
5fde13d7 278 struct ether_addr **hwaddr = data;
5fde13d7
TG
279 int r;
280
281 assert(filename);
282 assert(lvalue);
283 assert(rvalue);
284 assert(data);
285
a12fa420 286 n = new0(struct ether_addr, 1);
5fde13d7
TG
287 if (!n)
288 return log_oom();
289
e5c1be89
YW
290 r = ether_addr_from_string(rvalue, n);
291 if (r < 0) {
292 log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue);
5fde13d7
TG
293 return 0;
294 }
295
899f0d25 296 free_and_replace(*hwaddr, n);
5fde13d7
TG
297
298 return 0;
299}
f5284182 300
206b63ee
YW
301int config_parse_hwaddrs(const char *unit,
302 const char *filename,
303 unsigned line,
304 const char *section,
305 unsigned section_line,
306 const char *lvalue,
307 int ltype,
308 const char *rvalue,
309 void *data,
310 void *userdata) {
311
312 _cleanup_set_free_free_ Set *s = NULL;
313 const char *p = rvalue;
314 Set **hwaddrs = data;
315 int r;
316
317 assert(filename);
318 assert(lvalue);
319 assert(rvalue);
320 assert(data);
321
322 if (isempty(rvalue)) {
323 /* Empty assignment resets the list */
e90d0374 324 *hwaddrs = set_free_free(*hwaddrs);
206b63ee
YW
325 return 0;
326 }
327
328 s = set_new(&ether_addr_hash_ops);
329 if (!s)
330 return log_oom();
331
332 for (;;) {
333 _cleanup_free_ char *word = NULL;
334 _cleanup_free_ struct ether_addr *n = NULL;
335
336 r = extract_first_word(&p, &word, NULL, 0);
337 if (r == 0)
338 break;
339 if (r == -ENOMEM)
340 return log_oom();
341 if (r < 0) {
342 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
343 return 0;
344 }
345
e90d0374 346 n = new(struct ether_addr, 1);
206b63ee
YW
347 if (!n)
348 return log_oom();
349
350 r = ether_addr_from_string(word, n);
351 if (r < 0) {
352 log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word);
353 continue;
354 }
355
356 r = set_put(s, n);
357 if (r < 0)
358 return log_oom();
359 if (r > 0)
360 n = NULL; /* avoid cleanup */
361 }
362
363 r = set_ensure_allocated(hwaddrs, &ether_addr_hash_ops);
364 if (r < 0)
365 return log_oom();
366
367 r = set_move(*hwaddrs, s);
368 if (r < 0)
369 return log_oom();
370
371 return 0;
372}
373
f00ff0de
DJL
374int config_parse_bridge_port_priority(
375 const char *unit,
376 const char *filename,
377 unsigned line,
378 const char *section,
379 unsigned section_line,
380 const char *lvalue,
381 int ltype,
382 const char *rvalue,
383 void *data,
384 void *userdata) {
385
386 uint16_t i;
387 int r;
388
389 assert(filename);
390 assert(lvalue);
391 assert(rvalue);
392 assert(data);
393
394 r = safe_atou16(rvalue, &i);
395 if (r < 0) {
396 log_syntax(unit, LOG_ERR, filename, line, r,
397 "Failed to parse bridge port priority, ignoring: %s", rvalue);
398 return 0;
399 }
400
401 if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) {
402 log_syntax(unit, LOG_ERR, filename, line, r,
403 "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue);
404 return 0;
405 }
406
407 *((uint16_t *)data) = i;
408
409 return 0;
410}
411
b0e39c82 412void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
09bee74d
TG
413 unsigned i;
414
415 assert(f);
09bee74d
TG
416 assert(addresses);
417 assert(size);
418
09bee74d
TG
419 for (i = 0; i < size; i++)
420 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
421 (i < (size - 1)) ? " ": "");
09bee74d
TG
422}
423
a2ba62c7 424int deserialize_in_addrs(struct in_addr **ret, const char *string) {
09bee74d 425 _cleanup_free_ struct in_addr *addresses = NULL;
a2ba62c7 426 int size = 0;
09bee74d
TG
427
428 assert(ret);
09bee74d
TG
429 assert(string);
430
93e28226
SS
431 for (;;) {
432 _cleanup_free_ char *word = NULL;
09bee74d
TG
433 struct in_addr *new_addresses;
434 int r;
435
93e28226
SS
436 r = extract_first_word(&string, &word, NULL, 0);
437 if (r < 0)
438 return r;
439 if (r == 0)
440 break;
441
62d74c78 442 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
09bee74d
TG
443 if (!new_addresses)
444 return -ENOMEM;
445 else
446 addresses = new_addresses;
447
93e28226 448 r = inet_pton(AF_INET, word, &(addresses[size]));
09bee74d
TG
449 if (r <= 0)
450 continue;
451
313cefa1 452 size++;
09bee74d
TG
453 }
454
ae2a15bc 455 *ret = TAKE_PTR(addresses);
09bee74d 456
a2ba62c7 457 return size;
09bee74d
TG
458}
459
1f152e4b 460void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
b729fa14
PF
461 unsigned i;
462
463 assert(f);
464 assert(addresses);
465 assert(size);
466
1f152e4b
LP
467 for (i = 0; i < size; i++) {
468 char buffer[INET6_ADDRSTRLEN];
469
470 fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
471
472 if (i < size - 1)
473 fputc(' ', f);
474 }
b729fa14
PF
475}
476
a2ba62c7 477int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
09bee74d 478 _cleanup_free_ struct in6_addr *addresses = NULL;
a2ba62c7 479 int size = 0;
09bee74d
TG
480
481 assert(ret);
09bee74d
TG
482 assert(string);
483
93e28226
SS
484 for (;;) {
485 _cleanup_free_ char *word = NULL;
09bee74d
TG
486 struct in6_addr *new_addresses;
487 int r;
488
93e28226
SS
489 r = extract_first_word(&string, &word, NULL, 0);
490 if (r < 0)
491 return r;
492 if (r == 0)
493 break;
494
62d74c78 495 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
09bee74d
TG
496 if (!new_addresses)
497 return -ENOMEM;
498 else
499 addresses = new_addresses;
500
93e28226 501 r = inet_pton(AF_INET6, word, &(addresses[size]));
09bee74d
TG
502 if (r <= 0)
503 continue;
504
505 size++;
506 }
507
ae2a15bc 508 *ret = TAKE_PTR(addresses);
09bee74d 509
a2ba62c7 510 return size;
09bee74d 511}
e1ea665e 512
f8693fc7 513void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
e1ea665e
EY
514 unsigned i;
515
516 assert(f);
517 assert(key);
518 assert(routes);
519 assert(size);
520
521 fprintf(f, "%s=", key);
522
fbf7dcb5 523 for (i = 0; i < size; i++) {
f8693fc7
BG
524 struct in_addr dest, gw;
525 uint8_t length;
526
527 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
528 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
529 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
530
531 fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
532 fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
fbf7dcb5 533 }
e1ea665e
EY
534
535 fputs("\n", f);
536}
537
538int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
539 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
540 size_t size = 0, allocated = 0;
e1ea665e
EY
541
542 assert(ret);
543 assert(ret_size);
544 assert(ret_allocated);
545 assert(string);
546
93e28226
SS
547 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
548 for (;;) {
549 _cleanup_free_ char *word = NULL;
e1ea665e
EY
550 char *tok, *tok_end;
551 unsigned n;
552 int r;
553
93e28226
SS
554 r = extract_first_word(&string, &word, NULL, 0);
555 if (r < 0)
556 return r;
557 if (r == 0)
558 break;
e1ea665e 559
93e28226 560 if (!GREEDY_REALLOC(routes, allocated, size + 1))
31db0120 561 return -ENOMEM;
e1ea665e 562
93e28226 563 tok = word;
e1ea665e
EY
564
565 /* get the subnet */
566 tok_end = strchr(tok, '/');
567 if (!tok_end)
568 continue;
569 *tok_end = '\0';
570
571 r = inet_aton(tok, &routes[size].dst_addr);
572 if (r == 0)
573 continue;
574
575 tok = tok_end + 1;
576
577 /* get the prefixlen */
578 tok_end = strchr(tok, ',');
579 if (!tok_end)
580 continue;
581
582 *tok_end = '\0';
583
584 r = safe_atou(tok, &n);
585 if (r < 0 || n > 32)
586 continue;
587
588 routes[size].dst_prefixlen = (uint8_t) n;
589 tok = tok_end + 1;
590
591 /* get the gateway */
592 r = inet_aton(tok, &routes[size].gw_addr);
593 if (r == 0)
594 continue;
595
596 size++;
597 }
598
599 *ret_size = size;
600 *ret_allocated = allocated;
ae2a15bc 601 *ret = TAKE_PTR(routes);
e1ea665e
EY
602
603 return 0;
604}
a073309f 605
e4735228 606int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
a073309f
AC
607 _cleanup_free_ char *hex_buf = NULL;
608
609 assert(f);
610 assert(key);
611 assert(data);
612
613 hex_buf = hexmem(data, size);
614 if (hex_buf == NULL)
615 return -ENOMEM;
616
617 fprintf(f, "%s=%s\n", key, hex_buf);
618
619 return 0;
620}