]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
network-address,test-network: avoid undefined behaviour
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
f579559b
TG
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
f579559b
TG
24#include "utf8.h"
25#include "util.h"
26#include "conf-parser.h"
5a8bcb67 27#include "fw-util.h"
c6f7c917 28#include "network-internal.h"
5a8bcb67
LP
29#include "networkd.h"
30#include "networkd-link.h"
f579559b 31
aba496a5
UTL
32static 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
f048a16b 41int address_new_static(Network *network, unsigned section, Address **ret) {
f579559b
TG
42 _cleanup_address_free_ Address *address = NULL;
43
6ae115c1 44 if (section) {
16aa63a0 45 address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
6ae115c1
TG
46 if (address) {
47 *ret = address;
48 address = NULL;
49
50 return 0;
51 }
52 }
53
f579559b
TG
54 address = new0(Address, 1);
55 if (!address)
56 return -ENOMEM;
57
aba496a5 58 address_init(address);
801bd9e8 59
f579559b
TG
60 address->network = network;
61
1e39ff92 62 LIST_APPEND(addresses, network->static_addresses, address);
f579559b 63
6ae115c1
TG
64 if (section) {
65 address->section = section;
16aa63a0
TG
66 hashmap_put(network->addresses_by_section,
67 UINT_TO_PTR(address->section), address);
6ae115c1
TG
68 }
69
f579559b
TG
70 *ret = address;
71 address = NULL;
72
73 return 0;
74}
75
f048a16b
TG
76int 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
aba496a5 83 address_init(address);
801bd9e8 84
f048a16b
TG
85 *ret = address;
86 address = NULL;
87
88 return 0;
89}
90
f579559b
TG
91void address_free(Address *address) {
92 if (!address)
93 return;
94
f048a16b 95 if (address->network) {
3d3d4255 96 LIST_REMOVE(addresses, address->network->static_addresses, address);
f579559b 97
f048a16b
TG
98 if (address->section)
99 hashmap_remove(address->network->addresses_by_section,
16aa63a0 100 UINT_TO_PTR(address->section));
f048a16b 101 }
6ae115c1 102
f579559b
TG
103 free(address);
104}
105
5a8bcb67
LP
106int 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 */
fd6d906c 119 if (address->ip_masquerade_done != masq) {
5a8bcb67
LP
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
fd6d906c 127 address->ip_masquerade_done = masq;
5a8bcb67
LP
128 }
129
130 return 0;
131}
132
133int 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 */
fd6d906c 140 if (address->ip_masquerade_done) {
5a8bcb67
LP
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
fd6d906c 148 address->ip_masquerade_done = false;
5a8bcb67
LP
149 }
150
151 return 0;
152}
153
407fe036
TG
154int address_drop(Address *address, Link *link,
155 sd_rtnl_message_handler_t callback) {
cf6a8911 156 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
407fe036
TG
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
5a8bcb67
LP
166 address_release(address, link);
167
151b9b96
LP
168 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
169 link->ifindex, address->family);
eb56eb9b
MS
170 if (r < 0)
171 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
407fe036 172
5a723174 173 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
174 if (r < 0)
175 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 176
407fe036
TG
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);
eb56eb9b
MS
181 if (r < 0)
182 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
407fe036
TG
183
184 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
eb56eb9b
MS
185 if (r < 0)
186 return log_error_errno(r, "Could not send rtnetlink message: %m");
407fe036 187
563c69c6
TG
188 link_ref(link);
189
407fe036
TG
190 return 0;
191}
192
aba496a5
UTL
193int 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);
eb56eb9b
MS
206 if (r < 0)
207 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
aba496a5
UTL
208
209 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
210 if (r < 0)
211 return log_error_errno(r, "Could not set prefixlen: %m");
aba496a5
UTL
212
213 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
eb56eb9b
MS
214 if (r < 0)
215 return log_error_errno(r, "Could not set flags: %m");
aba496a5
UTL
216
217 r = sd_rtnl_message_addr_set_scope(req, address->scope);
eb56eb9b
MS
218 if (r < 0)
219 return log_error_errno(r, "Could not set scope: %m");
aba496a5
UTL
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);
eb56eb9b
MS
225 if (r < 0)
226 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
aba496a5
UTL
227
228 if (address->family == AF_INET) {
229 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
eb56eb9b
MS
230 if (r < 0)
231 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
aba496a5
UTL
232 }
233
234 if (address->label) {
235 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
eb56eb9b
MS
236 if (r < 0)
237 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
aba496a5
UTL
238 }
239
240 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
eb56eb9b
MS
241 if (r < 0)
242 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
aba496a5
UTL
243
244 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
eb56eb9b
MS
245 if (r < 0)
246 return log_error_errno(r, "Could not send rtnetlink message: %m");
aba496a5 247
563c69c6
TG
248 link_ref(link);
249
aba496a5
UTL
250 return 0;
251}
252
11bf3cce
LP
253static int address_acquire(Link *link, Address *original, Address **ret) {
254 union in_addr_union in_addr = {};
255 struct in_addr broadcast = {};
0099bc15 256 _cleanup_address_free_ Address *na = NULL;
11bf3cce
LP
257 int r;
258
259 assert(link);
260 assert(original);
261 assert(ret);
262
263 /* Something useful was configured? just use it */
af93291c 264 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
11bf3cce
LP
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) {
79008bdd 271 log_link_error(link, "Failed to acquire address from pool: %s", strerror(-r));
11bf3cce
LP
272 return r;
273 }
274 if (r == 0) {
79008bdd 275 log_link_error(link, "Couldn't find free address for interface, all taken.");
11bf3cce
LP
276 return -EBUSY;
277 }
278
279 if (original->family == AF_INET) {
d076c6f9 280 /* Pick first address in range for ourselves ... */
11bf3cce
LP
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);
0099bc15 299 if (!na->label)
11bf3cce 300 return -ENOMEM;
11bf3cce
LP
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;
0099bc15
SS
309 na = NULL;
310
11bf3cce
LP
311 return 0;
312}
313
f882c247
TG
314int address_configure(Address *address, Link *link,
315 sd_rtnl_message_handler_t callback) {
cf6a8911 316 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
317 int r;
318
c166a070
TG
319 assert(address);
320 assert(address->family == AF_INET || address->family == AF_INET6);
321 assert(link);
322 assert(link->ifindex > 0);
f882c247 323 assert(link->manager);
c166a070 324 assert(link->manager->rtnl);
f882c247 325
11bf3cce
LP
326 r = address_acquire(link, address, &address);
327 if (r < 0)
328 return r;
329
151b9b96
LP
330 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
331 link->ifindex, address->family);
eb56eb9b
MS
332 if (r < 0)
333 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
f579559b 334
5a723174 335 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
336 if (r < 0)
337 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174
TG
338
339 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
eb56eb9b
MS
340 if (r < 0)
341 return log_error_errno(r, "Could not set flags: %m");
5a723174 342
5c1d3fc9 343 r = sd_rtnl_message_addr_set_scope(req, address->scope);
eb56eb9b
MS
344 if (r < 0)
345 return log_error_errno(r, "Could not set scope: %m");
5a723174 346
0a0dc69b
TG
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);
eb56eb9b
MS
351 if (r < 0)
352 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
f579559b 353
af93291c 354 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
c081882f
SS
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);
eb56eb9b
MS
359 if (r < 0)
360 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
c081882f
SS
361 } else {
362 if (address->family == AF_INET) {
363 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
eb56eb9b
MS
364 if (r < 0)
365 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
c081882f 366 }
f579559b
TG
367 }
368
369 if (address->label) {
0a0dc69b 370 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
eb56eb9b
MS
371 if (r < 0)
372 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
f579559b
TG
373 }
374
68ceb9df
PF
375 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
376 &address->cinfo);
eb56eb9b
MS
377 if (r < 0)
378 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
68ceb9df 379
f882c247 380 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
eb56eb9b
MS
381 if (r < 0)
382 return log_error_errno(r, "Could not send rtnetlink message: %m");
f579559b 383
563c69c6
TG
384 link_ref(link);
385
5a8bcb67
LP
386 address_establish(address, link);
387
f579559b
TG
388 return 0;
389}
390
44e7b949
LP
391int config_parse_broadcast(
392 const char *unit,
eb0ea358
TG
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) {
44e7b949 402
eb0ea358
TG
403 Network *network = userdata;
404 _cleanup_address_free_ Address *n = NULL;
eb0ea358
TG
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
482e2ac1
TG
417 if (n->family == AF_INET6) {
418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
44e7b949 419 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
482e2ac1
TG
420 return 0;
421 }
422
44e7b949 423 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
eb0ea358
TG
424 if (r < 0) {
425 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
44e7b949 426 "Broadcast is invalid, ignoring assignment: %s", rvalue);
eb0ea358
TG
427 return 0;
428 }
429
44e7b949 430 n->family = AF_INET;
eb0ea358
TG
431 n = NULL;
432
433 return 0;
434}
435
f579559b
TG
436int config_parse_address(const char *unit,
437 const char *filename,
438 unsigned line,
439 const char *section,
71a61510 440 unsigned section_line,
f579559b
TG
441 const char *lvalue,
442 int ltype,
443 const char *rvalue,
444 void *data,
445 void *userdata) {
44e7b949 446
6ae115c1 447 Network *network = userdata;
f579559b 448 _cleanup_address_free_ Address *n = NULL;
44e7b949
LP
449 const char *address, *e;
450 union in_addr_union buffer;
451 int r, f;
f579559b
TG
452
453 assert(filename);
6ae115c1 454 assert(section);
f579559b
TG
455 assert(lvalue);
456 assert(rvalue);
457 assert(data);
458
92fe133a
TG
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
f048a16b 465 r = address_new_static(network, section_line, &n);
f579559b
TG
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,
a2a85a22 478 "Prefix length is invalid, ignoring assignment: %s", e + 1);
f579559b
TG
479 return 0;
480 }
481
482 n->prefixlen = (unsigned char) i;
8cd11a0f 483
44e7b949
LP
484 address = strndupa(rvalue, e - rvalue);
485 } else
486 address = rvalue;
f579559b 487
44e7b949 488 r = in_addr_from_string_auto(address, &f, &buffer);
f579559b
TG
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
a2a85a22
TG
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
44e7b949
LP
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);
eb0ea358 519
f579559b
TG
520 n = NULL;
521
522 return 0;
523}
6ae115c1
TG
524
525int 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;
6ae115c1
TG
537 char *label;
538 int r;
539
540 assert(filename);
541 assert(section);
542 assert(lvalue);
543 assert(rvalue);
544 assert(data);
545
f048a16b 546 r = address_new_static(network, section_line, &n);
6ae115c1
TG
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}
9505d3c6
TG
574
575bool 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;
6cb8e687
ZJS
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;
9505d3c6
TG
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
5a8bcb67 608 case AF_INET6: {
9505d3c6
TG
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 }
5a8bcb67 616
9505d3c6
TG
617 default:
618 assert_not_reached("Invalid address family");
619 }
620}