]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
treewide: use log_*_errno whenever %m is in the format string
[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 "dhcp-lease-internal.h"
31 #include "log.h"
32 #include "utf8.h"
33 #include "util.h"
34 #include "conf-parser.h"
35 #include "condition.h"
36 #include "network-internal.h"
37
38 const char *net_get_name(struct udev_device *device) {
39 const char *name, *field;
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", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
45 name = udev_device_get_property_value(device, field);
46 if (name)
47 return name;
48 }
49
50 return NULL;
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
55 int 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);
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
85 bool 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,
90 Condition *match_host,
91 Condition *match_virt,
92 Condition *match_kernel,
93 Condition *match_arch,
94 const struct ether_addr *dev_mac,
95 const char *dev_path,
96 const char *dev_parent_driver,
97 const char *dev_driver,
98 const char *dev_type,
99 const char *dev_name) {
100
101 if (match_host && !condition_test(match_host))
102 return 0;
103
104 if (match_virt && !condition_test(match_virt))
105 return 0;
106
107 if (match_kernel && !condition_test(match_kernel))
108 return 0;
109
110 if (match_arch && !condition_test(match_arch))
111 return 0;
112
113 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
114 return 0;
115
116 if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
117 return 0;
118
119 if (match_driver) {
120 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
121 return 0;
122 else if (!streq_ptr(match_driver, dev_driver))
123 return 0;
124 }
125
126 if (match_type && !streq_ptr(match_type, dev_type))
127 return 0;
128
129 if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
130 return 0;
131
132 return 1;
133 }
134
135 int 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
176 int config_parse_ifname(const char *unit,
177 const char *filename,
178 unsigned line,
179 const char *section,
180 unsigned section_line,
181 const char *lvalue,
182 int ltype,
183 const char *rvalue,
184 void *data,
185 void *userdata) {
186
187 char **s = data;
188 _cleanup_free_ char *n = NULL;
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);
202 return 0;
203 }
204
205 free(*s);
206 if (*n) {
207 *s = n;
208 n = NULL;
209 } else
210 *s = NULL;
211
212 return 0;
213 }
214
215 int config_parse_ifalias(const char *unit,
216 const char *filename,
217 unsigned line,
218 const char *section,
219 unsigned section_line,
220 const char *lvalue,
221 int ltype,
222 const char *rvalue,
223 void *data,
224 void *userdata) {
225
226 char **s = data;
227 char *n;
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);
241 free(n);
242 return 0;
243 }
244
245 free(*s);
246 if (*n)
247 *s = n;
248 else {
249 free(n);
250 *s = NULL;
251 }
252
253 return 0;
254 }
255
256 int config_parse_hwaddr(const char *unit,
257 const char *filename,
258 unsigned line,
259 const char *section,
260 unsigned section_line,
261 const char *lvalue,
262 int ltype,
263 const char *rvalue,
264 void *data,
265 void *userdata) {
266 struct ether_addr **hwaddr = data;
267 struct ether_addr *n;
268 int r;
269
270 assert(filename);
271 assert(lvalue);
272 assert(rvalue);
273 assert(data);
274
275 n = new0(struct ether_addr, 1);
276 if (!n)
277 return log_oom();
278
279 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
280 &n->ether_addr_octet[0],
281 &n->ether_addr_octet[1],
282 &n->ether_addr_octet[2],
283 &n->ether_addr_octet[3],
284 &n->ether_addr_octet[4],
285 &n->ether_addr_octet[5]);
286 if (r != 6) {
287 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
288 "Not a valid MAC address, ignoring assignment: %s", rvalue);
289 free(n);
290 return 0;
291 }
292
293 free(*hwaddr);
294 *hwaddr = n;
295
296 return 0;
297 }
298
299 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
300 unsigned i;
301
302 assert(f);
303 assert(addresses);
304 assert(size);
305
306 for (i = 0; i < size; i++)
307 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
308 (i < (size - 1)) ? " ": "");
309 }
310
311 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
312 _cleanup_free_ struct in_addr *addresses = NULL;
313 int size = 0;
314 const char *word, *state;
315 size_t len;
316
317 assert(ret);
318 assert(string);
319
320 FOREACH_WORD(word, len, string, state) {
321 _cleanup_free_ char *addr_str = NULL;
322 struct in_addr *new_addresses;
323 int r;
324
325 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
326 if (!new_addresses)
327 return -ENOMEM;
328 else
329 addresses = new_addresses;
330
331 addr_str = strndup(word, len);
332 if (!addr_str)
333 return -ENOMEM;
334
335 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
336 if (r <= 0)
337 continue;
338
339 size ++;
340 }
341
342 *ret = addresses;
343 addresses = NULL;
344
345 return size;
346 }
347
348 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
349 _cleanup_free_ struct in6_addr *addresses = NULL;
350 int size = 0;
351 const char *word, *state;
352 size_t len;
353
354 assert(ret);
355 assert(string);
356
357 FOREACH_WORD(word, len, string, state) {
358 _cleanup_free_ char *addr_str = NULL;
359 struct in6_addr *new_addresses;
360 int r;
361
362 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
363 if (!new_addresses)
364 return -ENOMEM;
365 else
366 addresses = new_addresses;
367
368 addr_str = strndup(word, len);
369 if (!addr_str)
370 return -ENOMEM;
371
372 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
373 if (r <= 0)
374 continue;
375
376 size++;
377 }
378
379 *ret = addresses;
380 addresses = NULL;
381
382 return size;
383 }
384
385 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
386 unsigned i;
387
388 assert(f);
389 assert(key);
390 assert(routes);
391 assert(size);
392
393 fprintf(f, "%s=", key);
394
395 for (i = 0; i < size; i++)
396 fprintf(f, "%s/%" PRIu8 ",%s%s", inet_ntoa(routes[i].dst_addr),
397 routes[i].dst_prefixlen, inet_ntoa(routes[i].gw_addr),
398 (i < (size - 1)) ? " ": "");
399
400 fputs("\n", f);
401 }
402
403 int 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;
406 const char *word, *state;
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 */
416 _cleanup_free_ char* entry = NULL;
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);
425 if(!entry)
426 return -ENOMEM;
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 }