]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/network-internal.c
network: improve readability of config_parse_ifalias()
[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
e5c1be89 296 *hwaddr = TAKE_PTR(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
413708d1
VK
374int config_parse_iaid(const char *unit,
375 const char *filename,
376 unsigned line,
377 const char *section,
378 unsigned section_line,
379 const char *lvalue,
380 int ltype,
381 const char *rvalue,
382 void *data,
383 void *userdata) {
384 uint32_t iaid;
385 int r;
386
387 assert(filename);
388 assert(lvalue);
389 assert(rvalue);
390 assert(data);
391
392 r = safe_atou32(rvalue, &iaid);
393 if (r < 0) {
b7f71444
VK
394 log_syntax(unit, LOG_ERR, filename, line, r,
395 "Unable to read IAID, ignoring assignment: %s", rvalue);
396 return 0;
413708d1
VK
397 }
398
399 *((uint32_t *)data) = iaid;
400
401 return 0;
402}
403
f00ff0de
DJL
404int config_parse_bridge_port_priority(
405 const char *unit,
406 const char *filename,
407 unsigned line,
408 const char *section,
409 unsigned section_line,
410 const char *lvalue,
411 int ltype,
412 const char *rvalue,
413 void *data,
414 void *userdata) {
415
416 uint16_t i;
417 int r;
418
419 assert(filename);
420 assert(lvalue);
421 assert(rvalue);
422 assert(data);
423
424 r = safe_atou16(rvalue, &i);
425 if (r < 0) {
426 log_syntax(unit, LOG_ERR, filename, line, r,
427 "Failed to parse bridge port priority, ignoring: %s", rvalue);
428 return 0;
429 }
430
431 if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) {
432 log_syntax(unit, LOG_ERR, filename, line, r,
433 "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue);
434 return 0;
435 }
436
437 *((uint16_t *)data) = i;
438
439 return 0;
440}
441
b0e39c82 442void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
09bee74d
TG
443 unsigned i;
444
445 assert(f);
09bee74d
TG
446 assert(addresses);
447 assert(size);
448
09bee74d
TG
449 for (i = 0; i < size; i++)
450 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
451 (i < (size - 1)) ? " ": "");
09bee74d
TG
452}
453
a2ba62c7 454int deserialize_in_addrs(struct in_addr **ret, const char *string) {
09bee74d 455 _cleanup_free_ struct in_addr *addresses = NULL;
a2ba62c7 456 int size = 0;
09bee74d
TG
457
458 assert(ret);
09bee74d
TG
459 assert(string);
460
93e28226
SS
461 for (;;) {
462 _cleanup_free_ char *word = NULL;
09bee74d
TG
463 struct in_addr *new_addresses;
464 int r;
465
93e28226
SS
466 r = extract_first_word(&string, &word, NULL, 0);
467 if (r < 0)
468 return r;
469 if (r == 0)
470 break;
471
62d74c78 472 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
09bee74d
TG
473 if (!new_addresses)
474 return -ENOMEM;
475 else
476 addresses = new_addresses;
477
93e28226 478 r = inet_pton(AF_INET, word, &(addresses[size]));
09bee74d
TG
479 if (r <= 0)
480 continue;
481
313cefa1 482 size++;
09bee74d
TG
483 }
484
ae2a15bc 485 *ret = TAKE_PTR(addresses);
09bee74d 486
a2ba62c7 487 return size;
09bee74d
TG
488}
489
1f152e4b 490void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
b729fa14
PF
491 unsigned i;
492
493 assert(f);
494 assert(addresses);
495 assert(size);
496
1f152e4b
LP
497 for (i = 0; i < size; i++) {
498 char buffer[INET6_ADDRSTRLEN];
499
500 fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
501
502 if (i < size - 1)
503 fputc(' ', f);
504 }
b729fa14
PF
505}
506
a2ba62c7 507int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
09bee74d 508 _cleanup_free_ struct in6_addr *addresses = NULL;
a2ba62c7 509 int size = 0;
09bee74d
TG
510
511 assert(ret);
09bee74d
TG
512 assert(string);
513
93e28226
SS
514 for (;;) {
515 _cleanup_free_ char *word = NULL;
09bee74d
TG
516 struct in6_addr *new_addresses;
517 int r;
518
93e28226
SS
519 r = extract_first_word(&string, &word, NULL, 0);
520 if (r < 0)
521 return r;
522 if (r == 0)
523 break;
524
62d74c78 525 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
09bee74d
TG
526 if (!new_addresses)
527 return -ENOMEM;
528 else
529 addresses = new_addresses;
530
93e28226 531 r = inet_pton(AF_INET6, word, &(addresses[size]));
09bee74d
TG
532 if (r <= 0)
533 continue;
534
535 size++;
536 }
537
ae2a15bc 538 *ret = TAKE_PTR(addresses);
09bee74d 539
a2ba62c7 540 return size;
09bee74d 541}
e1ea665e 542
f8693fc7 543void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
e1ea665e
EY
544 unsigned i;
545
546 assert(f);
547 assert(key);
548 assert(routes);
549 assert(size);
550
551 fprintf(f, "%s=", key);
552
fbf7dcb5 553 for (i = 0; i < size; i++) {
f8693fc7
BG
554 struct in_addr dest, gw;
555 uint8_t length;
556
557 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
558 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
559 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
560
561 fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
562 fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
fbf7dcb5 563 }
e1ea665e
EY
564
565 fputs("\n", f);
566}
567
568int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
569 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
570 size_t size = 0, allocated = 0;
e1ea665e
EY
571
572 assert(ret);
573 assert(ret_size);
574 assert(ret_allocated);
575 assert(string);
576
93e28226
SS
577 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
578 for (;;) {
579 _cleanup_free_ char *word = NULL;
e1ea665e
EY
580 char *tok, *tok_end;
581 unsigned n;
582 int r;
583
93e28226
SS
584 r = extract_first_word(&string, &word, NULL, 0);
585 if (r < 0)
586 return r;
587 if (r == 0)
588 break;
e1ea665e 589
93e28226 590 if (!GREEDY_REALLOC(routes, allocated, size + 1))
31db0120 591 return -ENOMEM;
e1ea665e 592
93e28226 593 tok = word;
e1ea665e
EY
594
595 /* get the subnet */
596 tok_end = strchr(tok, '/');
597 if (!tok_end)
598 continue;
599 *tok_end = '\0';
600
601 r = inet_aton(tok, &routes[size].dst_addr);
602 if (r == 0)
603 continue;
604
605 tok = tok_end + 1;
606
607 /* get the prefixlen */
608 tok_end = strchr(tok, ',');
609 if (!tok_end)
610 continue;
611
612 *tok_end = '\0';
613
614 r = safe_atou(tok, &n);
615 if (r < 0 || n > 32)
616 continue;
617
618 routes[size].dst_prefixlen = (uint8_t) n;
619 tok = tok_end + 1;
620
621 /* get the gateway */
622 r = inet_aton(tok, &routes[size].gw_addr);
623 if (r == 0)
624 continue;
625
626 size++;
627 }
628
629 *ret_size = size;
630 *ret_allocated = allocated;
ae2a15bc 631 *ret = TAKE_PTR(routes);
e1ea665e
EY
632
633 return 0;
634}
a073309f 635
e4735228 636int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
a073309f
AC
637 _cleanup_free_ char *hex_buf = NULL;
638
639 assert(f);
640 assert(key);
641 assert(data);
642
643 hex_buf = hexmem(data, size);
644 if (hex_buf == NULL)
645 return -ENOMEM;
646
647 fprintf(f, "%s=%s\n", key, hex_buf);
648
649 return 0;
650}