]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address.c
treewide: use log_*_errno whenever %m is in the format string
[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 "networkd.h"
25 #include "networkd-link.h"
26
27 #include "utf8.h"
28 #include "util.h"
29 #include "conf-parser.h"
30 #include "network-internal.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_PREPEND(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_drop(Address *address, Link *link,
107 sd_rtnl_message_handler_t callback) {
108 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
109 int r;
110
111 assert(address);
112 assert(address->family == AF_INET || address->family == AF_INET6);
113 assert(link);
114 assert(link->ifindex > 0);
115 assert(link->manager);
116 assert(link->manager->rtnl);
117
118 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
119 link->ifindex, address->family);
120 if (r < 0)
121 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
122
123 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
124 if (r < 0)
125 return log_error_errno(r, "Could not set prefixlen: %m");
126
127 if (address->family == AF_INET)
128 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
129 else if (address->family == AF_INET6)
130 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
131 if (r < 0)
132 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
133
134 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
135 if (r < 0)
136 return log_error_errno(r, "Could not send rtnetlink message: %m");
137
138 link_ref(link);
139
140 return 0;
141 }
142
143 int address_update(Address *address, Link *link,
144 sd_rtnl_message_handler_t callback) {
145 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
146 int r;
147
148 assert(address);
149 assert(address->family == AF_INET || address->family == AF_INET6);
150 assert(link->ifindex > 0);
151 assert(link->manager);
152 assert(link->manager->rtnl);
153
154 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
155 link->ifindex, address->family);
156 if (r < 0)
157 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
158
159 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
160 if (r < 0)
161 return log_error_errno(r, "Could not set prefixlen: %m");
162
163 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
164 if (r < 0)
165 return log_error_errno(r, "Could not set flags: %m");
166
167 r = sd_rtnl_message_addr_set_scope(req, address->scope);
168 if (r < 0)
169 return log_error_errno(r, "Could not set scope: %m");
170
171 if (address->family == AF_INET)
172 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
173 else if (address->family == AF_INET6)
174 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
175 if (r < 0)
176 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
177
178 if (address->family == AF_INET) {
179 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
180 if (r < 0)
181 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
182 }
183
184 if (address->label) {
185 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
186 if (r < 0)
187 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
188 }
189
190 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
191 if (r < 0)
192 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
193
194 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
195 if (r < 0)
196 return log_error_errno(r, "Could not send rtnetlink message: %m");
197
198 link_ref(link);
199
200 return 0;
201 }
202
203 static int address_acquire(Link *link, Address *original, Address **ret) {
204 union in_addr_union in_addr = {};
205 struct in_addr broadcast = {};
206 _cleanup_address_free_ Address *na = NULL;
207 int r;
208
209 assert(link);
210 assert(original);
211 assert(ret);
212
213 /* Something useful was configured? just use it */
214 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
215 return 0;
216
217 /* The address is configured to be 0.0.0.0 or [::] by the user?
218 * Then let's acquire something more useful from the pool. */
219 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
220 if (r < 0) {
221 log_link_error(link, "Failed to acquire address from pool: %s", strerror(-r));
222 return r;
223 }
224 if (r == 0) {
225 log_link_error(link, "Couldn't find free address for interface, all taken.");
226 return -EBUSY;
227 }
228
229 if (original->family == AF_INET) {
230 /* Pick first address in range for ourselves ...*/
231 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
232
233 /* .. and use last as broadcast address */
234 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
235 } else if (original->family == AF_INET6)
236 in_addr.in6.s6_addr[15] |= 1;
237
238 r = address_new_dynamic(&na);
239 if (r < 0)
240 return r;
241
242 na->family = original->family;
243 na->prefixlen = original->prefixlen;
244 na->scope = original->scope;
245 na->cinfo = original->cinfo;
246
247 if (original->label) {
248 na->label = strdup(original->label);
249 if (!na->label)
250 return -ENOMEM;
251 }
252
253 na->broadcast = broadcast;
254 na->in_addr = in_addr;
255
256 LIST_PREPEND(addresses, link->pool_addresses, na);
257
258 *ret = na;
259 na = NULL;
260
261 return 0;
262 }
263
264 int address_configure(Address *address, Link *link,
265 sd_rtnl_message_handler_t callback) {
266 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
267 int r;
268
269 assert(address);
270 assert(address->family == AF_INET || address->family == AF_INET6);
271 assert(link);
272 assert(link->ifindex > 0);
273 assert(link->manager);
274 assert(link->manager->rtnl);
275
276 r = address_acquire(link, address, &address);
277 if (r < 0)
278 return r;
279
280 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
281 link->ifindex, address->family);
282 if (r < 0)
283 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
284
285 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
286 if (r < 0)
287 return log_error_errno(r, "Could not set prefixlen: %m");
288
289 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
290 if (r < 0)
291 return log_error_errno(r, "Could not set flags: %m");
292
293 r = sd_rtnl_message_addr_set_scope(req, address->scope);
294 if (r < 0)
295 return log_error_errno(r, "Could not set scope: %m");
296
297 if (address->family == AF_INET)
298 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
299 else if (address->family == AF_INET6)
300 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
301 if (r < 0)
302 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
303
304 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
305 if (address->family == AF_INET)
306 r = sd_rtnl_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
307 else if (address->family == AF_INET6)
308 r = sd_rtnl_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
309 if (r < 0)
310 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
311 } else {
312 if (address->family == AF_INET) {
313 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
314 if (r < 0)
315 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
316 }
317 }
318
319 if (address->label) {
320 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
321 if (r < 0)
322 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
323 }
324
325 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
326 &address->cinfo);
327 if (r < 0)
328 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
329
330 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
331 if (r < 0)
332 return log_error_errno(r, "Could not send rtnetlink message: %m");
333
334 link_ref(link);
335
336 return 0;
337 }
338
339 int config_parse_broadcast(
340 const char *unit,
341 const char *filename,
342 unsigned line,
343 const char *section,
344 unsigned section_line,
345 const char *lvalue,
346 int ltype,
347 const char *rvalue,
348 void *data,
349 void *userdata) {
350
351 Network *network = userdata;
352 _cleanup_address_free_ Address *n = NULL;
353 int r;
354
355 assert(filename);
356 assert(section);
357 assert(lvalue);
358 assert(rvalue);
359 assert(data);
360
361 r = address_new_static(network, section_line, &n);
362 if (r < 0)
363 return r;
364
365 if (n->family == AF_INET6) {
366 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
367 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
368 return 0;
369 }
370
371 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
372 if (r < 0) {
373 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
374 "Broadcast is invalid, ignoring assignment: %s", rvalue);
375 return 0;
376 }
377
378 n->family = AF_INET;
379 n = NULL;
380
381 return 0;
382 }
383
384 int config_parse_address(const char *unit,
385 const char *filename,
386 unsigned line,
387 const char *section,
388 unsigned section_line,
389 const char *lvalue,
390 int ltype,
391 const char *rvalue,
392 void *data,
393 void *userdata) {
394
395 Network *network = userdata;
396 _cleanup_address_free_ Address *n = NULL;
397 const char *address, *e;
398 union in_addr_union buffer;
399 int r, f;
400
401 assert(filename);
402 assert(section);
403 assert(lvalue);
404 assert(rvalue);
405 assert(data);
406
407 if (streq(section, "Network")) {
408 /* we are not in an Address section, so treat
409 * this as the special '0' section */
410 section_line = 0;
411 }
412
413 r = address_new_static(network, section_line, &n);
414 if (r < 0)
415 return r;
416
417 /* Address=address/prefixlen */
418
419 /* prefixlen */
420 e = strchr(rvalue, '/');
421 if (e) {
422 unsigned i;
423 r = safe_atou(e + 1, &i);
424 if (r < 0) {
425 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
426 "Prefix length is invalid, ignoring assignment: %s", e + 1);
427 return 0;
428 }
429
430 n->prefixlen = (unsigned char) i;
431
432 address = strndupa(rvalue, e - rvalue);
433 } else
434 address = rvalue;
435
436 r = in_addr_from_string_auto(address, &f, &buffer);
437 if (r < 0) {
438 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
439 "Address is invalid, ignoring assignment: %s", address);
440 return 0;
441 }
442
443 if (!e && f == AF_INET) {
444 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
445 if (r < 0) {
446 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
447 "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
448 return 0;
449 }
450 }
451
452 if (n->family != AF_UNSPEC && f != n->family) {
453 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
454 "Address is incompatible, ignoring assignment: %s", address);
455 return 0;
456 }
457
458 n->family = f;
459
460 if (streq(lvalue, "Address"))
461 n->in_addr = buffer;
462 else
463 n->in_addr_peer = buffer;
464
465 if (n->family == AF_INET && n->broadcast.s_addr == 0)
466 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
467
468 n = NULL;
469
470 return 0;
471 }
472
473 int config_parse_label(const char *unit,
474 const char *filename,
475 unsigned line,
476 const char *section,
477 unsigned section_line,
478 const char *lvalue,
479 int ltype,
480 const char *rvalue,
481 void *data,
482 void *userdata) {
483 Network *network = userdata;
484 _cleanup_address_free_ Address *n = NULL;
485 char *label;
486 int r;
487
488 assert(filename);
489 assert(section);
490 assert(lvalue);
491 assert(rvalue);
492 assert(data);
493
494 r = address_new_static(network, section_line, &n);
495 if (r < 0)
496 return r;
497
498 label = strdup(rvalue);
499 if (!label)
500 return log_oom();
501
502 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
503 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
504 "Interface label is not ASCII clean or is too"
505 " long, ignoring assignment: %s", rvalue);
506 free(label);
507 return 0;
508 }
509
510 free(n->label);
511 if (*label)
512 n->label = label;
513 else {
514 free(label);
515 n->label = NULL;
516 }
517
518 n = NULL;
519
520 return 0;
521 }
522
523 bool address_equal(Address *a1, Address *a2) {
524 /* same object */
525 if (a1 == a2)
526 return true;
527
528 /* one, but not both, is NULL */
529 if (!a1 || !a2)
530 return false;
531
532 if (a1->family != a2->family)
533 return false;
534
535 switch (a1->family) {
536 /* use the same notion of equality as the kernel does */
537 case AF_UNSPEC:
538 return true;
539
540 case AF_INET:
541 if (a1->prefixlen != a2->prefixlen)
542 return false;
543 else {
544 uint32_t b1, b2;
545
546 b1 = be32toh(a1->in_addr.in.s_addr);
547 b2 = be32toh(a2->in_addr.in.s_addr);
548
549 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
550 }
551
552 case AF_INET6:
553 {
554 uint64_t *b1, *b2;
555
556 b1 = (uint64_t*)&a1->in_addr.in6;
557 b2 = (uint64_t*)&a2->in_addr.in6;
558
559 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
560 }
561 default:
562 assert_not_reached("Invalid address family");
563 }
564 }