]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
sd-icmp6-nd: fix namespacing
[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-icmp6-nd.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, EINVAL,
200 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
201 return 0;
202 }
203
204 free(*s);
205 if (*n) {
206 *s = n;
207 n = NULL;
208 } else
209 *s = NULL;
210
211 return 0;
212 }
213
214 int config_parse_ifnames(const char *unit,
215 const char *filename,
216 unsigned line,
217 const char *section,
218 unsigned section_line,
219 const char *lvalue,
220 int ltype,
221 const char *rvalue,
222 void *data,
223 void *userdata) {
224
225 char ***sv = data;
226 const char *word, *state;
227 size_t l;
228 int r;
229
230 assert(filename);
231 assert(lvalue);
232 assert(rvalue);
233 assert(data);
234
235 FOREACH_WORD(word, l, rvalue, state) {
236 char *n;
237
238 n = strndup(word, l);
239 if (!n)
240 return log_oom();
241
242 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
243 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
244 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
245 free(n);
246 return 0;
247 }
248
249 r = strv_consume(sv, n);
250 if (r < 0)
251 return log_oom();
252 }
253
254 return 0;
255 }
256
257 int config_parse_ifalias(const char *unit,
258 const char *filename,
259 unsigned line,
260 const char *section,
261 unsigned section_line,
262 const char *lvalue,
263 int ltype,
264 const char *rvalue,
265 void *data,
266 void *userdata) {
267
268 char **s = data;
269 _cleanup_free_ char *n = NULL;
270
271 assert(filename);
272 assert(lvalue);
273 assert(rvalue);
274 assert(data);
275
276 n = strdup(rvalue);
277 if (!n)
278 return log_oom();
279
280 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
281 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
282 "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, EINVAL,
328 "Not a valid MAC address, ignoring assignment: %s", rvalue);
329 free(n);
330 return 0;
331 }
332
333 free(*hwaddr);
334 *hwaddr = n;
335
336 return 0;
337 }
338
339 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
340 unsigned i;
341
342 assert(f);
343 assert(addresses);
344 assert(size);
345
346 for (i = 0; i < size; i++)
347 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
348 (i < (size - 1)) ? " ": "");
349 }
350
351 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
352 _cleanup_free_ struct in_addr *addresses = NULL;
353 int size = 0;
354 const char *word, *state;
355 size_t len;
356
357 assert(ret);
358 assert(string);
359
360 FOREACH_WORD(word, len, string, state) {
361 _cleanup_free_ char *addr_str = NULL;
362 struct in_addr *new_addresses;
363 int r;
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 addr_str = strndup(word, len);
372 if (!addr_str)
373 return -ENOMEM;
374
375 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
376 if (r <= 0)
377 continue;
378
379 size ++;
380 }
381
382 *ret = addresses;
383 addresses = NULL;
384
385 return size;
386 }
387
388 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
389 size_t size) {
390 unsigned i;
391
392 assert(f);
393 assert(addresses);
394 assert(size);
395
396 for (i = 0; i < size; i++)
397 fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s",
398 SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]),
399 (i < (size - 1)) ? " ": "");
400 }
401
402 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
403 _cleanup_free_ struct in6_addr *addresses = NULL;
404 int size = 0;
405 const char *word, *state;
406 size_t len;
407
408 assert(ret);
409 assert(string);
410
411 FOREACH_WORD(word, len, string, state) {
412 _cleanup_free_ char *addr_str = NULL;
413 struct in6_addr *new_addresses;
414 int r;
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 addr_str = strndup(word, len);
423 if (!addr_str)
424 return -ENOMEM;
425
426 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
427 if (r <= 0)
428 continue;
429
430 size++;
431 }
432
433 *ret = addresses;
434 addresses = NULL;
435
436 return size;
437 }
438
439 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
440 unsigned i;
441
442 assert(f);
443 assert(key);
444 assert(routes);
445 assert(size);
446
447 fprintf(f, "%s=", key);
448
449 for (i = 0; i < size; i++) {
450 fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
451 routes[i].dst_prefixlen);
452 fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
453 (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 const char *word, *state;
463 size_t len;
464
465 assert(ret);
466 assert(ret_size);
467 assert(ret_allocated);
468 assert(string);
469
470 FOREACH_WORD(word, len, string, state) {
471 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
472 _cleanup_free_ char* entry = NULL;
473 char *tok, *tok_end;
474 unsigned n;
475 int r;
476
477 if (!GREEDY_REALLOC(routes, allocated, size + 1))
478 return -ENOMEM;
479
480 entry = strndup(word, len);
481 if(!entry)
482 return -ENOMEM;
483
484 tok = entry;
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 }