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