]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/network-internal.c
networkd: fdb - refactor a bit
[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>
f28964e3 25#include <fnmatch.h>
5fde13d7 26
b5db00e5
UTL
27#include "strv.h"
28#include "siphash24.h"
29#include "libudev-private.h"
e1ea665e 30#include "dhcp-lease-internal.h"
be32eb9b 31#include "log.h"
5fde13d7 32#include "utf8.h"
a12fa420 33#include "util.h"
5fde13d7 34#include "conf-parser.h"
134e56dc 35#include "condition.h"
44e7b949 36#include "network-internal.h"
5fde13d7 37
fc541430 38const char *net_get_name(struct udev_device *device) {
44e7b949 39 const char *name, *field;
fc541430
TG
40
41 assert(device);
b5db00e5
UTL
42
43 /* fetch some persistent data unique (on this machine) to this device */
44e7b949 44 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
b5db00e5
UTL
45 name = udev_device_get_property_value(device, field);
46 if (name)
44e7b949 47 return name;
b5db00e5
UTL
48 }
49
44e7b949 50 return NULL;
fc541430
TG
51}
52
53#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
54
55int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
56 size_t l, sz = 0;
57 const char *name = NULL;
58 int r;
59 uint8_t *v;
60
61 assert(device);
62
63 name = net_get_name(device);
b5db00e5
UTL
64 if (!name)
65 return -ENOENT;
66
67 l = strlen(name);
68 sz = sizeof(sd_id128_t) + l;
69 v = alloca(sz);
70
71 /* fetch some persistent data unique to this machine */
72 r = sd_id128_get_machine((sd_id128_t*) v);
73 if (r < 0)
74 return r;
75 memcpy(v + sizeof(sd_id128_t), name, l);
76
77 /* Let's hash the machine ID plus the device name. We
78 * use a fixed, but originally randomly created hash
79 * key here. */
80 siphash24(result, v, sz, HASH_KEY.bytes);
81
82 return 0;
83}
84
be32eb9b
TG
85bool net_match_config(const struct ether_addr *match_mac,
86 const char *match_path,
87 const char *match_driver,
88 const char *match_type,
89 const char *match_name,
2cc412b5
TG
90 Condition *match_host,
91 Condition *match_virt,
92 Condition *match_kernel,
edbb03e9 93 Condition *match_arch,
505f8da7 94 const struct ether_addr *dev_mac,
b3e01314 95 const char *dev_path,
bf175aaf 96 const char *dev_parent_driver,
b3e01314
TG
97 const char *dev_driver,
98 const char *dev_type,
32bc8adc 99 const char *dev_name) {
be32eb9b 100
a4705396 101 if (match_host && !condition_test(match_host))
7eb08da4 102 return false;
2cc412b5 103
a4705396 104 if (match_virt && !condition_test(match_virt))
7eb08da4 105 return false;
2cc412b5 106
a4705396 107 if (match_kernel && !condition_test(match_kernel))
7eb08da4 108 return false;
2cc412b5 109
a4705396 110 if (match_arch && !condition_test(match_arch))
7eb08da4 111 return false;
edbb03e9 112
505f8da7 113 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
7eb08da4 114 return false;
be32eb9b 115
f28964e3 116 if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
7eb08da4 117 return false;
be32eb9b 118
bf175aaf
TG
119 if (match_driver) {
120 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
7eb08da4 121 return false;
bf175aaf 122 else if (!streq_ptr(match_driver, dev_driver))
7eb08da4 123 return false;
bf175aaf 124 }
5fde13d7 125
d69b12ac 126 if (match_type && !streq_ptr(match_type, dev_type))
7eb08da4
TG
127 return false;
128
32bc8adc 129 if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
7eb08da4 130 return false;
5fde13d7 131
7eb08da4 132 return true;
be32eb9b 133}
5fde13d7 134
2cc412b5
TG
135int config_parse_net_condition(const char *unit,
136 const char *filename,
137 unsigned line,
138 const char *section,
139 unsigned section_line,
140 const char *lvalue,
141 int ltype,
142 const char *rvalue,
143 void *data,
144 void *userdata) {
145
146 ConditionType cond = ltype;
147 Condition **ret = data;
148 bool negate;
149 Condition *c;
150 _cleanup_free_ char *s = NULL;
151
152 assert(filename);
153 assert(lvalue);
154 assert(rvalue);
155 assert(data);
156
157 negate = rvalue[0] == '!';
158 if (negate)
159 rvalue++;
160
161 s = strdup(rvalue);
162 if (!s)
163 return log_oom();
164
165 c = condition_new(cond, s, false, negate);
166 if (!c)
167 return log_oom();
168
169 if (*ret)
170 condition_free(*ret);
171
172 *ret = c;
173 return 0;
174}
175
5fde13d7
TG
176int config_parse_ifname(const char *unit,
177 const char *filename,
178 unsigned line,
179 const char *section,
71a61510 180 unsigned section_line,
5fde13d7
TG
181 const char *lvalue,
182 int ltype,
183 const char *rvalue,
184 void *data,
185 void *userdata) {
186
187 char **s = data;
5a3f1989 188 _cleanup_free_ char *n = NULL;
5fde13d7
TG
189
190 assert(filename);
191 assert(lvalue);
192 assert(rvalue);
193 assert(data);
194
195 n = strdup(rvalue);
196 if (!n)
197 return log_oom();
198
199 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
200 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
201 "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
d2df0d0e
TG
215int config_parse_ifalias(const char *unit,
216 const char *filename,
217 unsigned line,
218 const char *section,
71a61510 219 unsigned section_line,
d2df0d0e
TG
220 const char *lvalue,
221 int ltype,
222 const char *rvalue,
223 void *data,
224 void *userdata) {
225
226 char **s = data;
9c39eb5c 227 _cleanup_free_ char *n = NULL;
d2df0d0e
TG
228
229 assert(filename);
230 assert(lvalue);
231 assert(rvalue);
232 assert(data);
233
234 n = strdup(rvalue);
235 if (!n)
236 return log_oom();
237
238 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
239 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
240 "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
d2df0d0e
TG
241 return 0;
242 }
243
244 free(*s);
9c39eb5c 245 if (*n) {
d2df0d0e 246 *s = n;
9c39eb5c
TG
247 n = NULL;
248 } else
d2df0d0e 249 *s = NULL;
d2df0d0e
TG
250
251 return 0;
252}
253
5fde13d7
TG
254int config_parse_hwaddr(const char *unit,
255 const char *filename,
256 unsigned line,
257 const char *section,
71a61510 258 unsigned section_line,
5fde13d7
TG
259 const char *lvalue,
260 int ltype,
261 const char *rvalue,
262 void *data,
263 void *userdata) {
264 struct ether_addr **hwaddr = data;
265 struct ether_addr *n;
266 int r;
267
268 assert(filename);
269 assert(lvalue);
270 assert(rvalue);
271 assert(data);
272
a12fa420 273 n = new0(struct ether_addr, 1);
5fde13d7
TG
274 if (!n)
275 return log_oom();
276
277 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
278 &n->ether_addr_octet[0],
279 &n->ether_addr_octet[1],
280 &n->ether_addr_octet[2],
281 &n->ether_addr_octet[3],
282 &n->ether_addr_octet[4],
283 &n->ether_addr_octet[5]);
284 if (r != 6) {
285 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
286 "Not a valid MAC address, ignoring assignment: %s", rvalue);
287 free(n);
288 return 0;
289 }
290
291 free(*hwaddr);
292 *hwaddr = n;
293
294 return 0;
295}
f5284182 296
b0e39c82 297void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
09bee74d
TG
298 unsigned i;
299
300 assert(f);
09bee74d
TG
301 assert(addresses);
302 assert(size);
303
09bee74d
TG
304 for (i = 0; i < size; i++)
305 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
306 (i < (size - 1)) ? " ": "");
09bee74d
TG
307}
308
a2ba62c7 309int deserialize_in_addrs(struct in_addr **ret, const char *string) {
09bee74d 310 _cleanup_free_ struct in_addr *addresses = NULL;
a2ba62c7 311 int size = 0;
a2a5291b 312 const char *word, *state;
09bee74d
TG
313 size_t len;
314
315 assert(ret);
09bee74d
TG
316 assert(string);
317
318 FOREACH_WORD(word, len, string, state) {
319 _cleanup_free_ char *addr_str = NULL;
320 struct in_addr *new_addresses;
321 int r;
322
323 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
324 if (!new_addresses)
325 return -ENOMEM;
326 else
327 addresses = new_addresses;
328
329 addr_str = strndup(word, len);
330 if (!addr_str)
331 return -ENOMEM;
332
333 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
334 if (r <= 0)
335 continue;
336
337 size ++;
338 }
339
09bee74d
TG
340 *ret = addresses;
341 addresses = NULL;
342
a2ba62c7 343 return size;
09bee74d
TG
344}
345
a2ba62c7 346int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
09bee74d 347 _cleanup_free_ struct in6_addr *addresses = NULL;
a2ba62c7 348 int size = 0;
a2a5291b 349 const char *word, *state;
09bee74d
TG
350 size_t len;
351
352 assert(ret);
09bee74d
TG
353 assert(string);
354
355 FOREACH_WORD(word, len, string, state) {
356 _cleanup_free_ char *addr_str = NULL;
357 struct in6_addr *new_addresses;
358 int r;
359
360 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
361 if (!new_addresses)
362 return -ENOMEM;
363 else
364 addresses = new_addresses;
365
366 addr_str = strndup(word, len);
367 if (!addr_str)
368 return -ENOMEM;
369
370 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
371 if (r <= 0)
372 continue;
373
374 size++;
375 }
376
09bee74d
TG
377 *ret = addresses;
378 addresses = NULL;
379
a2ba62c7 380 return size;
09bee74d 381}
e1ea665e
EY
382
383void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
384 unsigned i;
385
386 assert(f);
387 assert(key);
388 assert(routes);
389 assert(size);
390
391 fprintf(f, "%s=", key);
392
fbf7dcb5
DW
393 for (i = 0; i < size; i++) {
394 fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
395 routes[i].dst_prefixlen);
396 fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
e1ea665e 397 (i < (size - 1)) ? " ": "");
fbf7dcb5 398 }
e1ea665e
EY
399
400 fputs("\n", f);
401}
402
403int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
404 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
405 size_t size = 0, allocated = 0;
a2a5291b 406 const char *word, *state;
e1ea665e
EY
407 size_t len;
408
409 assert(ret);
410 assert(ret_size);
411 assert(ret_allocated);
412 assert(string);
413
414 FOREACH_WORD(word, len, string, state) {
415 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
69f08c83 416 _cleanup_free_ char* entry = NULL;
e1ea665e
EY
417 char *tok, *tok_end;
418 unsigned n;
419 int r;
420
421 if (!GREEDY_REALLOC(routes, allocated, size + 1))
422 return -ENOMEM;
423
424 entry = strndup(word, len);
31db0120
SS
425 if(!entry)
426 return -ENOMEM;
e1ea665e
EY
427
428 tok = entry;
429
430 /* get the subnet */
431 tok_end = strchr(tok, '/');
432 if (!tok_end)
433 continue;
434 *tok_end = '\0';
435
436 r = inet_aton(tok, &routes[size].dst_addr);
437 if (r == 0)
438 continue;
439
440 tok = tok_end + 1;
441
442 /* get the prefixlen */
443 tok_end = strchr(tok, ',');
444 if (!tok_end)
445 continue;
446
447 *tok_end = '\0';
448
449 r = safe_atou(tok, &n);
450 if (r < 0 || n > 32)
451 continue;
452
453 routes[size].dst_prefixlen = (uint8_t) n;
454 tok = tok_end + 1;
455
456 /* get the gateway */
457 r = inet_aton(tok, &routes[size].gw_addr);
458 if (r == 0)
459 continue;
460
461 size++;
462 }
463
464 *ret_size = size;
465 *ret_allocated = allocated;
466 *ret = routes;
467 routes = NULL;
468
469 return 0;
470}