]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/network-internal.c
Merge pull request #8314 from poettering/rearrange-stdio
[thirdparty/systemd.git] / src / libsystemd-network / network-internal.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
5fde13d7
TG
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
f5284182 21#include <arpa/inet.h>
07630cea
LP
22#include <linux/if.h>
23#include <netinet/ether.h>
5fde13d7 24
dccca82b 25#include "sd-id128.h"
07630cea
LP
26#include "sd-ndisc.h"
27
b5efdb8a 28#include "alloc-util.h"
07630cea
LP
29#include "condition.h"
30#include "conf-parser.h"
e1ea665e 31#include "dhcp-lease-internal.h"
aa31ce18 32#include "ether-addr-util.h"
cf0fbc49 33#include "hexdecoct.h"
be32eb9b 34#include "log.h"
6bedfcbb
LP
35#include "network-internal.h"
36#include "parse-util.h"
07630cea 37#include "siphash24.h"
d31645ad 38#include "socket-util.h"
07630cea
LP
39#include "string-util.h"
40#include "strv.h"
5fde13d7 41#include "utf8.h"
a12fa420 42#include "util.h"
5fde13d7 43
fc541430 44const char *net_get_name(struct udev_device *device) {
44e7b949 45 const char *name, *field;
fc541430
TG
46
47 assert(device);
b5db00e5
UTL
48
49 /* fetch some persistent data unique (on this machine) to this device */
44e7b949 50 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
b5db00e5
UTL
51 name = udev_device_get_property_value(device, field);
52 if (name)
44e7b949 53 return name;
b5db00e5
UTL
54 }
55
44e7b949 56 return NULL;
fc541430
TG
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
dbe81cbd 61int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) {
fc541430
TG
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);
b5db00e5
UTL
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. */
933f9cae 86 *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
b5db00e5
UTL
87
88 return 0;
89}
90
1aa68db1
DM
91static bool net_condition_test_strv(char * const *raw_patterns,
92 const char *string) {
618b196e
DM
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
be32eb9b 113bool net_match_config(const struct ether_addr *match_mac,
5256e00e
TG
114 char * const *match_paths,
115 char * const *match_drivers,
116 char * const *match_types,
117 char * const *match_names,
2cc412b5
TG
118 Condition *match_host,
119 Condition *match_virt,
5022f08a
LP
120 Condition *match_kernel_cmdline,
121 Condition *match_kernel_version,
edbb03e9 122 Condition *match_arch,
505f8da7 123 const struct ether_addr *dev_mac,
b3e01314 124 const char *dev_path,
bf175aaf 125 const char *dev_parent_driver,
b3e01314
TG
126 const char *dev_driver,
127 const char *dev_type,
32bc8adc 128 const char *dev_name) {
be32eb9b 129
2cb62395 130 if (match_host && condition_test(match_host) <= 0)
7eb08da4 131 return false;
2cc412b5 132
2cb62395 133 if (match_virt && condition_test(match_virt) <= 0)
7eb08da4 134 return false;
2cc412b5 135
5022f08a
LP
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)
7eb08da4 140 return false;
2cc412b5 141
2cb62395 142 if (match_arch && condition_test(match_arch) <= 0)
7eb08da4 143 return false;
edbb03e9 144
505f8da7 145 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
7eb08da4 146 return false;
be32eb9b 147
618b196e 148 if (!net_condition_test_strv(match_paths, dev_path))
ee5de57b 149 return false;
5256e00e 150
618b196e 151 if (!net_condition_test_strv(match_drivers, dev_driver))
ee5de57b 152 return false;
5256e00e 153
618b196e 154 if (!net_condition_test_strv(match_types, dev_type))
ee5de57b 155 return false;
5256e00e 156
618b196e 157 if (!net_condition_test_strv(match_names, dev_name))
ee5de57b 158 return false;
5256e00e 159
7eb08da4 160 return true;
be32eb9b 161}
5fde13d7 162
2cc412b5
TG
163int 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
d31645ad
LP
204int 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) {
5256e00e
TG
215
216 char ***sv = data;
5256e00e
TG
217 int r;
218
219 assert(filename);
220 assert(lvalue);
221 assert(rvalue);
222 assert(data);
223
93e28226
SS
224 for (;;) {
225 _cleanup_free_ char *word = NULL;
5256e00e 226
93e28226 227 r = extract_first_word(&rvalue, &word, NULL, 0);
a9dd908d
LP
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 }
93e28226
SS
232 if (r == 0)
233 break;
5256e00e 234
d31645ad
LP
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);
5256e00e
TG
237 return 0;
238 }
239
93e28226 240 r = strv_push(sv, word);
5256e00e
TG
241 if (r < 0)
242 return log_oom();
93e28226
SS
243
244 word = NULL;
5256e00e
TG
245 }
246
247 return 0;
248}
249
d2df0d0e
TG
250int config_parse_ifalias(const char *unit,
251 const char *filename,
252 unsigned line,
253 const char *section,
71a61510 254 unsigned section_line,
d2df0d0e
TG
255 const char *lvalue,
256 int ltype,
257 const char *rvalue,
258 void *data,
259 void *userdata) {
260
261 char **s = data;
9c39eb5c 262 _cleanup_free_ char *n = NULL;
d2df0d0e
TG
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) {
12ca818f 274 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
d2df0d0e
TG
275 return 0;
276 }
277
278 free(*s);
9c39eb5c 279 if (*n) {
d2df0d0e 280 *s = n;
9c39eb5c
TG
281 n = NULL;
282 } else
d2df0d0e 283 *s = NULL;
d2df0d0e
TG
284
285 return 0;
286}
287
5fde13d7
TG
288int config_parse_hwaddr(const char *unit,
289 const char *filename,
290 unsigned line,
291 const char *section,
71a61510 292 unsigned section_line,
5fde13d7
TG
293 const char *lvalue,
294 int ltype,
295 const char *rvalue,
296 void *data,
297 void *userdata) {
298 struct ether_addr **hwaddr = data;
299 struct ether_addr *n;
9ed8b06c
DKG
300 const char *start;
301 size_t offset;
5fde13d7
TG
302 int r;
303
304 assert(filename);
305 assert(lvalue);
306 assert(rvalue);
307 assert(data);
308
a12fa420 309 n = new0(struct ether_addr, 1);
5fde13d7
TG
310 if (!n)
311 return log_oom();
312
9ed8b06c
DKG
313 start = rvalue + strspn(rvalue, WHITESPACE);
314 r = ether_addr_from_string(start, n, &offset);
315
316 if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) {
12ca818f 317 log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
5fde13d7
TG
318 free(n);
319 return 0;
320 }
321
322 free(*hwaddr);
323 *hwaddr = n;
324
325 return 0;
326}
f5284182 327
413708d1
VK
328int config_parse_iaid(const char *unit,
329 const char *filename,
330 unsigned line,
331 const char *section,
332 unsigned section_line,
333 const char *lvalue,
334 int ltype,
335 const char *rvalue,
336 void *data,
337 void *userdata) {
338 uint32_t iaid;
339 int r;
340
341 assert(filename);
342 assert(lvalue);
343 assert(rvalue);
344 assert(data);
345
346 r = safe_atou32(rvalue, &iaid);
347 if (r < 0) {
b7f71444
VK
348 log_syntax(unit, LOG_ERR, filename, line, r,
349 "Unable to read IAID, ignoring assignment: %s", rvalue);
350 return 0;
413708d1
VK
351 }
352
353 *((uint32_t *)data) = iaid;
354
355 return 0;
356}
357
f00ff0de
DJL
358int config_parse_bridge_port_priority(
359 const char *unit,
360 const char *filename,
361 unsigned line,
362 const char *section,
363 unsigned section_line,
364 const char *lvalue,
365 int ltype,
366 const char *rvalue,
367 void *data,
368 void *userdata) {
369
370 uint16_t i;
371 int r;
372
373 assert(filename);
374 assert(lvalue);
375 assert(rvalue);
376 assert(data);
377
378 r = safe_atou16(rvalue, &i);
379 if (r < 0) {
380 log_syntax(unit, LOG_ERR, filename, line, r,
381 "Failed to parse bridge port priority, ignoring: %s", rvalue);
382 return 0;
383 }
384
385 if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) {
386 log_syntax(unit, LOG_ERR, filename, line, r,
387 "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue);
388 return 0;
389 }
390
391 *((uint16_t *)data) = i;
392
393 return 0;
394}
395
396
b0e39c82 397void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
09bee74d
TG
398 unsigned i;
399
400 assert(f);
09bee74d
TG
401 assert(addresses);
402 assert(size);
403
09bee74d
TG
404 for (i = 0; i < size; i++)
405 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
406 (i < (size - 1)) ? " ": "");
09bee74d
TG
407}
408
a2ba62c7 409int deserialize_in_addrs(struct in_addr **ret, const char *string) {
09bee74d 410 _cleanup_free_ struct in_addr *addresses = NULL;
a2ba62c7 411 int size = 0;
09bee74d
TG
412
413 assert(ret);
09bee74d
TG
414 assert(string);
415
93e28226
SS
416 for (;;) {
417 _cleanup_free_ char *word = NULL;
09bee74d
TG
418 struct in_addr *new_addresses;
419 int r;
420
93e28226
SS
421 r = extract_first_word(&string, &word, NULL, 0);
422 if (r < 0)
423 return r;
424 if (r == 0)
425 break;
426
62d74c78 427 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
09bee74d
TG
428 if (!new_addresses)
429 return -ENOMEM;
430 else
431 addresses = new_addresses;
432
93e28226 433 r = inet_pton(AF_INET, word, &(addresses[size]));
09bee74d
TG
434 if (r <= 0)
435 continue;
436
313cefa1 437 size++;
09bee74d
TG
438 }
439
09bee74d
TG
440 *ret = addresses;
441 addresses = NULL;
442
a2ba62c7 443 return size;
09bee74d
TG
444}
445
1f152e4b 446void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
b729fa14
PF
447 unsigned i;
448
449 assert(f);
450 assert(addresses);
451 assert(size);
452
1f152e4b
LP
453 for (i = 0; i < size; i++) {
454 char buffer[INET6_ADDRSTRLEN];
455
456 fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
457
458 if (i < size - 1)
459 fputc(' ', f);
460 }
b729fa14
PF
461}
462
a2ba62c7 463int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
09bee74d 464 _cleanup_free_ struct in6_addr *addresses = NULL;
a2ba62c7 465 int size = 0;
09bee74d
TG
466
467 assert(ret);
09bee74d
TG
468 assert(string);
469
93e28226
SS
470 for (;;) {
471 _cleanup_free_ char *word = NULL;
09bee74d
TG
472 struct in6_addr *new_addresses;
473 int r;
474
93e28226
SS
475 r = extract_first_word(&string, &word, NULL, 0);
476 if (r < 0)
477 return r;
478 if (r == 0)
479 break;
480
62d74c78 481 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
09bee74d
TG
482 if (!new_addresses)
483 return -ENOMEM;
484 else
485 addresses = new_addresses;
486
93e28226 487 r = inet_pton(AF_INET6, word, &(addresses[size]));
09bee74d
TG
488 if (r <= 0)
489 continue;
490
491 size++;
492 }
493
09bee74d
TG
494 *ret = addresses;
495 addresses = NULL;
496
a2ba62c7 497 return size;
09bee74d 498}
e1ea665e 499
f8693fc7 500void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
e1ea665e
EY
501 unsigned i;
502
503 assert(f);
504 assert(key);
505 assert(routes);
506 assert(size);
507
508 fprintf(f, "%s=", key);
509
fbf7dcb5 510 for (i = 0; i < size; i++) {
f8693fc7
BG
511 struct in_addr dest, gw;
512 uint8_t length;
513
514 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
515 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
516 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
517
518 fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
519 fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
fbf7dcb5 520 }
e1ea665e
EY
521
522 fputs("\n", f);
523}
524
525int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
526 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
527 size_t size = 0, allocated = 0;
e1ea665e
EY
528
529 assert(ret);
530 assert(ret_size);
531 assert(ret_allocated);
532 assert(string);
533
93e28226
SS
534 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
535 for (;;) {
536 _cleanup_free_ char *word = NULL;
e1ea665e
EY
537 char *tok, *tok_end;
538 unsigned n;
539 int r;
540
93e28226
SS
541 r = extract_first_word(&string, &word, NULL, 0);
542 if (r < 0)
543 return r;
544 if (r == 0)
545 break;
e1ea665e 546
93e28226 547 if (!GREEDY_REALLOC(routes, allocated, size + 1))
31db0120 548 return -ENOMEM;
e1ea665e 549
93e28226 550 tok = word;
e1ea665e
EY
551
552 /* get the subnet */
553 tok_end = strchr(tok, '/');
554 if (!tok_end)
555 continue;
556 *tok_end = '\0';
557
558 r = inet_aton(tok, &routes[size].dst_addr);
559 if (r == 0)
560 continue;
561
562 tok = tok_end + 1;
563
564 /* get the prefixlen */
565 tok_end = strchr(tok, ',');
566 if (!tok_end)
567 continue;
568
569 *tok_end = '\0';
570
571 r = safe_atou(tok, &n);
572 if (r < 0 || n > 32)
573 continue;
574
575 routes[size].dst_prefixlen = (uint8_t) n;
576 tok = tok_end + 1;
577
578 /* get the gateway */
579 r = inet_aton(tok, &routes[size].gw_addr);
580 if (r == 0)
581 continue;
582
583 size++;
584 }
585
586 *ret_size = size;
587 *ret_allocated = allocated;
588 *ret = routes;
589 routes = NULL;
590
591 return 0;
592}
a073309f 593
e4735228 594int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
a073309f
AC
595 _cleanup_free_ char *hex_buf = NULL;
596
597 assert(f);
598 assert(key);
599 assert(data);
600
601 hex_buf = hexmem(data, size);
602 if (hex_buf == NULL)
603 return -ENOMEM;
604
605 fprintf(f, "%s=%s\n", key, hex_buf);
606
607 return 0;
608}
609
e4735228 610int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) {
a073309f
AC
611 assert(data);
612 assert(data_len);
613 assert(string);
614
615 if (strlen(string) % 2)
616 return -EINVAL;
617
618 return unhexmem(string, strlen(string), (void **)data, data_len);
619}