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