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