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