]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/network-internal.c
dhcp6-option: Add helper function for uncompressed domain names
[thirdparty/systemd.git] / src / libsystemd-network / network-internal.c
CommitLineData
5fde13d7
TG
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>
d2df0d0e 23#include <linux/if.h>
f5284182 24#include <arpa/inet.h>
5fde13d7 25
b5db00e5
UTL
26#include "strv.h"
27#include "siphash24.h"
e1ea665e 28#include "dhcp-lease-internal.h"
be32eb9b 29#include "log.h"
5fde13d7 30#include "utf8.h"
a12fa420 31#include "util.h"
5fde13d7 32#include "conf-parser.h"
134e56dc 33#include "condition.h"
44e7b949 34#include "network-internal.h"
5fde13d7 35
fc541430 36const char *net_get_name(struct udev_device *device) {
44e7b949 37 const char *name, *field;
fc541430
TG
38
39 assert(device);
b5db00e5
UTL
40
41 /* fetch some persistent data unique (on this machine) to this device */
44e7b949 42 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
b5db00e5
UTL
43 name = udev_device_get_property_value(device, field);
44 if (name)
44e7b949 45 return name;
b5db00e5
UTL
46 }
47
44e7b949 48 return NULL;
fc541430
TG
49}
50
51#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
52
53int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
54 size_t l, sz = 0;
55 const char *name = NULL;
56 int r;
57 uint8_t *v;
58
59 assert(device);
60
61 name = net_get_name(device);
b5db00e5
UTL
62 if (!name)
63 return -ENOENT;
64
65 l = strlen(name);
66 sz = sizeof(sd_id128_t) + l;
67 v = alloca(sz);
68
69 /* fetch some persistent data unique to this machine */
70 r = sd_id128_get_machine((sd_id128_t*) v);
71 if (r < 0)
72 return r;
73 memcpy(v + sizeof(sd_id128_t), name, l);
74
75 /* Let's hash the machine ID plus the device name. We
76 * use a fixed, but originally randomly created hash
77 * key here. */
78 siphash24(result, v, sz, HASH_KEY.bytes);
79
80 return 0;
81}
82
be32eb9b 83bool net_match_config(const struct ether_addr *match_mac,
5256e00e
TG
84 char * const *match_paths,
85 char * const *match_drivers,
86 char * const *match_types,
87 char * const *match_names,
2cc412b5
TG
88 Condition *match_host,
89 Condition *match_virt,
90 Condition *match_kernel,
edbb03e9 91 Condition *match_arch,
505f8da7 92 const struct ether_addr *dev_mac,
b3e01314 93 const char *dev_path,
bf175aaf 94 const char *dev_parent_driver,
b3e01314
TG
95 const char *dev_driver,
96 const char *dev_type,
32bc8adc 97 const char *dev_name) {
be32eb9b 98
a4705396 99 if (match_host && !condition_test(match_host))
7eb08da4 100 return false;
2cc412b5 101
a4705396 102 if (match_virt && !condition_test(match_virt))
7eb08da4 103 return false;
2cc412b5 104
a4705396 105 if (match_kernel && !condition_test(match_kernel))
7eb08da4 106 return false;
2cc412b5 107
a4705396 108 if (match_arch && !condition_test(match_arch))
7eb08da4 109 return false;
edbb03e9 110
505f8da7 111 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
7eb08da4 112 return false;
be32eb9b 113
d49dc812 114 if (!strv_isempty(match_paths) &&
2404701e 115 (!dev_path || !strv_fnmatch(match_paths, dev_path, 0)))
ee5de57b 116 return false;
5256e00e 117
d49dc812 118 if (!strv_isempty(match_drivers) &&
2404701e 119 (!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0)))
ee5de57b 120 return false;
5256e00e 121
d49dc812 122 if (!strv_isempty(match_types) &&
2404701e 123 (!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0)))
ee5de57b 124 return false;
5256e00e 125
d49dc812 126 if (!strv_isempty(match_names) &&
2404701e 127 (!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0)))
ee5de57b 128 return false;
5256e00e 129
7eb08da4 130 return true;
be32eb9b 131}
5fde13d7 132
2cc412b5
TG
133int config_parse_net_condition(const char *unit,
134 const char *filename,
135 unsigned line,
136 const char *section,
137 unsigned section_line,
138 const char *lvalue,
139 int ltype,
140 const char *rvalue,
141 void *data,
142 void *userdata) {
143
144 ConditionType cond = ltype;
145 Condition **ret = data;
146 bool negate;
147 Condition *c;
148 _cleanup_free_ char *s = NULL;
149
150 assert(filename);
151 assert(lvalue);
152 assert(rvalue);
153 assert(data);
154
155 negate = rvalue[0] == '!';
156 if (negate)
157 rvalue++;
158
159 s = strdup(rvalue);
160 if (!s)
161 return log_oom();
162
163 c = condition_new(cond, s, false, negate);
164 if (!c)
165 return log_oom();
166
167 if (*ret)
168 condition_free(*ret);
169
170 *ret = c;
171 return 0;
172}
173
5fde13d7
TG
174int config_parse_ifname(const char *unit,
175 const char *filename,
176 unsigned line,
177 const char *section,
71a61510 178 unsigned section_line,
5fde13d7
TG
179 const char *lvalue,
180 int ltype,
181 const char *rvalue,
182 void *data,
183 void *userdata) {
184
185 char **s = data;
5a3f1989 186 _cleanup_free_ char *n = NULL;
5fde13d7
TG
187
188 assert(filename);
189 assert(lvalue);
190 assert(rvalue);
191 assert(data);
192
193 n = strdup(rvalue);
194 if (!n)
195 return log_oom();
196
197 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
198 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
199 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
5fde13d7
TG
200 return 0;
201 }
202
203 free(*s);
5a3f1989 204 if (*n) {
5fde13d7 205 *s = n;
5a3f1989
TG
206 n = NULL;
207 } else
5fde13d7 208 *s = NULL;
5fde13d7
TG
209
210 return 0;
211}
212
5256e00e
TG
213int 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, EINVAL,
243 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
244 free(n);
245 return 0;
246 }
247
248 r = strv_consume(sv, n);
249 if (r < 0)
250 return log_oom();
251 }
252
253 return 0;
254}
255
d2df0d0e
TG
256int config_parse_ifalias(const char *unit,
257 const char *filename,
258 unsigned line,
259 const char *section,
71a61510 260 unsigned section_line,
d2df0d0e
TG
261 const char *lvalue,
262 int ltype,
263 const char *rvalue,
264 void *data,
265 void *userdata) {
266
267 char **s = data;
9c39eb5c 268 _cleanup_free_ char *n = NULL;
d2df0d0e
TG
269
270 assert(filename);
271 assert(lvalue);
272 assert(rvalue);
273 assert(data);
274
275 n = strdup(rvalue);
276 if (!n)
277 return log_oom();
278
279 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
280 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
281 "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
d2df0d0e
TG
282 return 0;
283 }
284
285 free(*s);
9c39eb5c 286 if (*n) {
d2df0d0e 287 *s = n;
9c39eb5c
TG
288 n = NULL;
289 } else
d2df0d0e 290 *s = NULL;
d2df0d0e
TG
291
292 return 0;
293}
294
5fde13d7
TG
295int config_parse_hwaddr(const char *unit,
296 const char *filename,
297 unsigned line,
298 const char *section,
71a61510 299 unsigned section_line,
5fde13d7
TG
300 const char *lvalue,
301 int ltype,
302 const char *rvalue,
303 void *data,
304 void *userdata) {
305 struct ether_addr **hwaddr = data;
306 struct ether_addr *n;
307 int r;
308
309 assert(filename);
310 assert(lvalue);
311 assert(rvalue);
312 assert(data);
313
a12fa420 314 n = new0(struct ether_addr, 1);
5fde13d7
TG
315 if (!n)
316 return log_oom();
317
318 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
319 &n->ether_addr_octet[0],
320 &n->ether_addr_octet[1],
321 &n->ether_addr_octet[2],
322 &n->ether_addr_octet[3],
323 &n->ether_addr_octet[4],
324 &n->ether_addr_octet[5]);
325 if (r != 6) {
326 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
327 "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}
f5284182 337
b0e39c82 338void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
09bee74d
TG
339 unsigned i;
340
341 assert(f);
09bee74d
TG
342 assert(addresses);
343 assert(size);
344
09bee74d
TG
345 for (i = 0; i < size; i++)
346 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
347 (i < (size - 1)) ? " ": "");
09bee74d
TG
348}
349
a2ba62c7 350int deserialize_in_addrs(struct in_addr **ret, const char *string) {
09bee74d 351 _cleanup_free_ struct in_addr *addresses = NULL;
a2ba62c7 352 int size = 0;
a2a5291b 353 const char *word, *state;
09bee74d
TG
354 size_t len;
355
356 assert(ret);
09bee74d
TG
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
09bee74d
TG
381 *ret = addresses;
382 addresses = NULL;
383
a2ba62c7 384 return size;
09bee74d
TG
385}
386
a2ba62c7 387int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
09bee74d 388 _cleanup_free_ struct in6_addr *addresses = NULL;
a2ba62c7 389 int size = 0;
a2a5291b 390 const char *word, *state;
09bee74d
TG
391 size_t len;
392
393 assert(ret);
09bee74d
TG
394 assert(string);
395
396 FOREACH_WORD(word, len, string, state) {
397 _cleanup_free_ char *addr_str = NULL;
398 struct in6_addr *new_addresses;
399 int r;
400
401 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
402 if (!new_addresses)
403 return -ENOMEM;
404 else
405 addresses = new_addresses;
406
407 addr_str = strndup(word, len);
408 if (!addr_str)
409 return -ENOMEM;
410
411 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
412 if (r <= 0)
413 continue;
414
415 size++;
416 }
417
09bee74d
TG
418 *ret = addresses;
419 addresses = NULL;
420
a2ba62c7 421 return size;
09bee74d 422}
e1ea665e
EY
423
424void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
425 unsigned i;
426
427 assert(f);
428 assert(key);
429 assert(routes);
430 assert(size);
431
432 fprintf(f, "%s=", key);
433
fbf7dcb5
DW
434 for (i = 0; i < size; i++) {
435 fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
436 routes[i].dst_prefixlen);
437 fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
e1ea665e 438 (i < (size - 1)) ? " ": "");
fbf7dcb5 439 }
e1ea665e
EY
440
441 fputs("\n", f);
442}
443
444int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
445 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
446 size_t size = 0, allocated = 0;
a2a5291b 447 const char *word, *state;
e1ea665e
EY
448 size_t len;
449
450 assert(ret);
451 assert(ret_size);
452 assert(ret_allocated);
453 assert(string);
454
455 FOREACH_WORD(word, len, string, state) {
456 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
69f08c83 457 _cleanup_free_ char* entry = NULL;
e1ea665e
EY
458 char *tok, *tok_end;
459 unsigned n;
460 int r;
461
462 if (!GREEDY_REALLOC(routes, allocated, size + 1))
463 return -ENOMEM;
464
465 entry = strndup(word, len);
31db0120
SS
466 if(!entry)
467 return -ENOMEM;
e1ea665e
EY
468
469 tok = entry;
470
471 /* get the subnet */
472 tok_end = strchr(tok, '/');
473 if (!tok_end)
474 continue;
475 *tok_end = '\0';
476
477 r = inet_aton(tok, &routes[size].dst_addr);
478 if (r == 0)
479 continue;
480
481 tok = tok_end + 1;
482
483 /* get the prefixlen */
484 tok_end = strchr(tok, ',');
485 if (!tok_end)
486 continue;
487
488 *tok_end = '\0';
489
490 r = safe_atou(tok, &n);
491 if (r < 0 || n > 32)
492 continue;
493
494 routes[size].dst_prefixlen = (uint8_t) n;
495 tok = tok_end + 1;
496
497 /* get the gateway */
498 r = inet_aton(tok, &routes[size].gw_addr);
499 if (r == 0)
500 continue;
501
502 size++;
503 }
504
505 *ret_size = size;
506 *ret_allocated = allocated;
507 *ret = routes;
508 routes = NULL;
509
510 return 0;
511}
a073309f
AC
512
513int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t size) {
514 _cleanup_free_ char *hex_buf = NULL;
515
516 assert(f);
517 assert(key);
518 assert(data);
519
520 hex_buf = hexmem(data, size);
521 if (hex_buf == NULL)
522 return -ENOMEM;
523
524 fprintf(f, "%s=%s\n", key, hex_buf);
525
526 return 0;
527}
528
529int deserialize_dhcp_option(uint8_t **data, size_t *data_len, const char *string) {
530 assert(data);
531 assert(data_len);
532 assert(string);
533
534 if (strlen(string) % 2)
535 return -EINVAL;
536
537 return unhexmem(string, strlen(string), (void **)data, data_len);
538}