]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
Merge pull request #8575 from keszybz/non-absolute-paths
[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
383 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
384 unsigned i;
385
386 assert(f);
387 assert(addresses);
388 assert(size);
389
390 for (i = 0; i < size; i++)
391 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
392 (i < (size - 1)) ? " ": "");
393 }
394
395 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
396 _cleanup_free_ struct in_addr *addresses = NULL;
397 int size = 0;
398
399 assert(ret);
400 assert(string);
401
402 for (;;) {
403 _cleanup_free_ char *word = NULL;
404 struct in_addr *new_addresses;
405 int r;
406
407 r = extract_first_word(&string, &word, NULL, 0);
408 if (r < 0)
409 return r;
410 if (r == 0)
411 break;
412
413 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
414 if (!new_addresses)
415 return -ENOMEM;
416 else
417 addresses = new_addresses;
418
419 r = inet_pton(AF_INET, word, &(addresses[size]));
420 if (r <= 0)
421 continue;
422
423 size++;
424 }
425
426 *ret = TAKE_PTR(addresses);
427
428 return size;
429 }
430
431 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
432 unsigned i;
433
434 assert(f);
435 assert(addresses);
436 assert(size);
437
438 for (i = 0; i < size; i++) {
439 char buffer[INET6_ADDRSTRLEN];
440
441 fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
442
443 if (i < size - 1)
444 fputc(' ', f);
445 }
446 }
447
448 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
449 _cleanup_free_ struct in6_addr *addresses = NULL;
450 int size = 0;
451
452 assert(ret);
453 assert(string);
454
455 for (;;) {
456 _cleanup_free_ char *word = NULL;
457 struct in6_addr *new_addresses;
458 int r;
459
460 r = extract_first_word(&string, &word, NULL, 0);
461 if (r < 0)
462 return r;
463 if (r == 0)
464 break;
465
466 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
467 if (!new_addresses)
468 return -ENOMEM;
469 else
470 addresses = new_addresses;
471
472 r = inet_pton(AF_INET6, word, &(addresses[size]));
473 if (r <= 0)
474 continue;
475
476 size++;
477 }
478
479 *ret = TAKE_PTR(addresses);
480
481 return size;
482 }
483
484 void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
485 unsigned i;
486
487 assert(f);
488 assert(key);
489 assert(routes);
490 assert(size);
491
492 fprintf(f, "%s=", key);
493
494 for (i = 0; i < size; i++) {
495 struct in_addr dest, gw;
496 uint8_t length;
497
498 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
499 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
500 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
501
502 fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
503 fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
504 }
505
506 fputs("\n", f);
507 }
508
509 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
510 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
511 size_t size = 0, allocated = 0;
512
513 assert(ret);
514 assert(ret_size);
515 assert(ret_allocated);
516 assert(string);
517
518 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
519 for (;;) {
520 _cleanup_free_ char *word = NULL;
521 char *tok, *tok_end;
522 unsigned n;
523 int r;
524
525 r = extract_first_word(&string, &word, NULL, 0);
526 if (r < 0)
527 return r;
528 if (r == 0)
529 break;
530
531 if (!GREEDY_REALLOC(routes, allocated, size + 1))
532 return -ENOMEM;
533
534 tok = word;
535
536 /* get the subnet */
537 tok_end = strchr(tok, '/');
538 if (!tok_end)
539 continue;
540 *tok_end = '\0';
541
542 r = inet_aton(tok, &routes[size].dst_addr);
543 if (r == 0)
544 continue;
545
546 tok = tok_end + 1;
547
548 /* get the prefixlen */
549 tok_end = strchr(tok, ',');
550 if (!tok_end)
551 continue;
552
553 *tok_end = '\0';
554
555 r = safe_atou(tok, &n);
556 if (r < 0 || n > 32)
557 continue;
558
559 routes[size].dst_prefixlen = (uint8_t) n;
560 tok = tok_end + 1;
561
562 /* get the gateway */
563 r = inet_aton(tok, &routes[size].gw_addr);
564 if (r == 0)
565 continue;
566
567 size++;
568 }
569
570 *ret_size = size;
571 *ret_allocated = allocated;
572 *ret = TAKE_PTR(routes);
573
574 return 0;
575 }
576
577 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
578 _cleanup_free_ char *hex_buf = NULL;
579
580 assert(f);
581 assert(key);
582 assert(data);
583
584 hex_buf = hexmem(data, size);
585 if (hex_buf == NULL)
586 return -ENOMEM;
587
588 fprintf(f, "%s=%s\n", key, hex_buf);
589
590 return 0;
591 }
592
593 int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) {
594 assert(data);
595 assert(data_len);
596 assert(string);
597
598 if (strlen(string) % 2)
599 return -EINVAL;
600
601 return unhexmem(string, strlen(string), (void **)data, data_len);
602 }