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