]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/network-internal.c
sd-dhcp6-client: Initialize DUID
[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"
be32eb9b 31#include "log.h"
5fde13d7 32#include "utf8.h"
a12fa420 33#include "util.h"
5fde13d7 34#include "conf-parser.h"
2cc412b5 35#include "condition.h"
5fde13d7 36
b5db00e5
UTL
37#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
38
39int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
40 size_t l, sz = 0;
9f2a50a3 41 const char *name = NULL, *field = NULL;
b5db00e5
UTL
42 int r;
43 uint8_t *v;
44
45 /* fetch some persistent data unique (on this machine) to this device */
46 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
47 name = udev_device_get_property_value(device, field);
48 if (name)
49 break;
50 }
51
52 if (!name)
53 return -ENOENT;
54
55 l = strlen(name);
56 sz = sizeof(sd_id128_t) + l;
57 v = alloca(sz);
58
59 /* fetch some persistent data unique to this machine */
60 r = sd_id128_get_machine((sd_id128_t*) v);
61 if (r < 0)
62 return r;
63 memcpy(v + sizeof(sd_id128_t), name, l);
64
65 /* Let's hash the machine ID plus the device name. We
66 * use a fixed, but originally randomly created hash
67 * key here. */
68 siphash24(result, v, sz, HASH_KEY.bytes);
69
70 return 0;
71}
72
be32eb9b
TG
73bool net_match_config(const struct ether_addr *match_mac,
74 const char *match_path,
75 const char *match_driver,
76 const char *match_type,
77 const char *match_name,
2cc412b5
TG
78 Condition *match_host,
79 Condition *match_virt,
80 Condition *match_kernel,
edbb03e9 81 Condition *match_arch,
505f8da7 82 const struct ether_addr *dev_mac,
b3e01314 83 const char *dev_path,
bf175aaf 84 const char *dev_parent_driver,
b3e01314
TG
85 const char *dev_driver,
86 const char *dev_type,
87 const char *dev_name) {
be32eb9b 88
2cc412b5
TG
89 if (match_host && !condition_test_host(match_host))
90 return 0;
91
92 if (match_virt && !condition_test_virtualization(match_virt))
93 return 0;
94
95 if (match_kernel && !condition_test_kernel_command_line(match_kernel))
96 return 0;
97
edbb03e9
TG
98 if (match_arch && !condition_test_architecture(match_arch))
99 return 0;
100
505f8da7 101 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
449f7554 102 return 0;
be32eb9b 103
f28964e3 104 if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
449f7554 105 return 0;
be32eb9b 106
bf175aaf
TG
107 if (match_driver) {
108 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
109 return 0;
110 else if (!streq_ptr(match_driver, dev_driver))
111 return 0;
112 }
5fde13d7 113
d69b12ac 114 if (match_type && !streq_ptr(match_type, dev_type))
449f7554 115 return 0;
5fde13d7 116
bf175aaf 117 if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
449f7554 118 return 0;
5fde13d7 119
be32eb9b
TG
120 return 1;
121}
5fde13d7 122
377a218f 123unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
377a218f
TG
124 assert(addr);
125
ba914311 126 return 32 - u32ctz(be32toh(addr->s_addr));
377a218f
TG
127}
128
2cc412b5
TG
129int config_parse_net_condition(const char *unit,
130 const char *filename,
131 unsigned line,
132 const char *section,
133 unsigned section_line,
134 const char *lvalue,
135 int ltype,
136 const char *rvalue,
137 void *data,
138 void *userdata) {
139
140 ConditionType cond = ltype;
141 Condition **ret = data;
142 bool negate;
143 Condition *c;
144 _cleanup_free_ char *s = NULL;
145
146 assert(filename);
147 assert(lvalue);
148 assert(rvalue);
149 assert(data);
150
151 negate = rvalue[0] == '!';
152 if (negate)
153 rvalue++;
154
155 s = strdup(rvalue);
156 if (!s)
157 return log_oom();
158
159 c = condition_new(cond, s, false, negate);
160 if (!c)
161 return log_oom();
162
163 if (*ret)
164 condition_free(*ret);
165
166 *ret = c;
167 return 0;
168}
169
5fde13d7
TG
170int config_parse_ifname(const char *unit,
171 const char *filename,
172 unsigned line,
173 const char *section,
71a61510 174 unsigned section_line,
5fde13d7
TG
175 const char *lvalue,
176 int ltype,
177 const char *rvalue,
178 void *data,
179 void *userdata) {
180
181 char **s = data;
5a3f1989 182 _cleanup_free_ char *n = NULL;
5fde13d7
TG
183
184 assert(filename);
185 assert(lvalue);
186 assert(rvalue);
187 assert(data);
188
189 n = strdup(rvalue);
190 if (!n)
191 return log_oom();
192
193 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
194 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
195 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
196 free(n);
197 return 0;
198 }
199
200 free(*s);
5a3f1989 201 if (*n) {
5fde13d7 202 *s = n;
5a3f1989
TG
203 n = NULL;
204 } else
5fde13d7 205 *s = NULL;
5fde13d7
TG
206
207 return 0;
208}
209
d2df0d0e
TG
210int config_parse_ifalias(const char *unit,
211 const char *filename,
212 unsigned line,
213 const char *section,
71a61510 214 unsigned section_line,
d2df0d0e
TG
215 const char *lvalue,
216 int ltype,
217 const char *rvalue,
218 void *data,
219 void *userdata) {
220
221 char **s = data;
222 char *n;
223
224 assert(filename);
225 assert(lvalue);
226 assert(rvalue);
227 assert(data);
228
229 n = strdup(rvalue);
230 if (!n)
231 return log_oom();
232
233 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
234 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
235 "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
236 free(n);
237 return 0;
238 }
239
240 free(*s);
241 if (*n)
242 *s = n;
243 else {
244 free(n);
245 *s = NULL;
246 }
247
248 return 0;
249}
250
5fde13d7
TG
251int config_parse_hwaddr(const char *unit,
252 const char *filename,
253 unsigned line,
254 const char *section,
71a61510 255 unsigned section_line,
5fde13d7
TG
256 const char *lvalue,
257 int ltype,
258 const char *rvalue,
259 void *data,
260 void *userdata) {
261 struct ether_addr **hwaddr = data;
262 struct ether_addr *n;
263 int r;
264
265 assert(filename);
266 assert(lvalue);
267 assert(rvalue);
268 assert(data);
269
a12fa420 270 n = new0(struct ether_addr, 1);
5fde13d7
TG
271 if (!n)
272 return log_oom();
273
274 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
275 &n->ether_addr_octet[0],
276 &n->ether_addr_octet[1],
277 &n->ether_addr_octet[2],
278 &n->ether_addr_octet[3],
279 &n->ether_addr_octet[4],
280 &n->ether_addr_octet[5]);
281 if (r != 6) {
282 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
283 "Not a valid MAC address, ignoring assignment: %s", rvalue);
284 free(n);
285 return 0;
286 }
287
288 free(*hwaddr);
289 *hwaddr = n;
290
291 return 0;
292}
f5284182
TG
293
294int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
295 int r;
296
297 assert(address);
298 assert(family);
299 assert(dst);
300
301 /* IPv4 */
302 r = inet_pton(AF_INET, address, dst);
801bd9e8
TG
303 if (r > 0) {
304 /* succsefully parsed IPv4 address */
305 if (*family == AF_UNSPEC)
306 *family = AF_INET;
307 else if (*family != AF_INET)
308 return -EINVAL;
309 } else if (r < 0)
f5284182
TG
310 return -errno;
311 else {
312 /* not an IPv4 address, so let's try IPv6 */
313 r = inet_pton(AF_INET6, address, dst);
801bd9e8
TG
314 if (r > 0) {
315 /* successfully parsed IPv6 address */
316 if (*family == AF_UNSPEC)
317 *family = AF_INET6;
318 else if (*family != AF_INET6)
319 return -EINVAL;
320 } else if (r < 0)
f5284182
TG
321 return -errno;
322 else
323 return -EINVAL;
324 }
325
326 return 0;
327}
7951dea2 328
09bee74d
TG
329void serialize_in_addrs(FILE *f, const char *key, struct in_addr *addresses, size_t size) {
330 unsigned i;
331
332 assert(f);
333 assert(key);
334 assert(addresses);
335 assert(size);
336
337 fprintf(f, "%s=", key);
338
339 for (i = 0; i < size; i++)
340 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
341 (i < (size - 1)) ? " ": "");
342
343 fputs("\n", f);
344}
345
346int deserialize_in_addrs(struct in_addr **ret, size_t *ret_size, const char *string) {
347 _cleanup_free_ struct in_addr *addresses = NULL;
348 size_t size = 0;
349 char *word, *state;
350 size_t len;
351
352 assert(ret);
353 assert(ret_size);
354 assert(string);
355
356 FOREACH_WORD(word, len, string, state) {
357 _cleanup_free_ char *addr_str = NULL;
358 struct in_addr *new_addresses;
359 int r;
360
361 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
362 if (!new_addresses)
363 return -ENOMEM;
364 else
365 addresses = new_addresses;
366
367 addr_str = strndup(word, len);
368 if (!addr_str)
369 return -ENOMEM;
370
371 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
372 if (r <= 0)
373 continue;
374
375 size ++;
376 }
377
378 *ret_size = size;
379 *ret = addresses;
380 addresses = NULL;
381
382 return 0;
383}
384
385int deserialize_in6_addrs(struct in6_addr **ret, size_t *ret_size, const char *string) {
386 _cleanup_free_ struct in6_addr *addresses = NULL;
387 size_t size = 0;
388 char *word, *state;
389 size_t len;
390
391 assert(ret);
392 assert(ret_size);
393 assert(string);
394
395 FOREACH_WORD(word, len, string, state) {
396 _cleanup_free_ char *addr_str = NULL;
397 struct in6_addr *new_addresses;
398 int r;
399
400 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
401 if (!new_addresses)
402 return -ENOMEM;
403 else
404 addresses = new_addresses;
405
406 addr_str = strndup(word, len);
407 if (!addr_str)
408 return -ENOMEM;
409
410 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
411 if (r <= 0)
412 continue;
413
414 size++;
415 }
416
417 *ret_size = size;
418 *ret = addresses;
419 addresses = NULL;
420
421 return 0;
422}