Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <arpa/inet.h>
4 : : #include <linux/if.h>
5 : : #include <netinet/ether.h>
6 : :
7 : : #include "sd-id128.h"
8 : : #include "sd-ndisc.h"
9 : :
10 : : #include "alloc-util.h"
11 : : #include "condition.h"
12 : : #include "conf-parser.h"
13 : : #include "device-util.h"
14 : : #include "dhcp-lease-internal.h"
15 : : #include "env-util.h"
16 : : #include "ether-addr-util.h"
17 : : #include "hexdecoct.h"
18 : : #include "log.h"
19 : : #include "network-internal.h"
20 : : #include "parse-util.h"
21 : : #include "siphash24.h"
22 : : #include "socket-util.h"
23 : : #include "string-util.h"
24 : : #include "strv.h"
25 : : #include "utf8.h"
26 : : #include "util.h"
27 : :
28 : 0 : const char *net_get_name_persistent(sd_device *device) {
29 : : const char *name, *field;
30 : :
31 [ # # ]: 0 : assert(device);
32 : :
33 : : /* fetch some persistent data unique (on this machine) to this device */
34 [ # # ]: 0 : FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC")
35 [ # # ]: 0 : if (sd_device_get_property_value(device, field, &name) >= 0)
36 : 0 : return name;
37 : :
38 : 0 : return NULL;
39 : : }
40 : :
41 : : #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
42 : :
43 : 0 : int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) {
44 : 0 : size_t l, sz = 0;
45 : : const char *name;
46 : : int r;
47 : : uint8_t *v;
48 : :
49 [ # # ]: 0 : assert(device);
50 : :
51 : : /* net_get_name_persistent() will return one of the device names based on stable information about
52 : : * the device. If this is not available, we fall back to using the actual device name. */
53 : 0 : name = net_get_name_persistent(device);
54 [ # # # # ]: 0 : if (!name && use_sysname)
55 : 0 : (void) sd_device_get_sysname(device, &name);
56 [ # # ]: 0 : if (!name)
57 [ # # # # : 0 : return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA),
# # ]
58 : : "No stable identifying information found");
59 : :
60 [ # # # # : 0 : log_device_debug(device, "Using \"%s\" as stable identifying information", name);
# # ]
61 : 0 : l = strlen(name);
62 : 0 : sz = sizeof(sd_id128_t) + l;
63 [ # # # # ]: 0 : v = newa(uint8_t, sz);
64 : :
65 : : /* Fetch some persistent data unique to this machine */
66 : 0 : r = sd_id128_get_machine((sd_id128_t*) v);
67 [ # # ]: 0 : if (r < 0)
68 : 0 : return r;
69 : 0 : memcpy(v + sizeof(sd_id128_t), name, l);
70 : :
71 : : /* Let's hash the machine ID plus the device name. We use
72 : : * a fixed, but originally randomly created hash key here. */
73 : 0 : *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
74 : 0 : return 0;
75 : : }
76 : :
77 : 16 : static bool net_condition_test_strv(char * const *patterns, const char *string) {
78 : : char * const *p;
79 : 16 : bool match = false, has_positive_rule = false;
80 : :
81 [ + + ]: 16 : if (strv_isempty(patterns))
82 : 8 : return true;
83 : :
84 [ + - + + ]: 16 : STRV_FOREACH(p, patterns) {
85 : 8 : const char *q = *p;
86 : : bool invert;
87 : :
88 : 8 : invert = *q == '!';
89 : 8 : q += invert;
90 : :
91 [ + - ]: 8 : if (!invert)
92 : 8 : has_positive_rule = true;
93 : :
94 [ - + # # ]: 8 : if (string && fnmatch(q, string, 0) == 0) {
95 [ # # ]: 0 : if (invert)
96 : 0 : return false;
97 : : else
98 : 0 : match = true;
99 : : }
100 : : }
101 : :
102 [ + - - + ]: 8 : return has_positive_rule ? match : true;
103 : : }
104 : :
105 : 0 : static int net_condition_test_property(char * const *match_property, sd_device *device) {
106 : : char * const *p;
107 : :
108 [ # # ]: 0 : if (strv_isempty(match_property))
109 : 0 : return true;
110 : :
111 [ # # # # ]: 0 : STRV_FOREACH(p, match_property) {
112 [ # # ]: 0 : _cleanup_free_ char *key = NULL;
113 : : const char *val, *dev_val;
114 : : bool invert, v;
115 : :
116 : 0 : invert = **p == '!';
117 : :
118 : 0 : val = strchr(*p + invert, '=');
119 [ # # ]: 0 : if (!val)
120 : 0 : return -EINVAL;
121 : :
122 : 0 : key = strndup(*p + invert, val - *p - invert);
123 [ # # ]: 0 : if (!key)
124 : 0 : return -ENOMEM;
125 : :
126 : 0 : val++;
127 : :
128 [ # # ]: 0 : v = device &&
129 [ # # # # ]: 0 : sd_device_get_property_value(device, key, &dev_val) >= 0 &&
130 : 0 : fnmatch(val, dev_val, 0) == 0;
131 : :
132 [ # # # # ]: 0 : if (invert ? v : !v)
133 : 0 : return false;
134 : : }
135 : :
136 : 0 : return true;
137 : : }
138 : :
139 : 8 : bool net_match_config(Set *match_mac,
140 : : char * const *match_paths,
141 : : char * const *match_drivers,
142 : : char * const *match_types,
143 : : char * const *match_names,
144 : : char * const *match_property,
145 : : sd_device *device,
146 : : const struct ether_addr *dev_mac,
147 : : const char *dev_name) {
148 : :
149 : 8 : const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
150 : :
151 [ + - ]: 8 : if (device) {
152 : 8 : (void) sd_device_get_property_value(device, "ID_PATH", &dev_path);
153 : 8 : (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
154 : 8 : (void) sd_device_get_devtype(device, &dev_type);
155 : :
156 [ - + ]: 8 : if (!dev_name)
157 : 0 : (void) sd_device_get_sysname(device, &dev_name);
158 [ - + # # ]: 8 : if (!dev_mac &&
159 : 0 : sd_device_get_sysattr_value(device, "address", &mac_str) >= 0)
160 : 0 : dev_mac = ether_aton(mac_str);
161 : : }
162 : :
163 [ - + # # : 8 : if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
# # ]
164 : 0 : return false;
165 : :
166 [ - + ]: 8 : if (!net_condition_test_strv(match_paths, dev_path))
167 : 0 : return false;
168 : :
169 [ + - ]: 8 : if (!net_condition_test_strv(match_drivers, dev_driver))
170 : 8 : return false;
171 : :
172 [ # # ]: 0 : if (!net_condition_test_strv(match_types, dev_type))
173 : 0 : return false;
174 : :
175 [ # # ]: 0 : if (!net_condition_test_strv(match_names, dev_name))
176 : 0 : return false;
177 : :
178 [ # # ]: 0 : if (!net_condition_test_property(match_property, device))
179 : 0 : return false;
180 : :
181 : 0 : return true;
182 : : }
183 : :
184 : 4 : int config_parse_net_condition(const char *unit,
185 : : const char *filename,
186 : : unsigned line,
187 : : const char *section,
188 : : unsigned section_line,
189 : : const char *lvalue,
190 : : int ltype,
191 : : const char *rvalue,
192 : : void *data,
193 : : void *userdata) {
194 : :
195 : 4 : ConditionType cond = ltype;
196 : 4 : Condition **list = data, *c;
197 : : bool negate;
198 : :
199 [ - + ]: 4 : assert(filename);
200 [ - + ]: 4 : assert(lvalue);
201 [ - + ]: 4 : assert(rvalue);
202 [ - + ]: 4 : assert(data);
203 : :
204 [ - + ]: 4 : if (isempty(rvalue)) {
205 : 0 : *list = condition_free_list_type(*list, cond);
206 : 0 : return 0;
207 : : }
208 : :
209 : 4 : negate = rvalue[0] == '!';
210 [ - + ]: 4 : if (negate)
211 : 0 : rvalue++;
212 : :
213 : 4 : c = condition_new(cond, rvalue, false, negate);
214 [ - + ]: 4 : if (!c)
215 : 0 : return log_oom();
216 : :
217 : : /* Drop previous assignment. */
218 : 4 : *list = condition_free_list_type(*list, cond);
219 : :
220 [ - + - + ]: 4 : LIST_PREPEND(conditions, *list, c);
221 : 4 : return 0;
222 : : }
223 : :
224 : 20 : int config_parse_match_strv(
225 : : const char *unit,
226 : : const char *filename,
227 : : unsigned line,
228 : : const char *section,
229 : : unsigned section_line,
230 : : const char *lvalue,
231 : : int ltype,
232 : : const char *rvalue,
233 : : void *data,
234 : : void *userdata) {
235 : :
236 : 20 : const char *p = rvalue;
237 : 20 : char ***sv = data;
238 : : bool invert;
239 : : int r;
240 : :
241 [ - + ]: 20 : assert(filename);
242 [ - + ]: 20 : assert(lvalue);
243 [ - + ]: 20 : assert(rvalue);
244 [ - + ]: 20 : assert(data);
245 : :
246 [ - + ]: 20 : if (isempty(rvalue)) {
247 : 0 : *sv = strv_free(*sv);
248 : 0 : return 0;
249 : : }
250 : :
251 : 20 : invert = *p == '!';
252 : 20 : p += invert;
253 : :
254 : 36 : for (;;) {
255 [ + + + + ]: 76 : _cleanup_free_ char *word = NULL, *k = NULL;
256 : :
257 : 56 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
258 [ + + ]: 56 : if (r == 0)
259 : 20 : return 0;
260 [ - + ]: 36 : if (r == -ENOMEM)
261 : 0 : return log_oom();
262 [ - + ]: 36 : if (r < 0) {
263 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
264 : 0 : return 0;
265 : : }
266 : :
267 [ + + ]: 36 : if (invert) {
268 : 16 : k = strjoin("!", word);
269 [ - + ]: 16 : if (!k)
270 : 0 : return log_oom();
271 : : } else
272 : 20 : k = TAKE_PTR(word);
273 : :
274 : 36 : r = strv_consume(sv, TAKE_PTR(k));
275 [ - + ]: 36 : if (r < 0)
276 : 0 : return log_oom();
277 : : }
278 : : }
279 : :
280 : 116 : int config_parse_match_ifnames(
281 : : const char *unit,
282 : : const char *filename,
283 : : unsigned line,
284 : : const char *section,
285 : : unsigned section_line,
286 : : const char *lvalue,
287 : : int ltype,
288 : : const char *rvalue,
289 : : void *data,
290 : : void *userdata) {
291 : :
292 : 116 : const char *p = rvalue;
293 : 116 : char ***sv = data;
294 : : bool invert;
295 : : int r;
296 : :
297 [ - + ]: 116 : assert(filename);
298 [ - + ]: 116 : assert(lvalue);
299 [ - + ]: 116 : assert(rvalue);
300 [ - + ]: 116 : assert(data);
301 : :
302 : 116 : invert = *p == '!';
303 : 116 : p += invert;
304 : :
305 : 132 : for (;;) {
306 [ + + - + : 364 : _cleanup_free_ char *word = NULL, *k = NULL;
+ - ]
307 : :
308 : 248 : r = extract_first_word(&p, &word, NULL, 0);
309 [ + + ]: 248 : if (r == 0)
310 : 116 : return 0;
311 [ - + ]: 132 : if (r == -ENOMEM)
312 : 0 : return log_oom();
313 [ - + ]: 132 : if (r < 0) {
314 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
315 : : "Failed to parse interface name list: %s", rvalue);
316 : 0 : return 0;
317 : : }
318 : :
319 [ - + ]: 132 : if (!ifname_valid(word)) {
320 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
321 : : "Interface name is not valid or too long, ignoring assignment: %s", word);
322 : 0 : continue;
323 : : }
324 : :
325 [ + + ]: 132 : if (invert) {
326 : 16 : k = strjoin("!", word);
327 [ - + ]: 16 : if (!k)
328 : 0 : return log_oom();
329 : : } else
330 : 116 : k = TAKE_PTR(word);
331 : :
332 : 132 : r = strv_consume(sv, TAKE_PTR(k));
333 [ - + ]: 132 : if (r < 0)
334 : 0 : return log_oom();
335 : : }
336 : : }
337 : :
338 : 0 : int config_parse_match_property(
339 : : const char *unit,
340 : : const char *filename,
341 : : unsigned line,
342 : : const char *section,
343 : : unsigned section_line,
344 : : const char *lvalue,
345 : : int ltype,
346 : : const char *rvalue,
347 : : void *data,
348 : : void *userdata) {
349 : :
350 : 0 : const char *p = rvalue;
351 : 0 : char ***sv = data;
352 : : bool invert;
353 : : int r;
354 : :
355 [ # # ]: 0 : assert(filename);
356 [ # # ]: 0 : assert(lvalue);
357 [ # # ]: 0 : assert(rvalue);
358 [ # # ]: 0 : assert(data);
359 : :
360 : 0 : invert = *p == '!';
361 : 0 : p += invert;
362 : :
363 : 0 : for (;;) {
364 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *k = NULL;
# # ]
365 : :
366 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
367 [ # # ]: 0 : if (r == 0)
368 : 0 : return 0;
369 [ # # ]: 0 : if (r == -ENOMEM)
370 : 0 : return log_oom();
371 [ # # ]: 0 : if (r < 0) {
372 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
373 : : "Invalid syntax, ignoring: %s", rvalue);
374 : 0 : return 0;
375 : : }
376 : :
377 [ # # ]: 0 : if (!env_assignment_is_valid(word)) {
378 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
379 : : "Invalid property or value, ignoring assignment: %s", word);
380 : 0 : continue;
381 : : }
382 : :
383 [ # # ]: 0 : if (invert) {
384 : 0 : k = strjoin("!", word);
385 [ # # ]: 0 : if (!k)
386 : 0 : return log_oom();
387 : : } else
388 : 0 : k = TAKE_PTR(word);
389 : :
390 : 0 : r = strv_consume(sv, TAKE_PTR(k));
391 [ # # ]: 0 : if (r < 0)
392 : 0 : return log_oom();
393 : : }
394 : : }
395 : :
396 : 0 : int config_parse_ifalias(const char *unit,
397 : : const char *filename,
398 : : unsigned line,
399 : : const char *section,
400 : : unsigned section_line,
401 : : const char *lvalue,
402 : : int ltype,
403 : : const char *rvalue,
404 : : void *data,
405 : : void *userdata) {
406 : :
407 : 0 : char **s = data;
408 : 0 : _cleanup_free_ char *n = NULL;
409 : :
410 [ # # ]: 0 : assert(filename);
411 [ # # ]: 0 : assert(lvalue);
412 [ # # ]: 0 : assert(rvalue);
413 [ # # ]: 0 : assert(data);
414 : :
415 : 0 : n = strdup(rvalue);
416 [ # # ]: 0 : if (!n)
417 : 0 : return log_oom();
418 : :
419 [ # # # # ]: 0 : if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
420 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
421 : 0 : return 0;
422 : : }
423 : :
424 [ # # ]: 0 : if (isempty(n))
425 : 0 : *s = mfree(*s);
426 : : else
427 : 0 : free_and_replace(*s, n);
428 : :
429 : 0 : return 0;
430 : : }
431 : :
432 : 104 : int config_parse_hwaddr(const char *unit,
433 : : const char *filename,
434 : : unsigned line,
435 : : const char *section,
436 : : unsigned section_line,
437 : : const char *lvalue,
438 : : int ltype,
439 : : const char *rvalue,
440 : : void *data,
441 : : void *userdata) {
442 : :
443 : 104 : _cleanup_free_ struct ether_addr *n = NULL;
444 : 104 : struct ether_addr **hwaddr = data;
445 : : int r;
446 : :
447 [ - + ]: 104 : assert(filename);
448 [ - + ]: 104 : assert(lvalue);
449 [ - + ]: 104 : assert(rvalue);
450 [ - + ]: 104 : assert(data);
451 : :
452 : 104 : n = new0(struct ether_addr, 1);
453 [ - + ]: 104 : if (!n)
454 : 0 : return log_oom();
455 : :
456 : 104 : r = ether_addr_from_string(rvalue, n);
457 [ + + ]: 104 : if (r < 0) {
458 [ + - ]: 60 : log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue);
459 : 60 : return 0;
460 : : }
461 : :
462 : 44 : free_and_replace(*hwaddr, n);
463 : :
464 : 44 : return 0;
465 : : }
466 : :
467 : 112 : int config_parse_hwaddrs(const char *unit,
468 : : const char *filename,
469 : : unsigned line,
470 : : const char *section,
471 : : unsigned section_line,
472 : : const char *lvalue,
473 : : int ltype,
474 : : const char *rvalue,
475 : : void *data,
476 : : void *userdata) {
477 : :
478 : 112 : _cleanup_set_free_free_ Set *s = NULL;
479 : 112 : const char *p = rvalue;
480 : 112 : Set **hwaddrs = data;
481 : : int r;
482 : :
483 [ - + ]: 112 : assert(filename);
484 [ - + ]: 112 : assert(lvalue);
485 [ - + ]: 112 : assert(rvalue);
486 [ - + ]: 112 : assert(data);
487 : :
488 [ + + ]: 112 : if (isempty(rvalue)) {
489 : : /* Empty assignment resets the list */
490 : 4 : *hwaddrs = set_free_free(*hwaddrs);
491 : 4 : return 0;
492 : : }
493 : :
494 : 108 : s = set_new(ðer_addr_hash_ops);
495 [ - + ]: 108 : if (!s)
496 : 0 : return log_oom();
497 : :
498 : 152 : for (;;) {
499 [ + + - + ]: 260 : _cleanup_free_ char *word = NULL;
500 [ + + - + ]: 260 : _cleanup_free_ struct ether_addr *n = NULL;
501 : :
502 : 260 : r = extract_first_word(&p, &word, NULL, 0);
503 [ + + ]: 260 : if (r == 0)
504 : 108 : break;
505 [ - + ]: 152 : if (r == -ENOMEM)
506 : 0 : return log_oom();
507 [ - + ]: 152 : if (r < 0) {
508 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
509 : 0 : return 0;
510 : : }
511 : :
512 : 152 : n = new(struct ether_addr, 1);
513 [ - + ]: 152 : if (!n)
514 : 0 : return log_oom();
515 : :
516 : 152 : r = ether_addr_from_string(word, n);
517 [ + + ]: 152 : if (r < 0) {
518 [ + - ]: 72 : log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word);
519 : 72 : continue;
520 : : }
521 : :
522 : 80 : r = set_put(s, n);
523 [ - + ]: 80 : if (r < 0)
524 : 0 : return log_oom();
525 [ + + ]: 80 : if (r > 0)
526 : 68 : n = NULL; /* avoid cleanup */
527 : : }
528 : :
529 : 108 : r = set_ensure_allocated(hwaddrs, ðer_addr_hash_ops);
530 [ - + ]: 108 : if (r < 0)
531 : 0 : return log_oom();
532 : :
533 : 108 : r = set_move(*hwaddrs, s);
534 [ - + ]: 108 : if (r < 0)
535 : 0 : return log_oom();
536 : :
537 : 108 : return 0;
538 : : }
539 : :
540 : 0 : int config_parse_bridge_port_priority(
541 : : const char *unit,
542 : : const char *filename,
543 : : unsigned line,
544 : : const char *section,
545 : : unsigned section_line,
546 : : const char *lvalue,
547 : : int ltype,
548 : : const char *rvalue,
549 : : void *data,
550 : : void *userdata) {
551 : :
552 : : uint16_t i;
553 : : int r;
554 : :
555 [ # # ]: 0 : assert(filename);
556 [ # # ]: 0 : assert(lvalue);
557 [ # # ]: 0 : assert(rvalue);
558 [ # # ]: 0 : assert(data);
559 : :
560 : 0 : r = safe_atou16(rvalue, &i);
561 [ # # ]: 0 : if (r < 0) {
562 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
563 : : "Failed to parse bridge port priority, ignoring: %s", rvalue);
564 : 0 : return 0;
565 : : }
566 : :
567 [ # # ]: 0 : if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) {
568 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
569 : : "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue);
570 : 0 : return 0;
571 : : }
572 : :
573 : 0 : *((uint16_t *)data) = i;
574 : :
575 : 0 : return 0;
576 : : }
577 : :
578 : 0 : size_t serialize_in_addrs(FILE *f,
579 : : const struct in_addr *addresses,
580 : : size_t size,
581 : : bool with_leading_space,
582 : : bool (*predicate)(const struct in_addr *addr)) {
583 : : size_t count;
584 : : size_t i;
585 : :
586 [ # # ]: 0 : assert(f);
587 [ # # ]: 0 : assert(addresses);
588 : :
589 : 0 : count = 0;
590 : :
591 [ # # ]: 0 : for (i = 0; i < size; i++) {
592 : : char sbuf[INET_ADDRSTRLEN];
593 : :
594 [ # # # # ]: 0 : if (predicate && !predicate(&addresses[i]))
595 : 0 : continue;
596 [ # # ]: 0 : if (with_leading_space)
597 : 0 : fputc(' ', f);
598 : : else
599 : 0 : with_leading_space = true;
600 : 0 : fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f);
601 : 0 : count++;
602 : : }
603 : :
604 : 0 : return count;
605 : : }
606 : :
607 : 4 : int deserialize_in_addrs(struct in_addr **ret, const char *string) {
608 : 4 : _cleanup_free_ struct in_addr *addresses = NULL;
609 : 4 : int size = 0;
610 : :
611 [ - + ]: 4 : assert(ret);
612 [ - + ]: 4 : assert(string);
613 : :
614 : 24 : for (;;) {
615 [ + - + + ]: 28 : _cleanup_free_ char *word = NULL;
616 : : struct in_addr *new_addresses;
617 : : int r;
618 : :
619 : 28 : r = extract_first_word(&string, &word, NULL, 0);
620 [ - + ]: 28 : if (r < 0)
621 : 0 : return r;
622 [ + + ]: 28 : if (r == 0)
623 : 4 : break;
624 : :
625 : 24 : new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
626 [ - + ]: 24 : if (!new_addresses)
627 : 0 : return -ENOMEM;
628 : : else
629 : 24 : addresses = new_addresses;
630 : :
631 : 24 : r = inet_pton(AF_INET, word, &(addresses[size]));
632 [ + + ]: 24 : if (r <= 0)
633 : 12 : continue;
634 : :
635 : 12 : size++;
636 : : }
637 : :
638 [ + - ]: 4 : *ret = size > 0 ? TAKE_PTR(addresses) : NULL;
639 : :
640 : 4 : return size;
641 : : }
642 : :
643 : 0 : void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
644 : : unsigned i;
645 : :
646 [ # # ]: 0 : assert(f);
647 [ # # ]: 0 : assert(addresses);
648 [ # # ]: 0 : assert(size);
649 : :
650 [ # # ]: 0 : for (i = 0; i < size; i++) {
651 : : char buffer[INET6_ADDRSTRLEN];
652 : :
653 : 0 : fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
654 : :
655 [ # # ]: 0 : if (i < size - 1)
656 : 0 : fputc(' ', f);
657 : : }
658 : 0 : }
659 : :
660 : 4 : int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
661 : 4 : _cleanup_free_ struct in6_addr *addresses = NULL;
662 : 4 : int size = 0;
663 : :
664 [ - + ]: 4 : assert(ret);
665 [ - + ]: 4 : assert(string);
666 : :
667 : 24 : for (;;) {
668 [ + - + + ]: 28 : _cleanup_free_ char *word = NULL;
669 : : struct in6_addr *new_addresses;
670 : : int r;
671 : :
672 : 28 : r = extract_first_word(&string, &word, NULL, 0);
673 [ - + ]: 28 : if (r < 0)
674 : 0 : return r;
675 [ + + ]: 28 : if (r == 0)
676 : 4 : break;
677 : :
678 : 24 : new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
679 [ - + ]: 24 : if (!new_addresses)
680 : 0 : return -ENOMEM;
681 : : else
682 : 24 : addresses = new_addresses;
683 : :
684 : 24 : r = inet_pton(AF_INET6, word, &(addresses[size]));
685 [ + + ]: 24 : if (r <= 0)
686 : 12 : continue;
687 : :
688 : 12 : size++;
689 : : }
690 : :
691 : 4 : *ret = TAKE_PTR(addresses);
692 : :
693 : 4 : return size;
694 : : }
695 : :
696 : 0 : void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
697 : : unsigned i;
698 : :
699 [ # # ]: 0 : assert(f);
700 [ # # ]: 0 : assert(key);
701 [ # # ]: 0 : assert(routes);
702 [ # # ]: 0 : assert(size);
703 : :
704 : 0 : fprintf(f, "%s=", key);
705 : :
706 [ # # ]: 0 : for (i = 0; i < size; i++) {
707 : : char sbuf[INET_ADDRSTRLEN];
708 : : struct in_addr dest, gw;
709 : : uint8_t length;
710 : :
711 [ # # ]: 0 : assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
712 [ # # ]: 0 : assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
713 [ # # ]: 0 : assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
714 : :
715 : 0 : fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof(sbuf)), length);
716 [ # # ]: 0 : fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof(sbuf)), (i < (size - 1)) ? " ": "");
717 : : }
718 : :
719 : 0 : fputs("\n", f);
720 : 0 : }
721 : :
722 : 16 : int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
723 : 16 : _cleanup_free_ struct sd_dhcp_route *routes = NULL;
724 : 16 : size_t size = 0, allocated = 0;
725 : :
726 [ - + ]: 16 : assert(ret);
727 [ - + ]: 16 : assert(ret_size);
728 [ - + ]: 16 : assert(ret_allocated);
729 [ - + ]: 16 : assert(string);
730 : :
731 : : /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
732 : 36 : for (;;) {
733 [ + - + + ]: 52 : _cleanup_free_ char *word = NULL;
734 : : char *tok, *tok_end;
735 : : unsigned n;
736 : : int r;
737 : :
738 : 52 : r = extract_first_word(&string, &word, NULL, 0);
739 [ - + ]: 52 : if (r < 0)
740 : 0 : return r;
741 [ + + ]: 52 : if (r == 0)
742 : 16 : break;
743 : :
744 [ - + ]: 36 : if (!GREEDY_REALLOC(routes, allocated, size + 1))
745 : 0 : return -ENOMEM;
746 : :
747 : 36 : tok = word;
748 : :
749 : : /* get the subnet */
750 : 36 : tok_end = strchr(tok, '/');
751 [ + + ]: 36 : if (!tok_end)
752 : 8 : continue;
753 : 28 : *tok_end = '\0';
754 : :
755 : 28 : r = inet_aton(tok, &routes[size].dst_addr);
756 [ - + ]: 28 : if (r == 0)
757 : 0 : continue;
758 : :
759 : 28 : tok = tok_end + 1;
760 : :
761 : : /* get the prefixlen */
762 : 28 : tok_end = strchr(tok, ',');
763 [ - + ]: 28 : if (!tok_end)
764 : 0 : continue;
765 : :
766 : 28 : *tok_end = '\0';
767 : :
768 : 28 : r = safe_atou(tok, &n);
769 [ + - + + ]: 28 : if (r < 0 || n > 32)
770 : 4 : continue;
771 : :
772 : 24 : routes[size].dst_prefixlen = (uint8_t) n;
773 : 24 : tok = tok_end + 1;
774 : :
775 : : /* get the gateway */
776 : 24 : r = inet_aton(tok, &routes[size].gw_addr);
777 [ + + ]: 24 : if (r == 0)
778 : 4 : continue;
779 : :
780 : 20 : size++;
781 : : }
782 : :
783 : 16 : *ret_size = size;
784 : 16 : *ret_allocated = allocated;
785 : 16 : *ret = TAKE_PTR(routes);
786 : :
787 : 16 : return 0;
788 : : }
789 : :
790 : 0 : int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
791 : 0 : _cleanup_free_ char *hex_buf = NULL;
792 : :
793 [ # # ]: 0 : assert(f);
794 [ # # ]: 0 : assert(key);
795 [ # # ]: 0 : assert(data);
796 : :
797 : 0 : hex_buf = hexmem(data, size);
798 [ # # ]: 0 : if (!hex_buf)
799 : 0 : return -ENOMEM;
800 : :
801 : 0 : fprintf(f, "%s=%s\n", key, hex_buf);
802 : :
803 : 0 : return 0;
804 : : }
|