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