]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/network-internal.c
networkd: veth - fix memleak
[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 "log.h"
32 #include "utf8.h"
33 #include "util.h"
34 #include "conf-parser.h"
35 #include "condition.h"
36
37 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
38
39 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
40 size_t l, sz = 0;
41 const char *name = NULL, *field = NULL;
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
73 bool 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,
78 Condition *match_host,
79 Condition *match_virt,
80 Condition *match_kernel,
81 Condition *match_arch,
82 const struct ether_addr *dev_mac,
83 const char *dev_path,
84 const char *dev_parent_driver,
85 const char *dev_driver,
86 const char *dev_type,
87 const char *dev_name) {
88
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
98 if (match_arch && !condition_test_architecture(match_arch))
99 return 0;
100
101 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
102 return 0;
103
104 if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
105 return 0;
106
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 }
113
114 if (match_type && !streq_ptr(match_type, dev_type))
115 return 0;
116
117 if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
118 return 0;
119
120 return 1;
121 }
122
123 unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
124 assert(addr);
125
126 return 32 - u32ctz(be32toh(addr->s_addr));
127 }
128
129 int 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
170 int config_parse_ifname(const char *unit,
171 const char *filename,
172 unsigned line,
173 const char *section,
174 unsigned section_line,
175 const char *lvalue,
176 int ltype,
177 const char *rvalue,
178 void *data,
179 void *userdata) {
180
181 char **s = data;
182 _cleanup_free_ char *n = NULL;
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);
201 if (*n) {
202 *s = n;
203 n = NULL;
204 } else
205 *s = NULL;
206
207 return 0;
208 }
209
210 int config_parse_ifalias(const char *unit,
211 const char *filename,
212 unsigned line,
213 const char *section,
214 unsigned section_line,
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
251 int config_parse_hwaddr(const char *unit,
252 const char *filename,
253 unsigned line,
254 const char *section,
255 unsigned section_line,
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
270 n = new0(struct ether_addr, 1);
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 }
293
294 int 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);
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)
310 return -errno;
311 else {
312 /* not an IPv4 address, so let's try IPv6 */
313 r = inet_pton(AF_INET6, address, dst);
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)
321 return -errno;
322 else
323 return -EINVAL;
324 }
325
326 return 0;
327 }
328
329 void 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
346 int 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
385 int 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 }