]> git.ipfire.org Git - thirdparty/systemd.git/blame - 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
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
07630cea
LP
25#include "sd-ndisc.h"
26
b5efdb8a 27#include "alloc-util.h"
07630cea
LP
28#include "condition.h"
29#include "conf-parser.h"
e1ea665e 30#include "dhcp-lease-internal.h"
aa31ce18 31#include "ether-addr-util.h"
cf0fbc49 32#include "hexdecoct.h"
be32eb9b 33#include "log.h"
6bedfcbb
LP
34#include "network-internal.h"
35#include "parse-util.h"
07630cea 36#include "siphash24.h"
d31645ad 37#include "socket-util.h"
07630cea
LP
38#include "string-util.h"
39#include "strv.h"
5fde13d7 40#include "utf8.h"
a12fa420 41#include "util.h"
5fde13d7 42
fc541430 43const char *net_get_name(struct udev_device *device) {
44e7b949 44 const char *name, *field;
fc541430
TG
45
46 assert(device);
b5db00e5
UTL
47
48 /* fetch some persistent data unique (on this machine) to this device */
44e7b949 49 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
b5db00e5
UTL
50 name = udev_device_get_property_value(device, field);
51 if (name)
44e7b949 52 return name;
b5db00e5
UTL
53 }
54
44e7b949 55 return NULL;
fc541430
TG
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
dbe81cbd 60int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) {
fc541430
TG
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);
b5db00e5
UTL
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. */
933f9cae 85 *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
b5db00e5
UTL
86
87 return 0;
88}
89
1aa68db1
DM
90static bool net_condition_test_strv(char * const *raw_patterns,
91 const char *string) {
618b196e
DM
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
be32eb9b 112bool net_match_config(const struct ether_addr *match_mac,
5256e00e
TG
113 char * const *match_paths,
114 char * const *match_drivers,
115 char * const *match_types,
116 char * const *match_names,
2cc412b5
TG
117 Condition *match_host,
118 Condition *match_virt,
119 Condition *match_kernel,
edbb03e9 120 Condition *match_arch,
505f8da7 121 const struct ether_addr *dev_mac,
b3e01314 122 const char *dev_path,
bf175aaf 123 const char *dev_parent_driver,
b3e01314
TG
124 const char *dev_driver,
125 const char *dev_type,
32bc8adc 126 const char *dev_name) {
be32eb9b 127
2cb62395 128 if (match_host && condition_test(match_host) <= 0)
7eb08da4 129 return false;
2cc412b5 130
2cb62395 131 if (match_virt && condition_test(match_virt) <= 0)
7eb08da4 132 return false;
2cc412b5 133
2cb62395 134 if (match_kernel && condition_test(match_kernel) <= 0)
7eb08da4 135 return false;
2cc412b5 136
2cb62395 137 if (match_arch && condition_test(match_arch) <= 0)
7eb08da4 138 return false;
edbb03e9 139
505f8da7 140 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
7eb08da4 141 return false;
be32eb9b 142
618b196e 143 if (!net_condition_test_strv(match_paths, dev_path))
ee5de57b 144 return false;
5256e00e 145
618b196e 146 if (!net_condition_test_strv(match_drivers, dev_driver))
ee5de57b 147 return false;
5256e00e 148
618b196e 149 if (!net_condition_test_strv(match_types, dev_type))
ee5de57b 150 return false;
5256e00e 151
618b196e 152 if (!net_condition_test_strv(match_names, dev_name))
ee5de57b 153 return false;
5256e00e 154
7eb08da4 155 return true;
be32eb9b 156}
5fde13d7 157
2cc412b5
TG
158int 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
d31645ad
LP
199int 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) {
5256e00e
TG
210
211 char ***sv = data;
5256e00e
TG
212 int r;
213
214 assert(filename);
215 assert(lvalue);
216 assert(rvalue);
217 assert(data);
218
93e28226
SS
219 for (;;) {
220 _cleanup_free_ char *word = NULL;
5256e00e 221
93e28226 222 r = extract_first_word(&rvalue, &word, NULL, 0);
a9dd908d
LP
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 }
93e28226
SS
227 if (r == 0)
228 break;
5256e00e 229
d31645ad
LP
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);
5256e00e
TG
232 return 0;
233 }
234
93e28226 235 r = strv_push(sv, word);
5256e00e
TG
236 if (r < 0)
237 return log_oom();
93e28226
SS
238
239 word = NULL;
5256e00e
TG
240 }
241
242 return 0;
243}
244
d2df0d0e
TG
245int config_parse_ifalias(const char *unit,
246 const char *filename,
247 unsigned line,
248 const char *section,
71a61510 249 unsigned section_line,
d2df0d0e
TG
250 const char *lvalue,
251 int ltype,
252 const char *rvalue,
253 void *data,
254 void *userdata) {
255
256 char **s = data;
9c39eb5c 257 _cleanup_free_ char *n = NULL;
d2df0d0e
TG
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) {
12ca818f 269 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
d2df0d0e
TG
270 return 0;
271 }
272
273 free(*s);
9c39eb5c 274 if (*n) {
d2df0d0e 275 *s = n;
9c39eb5c
TG
276 n = NULL;
277 } else
d2df0d0e 278 *s = NULL;
d2df0d0e
TG
279
280 return 0;
281}
282
5fde13d7
TG
283int config_parse_hwaddr(const char *unit,
284 const char *filename,
285 unsigned line,
286 const char *section,
71a61510 287 unsigned section_line,
5fde13d7
TG
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;
9ed8b06c
DKG
295 const char *start;
296 size_t offset;
5fde13d7
TG
297 int r;
298
299 assert(filename);
300 assert(lvalue);
301 assert(rvalue);
302 assert(data);
303
a12fa420 304 n = new0(struct ether_addr, 1);
5fde13d7
TG
305 if (!n)
306 return log_oom();
307
9ed8b06c
DKG
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')) {
12ca818f 312 log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
5fde13d7
TG
313 free(n);
314 return 0;
315 }
316
317 free(*hwaddr);
318 *hwaddr = n;
319
320 return 0;
321}
f5284182 322
413708d1
VK
323int 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) {
b7f71444
VK
343 log_syntax(unit, LOG_ERR, filename, line, r,
344 "Unable to read IAID, ignoring assignment: %s", rvalue);
345 return 0;
413708d1
VK
346 }
347
348 *((uint32_t *)data) = iaid;
349
350 return 0;
351}
352
f00ff0de
DJL
353int 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
b0e39c82 392void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
09bee74d
TG
393 unsigned i;
394
395 assert(f);
09bee74d
TG
396 assert(addresses);
397 assert(size);
398
09bee74d
TG
399 for (i = 0; i < size; i++)
400 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
401 (i < (size - 1)) ? " ": "");
09bee74d
TG
402}
403
a2ba62c7 404int deserialize_in_addrs(struct in_addr **ret, const char *string) {
09bee74d 405 _cleanup_free_ struct in_addr *addresses = NULL;
a2ba62c7 406 int size = 0;
09bee74d
TG
407
408 assert(ret);
09bee74d
TG
409 assert(string);
410
93e28226
SS
411 for (;;) {
412 _cleanup_free_ char *word = NULL;
09bee74d
TG
413 struct in_addr *new_addresses;
414 int r;
415
93e28226
SS
416 r = extract_first_word(&string, &word, NULL, 0);
417 if (r < 0)
418 return r;
419 if (r == 0)
420 break;
421
09bee74d
TG
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
93e28226 428 r = inet_pton(AF_INET, word, &(addresses[size]));
09bee74d
TG
429 if (r <= 0)
430 continue;
431
313cefa1 432 size++;
09bee74d
TG
433 }
434
09bee74d
TG
435 *ret = addresses;
436 addresses = NULL;
437
a2ba62c7 438 return size;
09bee74d
TG
439}
440
1f152e4b 441void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
b729fa14
PF
442 unsigned i;
443
444 assert(f);
445 assert(addresses);
446 assert(size);
447
1f152e4b
LP
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 }
b729fa14
PF
456}
457
a2ba62c7 458int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
09bee74d 459 _cleanup_free_ struct in6_addr *addresses = NULL;
a2ba62c7 460 int size = 0;
09bee74d
TG
461
462 assert(ret);
09bee74d
TG
463 assert(string);
464
93e28226
SS
465 for (;;) {
466 _cleanup_free_ char *word = NULL;
09bee74d
TG
467 struct in6_addr *new_addresses;
468 int r;
469
93e28226
SS
470 r = extract_first_word(&string, &word, NULL, 0);
471 if (r < 0)
472 return r;
473 if (r == 0)
474 break;
475
09bee74d
TG
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
93e28226 482 r = inet_pton(AF_INET6, word, &(addresses[size]));
09bee74d
TG
483 if (r <= 0)
484 continue;
485
486 size++;
487 }
488
09bee74d
TG
489 *ret = addresses;
490 addresses = NULL;
491
a2ba62c7 492 return size;
09bee74d 493}
e1ea665e 494
f8693fc7 495void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
e1ea665e
EY
496 unsigned i;
497
498 assert(f);
499 assert(key);
500 assert(routes);
501 assert(size);
502
503 fprintf(f, "%s=", key);
504
fbf7dcb5 505 for (i = 0; i < size; i++) {
f8693fc7
BG
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)) ? " ": "");
fbf7dcb5 515 }
e1ea665e
EY
516
517 fputs("\n", f);
518}
519
520int 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;
e1ea665e
EY
523
524 assert(ret);
525 assert(ret_size);
526 assert(ret_allocated);
527 assert(string);
528
93e28226
SS
529 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
530 for (;;) {
531 _cleanup_free_ char *word = NULL;
e1ea665e
EY
532 char *tok, *tok_end;
533 unsigned n;
534 int r;
535
93e28226
SS
536 r = extract_first_word(&string, &word, NULL, 0);
537 if (r < 0)
538 return r;
539 if (r == 0)
540 break;
e1ea665e 541
93e28226 542 if (!GREEDY_REALLOC(routes, allocated, size + 1))
31db0120 543 return -ENOMEM;
e1ea665e 544
93e28226 545 tok = word;
e1ea665e
EY
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}
a073309f 588
e4735228 589int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
a073309f
AC
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
e4735228 605int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) {
a073309f
AC
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}