chiark / gitweb /
networkctl: also draw a nice unicode cirlce when "networkctl status" is run without...
[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 #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 }