]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
sd-network: remove redundant array size parameter from functions that return arrays
[thirdparty/systemd.git] / src / libsystemd-network / network-internal.c
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>
23 #include <linux/if.h>
24 #include <arpa/inet.h>
25 #include <fnmatch.h>
26
27 #include "strv.h"
28 #include "siphash24.h"
29 #include "libudev-private.h"
30 #include "network-internal.h"
31 #include "dhcp-lease-internal.h"
32 #include "log.h"
33 #include "utf8.h"
34 #include "util.h"
35 #include "conf-parser.h"
36 #include "condition.h"
37
38 const char *net_get_name(struct udev_device *device) {
39 const char *name = NULL, *field = NULL;
40
41 assert(device);
42
43 /* fetch some persistent data unique (on this machine) to this device */
44 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT",
45 "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
46 name = udev_device_get_property_value(device, field);
47 if (name)
48 break;
49 }
50
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
56 int 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);
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
86 bool 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,
91 Condition *match_host,
92 Condition *match_virt,
93 Condition *match_kernel,
94 Condition *match_arch,
95 const struct ether_addr *dev_mac,
96 const char *dev_path,
97 const char *dev_parent_driver,
98 const char *dev_driver,
99 const char *dev_type,
100 const char *dev_name) {
101
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
111 if (match_arch && !condition_test_architecture(match_arch))
112 return 0;
113
114 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
115 return 0;
116
117 if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
118 return 0;
119
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 }
126
127 if (match_type && !streq_ptr(match_type, dev_type))
128 return 0;
129
130 if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
131 return 0;
132
133 return 1;
134 }
135
136 unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
137 assert(addr);
138
139 return 32 - u32ctz(be32toh(addr->s_addr));
140 }
141
142 int 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
183 int config_parse_ifname(const char *unit,
184 const char *filename,
185 unsigned line,
186 const char *section,
187 unsigned section_line,
188 const char *lvalue,
189 int ltype,
190 const char *rvalue,
191 void *data,
192 void *userdata) {
193
194 char **s = data;
195 _cleanup_free_ char *n = NULL;
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);
214 if (*n) {
215 *s = n;
216 n = NULL;
217 } else
218 *s = NULL;
219
220 return 0;
221 }
222
223 int config_parse_ifalias(const char *unit,
224 const char *filename,
225 unsigned line,
226 const char *section,
227 unsigned section_line,
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
264 int config_parse_hwaddr(const char *unit,
265 const char *filename,
266 unsigned line,
267 const char *section,
268 unsigned section_line,
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
283 n = new0(struct ether_addr, 1);
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 }
306
307 int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
308 int r;
309
310 assert(address);
311 assert(family);
312 assert(dst);
313
314 /* IPv4 */
315 r = inet_pton(AF_INET, address, dst);
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)
323 return -errno;
324 else {
325 /* not an IPv4 address, so let's try IPv6 */
326 r = inet_pton(AF_INET6, address, dst);
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)
334 return -errno;
335 else
336 return -EINVAL;
337 }
338
339 return 0;
340 }
341
342 void serialize_in_addrs(FILE *f, const char *key, const struct in_addr *addresses, size_t size) {
343 unsigned i;
344
345 assert(f);
346 assert(key);
347 assert(addresses);
348 assert(size);
349
350 fprintf(f, "%s=", key);
351
352 for (i = 0; i < size; i++)
353 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
354 (i < (size - 1)) ? " ": "");
355
356 fputs("\n", f);
357 }
358
359 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
360 _cleanup_free_ struct in_addr *addresses = NULL;
361 int size = 0;
362 char *word, *state;
363 size_t len;
364
365 assert(ret);
366 assert(string);
367
368 FOREACH_WORD(word, len, string, state) {
369 _cleanup_free_ char *addr_str = NULL;
370 struct in_addr *new_addresses;
371 int r;
372
373 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
374 if (!new_addresses)
375 return -ENOMEM;
376 else
377 addresses = new_addresses;
378
379 addr_str = strndup(word, len);
380 if (!addr_str)
381 return -ENOMEM;
382
383 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
384 if (r <= 0)
385 continue;
386
387 size ++;
388 }
389
390 *ret = addresses;
391 addresses = NULL;
392
393 return size;
394 }
395
396 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
397 _cleanup_free_ struct in6_addr *addresses = NULL;
398 int size = 0;
399 char *word, *state;
400 size_t len;
401
402 assert(ret);
403 assert(string);
404
405 FOREACH_WORD(word, len, string, state) {
406 _cleanup_free_ char *addr_str = NULL;
407 struct in6_addr *new_addresses;
408 int r;
409
410 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
411 if (!new_addresses)
412 return -ENOMEM;
413 else
414 addresses = new_addresses;
415
416 addr_str = strndup(word, len);
417 if (!addr_str)
418 return -ENOMEM;
419
420 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
421 if (r <= 0)
422 continue;
423
424 size++;
425 }
426
427 *ret = addresses;
428 addresses = NULL;
429
430 return size;
431 }
432
433 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
434 unsigned i;
435
436 assert(f);
437 assert(key);
438 assert(routes);
439 assert(size);
440
441 fprintf(f, "%s=", key);
442
443 for (i = 0; i < size; i++)
444 fprintf(f, "%s/%" PRIu8 ",%s%s", inet_ntoa(routes[i].dst_addr),
445 routes[i].dst_prefixlen, inet_ntoa(routes[i].gw_addr),
446 (i < (size - 1)) ? " ": "");
447
448 fputs("\n", f);
449 }
450
451 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
452 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
453 size_t size = 0, allocated = 0;
454 char *word, *state;
455 size_t len;
456
457 assert(ret);
458 assert(ret_size);
459 assert(ret_allocated);
460 assert(string);
461
462 FOREACH_WORD(word, len, string, state) {
463 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
464 _cleanup_free_ char* entry = NULL;
465 char *tok, *tok_end;
466 unsigned n;
467 int r;
468
469 if (!GREEDY_REALLOC(routes, allocated, size + 1))
470 return -ENOMEM;
471
472 entry = strndup(word, len);
473 if(!entry)
474 return -ENOMEM;
475
476 tok = entry;
477
478 /* get the subnet */
479 tok_end = strchr(tok, '/');
480 if (!tok_end)
481 continue;
482 *tok_end = '\0';
483
484 r = inet_aton(tok, &routes[size].dst_addr);
485 if (r == 0)
486 continue;
487
488 tok = tok_end + 1;
489
490 /* get the prefixlen */
491 tok_end = strchr(tok, ',');
492 if (!tok_end)
493 continue;
494
495 *tok_end = '\0';
496
497 r = safe_atou(tok, &n);
498 if (r < 0 || n > 32)
499 continue;
500
501 routes[size].dst_prefixlen = (uint8_t) n;
502 tok = tok_end + 1;
503
504 /* get the gateway */
505 r = inet_aton(tok, &routes[size].gw_addr);
506 if (r == 0)
507 continue;
508
509 size++;
510 }
511
512 *ret_size = size;
513 *ret_allocated = allocated;
514 *ret = routes;
515 routes = NULL;
516
517 return 0;
518 }