]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address.c
network-address,test-network: avoid undefined behaviour
[thirdparty/systemd.git] / src / network / networkd-address.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 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 <net/if.h>
23
24 #include "utf8.h"
25 #include "util.h"
26 #include "conf-parser.h"
27 #include "fw-util.h"
28 #include "network-internal.h"
29 #include "networkd.h"
30 #include "networkd-link.h"
31
32 static void address_init(Address *address) {
33 assert(address);
34
35 address->family = AF_UNSPEC;
36 address->scope = RT_SCOPE_UNIVERSE;
37 address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
38 address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
39 }
40
41 int address_new_static(Network *network, unsigned section, Address **ret) {
42 _cleanup_address_free_ Address *address = NULL;
43
44 if (section) {
45 address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
46 if (address) {
47 *ret = address;
48 address = NULL;
49
50 return 0;
51 }
52 }
53
54 address = new0(Address, 1);
55 if (!address)
56 return -ENOMEM;
57
58 address_init(address);
59
60 address->network = network;
61
62 LIST_APPEND(addresses, network->static_addresses, address);
63
64 if (section) {
65 address->section = section;
66 hashmap_put(network->addresses_by_section,
67 UINT_TO_PTR(address->section), address);
68 }
69
70 *ret = address;
71 address = NULL;
72
73 return 0;
74 }
75
76 int address_new_dynamic(Address **ret) {
77 _cleanup_address_free_ Address *address = NULL;
78
79 address = new0(Address, 1);
80 if (!address)
81 return -ENOMEM;
82
83 address_init(address);
84
85 *ret = address;
86 address = NULL;
87
88 return 0;
89 }
90
91 void address_free(Address *address) {
92 if (!address)
93 return;
94
95 if (address->network) {
96 LIST_REMOVE(addresses, address->network->static_addresses, address);
97
98 if (address->section)
99 hashmap_remove(address->network->addresses_by_section,
100 UINT_TO_PTR(address->section));
101 }
102
103 free(address);
104 }
105
106 int address_establish(Address *address, Link *link) {
107 bool masq;
108 int r;
109
110 assert(address);
111 assert(link);
112
113 masq = link->network &&
114 link->network->ip_masquerade &&
115 address->family == AF_INET &&
116 address->scope < RT_SCOPE_LINK;
117
118 /* Add firewall entry if this is requested */
119 if (address->ip_masquerade_done != masq) {
120 union in_addr_union masked = address->in_addr;
121 in_addr_mask(address->family, &masked, address->prefixlen);
122
123 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
124 if (r < 0)
125 log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
126
127 address->ip_masquerade_done = masq;
128 }
129
130 return 0;
131 }
132
133 int address_release(Address *address, Link *link) {
134 int r;
135
136 assert(address);
137 assert(link);
138
139 /* Remove masquerading firewall entry if it was added */
140 if (address->ip_masquerade_done) {
141 union in_addr_union masked = address->in_addr;
142 in_addr_mask(address->family, &masked, address->prefixlen);
143
144 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
145 if (r < 0)
146 log_link_warning_errno(link, r, "Failed to disable IP masquerading: %m");
147
148 address->ip_masquerade_done = false;
149 }
150
151 return 0;
152 }
153
154 int address_drop(Address *address, Link *link,
155 sd_rtnl_message_handler_t callback) {
156 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
157 int r;
158
159 assert(address);
160 assert(address->family == AF_INET || address->family == AF_INET6);
161 assert(link);
162 assert(link->ifindex > 0);
163 assert(link->manager);
164 assert(link->manager->rtnl);
165
166 address_release(address, link);
167
168 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
169 link->ifindex, address->family);
170 if (r < 0)
171 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
172
173 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
174 if (r < 0)
175 return log_error_errno(r, "Could not set prefixlen: %m");
176
177 if (address->family == AF_INET)
178 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
179 else if (address->family == AF_INET6)
180 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
181 if (r < 0)
182 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
183
184 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
185 if (r < 0)
186 return log_error_errno(r, "Could not send rtnetlink message: %m");
187
188 link_ref(link);
189
190 return 0;
191 }
192
193 int address_update(Address *address, Link *link,
194 sd_rtnl_message_handler_t callback) {
195 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
196 int r;
197
198 assert(address);
199 assert(address->family == AF_INET || address->family == AF_INET6);
200 assert(link->ifindex > 0);
201 assert(link->manager);
202 assert(link->manager->rtnl);
203
204 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
205 link->ifindex, address->family);
206 if (r < 0)
207 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
208
209 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
210 if (r < 0)
211 return log_error_errno(r, "Could not set prefixlen: %m");
212
213 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
214 if (r < 0)
215 return log_error_errno(r, "Could not set flags: %m");
216
217 r = sd_rtnl_message_addr_set_scope(req, address->scope);
218 if (r < 0)
219 return log_error_errno(r, "Could not set scope: %m");
220
221 if (address->family == AF_INET)
222 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
223 else if (address->family == AF_INET6)
224 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
225 if (r < 0)
226 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
227
228 if (address->family == AF_INET) {
229 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
230 if (r < 0)
231 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
232 }
233
234 if (address->label) {
235 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
236 if (r < 0)
237 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
238 }
239
240 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
241 if (r < 0)
242 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
243
244 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
245 if (r < 0)
246 return log_error_errno(r, "Could not send rtnetlink message: %m");
247
248 link_ref(link);
249
250 return 0;
251 }
252
253 static int address_acquire(Link *link, Address *original, Address **ret) {
254 union in_addr_union in_addr = {};
255 struct in_addr broadcast = {};
256 _cleanup_address_free_ Address *na = NULL;
257 int r;
258
259 assert(link);
260 assert(original);
261 assert(ret);
262
263 /* Something useful was configured? just use it */
264 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
265 return 0;
266
267 /* The address is configured to be 0.0.0.0 or [::] by the user?
268 * Then let's acquire something more useful from the pool. */
269 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
270 if (r < 0) {
271 log_link_error(link, "Failed to acquire address from pool: %s", strerror(-r));
272 return r;
273 }
274 if (r == 0) {
275 log_link_error(link, "Couldn't find free address for interface, all taken.");
276 return -EBUSY;
277 }
278
279 if (original->family == AF_INET) {
280 /* Pick first address in range for ourselves ... */
281 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
282
283 /* .. and use last as broadcast address */
284 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
285 } else if (original->family == AF_INET6)
286 in_addr.in6.s6_addr[15] |= 1;
287
288 r = address_new_dynamic(&na);
289 if (r < 0)
290 return r;
291
292 na->family = original->family;
293 na->prefixlen = original->prefixlen;
294 na->scope = original->scope;
295 na->cinfo = original->cinfo;
296
297 if (original->label) {
298 na->label = strdup(original->label);
299 if (!na->label)
300 return -ENOMEM;
301 }
302
303 na->broadcast = broadcast;
304 na->in_addr = in_addr;
305
306 LIST_PREPEND(addresses, link->pool_addresses, na);
307
308 *ret = na;
309 na = NULL;
310
311 return 0;
312 }
313
314 int address_configure(Address *address, Link *link,
315 sd_rtnl_message_handler_t callback) {
316 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
317 int r;
318
319 assert(address);
320 assert(address->family == AF_INET || address->family == AF_INET6);
321 assert(link);
322 assert(link->ifindex > 0);
323 assert(link->manager);
324 assert(link->manager->rtnl);
325
326 r = address_acquire(link, address, &address);
327 if (r < 0)
328 return r;
329
330 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
331 link->ifindex, address->family);
332 if (r < 0)
333 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
334
335 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
336 if (r < 0)
337 return log_error_errno(r, "Could not set prefixlen: %m");
338
339 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
340 if (r < 0)
341 return log_error_errno(r, "Could not set flags: %m");
342
343 r = sd_rtnl_message_addr_set_scope(req, address->scope);
344 if (r < 0)
345 return log_error_errno(r, "Could not set scope: %m");
346
347 if (address->family == AF_INET)
348 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
349 else if (address->family == AF_INET6)
350 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
351 if (r < 0)
352 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
353
354 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
355 if (address->family == AF_INET)
356 r = sd_rtnl_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
357 else if (address->family == AF_INET6)
358 r = sd_rtnl_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
359 if (r < 0)
360 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
361 } else {
362 if (address->family == AF_INET) {
363 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
364 if (r < 0)
365 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
366 }
367 }
368
369 if (address->label) {
370 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
371 if (r < 0)
372 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
373 }
374
375 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
376 &address->cinfo);
377 if (r < 0)
378 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
379
380 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
381 if (r < 0)
382 return log_error_errno(r, "Could not send rtnetlink message: %m");
383
384 link_ref(link);
385
386 address_establish(address, link);
387
388 return 0;
389 }
390
391 int config_parse_broadcast(
392 const char *unit,
393 const char *filename,
394 unsigned line,
395 const char *section,
396 unsigned section_line,
397 const char *lvalue,
398 int ltype,
399 const char *rvalue,
400 void *data,
401 void *userdata) {
402
403 Network *network = userdata;
404 _cleanup_address_free_ Address *n = NULL;
405 int r;
406
407 assert(filename);
408 assert(section);
409 assert(lvalue);
410 assert(rvalue);
411 assert(data);
412
413 r = address_new_static(network, section_line, &n);
414 if (r < 0)
415 return r;
416
417 if (n->family == AF_INET6) {
418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
419 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
420 return 0;
421 }
422
423 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
424 if (r < 0) {
425 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
426 "Broadcast is invalid, ignoring assignment: %s", rvalue);
427 return 0;
428 }
429
430 n->family = AF_INET;
431 n = NULL;
432
433 return 0;
434 }
435
436 int config_parse_address(const char *unit,
437 const char *filename,
438 unsigned line,
439 const char *section,
440 unsigned section_line,
441 const char *lvalue,
442 int ltype,
443 const char *rvalue,
444 void *data,
445 void *userdata) {
446
447 Network *network = userdata;
448 _cleanup_address_free_ Address *n = NULL;
449 const char *address, *e;
450 union in_addr_union buffer;
451 int r, f;
452
453 assert(filename);
454 assert(section);
455 assert(lvalue);
456 assert(rvalue);
457 assert(data);
458
459 if (streq(section, "Network")) {
460 /* we are not in an Address section, so treat
461 * this as the special '0' section */
462 section_line = 0;
463 }
464
465 r = address_new_static(network, section_line, &n);
466 if (r < 0)
467 return r;
468
469 /* Address=address/prefixlen */
470
471 /* prefixlen */
472 e = strchr(rvalue, '/');
473 if (e) {
474 unsigned i;
475 r = safe_atou(e + 1, &i);
476 if (r < 0) {
477 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
478 "Prefix length is invalid, ignoring assignment: %s", e + 1);
479 return 0;
480 }
481
482 n->prefixlen = (unsigned char) i;
483
484 address = strndupa(rvalue, e - rvalue);
485 } else
486 address = rvalue;
487
488 r = in_addr_from_string_auto(address, &f, &buffer);
489 if (r < 0) {
490 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
491 "Address is invalid, ignoring assignment: %s", address);
492 return 0;
493 }
494
495 if (!e && f == AF_INET) {
496 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
497 if (r < 0) {
498 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
499 "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
500 return 0;
501 }
502 }
503
504 if (n->family != AF_UNSPEC && f != n->family) {
505 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
506 "Address is incompatible, ignoring assignment: %s", address);
507 return 0;
508 }
509
510 n->family = f;
511
512 if (streq(lvalue, "Address"))
513 n->in_addr = buffer;
514 else
515 n->in_addr_peer = buffer;
516
517 if (n->family == AF_INET && n->broadcast.s_addr == 0)
518 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
519
520 n = NULL;
521
522 return 0;
523 }
524
525 int config_parse_label(const char *unit,
526 const char *filename,
527 unsigned line,
528 const char *section,
529 unsigned section_line,
530 const char *lvalue,
531 int ltype,
532 const char *rvalue,
533 void *data,
534 void *userdata) {
535 Network *network = userdata;
536 _cleanup_address_free_ Address *n = NULL;
537 char *label;
538 int r;
539
540 assert(filename);
541 assert(section);
542 assert(lvalue);
543 assert(rvalue);
544 assert(data);
545
546 r = address_new_static(network, section_line, &n);
547 if (r < 0)
548 return r;
549
550 label = strdup(rvalue);
551 if (!label)
552 return log_oom();
553
554 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
555 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
556 "Interface label is not ASCII clean or is too"
557 " long, ignoring assignment: %s", rvalue);
558 free(label);
559 return 0;
560 }
561
562 free(n->label);
563 if (*label)
564 n->label = label;
565 else {
566 free(label);
567 n->label = NULL;
568 }
569
570 n = NULL;
571
572 return 0;
573 }
574
575 bool address_equal(Address *a1, Address *a2) {
576 /* same object */
577 if (a1 == a2)
578 return true;
579
580 /* one, but not both, is NULL */
581 if (!a1 || !a2)
582 return false;
583
584 if (a1->family != a2->family)
585 return false;
586
587 switch (a1->family) {
588 /* use the same notion of equality as the kernel does */
589 case AF_UNSPEC:
590 return true;
591
592 case AF_INET:
593 if (a1->prefixlen != a2->prefixlen)
594 return false;
595 else if (a1->prefixlen == 0)
596 /* make sure we don't try to shift by 32.
597 * See ISO/IEC 9899:TC3 ยง 6.5.7.3. */
598 return true;
599 else {
600 uint32_t b1, b2;
601
602 b1 = be32toh(a1->in_addr.in.s_addr);
603 b2 = be32toh(a2->in_addr.in.s_addr);
604
605 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
606 }
607
608 case AF_INET6: {
609 uint64_t *b1, *b2;
610
611 b1 = (uint64_t*)&a1->in_addr.in6;
612 b2 = (uint64_t*)&a2->in_addr.in6;
613
614 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
615 }
616
617 default:
618 assert_not_reached("Invalid address family");
619 }
620 }