]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
hostname-util: ignore case when checking if hostname is localhost
[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
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 const char *net_get_name(struct udev_device *device) {
37 const char *name, *field;
38
39 assert(device);
40
41 /* fetch some persistent data unique (on this machine) to this device */
42 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
43 name = udev_device_get_property_value(device, field);
44 if (name)
45 return name;
46 }
47
48 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 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
54 size_t l, sz = 0;
55 const char *name = NULL;
56 int r;
57 uint8_t *v;
58
59 assert(device);
60
61 name = net_get_name(device);
62 if (!name)
63 return -ENOENT;
64
65 l = strlen(name);
66 sz = sizeof(sd_id128_t) + l;
67 v = alloca(sz);
68
69 /* fetch some persistent data unique to this machine */
70 r = sd_id128_get_machine((sd_id128_t*) v);
71 if (r < 0)
72 return r;
73 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 siphash24(result, v, sz, HASH_KEY.bytes);
79
80 return 0;
81 }
82
83 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 if (match_host && !condition_test(match_host))
100 return false;
101
102 if (match_virt && !condition_test(match_virt))
103 return false;
104
105 if (match_kernel && !condition_test(match_kernel))
106 return false;
107
108 if (match_arch && !condition_test(match_arch))
109 return false;
110
111 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
112 return false;
113
114 if (!strv_isempty(match_paths) &&
115 (!dev_path || !strv_fnmatch(match_paths, dev_path, 0)))
116 return false;
117
118 if (!strv_isempty(match_drivers) &&
119 (!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0)))
120 return false;
121
122 if (!strv_isempty(match_types) &&
123 (!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0)))
124 return false;
125
126 if (!strv_isempty(match_names) &&
127 (!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0)))
128 return false;
129
130 return true;
131 }
132
133 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 ConditionType cond = ltype;
145 Condition **ret = data;
146 bool negate;
147 Condition *c;
148 _cleanup_free_ char *s = NULL;
149
150 assert(filename);
151 assert(lvalue);
152 assert(rvalue);
153 assert(data);
154
155 negate = rvalue[0] == '!';
156 if (negate)
157 rvalue++;
158
159 s = strdup(rvalue);
160 if (!s)
161 return log_oom();
162
163 c = condition_new(cond, s, false, negate);
164 if (!c)
165 return log_oom();
166
167 if (*ret)
168 condition_free(*ret);
169
170 *ret = c;
171 return 0;
172 }
173
174 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 char **s = data;
186 _cleanup_free_ char *n = NULL;
187
188 assert(filename);
189 assert(lvalue);
190 assert(rvalue);
191 assert(data);
192
193 n = strdup(rvalue);
194 if (!n)
195 return log_oom();
196
197 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
198 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
199 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
200 return 0;
201 }
202
203 free(*s);
204 if (*n) {
205 *s = n;
206 n = NULL;
207 } else
208 *s = NULL;
209
210 return 0;
211 }
212
213 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 char ***sv = data;
225 const char *word, *state;
226 size_t l;
227 int r;
228
229 assert(filename);
230 assert(lvalue);
231 assert(rvalue);
232 assert(data);
233
234 FOREACH_WORD(word, l, rvalue, state) {
235 char *n;
236
237 n = strndup(word, l);
238 if (!n)
239 return log_oom();
240
241 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
242 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
243 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
244 free(n);
245 return 0;
246 }
247
248 r = strv_consume(sv, n);
249 if (r < 0)
250 return log_oom();
251 }
252
253 return 0;
254 }
255
256 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 char **s = data;
268 _cleanup_free_ char *n = NULL;
269
270 assert(filename);
271 assert(lvalue);
272 assert(rvalue);
273 assert(data);
274
275 n = strdup(rvalue);
276 if (!n)
277 return log_oom();
278
279 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
280 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
281 "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
282 return 0;
283 }
284
285 free(*s);
286 if (*n) {
287 *s = n;
288 n = NULL;
289 } else
290 *s = NULL;
291
292 return 0;
293 }
294
295 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 struct ether_addr **hwaddr = data;
306 struct ether_addr *n;
307 int r;
308
309 assert(filename);
310 assert(lvalue);
311 assert(rvalue);
312 assert(data);
313
314 n = new0(struct ether_addr, 1);
315 if (!n)
316 return log_oom();
317
318 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 if (r != 6) {
326 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
327 "Not a valid MAC address, ignoring assignment: %s", rvalue);
328 free(n);
329 return 0;
330 }
331
332 free(*hwaddr);
333 *hwaddr = n;
334
335 return 0;
336 }
337
338 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
339 unsigned i;
340
341 assert(f);
342 assert(addresses);
343 assert(size);
344
345 for (i = 0; i < size; i++)
346 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
347 (i < (size - 1)) ? " ": "");
348 }
349
350 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
351 _cleanup_free_ struct in_addr *addresses = NULL;
352 int size = 0;
353 const char *word, *state;
354 size_t len;
355
356 assert(ret);
357 assert(string);
358
359 FOREACH_WORD(word, len, string, state) {
360 _cleanup_free_ char *addr_str = NULL;
361 struct in_addr *new_addresses;
362 int r;
363
364 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
365 if (!new_addresses)
366 return -ENOMEM;
367 else
368 addresses = new_addresses;
369
370 addr_str = strndup(word, len);
371 if (!addr_str)
372 return -ENOMEM;
373
374 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
375 if (r <= 0)
376 continue;
377
378 size ++;
379 }
380
381 *ret = addresses;
382 addresses = NULL;
383
384 return size;
385 }
386
387 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
388 _cleanup_free_ struct in6_addr *addresses = NULL;
389 int size = 0;
390 const char *word, *state;
391 size_t len;
392
393 assert(ret);
394 assert(string);
395
396 FOREACH_WORD(word, len, string, state) {
397 _cleanup_free_ char *addr_str = NULL;
398 struct in6_addr *new_addresses;
399 int r;
400
401 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
402 if (!new_addresses)
403 return -ENOMEM;
404 else
405 addresses = new_addresses;
406
407 addr_str = strndup(word, len);
408 if (!addr_str)
409 return -ENOMEM;
410
411 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
412 if (r <= 0)
413 continue;
414
415 size++;
416 }
417
418 *ret = addresses;
419 addresses = NULL;
420
421 return size;
422 }
423
424 void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) {
425 unsigned i;
426
427 assert(f);
428 assert(key);
429 assert(routes);
430 assert(size);
431
432 fprintf(f, "%s=", key);
433
434 for (i = 0; i < size; i++) {
435 fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
436 routes[i].dst_prefixlen);
437 fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
438 (i < (size - 1)) ? " ": "");
439 }
440
441 fputs("\n", f);
442 }
443
444 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
445 _cleanup_free_ struct sd_dhcp_route *routes = NULL;
446 size_t size = 0, allocated = 0;
447 const char *word, *state;
448 size_t len;
449
450 assert(ret);
451 assert(ret_size);
452 assert(ret_allocated);
453 assert(string);
454
455 FOREACH_WORD(word, len, string, state) {
456 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
457 _cleanup_free_ char* entry = NULL;
458 char *tok, *tok_end;
459 unsigned n;
460 int r;
461
462 if (!GREEDY_REALLOC(routes, allocated, size + 1))
463 return -ENOMEM;
464
465 entry = strndup(word, len);
466 if(!entry)
467 return -ENOMEM;
468
469 tok = entry;
470
471 /* get the subnet */
472 tok_end = strchr(tok, '/');
473 if (!tok_end)
474 continue;
475 *tok_end = '\0';
476
477 r = inet_aton(tok, &routes[size].dst_addr);
478 if (r == 0)
479 continue;
480
481 tok = tok_end + 1;
482
483 /* get the prefixlen */
484 tok_end = strchr(tok, ',');
485 if (!tok_end)
486 continue;
487
488 *tok_end = '\0';
489
490 r = safe_atou(tok, &n);
491 if (r < 0 || n > 32)
492 continue;
493
494 routes[size].dst_prefixlen = (uint8_t) n;
495 tok = tok_end + 1;
496
497 /* get the gateway */
498 r = inet_aton(tok, &routes[size].gw_addr);
499 if (r == 0)
500 continue;
501
502 size++;
503 }
504
505 *ret_size = size;
506 *ret_allocated = allocated;
507 *ret = routes;
508 routes = NULL;
509
510 return 0;
511 }