]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/network-internal.c
test-network: fix segfault with NULL dev_path/driver/type/name
[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"
28#include "libudev-private.h"
e1ea665e 29#include "dhcp-lease-internal.h"
be32eb9b 30#include "log.h"
5fde13d7 31#include "utf8.h"
a12fa420 32#include "util.h"
5fde13d7 33#include "conf-parser.h"
134e56dc 34#include "condition.h"
44e7b949 35#include "network-internal.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
ZJS
115 if (!strv_isempty(match_paths) &&
116 (!dev_path || !strv_fnmatch(dev_path, match_paths, 0)))
ee5de57b 117 return false;
5256e00e 118
d49dc812
ZJS
119 if (!strv_isempty(match_drivers) &&
120 (!dev_driver || !strv_fnmatch(dev_driver, match_drivers, 0)))
ee5de57b 121 return false;
5256e00e 122
d49dc812
ZJS
123 if (!strv_isempty(match_types) &&
124 (!dev_type || !strv_fnmatch_or_empty(dev_type, match_types, 0)))
ee5de57b 125 return false;
5256e00e 126
d49dc812
ZJS
127 if (!strv_isempty(match_names) &&
128 (!dev_name || !strv_fnmatch_or_empty(dev_name, match_names, 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
a2ba62c7 388int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
09bee74d 389 _cleanup_free_ struct in6_addr *addresses = NULL;
a2ba62c7 390 int size = 0;
a2a5291b 391 const char *word, *state;
09bee74d
TG
392 size_t len;
393
394 assert(ret);
09bee74d
TG
395 assert(string);
396
397 FOREACH_WORD(word, len, string, state) {
398 _cleanup_free_ char *addr_str = NULL;
399 struct in6_addr *new_addresses;
400 int r;
401
402 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
403 if (!new_addresses)
404 return -ENOMEM;
405 else
406 addresses = new_addresses;
407
408 addr_str = strndup(word, len);
409 if (!addr_str)
410 return -ENOMEM;
411
412 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
413 if (r <= 0)
414 continue;
415
416 size++;
417 }
418
09bee74d
TG
419 *ret = addresses;
420 addresses = NULL;
421
a2ba62c7 422 return size;
09bee74d 423}
e1ea665e
EY
424
425void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
426 unsigned i;
427
428 assert(f);
429 assert(key);
430 assert(routes);
431 assert(size);
432
433 fprintf(f, "%s=", key);
434
fbf7dcb5
DW
435 for (i = 0; i < size; i++) {
436 fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
437 routes[i].dst_prefixlen);
438 fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
e1ea665e 439 (i < (size - 1)) ? " ": "");
fbf7dcb5 440 }
e1ea665e
EY
441
442 fputs("\n", f);
443}
444
445int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
446 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
447 size_t size = 0, allocated = 0;
a2a5291b 448 const char *word, *state;
e1ea665e
EY
449 size_t len;
450
451 assert(ret);
452 assert(ret_size);
453 assert(ret_allocated);
454 assert(string);
455
456 FOREACH_WORD(word, len, string, state) {
457 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
69f08c83 458 _cleanup_free_ char* entry = NULL;
e1ea665e
EY
459 char *tok, *tok_end;
460 unsigned n;
461 int r;
462
463 if (!GREEDY_REALLOC(routes, allocated, size + 1))
464 return -ENOMEM;
465
466 entry = strndup(word, len);
31db0120
SS
467 if(!entry)
468 return -ENOMEM;
e1ea665e
EY
469
470 tok = entry;
471
472 /* get the subnet */
473 tok_end = strchr(tok, '/');
474 if (!tok_end)
475 continue;
476 *tok_end = '\0';
477
478 r = inet_aton(tok, &routes[size].dst_addr);
479 if (r == 0)
480 continue;
481
482 tok = tok_end + 1;
483
484 /* get the prefixlen */
485 tok_end = strchr(tok, ',');
486 if (!tok_end)
487 continue;
488
489 *tok_end = '\0';
490
491 r = safe_atou(tok, &n);
492 if (r < 0 || n > 32)
493 continue;
494
495 routes[size].dst_prefixlen = (uint8_t) n;
496 tok = tok_end + 1;
497
498 /* get the gateway */
499 r = inet_aton(tok, &routes[size].gw_addr);
500 if (r == 0)
501 continue;
502
503 size++;
504 }
505
506 *ret_size = size;
507 *ret_allocated = allocated;
508 *ret = routes;
509 routes = NULL;
510
511 return 0;
512}