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