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