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