]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
pkgconfig: define variables relative to ${prefix}/${rootprefix}/${sysconfdir}
[thirdparty/systemd.git] / src / libsystemd-network / network-internal.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <arpa/inet.h>
4 #include <linux/if.h>
5 #include <netinet/ether.h>
6
7 #include "sd-id128.h"
8 #include "sd-ndisc.h"
9
10 #include "alloc-util.h"
11 #include "condition.h"
12 #include "conf-parser.h"
13 #include "dhcp-lease-internal.h"
14 #include "ether-addr-util.h"
15 #include "hexdecoct.h"
16 #include "log.h"
17 #include "network-internal.h"
18 #include "parse-util.h"
19 #include "siphash24.h"
20 #include "socket-util.h"
21 #include "string-util.h"
22 #include "strv.h"
23 #include "utf8.h"
24 #include "util.h"
25
26 const char *net_get_name(sd_device *device) {
27 const char *name, *field;
28
29 assert(device);
30
31 /* fetch some persistent data unique (on this machine) to this device */
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)
34 return name;
35
36 return NULL;
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
41 int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
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);
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. */
66 *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
67
68 return 0;
69 }
70
71 static bool net_condition_test_strv(char * const *raw_patterns,
72 const char *string) {
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;
79 size_t i, length;
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
93 bool net_match_config(Set *match_mac,
94 char * const *match_paths,
95 char * const *match_drivers,
96 char * const *match_types,
97 char * const *match_names,
98 Condition *match_host,
99 Condition *match_virt,
100 Condition *match_kernel_cmdline,
101 Condition *match_kernel_version,
102 Condition *match_arch,
103 const struct ether_addr *dev_mac,
104 const char *dev_path,
105 const char *dev_parent_driver,
106 const char *dev_driver,
107 const char *dev_type,
108 const char *dev_name) {
109
110 if (match_host && condition_test(match_host) <= 0)
111 return false;
112
113 if (match_virt && condition_test(match_virt) <= 0)
114 return false;
115
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)
120 return false;
121
122 if (match_arch && condition_test(match_arch) <= 0)
123 return false;
124
125 if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
126 return false;
127
128 if (!net_condition_test_strv(match_paths, dev_path))
129 return false;
130
131 if (!net_condition_test_strv(match_drivers, dev_driver))
132 return false;
133
134 if (!net_condition_test_strv(match_types, dev_type))
135 return false;
136
137 if (!net_condition_test_strv(match_names, dev_name))
138 return false;
139
140 return true;
141 }
142
143 int 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
184 int 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) {
195
196 char ***sv = data;
197 int r;
198
199 assert(filename);
200 assert(lvalue);
201 assert(rvalue);
202 assert(data);
203
204 for (;;) {
205 _cleanup_free_ char *word = NULL;
206
207 r = extract_first_word(&rvalue, &word, NULL, 0);
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 }
212 if (r == 0)
213 break;
214
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);
217 return 0;
218 }
219
220 r = strv_push(sv, word);
221 if (r < 0)
222 return log_oom();
223
224 word = NULL;
225 }
226
227 return 0;
228 }
229
230 int config_parse_ifalias(const char *unit,
231 const char *filename,
232 unsigned line,
233 const char *section,
234 unsigned section_line,
235 const char *lvalue,
236 int ltype,
237 const char *rvalue,
238 void *data,
239 void *userdata) {
240
241 char **s = data;
242 _cleanup_free_ char *n = NULL;
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) {
254 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
255 return 0;
256 }
257
258 if (isempty(n))
259 *s = mfree(*s);
260 else
261 free_and_replace(*s, n);
262
263 return 0;
264 }
265
266 int config_parse_hwaddr(const char *unit,
267 const char *filename,
268 unsigned line,
269 const char *section,
270 unsigned section_line,
271 const char *lvalue,
272 int ltype,
273 const char *rvalue,
274 void *data,
275 void *userdata) {
276
277 _cleanup_free_ struct ether_addr *n = NULL;
278 struct ether_addr **hwaddr = data;
279 int r;
280
281 assert(filename);
282 assert(lvalue);
283 assert(rvalue);
284 assert(data);
285
286 n = new0(struct ether_addr, 1);
287 if (!n)
288 return log_oom();
289
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);
293 return 0;
294 }
295
296 free_and_replace(*hwaddr, n);
297
298 return 0;
299 }
300
301 int 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 */
324 *hwaddrs = set_free_free(*hwaddrs);
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
346 n = new(struct ether_addr, 1);
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
374 int 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) {
394 log_syntax(unit, LOG_ERR, filename, line, r,
395 "Unable to read IAID, ignoring assignment: %s", rvalue);
396 return 0;
397 }
398
399 *((uint32_t *)data) = iaid;
400
401 return 0;
402 }
403
404 int 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
442 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
443 unsigned i;
444
445 assert(f);
446 assert(addresses);
447 assert(size);
448
449 for (i = 0; i < size; i++)
450 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
451 (i < (size - 1)) ? " ": "");
452 }
453
454 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
455 _cleanup_free_ struct in_addr *addresses = NULL;
456 int size = 0;
457
458 assert(ret);
459 assert(string);
460
461 for (;;) {
462 _cleanup_free_ char *word = NULL;
463 struct in_addr *new_addresses;
464 int r;
465
466 r = extract_first_word(&string, &word, NULL, 0);
467 if (r < 0)
468 return r;
469 if (r == 0)
470 break;
471
472 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
473 if (!new_addresses)
474 return -ENOMEM;
475 else
476 addresses = new_addresses;
477
478 r = inet_pton(AF_INET, word, &(addresses[size]));
479 if (r <= 0)
480 continue;
481
482 size++;
483 }
484
485 *ret = TAKE_PTR(addresses);
486
487 return size;
488 }
489
490 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
491 unsigned i;
492
493 assert(f);
494 assert(addresses);
495 assert(size);
496
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 }
505 }
506
507 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
508 _cleanup_free_ struct in6_addr *addresses = NULL;
509 int size = 0;
510
511 assert(ret);
512 assert(string);
513
514 for (;;) {
515 _cleanup_free_ char *word = NULL;
516 struct in6_addr *new_addresses;
517 int r;
518
519 r = extract_first_word(&string, &word, NULL, 0);
520 if (r < 0)
521 return r;
522 if (r == 0)
523 break;
524
525 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
526 if (!new_addresses)
527 return -ENOMEM;
528 else
529 addresses = new_addresses;
530
531 r = inet_pton(AF_INET6, word, &(addresses[size]));
532 if (r <= 0)
533 continue;
534
535 size++;
536 }
537
538 *ret = TAKE_PTR(addresses);
539
540 return size;
541 }
542
543 void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
544 unsigned i;
545
546 assert(f);
547 assert(key);
548 assert(routes);
549 assert(size);
550
551 fprintf(f, "%s=", key);
552
553 for (i = 0; i < size; i++) {
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)) ? " ": "");
563 }
564
565 fputs("\n", f);
566 }
567
568 int 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;
571
572 assert(ret);
573 assert(ret_size);
574 assert(ret_allocated);
575 assert(string);
576
577 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
578 for (;;) {
579 _cleanup_free_ char *word = NULL;
580 char *tok, *tok_end;
581 unsigned n;
582 int r;
583
584 r = extract_first_word(&string, &word, NULL, 0);
585 if (r < 0)
586 return r;
587 if (r == 0)
588 break;
589
590 if (!GREEDY_REALLOC(routes, allocated, size + 1))
591 return -ENOMEM;
592
593 tok = word;
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;
631 *ret = TAKE_PTR(routes);
632
633 return 0;
634 }
635
636 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
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 }