]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/network-internal.c
network: s/user_data/userdata/
[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"
b729fa14 35#include "sd-icmp6-nd.h"
5fde13d7 36
fc541430 37const char *net_get_name(struct udev_device *device) {
44e7b949 38 const char *name, *field;
fc541430
TG
39
40 assert(device);
b5db00e5
UTL
41
42 /* fetch some persistent data unique (on this machine) to this device */
44e7b949 43 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
b5db00e5
UTL
44 name = udev_device_get_property_value(device, field);
45 if (name)
44e7b949 46 return name;
b5db00e5
UTL
47 }
48
44e7b949 49 return NULL;
fc541430
TG
50}
51
52#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
53
54int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
55 size_t l, sz = 0;
56 const char *name = NULL;
57 int r;
58 uint8_t *v;
59
60 assert(device);
61
62 name = net_get_name(device);
b5db00e5
UTL
63 if (!name)
64 return -ENOENT;
65
66 l = strlen(name);
67 sz = sizeof(sd_id128_t) + l;
68 v = alloca(sz);
69
70 /* fetch some persistent data unique to this machine */
71 r = sd_id128_get_machine((sd_id128_t*) v);
72 if (r < 0)
73 return r;
74 memcpy(v + sizeof(sd_id128_t), name, l);
75
76 /* Let's hash the machine ID plus the device name. We
77 * use a fixed, but originally randomly created hash
78 * key here. */
79 siphash24(result, v, sz, HASH_KEY.bytes);
80
81 return 0;
82}
83
be32eb9b 84bool net_match_config(const struct ether_addr *match_mac,
5256e00e
TG
85 char * const *match_paths,
86 char * const *match_drivers,
87 char * const *match_types,
88 char * const *match_names,
2cc412b5
TG
89 Condition *match_host,
90 Condition *match_virt,
91 Condition *match_kernel,
edbb03e9 92 Condition *match_arch,
505f8da7 93 const struct ether_addr *dev_mac,
b3e01314 94 const char *dev_path,
bf175aaf 95 const char *dev_parent_driver,
b3e01314
TG
96 const char *dev_driver,
97 const char *dev_type,
32bc8adc 98 const char *dev_name) {
be32eb9b 99
a4705396 100 if (match_host && !condition_test(match_host))
7eb08da4 101 return false;
2cc412b5 102
a4705396 103 if (match_virt && !condition_test(match_virt))
7eb08da4 104 return false;
2cc412b5 105
a4705396 106 if (match_kernel && !condition_test(match_kernel))
7eb08da4 107 return false;
2cc412b5 108
a4705396 109 if (match_arch && !condition_test(match_arch))
7eb08da4 110 return false;
edbb03e9 111
505f8da7 112 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
7eb08da4 113 return false;
be32eb9b 114
d49dc812 115 if (!strv_isempty(match_paths) &&
2404701e 116 (!dev_path || !strv_fnmatch(match_paths, dev_path, 0)))
ee5de57b 117 return false;
5256e00e 118
d49dc812 119 if (!strv_isempty(match_drivers) &&
2404701e 120 (!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0)))
ee5de57b 121 return false;
5256e00e 122
d49dc812 123 if (!strv_isempty(match_types) &&
2404701e 124 (!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0)))
ee5de57b 125 return false;
5256e00e 126
d49dc812 127 if (!strv_isempty(match_names) &&
2404701e 128 (!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0)))
ee5de57b 129 return false;
5256e00e 130
7eb08da4 131 return true;
be32eb9b 132}
5fde13d7 133
2cc412b5
TG
134int config_parse_net_condition(const char *unit,
135 const char *filename,
136 unsigned line,
137 const char *section,
138 unsigned section_line,
139 const char *lvalue,
140 int ltype,
141 const char *rvalue,
142 void *data,
143 void *userdata) {
144
145 ConditionType cond = ltype;
146 Condition **ret = data;
147 bool negate;
148 Condition *c;
149 _cleanup_free_ char *s = NULL;
150
151 assert(filename);
152 assert(lvalue);
153 assert(rvalue);
154 assert(data);
155
156 negate = rvalue[0] == '!';
157 if (negate)
158 rvalue++;
159
160 s = strdup(rvalue);
161 if (!s)
162 return log_oom();
163
164 c = condition_new(cond, s, false, negate);
165 if (!c)
166 return log_oom();
167
168 if (*ret)
169 condition_free(*ret);
170
171 *ret = c;
172 return 0;
173}
174
5fde13d7
TG
175int config_parse_ifname(const char *unit,
176 const char *filename,
177 unsigned line,
178 const char *section,
71a61510 179 unsigned section_line,
5fde13d7
TG
180 const char *lvalue,
181 int ltype,
182 const char *rvalue,
183 void *data,
184 void *userdata) {
185
186 char **s = data;
5a3f1989 187 _cleanup_free_ char *n = NULL;
5fde13d7
TG
188
189 assert(filename);
190 assert(lvalue);
191 assert(rvalue);
192 assert(data);
193
194 n = strdup(rvalue);
195 if (!n)
196 return log_oom();
197
198 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
199 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
200 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
5fde13d7
TG
201 return 0;
202 }
203
204 free(*s);
5a3f1989 205 if (*n) {
5fde13d7 206 *s = n;
5a3f1989
TG
207 n = NULL;
208 } else
5fde13d7 209 *s = NULL;
5fde13d7
TG
210
211 return 0;
212}
213
5256e00e
TG
214int config_parse_ifnames(const char *unit,
215 const char *filename,
216 unsigned line,
217 const char *section,
218 unsigned section_line,
219 const char *lvalue,
220 int ltype,
221 const char *rvalue,
222 void *data,
223 void *userdata) {
224
225 char ***sv = data;
226 const char *word, *state;
227 size_t l;
228 int r;
229
230 assert(filename);
231 assert(lvalue);
232 assert(rvalue);
233 assert(data);
234
235 FOREACH_WORD(word, l, rvalue, state) {
236 char *n;
237
238 n = strndup(word, l);
239 if (!n)
240 return log_oom();
241
242 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
243 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
244 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
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) {
281 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
282 "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
d2df0d0e
TG
283 return 0;
284 }
285
286 free(*s);
9c39eb5c 287 if (*n) {
d2df0d0e 288 *s = n;
9c39eb5c
TG
289 n = NULL;
290 } else
d2df0d0e 291 *s = NULL;
d2df0d0e
TG
292
293 return 0;
294}
295
5fde13d7
TG
296int config_parse_hwaddr(const char *unit,
297 const char *filename,
298 unsigned line,
299 const char *section,
71a61510 300 unsigned section_line,
5fde13d7
TG
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
a12fa420 315 n = new0(struct ether_addr, 1);
5fde13d7
TG
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, EINVAL,
328 "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}
f5284182 338
b0e39c82 339void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
09bee74d
TG
340 unsigned i;
341
342 assert(f);
09bee74d
TG
343 assert(addresses);
344 assert(size);
345
09bee74d
TG
346 for (i = 0; i < size; i++)
347 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
348 (i < (size - 1)) ? " ": "");
09bee74d
TG
349}
350
a2ba62c7 351int deserialize_in_addrs(struct in_addr **ret, const char *string) {
09bee74d 352 _cleanup_free_ struct in_addr *addresses = NULL;
a2ba62c7 353 int size = 0;
a2a5291b 354 const char *word, *state;
09bee74d
TG
355 size_t len;
356
357 assert(ret);
09bee74d
TG
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
09bee74d
TG
382 *ret = addresses;
383 addresses = NULL;
384
a2ba62c7 385 return size;
09bee74d
TG
386}
387
b729fa14
PF
388void 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_ICMP6_ADDRESS_FORMAT_STR"%s",
398 SD_ICMP6_ADDRESS_FORMAT_VAL(addresses[i]),
399 (i < (size - 1)) ? " ": "");
400}
401
a2ba62c7 402int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
09bee74d 403 _cleanup_free_ struct in6_addr *addresses = NULL;
a2ba62c7 404 int size = 0;
a2a5291b 405 const char *word, *state;
09bee74d
TG
406 size_t len;
407
408 assert(ret);
09bee74d
TG
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
09bee74d
TG
433 *ret = addresses;
434 addresses = NULL;
435
a2ba62c7 436 return size;
09bee74d 437}
e1ea665e
EY
438
439void 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
fbf7dcb5
DW
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),
e1ea665e 453 (i < (size - 1)) ? " ": "");
fbf7dcb5 454 }
e1ea665e
EY
455
456 fputs("\n", f);
457}
458
459int 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;
a2a5291b 462 const char *word, *state;
e1ea665e
EY
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 */
69f08c83 472 _cleanup_free_ char* entry = NULL;
e1ea665e
EY
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);
31db0120
SS
481 if(!entry)
482 return -ENOMEM;
e1ea665e
EY
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}
a073309f
AC
527
528int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *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
544int deserialize_dhcp_option(uint8_t **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}