]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
dhcp: export routes as opaque objects
[thirdparty/systemd.git] / src / libsystemd-network / network-internal.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <arpa/inet.h>
23 #include <linux/if.h>
24 #include <netinet/ether.h>
25
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 "hexdecoct.h"
33 #include "log.h"
34 #include "network-internal.h"
35 #include "parse-util.h"
36 #include "siphash24.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_ifname(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 **s = data;
192 _cleanup_free_ char *n = NULL;
193
194 assert(filename);
195 assert(lvalue);
196 assert(rvalue);
197 assert(data);
198
199 n = strdup(rvalue);
200 if (!n)
201 return log_oom();
202
203 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
204 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
205 return 0;
206 }
207
208 free(*s);
209 if (*n) {
210 *s = n;
211 n = NULL;
212 } else
213 *s = NULL;
214
215 return 0;
216 }
217
218 int config_parse_ifnames(const char *unit,
219 const char *filename,
220 unsigned line,
221 const char *section,
222 unsigned section_line,
223 const char *lvalue,
224 int ltype,
225 const char *rvalue,
226 void *data,
227 void *userdata) {
228
229 char ***sv = data;
230 const char *word, *state;
231 size_t l;
232 int r;
233
234 assert(filename);
235 assert(lvalue);
236 assert(rvalue);
237 assert(data);
238
239 FOREACH_WORD(word, l, rvalue, state) {
240 char *n;
241
242 n = strndup(word, l);
243 if (!n)
244 return log_oom();
245
246 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
247 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
248 free(n);
249 return 0;
250 }
251
252 r = strv_consume(sv, n);
253 if (r < 0)
254 return log_oom();
255 }
256
257 return 0;
258 }
259
260 int config_parse_ifalias(const char *unit,
261 const char *filename,
262 unsigned line,
263 const char *section,
264 unsigned section_line,
265 const char *lvalue,
266 int ltype,
267 const char *rvalue,
268 void *data,
269 void *userdata) {
270
271 char **s = data;
272 _cleanup_free_ char *n = NULL;
273
274 assert(filename);
275 assert(lvalue);
276 assert(rvalue);
277 assert(data);
278
279 n = strdup(rvalue);
280 if (!n)
281 return log_oom();
282
283 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
284 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
285 return 0;
286 }
287
288 free(*s);
289 if (*n) {
290 *s = n;
291 n = NULL;
292 } else
293 *s = NULL;
294
295 return 0;
296 }
297
298 int config_parse_hwaddr(const char *unit,
299 const char *filename,
300 unsigned line,
301 const char *section,
302 unsigned section_line,
303 const char *lvalue,
304 int ltype,
305 const char *rvalue,
306 void *data,
307 void *userdata) {
308 struct ether_addr **hwaddr = data;
309 struct ether_addr *n;
310 int r;
311
312 assert(filename);
313 assert(lvalue);
314 assert(rvalue);
315 assert(data);
316
317 n = new0(struct ether_addr, 1);
318 if (!n)
319 return log_oom();
320
321 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
322 &n->ether_addr_octet[0],
323 &n->ether_addr_octet[1],
324 &n->ether_addr_octet[2],
325 &n->ether_addr_octet[3],
326 &n->ether_addr_octet[4],
327 &n->ether_addr_octet[5]);
328 if (r != 6) {
329 log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
330 free(n);
331 return 0;
332 }
333
334 free(*hwaddr);
335 *hwaddr = n;
336
337 return 0;
338 }
339
340 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
341 unsigned i;
342
343 assert(f);
344 assert(addresses);
345 assert(size);
346
347 for (i = 0; i < size; i++)
348 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
349 (i < (size - 1)) ? " ": "");
350 }
351
352 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
353 _cleanup_free_ struct in_addr *addresses = NULL;
354 int size = 0;
355 const char *word, *state;
356 size_t len;
357
358 assert(ret);
359 assert(string);
360
361 FOREACH_WORD(word, len, string, state) {
362 _cleanup_free_ char *addr_str = NULL;
363 struct in_addr *new_addresses;
364 int r;
365
366 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
367 if (!new_addresses)
368 return -ENOMEM;
369 else
370 addresses = new_addresses;
371
372 addr_str = strndup(word, len);
373 if (!addr_str)
374 return -ENOMEM;
375
376 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
377 if (r <= 0)
378 continue;
379
380 size ++;
381 }
382
383 *ret = addresses;
384 addresses = NULL;
385
386 return size;
387 }
388
389 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
390 size_t size) {
391 unsigned i;
392
393 assert(f);
394 assert(addresses);
395 assert(size);
396
397 for (i = 0; i < size; i++)
398 fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s",
399 SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]),
400 (i < (size - 1)) ? " ": "");
401 }
402
403 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
404 _cleanup_free_ struct in6_addr *addresses = NULL;
405 int size = 0;
406 const char *word, *state;
407 size_t len;
408
409 assert(ret);
410 assert(string);
411
412 FOREACH_WORD(word, len, string, state) {
413 _cleanup_free_ char *addr_str = NULL;
414 struct in6_addr *new_addresses;
415 int r;
416
417 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
418 if (!new_addresses)
419 return -ENOMEM;
420 else
421 addresses = new_addresses;
422
423 addr_str = strndup(word, len);
424 if (!addr_str)
425 return -ENOMEM;
426
427 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
428 if (r <= 0)
429 continue;
430
431 size++;
432 }
433
434 *ret = addresses;
435 addresses = NULL;
436
437 return size;
438 }
439
440 void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
441 unsigned i;
442
443 assert(f);
444 assert(key);
445 assert(routes);
446 assert(size);
447
448 fprintf(f, "%s=", key);
449
450 for (i = 0; i < size; i++) {
451 struct in_addr dest, gw;
452 uint8_t length;
453
454 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
455 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
456 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
457
458 fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
459 fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
460 }
461
462 fputs("\n", f);
463 }
464
465 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
466 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
467 size_t size = 0, allocated = 0;
468 const char *word, *state;
469 size_t len;
470
471 assert(ret);
472 assert(ret_size);
473 assert(ret_allocated);
474 assert(string);
475
476 FOREACH_WORD(word, len, string, state) {
477 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
478 _cleanup_free_ char* entry = NULL;
479 char *tok, *tok_end;
480 unsigned n;
481 int r;
482
483 if (!GREEDY_REALLOC(routes, allocated, size + 1))
484 return -ENOMEM;
485
486 entry = strndup(word, len);
487 if(!entry)
488 return -ENOMEM;
489
490 tok = entry;
491
492 /* get the subnet */
493 tok_end = strchr(tok, '/');
494 if (!tok_end)
495 continue;
496 *tok_end = '\0';
497
498 r = inet_aton(tok, &routes[size].dst_addr);
499 if (r == 0)
500 continue;
501
502 tok = tok_end + 1;
503
504 /* get the prefixlen */
505 tok_end = strchr(tok, ',');
506 if (!tok_end)
507 continue;
508
509 *tok_end = '\0';
510
511 r = safe_atou(tok, &n);
512 if (r < 0 || n > 32)
513 continue;
514
515 routes[size].dst_prefixlen = (uint8_t) n;
516 tok = tok_end + 1;
517
518 /* get the gateway */
519 r = inet_aton(tok, &routes[size].gw_addr);
520 if (r == 0)
521 continue;
522
523 size++;
524 }
525
526 *ret_size = size;
527 *ret_allocated = allocated;
528 *ret = routes;
529 routes = NULL;
530
531 return 0;
532 }
533
534 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
535 _cleanup_free_ char *hex_buf = NULL;
536
537 assert(f);
538 assert(key);
539 assert(data);
540
541 hex_buf = hexmem(data, size);
542 if (hex_buf == NULL)
543 return -ENOMEM;
544
545 fprintf(f, "%s=%s\n", key, hex_buf);
546
547 return 0;
548 }
549
550 int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) {
551 assert(data);
552 assert(data_len);
553 assert(string);
554
555 if (strlen(string) % 2)
556 return -EINVAL;
557
558 return unhexmem(string, strlen(string), (void **)data, data_len);
559 }