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