]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
log: minimize includes in log.h
[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 = n;
281 n = NULL;
282 } else
283 *s = NULL;
284
285 return 0;
286 }
287
288 int config_parse_hwaddr(const char *unit,
289 const char *filename,
290 unsigned line,
291 const char *section,
292 unsigned section_line,
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;
300 const char *start;
301 size_t offset;
302 int r;
303
304 assert(filename);
305 assert(lvalue);
306 assert(rvalue);
307 assert(data);
308
309 n = new0(struct ether_addr, 1);
310 if (!n)
311 return log_oom();
312
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')) {
317 log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
318 free(n);
319 return 0;
320 }
321
322 free(*hwaddr);
323 *hwaddr = n;
324
325 return 0;
326 }
327
328 int 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) {
348 log_syntax(unit, LOG_ERR, filename, line, r,
349 "Unable to read IAID, ignoring assignment: %s", rvalue);
350 return 0;
351 }
352
353 *((uint32_t *)data) = iaid;
354
355 return 0;
356 }
357
358 int 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
397 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
398 unsigned i;
399
400 assert(f);
401 assert(addresses);
402 assert(size);
403
404 for (i = 0; i < size; i++)
405 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
406 (i < (size - 1)) ? " ": "");
407 }
408
409 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
410 _cleanup_free_ struct in_addr *addresses = NULL;
411 int size = 0;
412
413 assert(ret);
414 assert(string);
415
416 for (;;) {
417 _cleanup_free_ char *word = NULL;
418 struct in_addr *new_addresses;
419 int r;
420
421 r = extract_first_word(&string, &word, NULL, 0);
422 if (r < 0)
423 return r;
424 if (r == 0)
425 break;
426
427 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
428 if (!new_addresses)
429 return -ENOMEM;
430 else
431 addresses = new_addresses;
432
433 r = inet_pton(AF_INET, word, &(addresses[size]));
434 if (r <= 0)
435 continue;
436
437 size++;
438 }
439
440 *ret = addresses;
441 addresses = NULL;
442
443 return size;
444 }
445
446 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
447 unsigned i;
448
449 assert(f);
450 assert(addresses);
451 assert(size);
452
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 }
461 }
462
463 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
464 _cleanup_free_ struct in6_addr *addresses = NULL;
465 int size = 0;
466
467 assert(ret);
468 assert(string);
469
470 for (;;) {
471 _cleanup_free_ char *word = NULL;
472 struct in6_addr *new_addresses;
473 int r;
474
475 r = extract_first_word(&string, &word, NULL, 0);
476 if (r < 0)
477 return r;
478 if (r == 0)
479 break;
480
481 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
482 if (!new_addresses)
483 return -ENOMEM;
484 else
485 addresses = new_addresses;
486
487 r = inet_pton(AF_INET6, word, &(addresses[size]));
488 if (r <= 0)
489 continue;
490
491 size++;
492 }
493
494 *ret = addresses;
495 addresses = NULL;
496
497 return size;
498 }
499
500 void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
501 unsigned i;
502
503 assert(f);
504 assert(key);
505 assert(routes);
506 assert(size);
507
508 fprintf(f, "%s=", key);
509
510 for (i = 0; i < size; i++) {
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)) ? " ": "");
520 }
521
522 fputs("\n", f);
523 }
524
525 int 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;
528
529 assert(ret);
530 assert(ret_size);
531 assert(ret_allocated);
532 assert(string);
533
534 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
535 for (;;) {
536 _cleanup_free_ char *word = NULL;
537 char *tok, *tok_end;
538 unsigned n;
539 int r;
540
541 r = extract_first_word(&string, &word, NULL, 0);
542 if (r < 0)
543 return r;
544 if (r == 0)
545 break;
546
547 if (!GREEDY_REALLOC(routes, allocated, size + 1))
548 return -ENOMEM;
549
550 tok = word;
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 }
593
594 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
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
610 int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) {
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 }