]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
util-lib: split out hex/dec/oct encoding/decoding into its own file
[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 "condition.h"
29 #include "conf-parser.h"
30 #include "dhcp-lease-internal.h"
31 #include "log.h"
32 #include "network-internal.h"
33 #include "hexdecoct.h"
34 #include "parse-util.h"
35 #include "siphash24.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, uint8_t result[8]) {
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 siphash24(result, 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_ifname(const char *unit,
180 const char *filename,
181 unsigned line,
182 const char *section,
183 unsigned section_line,
184 const char *lvalue,
185 int ltype,
186 const char *rvalue,
187 void *data,
188 void *userdata) {
189
190 char **s = data;
191 _cleanup_free_ char *n = NULL;
192
193 assert(filename);
194 assert(lvalue);
195 assert(rvalue);
196 assert(data);
197
198 n = strdup(rvalue);
199 if (!n)
200 return log_oom();
201
202 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
203 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
204 return 0;
205 }
206
207 free(*s);
208 if (*n) {
209 *s = n;
210 n = NULL;
211 } else
212 *s = NULL;
213
214 return 0;
215 }
216
217 int config_parse_ifnames(const char *unit,
218 const char *filename,
219 unsigned line,
220 const char *section,
221 unsigned section_line,
222 const char *lvalue,
223 int ltype,
224 const char *rvalue,
225 void *data,
226 void *userdata) {
227
228 char ***sv = data;
229 const char *word, *state;
230 size_t l;
231 int r;
232
233 assert(filename);
234 assert(lvalue);
235 assert(rvalue);
236 assert(data);
237
238 FOREACH_WORD(word, l, rvalue, state) {
239 char *n;
240
241 n = strndup(word, l);
242 if (!n)
243 return log_oom();
244
245 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
246 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
247 free(n);
248 return 0;
249 }
250
251 r = strv_consume(sv, n);
252 if (r < 0)
253 return log_oom();
254 }
255
256 return 0;
257 }
258
259 int config_parse_ifalias(const char *unit,
260 const char *filename,
261 unsigned line,
262 const char *section,
263 unsigned section_line,
264 const char *lvalue,
265 int ltype,
266 const char *rvalue,
267 void *data,
268 void *userdata) {
269
270 char **s = data;
271 _cleanup_free_ char *n = NULL;
272
273 assert(filename);
274 assert(lvalue);
275 assert(rvalue);
276 assert(data);
277
278 n = strdup(rvalue);
279 if (!n)
280 return log_oom();
281
282 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
283 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
284 return 0;
285 }
286
287 free(*s);
288 if (*n) {
289 *s = n;
290 n = NULL;
291 } else
292 *s = NULL;
293
294 return 0;
295 }
296
297 int config_parse_hwaddr(const char *unit,
298 const char *filename,
299 unsigned line,
300 const char *section,
301 unsigned section_line,
302 const char *lvalue,
303 int ltype,
304 const char *rvalue,
305 void *data,
306 void *userdata) {
307 struct ether_addr **hwaddr = data;
308 struct ether_addr *n;
309 int r;
310
311 assert(filename);
312 assert(lvalue);
313 assert(rvalue);
314 assert(data);
315
316 n = new0(struct ether_addr, 1);
317 if (!n)
318 return log_oom();
319
320 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
321 &n->ether_addr_octet[0],
322 &n->ether_addr_octet[1],
323 &n->ether_addr_octet[2],
324 &n->ether_addr_octet[3],
325 &n->ether_addr_octet[4],
326 &n->ether_addr_octet[5]);
327 if (r != 6) {
328 log_syntax(unit, LOG_ERR, filename, line, 0, "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_NDISC_ADDRESS_FORMAT_STR"%s",
398 SD_NDISC_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 }