]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/network-internal.c
test-strv: add test which shows access to random memory
[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"
c6f7c917 30#include "network-internal.h"
e1ea665e 31#include "dhcp-lease-internal.h"
be32eb9b 32#include "log.h"
5fde13d7 33#include "utf8.h"
a12fa420 34#include "util.h"
5fde13d7 35#include "conf-parser.h"
2cc412b5 36#include "condition.h"
5fde13d7 37
fc541430 38const char *net_get_name(struct udev_device *device) {
9f2a50a3 39 const char *name = NULL, *field = NULL;
fc541430
TG
40
41 assert(device);
b5db00e5
UTL
42
43 /* fetch some persistent data unique (on this machine) to this device */
fc541430
TG
44 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT",
45 "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
b5db00e5
UTL
46 name = udev_device_get_property_value(device, field);
47 if (name)
48 break;
49 }
50
fc541430
TG
51 return name;
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
TG
86bool net_match_config(const struct ether_addr *match_mac,
87 const char *match_path,
88 const char *match_driver,
89 const char *match_type,
90 const char *match_name,
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,
100 const char *dev_name) {
be32eb9b 101
2cc412b5
TG
102 if (match_host && !condition_test_host(match_host))
103 return 0;
104
105 if (match_virt && !condition_test_virtualization(match_virt))
106 return 0;
107
108 if (match_kernel && !condition_test_kernel_command_line(match_kernel))
109 return 0;
110
edbb03e9
TG
111 if (match_arch && !condition_test_architecture(match_arch))
112 return 0;
113
505f8da7 114 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
449f7554 115 return 0;
be32eb9b 116
f28964e3 117 if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
449f7554 118 return 0;
be32eb9b 119
bf175aaf
TG
120 if (match_driver) {
121 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
122 return 0;
123 else if (!streq_ptr(match_driver, dev_driver))
124 return 0;
125 }
5fde13d7 126
d69b12ac 127 if (match_type && !streq_ptr(match_type, dev_type))
449f7554 128 return 0;
5fde13d7 129
bf175aaf 130 if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
449f7554 131 return 0;
5fde13d7 132
be32eb9b
TG
133 return 1;
134}
5fde13d7 135
377a218f 136unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
377a218f
TG
137 assert(addr);
138
ba914311 139 return 32 - u32ctz(be32toh(addr->s_addr));
377a218f
TG
140}
141
2cc412b5
TG
142int config_parse_net_condition(const char *unit,
143 const char *filename,
144 unsigned line,
145 const char *section,
146 unsigned section_line,
147 const char *lvalue,
148 int ltype,
149 const char *rvalue,
150 void *data,
151 void *userdata) {
152
153 ConditionType cond = ltype;
154 Condition **ret = data;
155 bool negate;
156 Condition *c;
157 _cleanup_free_ char *s = NULL;
158
159 assert(filename);
160 assert(lvalue);
161 assert(rvalue);
162 assert(data);
163
164 negate = rvalue[0] == '!';
165 if (negate)
166 rvalue++;
167
168 s = strdup(rvalue);
169 if (!s)
170 return log_oom();
171
172 c = condition_new(cond, s, false, negate);
173 if (!c)
174 return log_oom();
175
176 if (*ret)
177 condition_free(*ret);
178
179 *ret = c;
180 return 0;
181}
182
5fde13d7
TG
183int config_parse_ifname(const char *unit,
184 const char *filename,
185 unsigned line,
186 const char *section,
71a61510 187 unsigned section_line,
5fde13d7
TG
188 const char *lvalue,
189 int ltype,
190 const char *rvalue,
191 void *data,
192 void *userdata) {
193
194 char **s = data;
5a3f1989 195 _cleanup_free_ char *n = NULL;
5fde13d7
TG
196
197 assert(filename);
198 assert(lvalue);
199 assert(rvalue);
200 assert(data);
201
202 n = strdup(rvalue);
203 if (!n)
204 return log_oom();
205
206 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
207 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
208 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
209 free(n);
210 return 0;
211 }
212
213 free(*s);
5a3f1989 214 if (*n) {
5fde13d7 215 *s = n;
5a3f1989
TG
216 n = NULL;
217 } else
5fde13d7 218 *s = NULL;
5fde13d7
TG
219
220 return 0;
221}
222
d2df0d0e
TG
223int config_parse_ifalias(const char *unit,
224 const char *filename,
225 unsigned line,
226 const char *section,
71a61510 227 unsigned section_line,
d2df0d0e
TG
228 const char *lvalue,
229 int ltype,
230 const char *rvalue,
231 void *data,
232 void *userdata) {
233
234 char **s = data;
235 char *n;
236
237 assert(filename);
238 assert(lvalue);
239 assert(rvalue);
240 assert(data);
241
242 n = strdup(rvalue);
243 if (!n)
244 return log_oom();
245
246 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
247 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
248 "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
249 free(n);
250 return 0;
251 }
252
253 free(*s);
254 if (*n)
255 *s = n;
256 else {
257 free(n);
258 *s = NULL;
259 }
260
261 return 0;
262}
263
5fde13d7
TG
264int config_parse_hwaddr(const char *unit,
265 const char *filename,
266 unsigned line,
267 const char *section,
71a61510 268 unsigned section_line,
5fde13d7
TG
269 const char *lvalue,
270 int ltype,
271 const char *rvalue,
272 void *data,
273 void *userdata) {
274 struct ether_addr **hwaddr = data;
275 struct ether_addr *n;
276 int r;
277
278 assert(filename);
279 assert(lvalue);
280 assert(rvalue);
281 assert(data);
282
a12fa420 283 n = new0(struct ether_addr, 1);
5fde13d7
TG
284 if (!n)
285 return log_oom();
286
287 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
288 &n->ether_addr_octet[0],
289 &n->ether_addr_octet[1],
290 &n->ether_addr_octet[2],
291 &n->ether_addr_octet[3],
292 &n->ether_addr_octet[4],
293 &n->ether_addr_octet[5]);
294 if (r != 6) {
295 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
296 "Not a valid MAC address, ignoring assignment: %s", rvalue);
297 free(n);
298 return 0;
299 }
300
301 free(*hwaddr);
302 *hwaddr = n;
303
304 return 0;
305}
f5284182 306
0dd25fb9 307int net_parse_inaddr(const char *address, int *family, void *dst) {
f5284182
TG
308 int r;
309
310 assert(address);
311 assert(family);
312 assert(dst);
313
314 /* IPv4 */
315 r = inet_pton(AF_INET, address, dst);
801bd9e8
TG
316 if (r > 0) {
317 /* succsefully parsed IPv4 address */
318 if (*family == AF_UNSPEC)
319 *family = AF_INET;
320 else if (*family != AF_INET)
321 return -EINVAL;
322 } else if (r < 0)
f5284182
TG
323 return -errno;
324 else {
325 /* not an IPv4 address, so let's try IPv6 */
326 r = inet_pton(AF_INET6, address, dst);
801bd9e8
TG
327 if (r > 0) {
328 /* successfully parsed IPv6 address */
329 if (*family == AF_UNSPEC)
330 *family = AF_INET6;
331 else if (*family != AF_INET6)
332 return -EINVAL;
333 } else if (r < 0)
f5284182
TG
334 return -errno;
335 else
336 return -EINVAL;
337 }
338
339 return 0;
340}
7951dea2 341
b0e39c82 342void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
09bee74d
TG
343 unsigned i;
344
345 assert(f);
09bee74d
TG
346 assert(addresses);
347 assert(size);
348
09bee74d
TG
349 for (i = 0; i < size; i++)
350 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
351 (i < (size - 1)) ? " ": "");
09bee74d
TG
352}
353
a2ba62c7 354int deserialize_in_addrs(struct in_addr **ret, const char *string) {
09bee74d 355 _cleanup_free_ struct in_addr *addresses = NULL;
a2ba62c7 356 int size = 0;
09bee74d
TG
357 char *word, *state;
358 size_t len;
359
360 assert(ret);
09bee74d
TG
361 assert(string);
362
363 FOREACH_WORD(word, len, string, state) {
364 _cleanup_free_ char *addr_str = NULL;
365 struct in_addr *new_addresses;
366 int r;
367
368 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
369 if (!new_addresses)
370 return -ENOMEM;
371 else
372 addresses = new_addresses;
373
374 addr_str = strndup(word, len);
375 if (!addr_str)
376 return -ENOMEM;
377
378 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
379 if (r <= 0)
380 continue;
381
382 size ++;
383 }
384
09bee74d
TG
385 *ret = addresses;
386 addresses = NULL;
387
a2ba62c7 388 return size;
09bee74d
TG
389}
390
a2ba62c7 391int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
09bee74d 392 _cleanup_free_ struct in6_addr *addresses = NULL;
a2ba62c7 393 int size = 0;
09bee74d
TG
394 char *word, *state;
395 size_t len;
396
397 assert(ret);
09bee74d
TG
398 assert(string);
399
400 FOREACH_WORD(word, len, string, state) {
401 _cleanup_free_ char *addr_str = NULL;
402 struct in6_addr *new_addresses;
403 int r;
404
405 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
406 if (!new_addresses)
407 return -ENOMEM;
408 else
409 addresses = new_addresses;
410
411 addr_str = strndup(word, len);
412 if (!addr_str)
413 return -ENOMEM;
414
415 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
416 if (r <= 0)
417 continue;
418
419 size++;
420 }
421
09bee74d
TG
422 *ret = addresses;
423 addresses = NULL;
424
a2ba62c7 425 return size;
09bee74d 426}
e1ea665e
EY
427
428void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
429 unsigned i;
430
431 assert(f);
432 assert(key);
433 assert(routes);
434 assert(size);
435
436 fprintf(f, "%s=", key);
437
438 for (i = 0; i < size; i++)
439 fprintf(f, "%s/%" PRIu8 ",%s%s", inet_ntoa(routes[i].dst_addr),
440 routes[i].dst_prefixlen, inet_ntoa(routes[i].gw_addr),
441 (i < (size - 1)) ? " ": "");
442
443 fputs("\n", f);
444}
445
446int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
447 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
448 size_t size = 0, allocated = 0;
449 char *word, *state;
450 size_t len;
451
452 assert(ret);
453 assert(ret_size);
454 assert(ret_allocated);
455 assert(string);
456
457 FOREACH_WORD(word, len, string, state) {
458 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
69f08c83 459 _cleanup_free_ char* entry = NULL;
e1ea665e
EY
460 char *tok, *tok_end;
461 unsigned n;
462 int r;
463
464 if (!GREEDY_REALLOC(routes, allocated, size + 1))
465 return -ENOMEM;
466
467 entry = strndup(word, len);
31db0120
SS
468 if(!entry)
469 return -ENOMEM;
e1ea665e
EY
470
471 tok = entry;
472
473 /* get the subnet */
474 tok_end = strchr(tok, '/');
475 if (!tok_end)
476 continue;
477 *tok_end = '\0';
478
479 r = inet_aton(tok, &routes[size].dst_addr);
480 if (r == 0)
481 continue;
482
483 tok = tok_end + 1;
484
485 /* get the prefixlen */
486 tok_end = strchr(tok, ',');
487 if (!tok_end)
488 continue;
489
490 *tok_end = '\0';
491
492 r = safe_atou(tok, &n);
493 if (r < 0 || n > 32)
494 continue;
495
496 routes[size].dst_prefixlen = (uint8_t) n;
497 tok = tok_end + 1;
498
499 /* get the gateway */
500 r = inet_aton(tok, &routes[size].gw_addr);
501 if (r == 0)
502 continue;
503
504 size++;
505 }
506
507 *ret_size = size;
508 *ret_allocated = allocated;
509 *ret = routes;
510 routes = NULL;
511
512 return 0;
513}