]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
Merge pull request #3276 from ssahani/issue-3264
[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.c"
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 bool net_match_config(const struct ether_addr *match_mac,
90 char * const *match_paths,
91 char * const *match_drivers,
92 char * const *match_types,
93 char * const *match_names,
94 Condition *match_host,
95 Condition *match_virt,
96 Condition *match_kernel,
97 Condition *match_arch,
98 const struct ether_addr *dev_mac,
99 const char *dev_path,
100 const char *dev_parent_driver,
101 const char *dev_driver,
102 const char *dev_type,
103 const char *dev_name) {
104
105 if (match_host && !condition_test(match_host))
106 return false;
107
108 if (match_virt && !condition_test(match_virt))
109 return false;
110
111 if (match_kernel && !condition_test(match_kernel))
112 return false;
113
114 if (match_arch && !condition_test(match_arch))
115 return false;
116
117 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
118 return false;
119
120 if (!strv_isempty(match_paths) &&
121 (!dev_path || !strv_fnmatch(match_paths, dev_path, 0)))
122 return false;
123
124 if (!strv_isempty(match_drivers) &&
125 (!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0)))
126 return false;
127
128 if (!strv_isempty(match_types) &&
129 (!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0)))
130 return false;
131
132 if (!strv_isempty(match_names) &&
133 (!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0)))
134 return false;
135
136 return true;
137 }
138
139 int config_parse_net_condition(const char *unit,
140 const char *filename,
141 unsigned line,
142 const char *section,
143 unsigned section_line,
144 const char *lvalue,
145 int ltype,
146 const char *rvalue,
147 void *data,
148 void *userdata) {
149
150 ConditionType cond = ltype;
151 Condition **ret = data;
152 bool negate;
153 Condition *c;
154 _cleanup_free_ char *s = NULL;
155
156 assert(filename);
157 assert(lvalue);
158 assert(rvalue);
159 assert(data);
160
161 negate = rvalue[0] == '!';
162 if (negate)
163 rvalue++;
164
165 s = strdup(rvalue);
166 if (!s)
167 return log_oom();
168
169 c = condition_new(cond, s, false, negate);
170 if (!c)
171 return log_oom();
172
173 if (*ret)
174 condition_free(*ret);
175
176 *ret = c;
177 return 0;
178 }
179
180 int config_parse_ifnames(
181 const char *unit,
182 const char *filename,
183 unsigned line,
184 const char *section,
185 unsigned section_line,
186 const char *lvalue,
187 int ltype,
188 const char *rvalue,
189 void *data,
190 void *userdata) {
191
192 char ***sv = data;
193 int r;
194
195 assert(filename);
196 assert(lvalue);
197 assert(rvalue);
198 assert(data);
199
200 for (;;) {
201 _cleanup_free_ char *word = NULL;
202
203 r = extract_first_word(&rvalue, &word, NULL, 0);
204 if (r < 0) {
205 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue);
206 return 0;
207 }
208 if (r == 0)
209 break;
210
211 if (!ifname_valid(word)) {
212 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
213 return 0;
214 }
215
216 r = strv_push(sv, word);
217 if (r < 0)
218 return log_oom();
219
220 word = NULL;
221 }
222
223 return 0;
224 }
225
226 int config_parse_ifalias(const char *unit,
227 const char *filename,
228 unsigned line,
229 const char *section,
230 unsigned section_line,
231 const char *lvalue,
232 int ltype,
233 const char *rvalue,
234 void *data,
235 void *userdata) {
236
237 char **s = data;
238 _cleanup_free_ char *n = NULL;
239
240 assert(filename);
241 assert(lvalue);
242 assert(rvalue);
243 assert(data);
244
245 n = strdup(rvalue);
246 if (!n)
247 return log_oom();
248
249 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
250 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
251 return 0;
252 }
253
254 free(*s);
255 if (*n) {
256 *s = n;
257 n = NULL;
258 } else
259 *s = NULL;
260
261 return 0;
262 }
263
264 int config_parse_hwaddr(const char *unit,
265 const char *filename,
266 unsigned line,
267 const char *section,
268 unsigned section_line,
269 const char *lvalue,
270 int ltype,
271 const char *rvalue,
272 void *data,
273 void *userdata) {
274 struct ether_addr **hwaddr = data;
275 struct ether_addr *n;
276 const char *start;
277 size_t offset;
278 int r;
279
280 assert(filename);
281 assert(lvalue);
282 assert(rvalue);
283 assert(data);
284
285 n = new0(struct ether_addr, 1);
286 if (!n)
287 return log_oom();
288
289 start = rvalue + strspn(rvalue, WHITESPACE);
290 r = ether_addr_from_string(start, n, &offset);
291
292 if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) {
293 log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
294 free(n);
295 return 0;
296 }
297
298 free(*hwaddr);
299 *hwaddr = n;
300
301 return 0;
302 }
303
304 int config_parse_iaid(const char *unit,
305 const char *filename,
306 unsigned line,
307 const char *section,
308 unsigned section_line,
309 const char *lvalue,
310 int ltype,
311 const char *rvalue,
312 void *data,
313 void *userdata) {
314 uint32_t iaid;
315 int r;
316
317 assert(filename);
318 assert(lvalue);
319 assert(rvalue);
320 assert(data);
321
322 r = safe_atou32(rvalue, &iaid);
323 if (r < 0) {
324 log_syntax(unit, LOG_ERR, filename, line, r,
325 "Unable to read IAID, ignoring assignment: %s", rvalue);
326 return 0;
327 }
328
329 *((uint32_t *)data) = iaid;
330
331 return 0;
332 }
333
334 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
335 unsigned i;
336
337 assert(f);
338 assert(addresses);
339 assert(size);
340
341 for (i = 0; i < size; i++)
342 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
343 (i < (size - 1)) ? " ": "");
344 }
345
346 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
347 _cleanup_free_ struct in_addr *addresses = NULL;
348 int size = 0;
349
350 assert(ret);
351 assert(string);
352
353 for (;;) {
354 _cleanup_free_ char *word = NULL;
355 struct in_addr *new_addresses;
356 int r;
357
358 r = extract_first_word(&string, &word, NULL, 0);
359 if (r < 0)
360 return r;
361 if (r == 0)
362 break;
363
364 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
365 if (!new_addresses)
366 return -ENOMEM;
367 else
368 addresses = new_addresses;
369
370 r = inet_pton(AF_INET, word, &(addresses[size]));
371 if (r <= 0)
372 continue;
373
374 size++;
375 }
376
377 *ret = addresses;
378 addresses = NULL;
379
380 return size;
381 }
382
383 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
384 size_t size) {
385 unsigned i;
386
387 assert(f);
388 assert(addresses);
389 assert(size);
390
391 for (i = 0; i < size; i++)
392 fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s",
393 SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]),
394 (i < (size - 1)) ? " ": "");
395 }
396
397 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
398 _cleanup_free_ struct in6_addr *addresses = NULL;
399 int size = 0;
400
401 assert(ret);
402 assert(string);
403
404 for (;;) {
405 _cleanup_free_ char *word = NULL;
406 struct in6_addr *new_addresses;
407 int r;
408
409 r = extract_first_word(&string, &word, NULL, 0);
410 if (r < 0)
411 return r;
412 if (r == 0)
413 break;
414
415 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
416 if (!new_addresses)
417 return -ENOMEM;
418 else
419 addresses = new_addresses;
420
421 r = inet_pton(AF_INET6, word, &(addresses[size]));
422 if (r <= 0)
423 continue;
424
425 size++;
426 }
427
428 *ret = addresses;
429 addresses = NULL;
430
431 return size;
432 }
433
434 void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
435 unsigned i;
436
437 assert(f);
438 assert(key);
439 assert(routes);
440 assert(size);
441
442 fprintf(f, "%s=", key);
443
444 for (i = 0; i < size; i++) {
445 struct in_addr dest, gw;
446 uint8_t length;
447
448 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
449 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
450 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
451
452 fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
453 fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
454 }
455
456 fputs("\n", f);
457 }
458
459 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
460 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
461 size_t size = 0, allocated = 0;
462
463 assert(ret);
464 assert(ret_size);
465 assert(ret_allocated);
466 assert(string);
467
468 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
469 for (;;) {
470 _cleanup_free_ char *word = NULL;
471 char *tok, *tok_end;
472 unsigned n;
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 if (!GREEDY_REALLOC(routes, allocated, size + 1))
482 return -ENOMEM;
483
484 tok = word;
485
486 /* get the subnet */
487 tok_end = strchr(tok, '/');
488 if (!tok_end)
489 continue;
490 *tok_end = '\0';
491
492 r = inet_aton(tok, &routes[size].dst_addr);
493 if (r == 0)
494 continue;
495
496 tok = tok_end + 1;
497
498 /* get the prefixlen */
499 tok_end = strchr(tok, ',');
500 if (!tok_end)
501 continue;
502
503 *tok_end = '\0';
504
505 r = safe_atou(tok, &n);
506 if (r < 0 || n > 32)
507 continue;
508
509 routes[size].dst_prefixlen = (uint8_t) n;
510 tok = tok_end + 1;
511
512 /* get the gateway */
513 r = inet_aton(tok, &routes[size].gw_addr);
514 if (r == 0)
515 continue;
516
517 size++;
518 }
519
520 *ret_size = size;
521 *ret_allocated = allocated;
522 *ret = routes;
523 routes = NULL;
524
525 return 0;
526 }
527
528 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
529 _cleanup_free_ char *hex_buf = NULL;
530
531 assert(f);
532 assert(key);
533 assert(data);
534
535 hex_buf = hexmem(data, size);
536 if (hex_buf == NULL)
537 return -ENOMEM;
538
539 fprintf(f, "%s=%s\n", key, hex_buf);
540
541 return 0;
542 }
543
544 int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) {
545 assert(data);
546 assert(data_len);
547 assert(string);
548
549 if (strlen(string) % 2)
550 return -EINVAL;
551
552 return unhexmem(string, strlen(string), (void **)data, data_len);
553 }