]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
Merge pull request #8623 from yuwata/resolvectl
[thirdparty/systemd.git] / src / libsystemd-network / network-internal.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
6 ***/
7
8 #include <arpa/inet.h>
9 #include <linux/if.h>
10 #include <netinet/ether.h>
11
12 #include "sd-id128.h"
13 #include "sd-ndisc.h"
14
15 #include "alloc-util.h"
16 #include "condition.h"
17 #include "conf-parser.h"
18 #include "dhcp-lease-internal.h"
19 #include "ether-addr-util.h"
20 #include "hexdecoct.h"
21 #include "log.h"
22 #include "network-internal.h"
23 #include "parse-util.h"
24 #include "siphash24.h"
25 #include "socket-util.h"
26 #include "string-util.h"
27 #include "strv.h"
28 #include "utf8.h"
29 #include "util.h"
30
31 const char *net_get_name(struct udev_device *device) {
32 const char *name, *field;
33
34 assert(device);
35
36 /* fetch some persistent data unique (on this machine) to this device */
37 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
38 name = udev_device_get_property_value(device, field);
39 if (name)
40 return name;
41 }
42
43 return NULL;
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
48 int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) {
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);
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. */
73 *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
74
75 return 0;
76 }
77
78 static bool net_condition_test_strv(char * const *raw_patterns,
79 const char *string) {
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;
86 unsigned i, length;
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
100 bool net_match_config(const struct ether_addr *match_mac,
101 char * const *match_paths,
102 char * const *match_drivers,
103 char * const *match_types,
104 char * const *match_names,
105 Condition *match_host,
106 Condition *match_virt,
107 Condition *match_kernel_cmdline,
108 Condition *match_kernel_version,
109 Condition *match_arch,
110 const struct ether_addr *dev_mac,
111 const char *dev_path,
112 const char *dev_parent_driver,
113 const char *dev_driver,
114 const char *dev_type,
115 const char *dev_name) {
116
117 if (match_host && condition_test(match_host) <= 0)
118 return false;
119
120 if (match_virt && condition_test(match_virt) <= 0)
121 return false;
122
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)
127 return false;
128
129 if (match_arch && condition_test(match_arch) <= 0)
130 return false;
131
132 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
133 return false;
134
135 if (!net_condition_test_strv(match_paths, dev_path))
136 return false;
137
138 if (!net_condition_test_strv(match_drivers, dev_driver))
139 return false;
140
141 if (!net_condition_test_strv(match_types, dev_type))
142 return false;
143
144 if (!net_condition_test_strv(match_names, dev_name))
145 return false;
146
147 return true;
148 }
149
150 int 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
191 int 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) {
202
203 char ***sv = data;
204 int r;
205
206 assert(filename);
207 assert(lvalue);
208 assert(rvalue);
209 assert(data);
210
211 for (;;) {
212 _cleanup_free_ char *word = NULL;
213
214 r = extract_first_word(&rvalue, &word, NULL, 0);
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 }
219 if (r == 0)
220 break;
221
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);
224 return 0;
225 }
226
227 r = strv_push(sv, word);
228 if (r < 0)
229 return log_oom();
230
231 word = NULL;
232 }
233
234 return 0;
235 }
236
237 int config_parse_ifalias(const char *unit,
238 const char *filename,
239 unsigned line,
240 const char *section,
241 unsigned section_line,
242 const char *lvalue,
243 int ltype,
244 const char *rvalue,
245 void *data,
246 void *userdata) {
247
248 char **s = data;
249 _cleanup_free_ char *n = NULL;
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) {
261 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
262 return 0;
263 }
264
265 free(*s);
266 if (*n)
267 *s = TAKE_PTR(n);
268 else
269 *s = NULL;
270
271 return 0;
272 }
273
274 int config_parse_hwaddr(const char *unit,
275 const char *filename,
276 unsigned line,
277 const char *section,
278 unsigned section_line,
279 const char *lvalue,
280 int ltype,
281 const char *rvalue,
282 void *data,
283 void *userdata) {
284 struct ether_addr **hwaddr = data;
285 struct ether_addr *n;
286 const char *start;
287 size_t offset;
288 int r;
289
290 assert(filename);
291 assert(lvalue);
292 assert(rvalue);
293 assert(data);
294
295 n = new0(struct ether_addr, 1);
296 if (!n)
297 return log_oom();
298
299 start = rvalue + strspn(rvalue, WHITESPACE);
300 r = ether_addr_from_string(start, n, &offset);
301
302 if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) {
303 log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
304 free(n);
305 return 0;
306 }
307
308 free(*hwaddr);
309 *hwaddr = n;
310
311 return 0;
312 }
313
314 int config_parse_iaid(const char *unit,
315 const char *filename,
316 unsigned line,
317 const char *section,
318 unsigned section_line,
319 const char *lvalue,
320 int ltype,
321 const char *rvalue,
322 void *data,
323 void *userdata) {
324 uint32_t iaid;
325 int r;
326
327 assert(filename);
328 assert(lvalue);
329 assert(rvalue);
330 assert(data);
331
332 r = safe_atou32(rvalue, &iaid);
333 if (r < 0) {
334 log_syntax(unit, LOG_ERR, filename, line, r,
335 "Unable to read IAID, ignoring assignment: %s", rvalue);
336 return 0;
337 }
338
339 *((uint32_t *)data) = iaid;
340
341 return 0;
342 }
343
344 int config_parse_bridge_port_priority(
345 const char *unit,
346 const char *filename,
347 unsigned line,
348 const char *section,
349 unsigned section_line,
350 const char *lvalue,
351 int ltype,
352 const char *rvalue,
353 void *data,
354 void *userdata) {
355
356 uint16_t i;
357 int r;
358
359 assert(filename);
360 assert(lvalue);
361 assert(rvalue);
362 assert(data);
363
364 r = safe_atou16(rvalue, &i);
365 if (r < 0) {
366 log_syntax(unit, LOG_ERR, filename, line, r,
367 "Failed to parse bridge port priority, ignoring: %s", rvalue);
368 return 0;
369 }
370
371 if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) {
372 log_syntax(unit, LOG_ERR, filename, line, r,
373 "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue);
374 return 0;
375 }
376
377 *((uint16_t *)data) = i;
378
379 return 0;
380 }
381
382 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
383 unsigned i;
384
385 assert(f);
386 assert(addresses);
387 assert(size);
388
389 for (i = 0; i < size; i++)
390 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
391 (i < (size - 1)) ? " ": "");
392 }
393
394 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
395 _cleanup_free_ struct in_addr *addresses = NULL;
396 int size = 0;
397
398 assert(ret);
399 assert(string);
400
401 for (;;) {
402 _cleanup_free_ char *word = NULL;
403 struct in_addr *new_addresses;
404 int r;
405
406 r = extract_first_word(&string, &word, NULL, 0);
407 if (r < 0)
408 return r;
409 if (r == 0)
410 break;
411
412 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
413 if (!new_addresses)
414 return -ENOMEM;
415 else
416 addresses = new_addresses;
417
418 r = inet_pton(AF_INET, word, &(addresses[size]));
419 if (r <= 0)
420 continue;
421
422 size++;
423 }
424
425 *ret = TAKE_PTR(addresses);
426
427 return size;
428 }
429
430 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
431 unsigned i;
432
433 assert(f);
434 assert(addresses);
435 assert(size);
436
437 for (i = 0; i < size; i++) {
438 char buffer[INET6_ADDRSTRLEN];
439
440 fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
441
442 if (i < size - 1)
443 fputc(' ', f);
444 }
445 }
446
447 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
448 _cleanup_free_ struct in6_addr *addresses = NULL;
449 int size = 0;
450
451 assert(ret);
452 assert(string);
453
454 for (;;) {
455 _cleanup_free_ char *word = NULL;
456 struct in6_addr *new_addresses;
457 int r;
458
459 r = extract_first_word(&string, &word, NULL, 0);
460 if (r < 0)
461 return r;
462 if (r == 0)
463 break;
464
465 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
466 if (!new_addresses)
467 return -ENOMEM;
468 else
469 addresses = new_addresses;
470
471 r = inet_pton(AF_INET6, word, &(addresses[size]));
472 if (r <= 0)
473 continue;
474
475 size++;
476 }
477
478 *ret = TAKE_PTR(addresses);
479
480 return size;
481 }
482
483 void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
484 unsigned i;
485
486 assert(f);
487 assert(key);
488 assert(routes);
489 assert(size);
490
491 fprintf(f, "%s=", key);
492
493 for (i = 0; i < size; i++) {
494 struct in_addr dest, gw;
495 uint8_t length;
496
497 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
498 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
499 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
500
501 fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
502 fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
503 }
504
505 fputs("\n", f);
506 }
507
508 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
509 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
510 size_t size = 0, allocated = 0;
511
512 assert(ret);
513 assert(ret_size);
514 assert(ret_allocated);
515 assert(string);
516
517 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
518 for (;;) {
519 _cleanup_free_ char *word = NULL;
520 char *tok, *tok_end;
521 unsigned n;
522 int r;
523
524 r = extract_first_word(&string, &word, NULL, 0);
525 if (r < 0)
526 return r;
527 if (r == 0)
528 break;
529
530 if (!GREEDY_REALLOC(routes, allocated, size + 1))
531 return -ENOMEM;
532
533 tok = word;
534
535 /* get the subnet */
536 tok_end = strchr(tok, '/');
537 if (!tok_end)
538 continue;
539 *tok_end = '\0';
540
541 r = inet_aton(tok, &routes[size].dst_addr);
542 if (r == 0)
543 continue;
544
545 tok = tok_end + 1;
546
547 /* get the prefixlen */
548 tok_end = strchr(tok, ',');
549 if (!tok_end)
550 continue;
551
552 *tok_end = '\0';
553
554 r = safe_atou(tok, &n);
555 if (r < 0 || n > 32)
556 continue;
557
558 routes[size].dst_prefixlen = (uint8_t) n;
559 tok = tok_end + 1;
560
561 /* get the gateway */
562 r = inet_aton(tok, &routes[size].gw_addr);
563 if (r == 0)
564 continue;
565
566 size++;
567 }
568
569 *ret_size = size;
570 *ret_allocated = allocated;
571 *ret = TAKE_PTR(routes);
572
573 return 0;
574 }
575
576 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
577 _cleanup_free_ char *hex_buf = NULL;
578
579 assert(f);
580 assert(key);
581 assert(data);
582
583 hex_buf = hexmem(data, size);
584 if (hex_buf == NULL)
585 return -ENOMEM;
586
587 fprintf(f, "%s=%s\n", key, hex_buf);
588
589 return 0;
590 }
591
592 int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) {
593 assert(data);
594 assert(data_len);
595 assert(string);
596
597 if (strlen(string) % 2)
598 return -EINVAL;
599
600 return unhexmem(string, strlen(string), (void **)data, data_len);
601 }