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