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