]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
Merge pull request #8553 from poettering/take-take
[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 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <arpa/inet.h>
22 #include <linux/if.h>
23 #include <netinet/ether.h>
24
25 #include "sd-id128.h"
26 #include "sd-ndisc.h"
27
28 #include "alloc-util.h"
29 #include "condition.h"
30 #include "conf-parser.h"
31 #include "dhcp-lease-internal.h"
32 #include "ether-addr-util.h"
33 #include "hexdecoct.h"
34 #include "log.h"
35 #include "network-internal.h"
36 #include "parse-util.h"
37 #include "siphash24.h"
38 #include "socket-util.h"
39 #include "string-util.h"
40 #include "strv.h"
41 #include "utf8.h"
42 #include "util.h"
43
44 const char *net_get_name(struct udev_device *device) {
45 const char *name, *field;
46
47 assert(device);
48
49 /* fetch some persistent data unique (on this machine) to this device */
50 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
51 name = udev_device_get_property_value(device, field);
52 if (name)
53 return name;
54 }
55
56 return NULL;
57 }
58
59 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
60
61 int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) {
62 size_t l, sz = 0;
63 const char *name = NULL;
64 int r;
65 uint8_t *v;
66
67 assert(device);
68
69 name = net_get_name(device);
70 if (!name)
71 return -ENOENT;
72
73 l = strlen(name);
74 sz = sizeof(sd_id128_t) + l;
75 v = alloca(sz);
76
77 /* fetch some persistent data unique to this machine */
78 r = sd_id128_get_machine((sd_id128_t*) v);
79 if (r < 0)
80 return r;
81 memcpy(v + sizeof(sd_id128_t), name, l);
82
83 /* Let's hash the machine ID plus the device name. We
84 * use a fixed, but originally randomly created hash
85 * key here. */
86 *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
87
88 return 0;
89 }
90
91 static bool net_condition_test_strv(char * const *raw_patterns,
92 const char *string) {
93 if (strv_isempty(raw_patterns))
94 return true;
95
96 /* If the patterns begin with "!", edit it out and negate the test. */
97 if (raw_patterns[0][0] == '!') {
98 char **patterns;
99 unsigned i, length;
100
101 length = strv_length(raw_patterns) + 1; /* Include the NULL. */
102 patterns = newa(char*, length);
103 patterns[0] = raw_patterns[0] + 1; /* Skip the "!". */
104 for (i = 1; i < length; i++)
105 patterns[i] = raw_patterns[i];
106
107 return !string || !strv_fnmatch(patterns, string, 0);
108 }
109
110 return string && strv_fnmatch(raw_patterns, string, 0);
111 }
112
113 bool net_match_config(const struct ether_addr *match_mac,
114 char * const *match_paths,
115 char * const *match_drivers,
116 char * const *match_types,
117 char * const *match_names,
118 Condition *match_host,
119 Condition *match_virt,
120 Condition *match_kernel_cmdline,
121 Condition *match_kernel_version,
122 Condition *match_arch,
123 const struct ether_addr *dev_mac,
124 const char *dev_path,
125 const char *dev_parent_driver,
126 const char *dev_driver,
127 const char *dev_type,
128 const char *dev_name) {
129
130 if (match_host && condition_test(match_host) <= 0)
131 return false;
132
133 if (match_virt && condition_test(match_virt) <= 0)
134 return false;
135
136 if (match_kernel_cmdline && condition_test(match_kernel_cmdline) <= 0)
137 return false;
138
139 if (match_kernel_version && condition_test(match_kernel_version) <= 0)
140 return false;
141
142 if (match_arch && condition_test(match_arch) <= 0)
143 return false;
144
145 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
146 return false;
147
148 if (!net_condition_test_strv(match_paths, dev_path))
149 return false;
150
151 if (!net_condition_test_strv(match_drivers, dev_driver))
152 return false;
153
154 if (!net_condition_test_strv(match_types, dev_type))
155 return false;
156
157 if (!net_condition_test_strv(match_names, dev_name))
158 return false;
159
160 return true;
161 }
162
163 int config_parse_net_condition(const char *unit,
164 const char *filename,
165 unsigned line,
166 const char *section,
167 unsigned section_line,
168 const char *lvalue,
169 int ltype,
170 const char *rvalue,
171 void *data,
172 void *userdata) {
173
174 ConditionType cond = ltype;
175 Condition **ret = data;
176 bool negate;
177 Condition *c;
178 _cleanup_free_ char *s = NULL;
179
180 assert(filename);
181 assert(lvalue);
182 assert(rvalue);
183 assert(data);
184
185 negate = rvalue[0] == '!';
186 if (negate)
187 rvalue++;
188
189 s = strdup(rvalue);
190 if (!s)
191 return log_oom();
192
193 c = condition_new(cond, s, false, negate);
194 if (!c)
195 return log_oom();
196
197 if (*ret)
198 condition_free(*ret);
199
200 *ret = c;
201 return 0;
202 }
203
204 int config_parse_ifnames(
205 const char *unit,
206 const char *filename,
207 unsigned line,
208 const char *section,
209 unsigned section_line,
210 const char *lvalue,
211 int ltype,
212 const char *rvalue,
213 void *data,
214 void *userdata) {
215
216 char ***sv = data;
217 int r;
218
219 assert(filename);
220 assert(lvalue);
221 assert(rvalue);
222 assert(data);
223
224 for (;;) {
225 _cleanup_free_ char *word = NULL;
226
227 r = extract_first_word(&rvalue, &word, NULL, 0);
228 if (r < 0) {
229 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue);
230 return 0;
231 }
232 if (r == 0)
233 break;
234
235 if (!ifname_valid(word)) {
236 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
237 return 0;
238 }
239
240 r = strv_push(sv, word);
241 if (r < 0)
242 return log_oom();
243
244 word = NULL;
245 }
246
247 return 0;
248 }
249
250 int config_parse_ifalias(const char *unit,
251 const char *filename,
252 unsigned line,
253 const char *section,
254 unsigned section_line,
255 const char *lvalue,
256 int ltype,
257 const char *rvalue,
258 void *data,
259 void *userdata) {
260
261 char **s = data;
262 _cleanup_free_ char *n = NULL;
263
264 assert(filename);
265 assert(lvalue);
266 assert(rvalue);
267 assert(data);
268
269 n = strdup(rvalue);
270 if (!n)
271 return log_oom();
272
273 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
274 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
275 return 0;
276 }
277
278 free(*s);
279 if (*n)
280 *s = TAKE_PTR(n);
281 else
282 *s = NULL;
283
284 return 0;
285 }
286
287 int config_parse_hwaddr(const char *unit,
288 const char *filename,
289 unsigned line,
290 const char *section,
291 unsigned section_line,
292 const char *lvalue,
293 int ltype,
294 const char *rvalue,
295 void *data,
296 void *userdata) {
297 struct ether_addr **hwaddr = data;
298 struct ether_addr *n;
299 const char *start;
300 size_t offset;
301 int r;
302
303 assert(filename);
304 assert(lvalue);
305 assert(rvalue);
306 assert(data);
307
308 n = new0(struct ether_addr, 1);
309 if (!n)
310 return log_oom();
311
312 start = rvalue + strspn(rvalue, WHITESPACE);
313 r = ether_addr_from_string(start, n, &offset);
314
315 if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) {
316 log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
317 free(n);
318 return 0;
319 }
320
321 free(*hwaddr);
322 *hwaddr = n;
323
324 return 0;
325 }
326
327 int config_parse_iaid(const char *unit,
328 const char *filename,
329 unsigned line,
330 const char *section,
331 unsigned section_line,
332 const char *lvalue,
333 int ltype,
334 const char *rvalue,
335 void *data,
336 void *userdata) {
337 uint32_t iaid;
338 int r;
339
340 assert(filename);
341 assert(lvalue);
342 assert(rvalue);
343 assert(data);
344
345 r = safe_atou32(rvalue, &iaid);
346 if (r < 0) {
347 log_syntax(unit, LOG_ERR, filename, line, r,
348 "Unable to read IAID, ignoring assignment: %s", rvalue);
349 return 0;
350 }
351
352 *((uint32_t *)data) = iaid;
353
354 return 0;
355 }
356
357 int config_parse_bridge_port_priority(
358 const char *unit,
359 const char *filename,
360 unsigned line,
361 const char *section,
362 unsigned section_line,
363 const char *lvalue,
364 int ltype,
365 const char *rvalue,
366 void *data,
367 void *userdata) {
368
369 uint16_t i;
370 int r;
371
372 assert(filename);
373 assert(lvalue);
374 assert(rvalue);
375 assert(data);
376
377 r = safe_atou16(rvalue, &i);
378 if (r < 0) {
379 log_syntax(unit, LOG_ERR, filename, line, r,
380 "Failed to parse bridge port priority, ignoring: %s", rvalue);
381 return 0;
382 }
383
384 if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) {
385 log_syntax(unit, LOG_ERR, filename, line, r,
386 "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue);
387 return 0;
388 }
389
390 *((uint16_t *)data) = i;
391
392 return 0;
393 }
394
395
396 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
397 unsigned i;
398
399 assert(f);
400 assert(addresses);
401 assert(size);
402
403 for (i = 0; i < size; i++)
404 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
405 (i < (size - 1)) ? " ": "");
406 }
407
408 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
409 _cleanup_free_ struct in_addr *addresses = NULL;
410 int size = 0;
411
412 assert(ret);
413 assert(string);
414
415 for (;;) {
416 _cleanup_free_ char *word = NULL;
417 struct in_addr *new_addresses;
418 int r;
419
420 r = extract_first_word(&string, &word, NULL, 0);
421 if (r < 0)
422 return r;
423 if (r == 0)
424 break;
425
426 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
427 if (!new_addresses)
428 return -ENOMEM;
429 else
430 addresses = new_addresses;
431
432 r = inet_pton(AF_INET, word, &(addresses[size]));
433 if (r <= 0)
434 continue;
435
436 size++;
437 }
438
439 *ret = TAKE_PTR(addresses);
440
441 return size;
442 }
443
444 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
445 unsigned i;
446
447 assert(f);
448 assert(addresses);
449 assert(size);
450
451 for (i = 0; i < size; i++) {
452 char buffer[INET6_ADDRSTRLEN];
453
454 fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
455
456 if (i < size - 1)
457 fputc(' ', f);
458 }
459 }
460
461 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
462 _cleanup_free_ struct in6_addr *addresses = NULL;
463 int size = 0;
464
465 assert(ret);
466 assert(string);
467
468 for (;;) {
469 _cleanup_free_ char *word = NULL;
470 struct in6_addr *new_addresses;
471 int r;
472
473 r = extract_first_word(&string, &word, NULL, 0);
474 if (r < 0)
475 return r;
476 if (r == 0)
477 break;
478
479 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
480 if (!new_addresses)
481 return -ENOMEM;
482 else
483 addresses = new_addresses;
484
485 r = inet_pton(AF_INET6, word, &(addresses[size]));
486 if (r <= 0)
487 continue;
488
489 size++;
490 }
491
492 *ret = TAKE_PTR(addresses);
493
494 return size;
495 }
496
497 void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
498 unsigned i;
499
500 assert(f);
501 assert(key);
502 assert(routes);
503 assert(size);
504
505 fprintf(f, "%s=", key);
506
507 for (i = 0; i < size; i++) {
508 struct in_addr dest, gw;
509 uint8_t length;
510
511 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
512 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
513 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
514
515 fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
516 fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
517 }
518
519 fputs("\n", f);
520 }
521
522 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
523 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
524 size_t size = 0, allocated = 0;
525
526 assert(ret);
527 assert(ret_size);
528 assert(ret_allocated);
529 assert(string);
530
531 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
532 for (;;) {
533 _cleanup_free_ char *word = NULL;
534 char *tok, *tok_end;
535 unsigned n;
536 int r;
537
538 r = extract_first_word(&string, &word, NULL, 0);
539 if (r < 0)
540 return r;
541 if (r == 0)
542 break;
543
544 if (!GREEDY_REALLOC(routes, allocated, size + 1))
545 return -ENOMEM;
546
547 tok = word;
548
549 /* get the subnet */
550 tok_end = strchr(tok, '/');
551 if (!tok_end)
552 continue;
553 *tok_end = '\0';
554
555 r = inet_aton(tok, &routes[size].dst_addr);
556 if (r == 0)
557 continue;
558
559 tok = tok_end + 1;
560
561 /* get the prefixlen */
562 tok_end = strchr(tok, ',');
563 if (!tok_end)
564 continue;
565
566 *tok_end = '\0';
567
568 r = safe_atou(tok, &n);
569 if (r < 0 || n > 32)
570 continue;
571
572 routes[size].dst_prefixlen = (uint8_t) n;
573 tok = tok_end + 1;
574
575 /* get the gateway */
576 r = inet_aton(tok, &routes[size].gw_addr);
577 if (r == 0)
578 continue;
579
580 size++;
581 }
582
583 *ret_size = size;
584 *ret_allocated = allocated;
585 *ret = TAKE_PTR(routes);
586
587 return 0;
588 }
589
590 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
591 _cleanup_free_ char *hex_buf = NULL;
592
593 assert(f);
594 assert(key);
595 assert(data);
596
597 hex_buf = hexmem(data, size);
598 if (hex_buf == NULL)
599 return -ENOMEM;
600
601 fprintf(f, "%s=%s\n", key, hex_buf);
602
603 return 0;
604 }
605
606 int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) {
607 assert(data);
608 assert(data_len);
609 assert(string);
610
611 if (strlen(string) % 2)
612 return -EINVAL;
613
614 return unhexmem(string, strlen(string), (void **)data, data_len);
615 }