chiark / gitweb /
sysusers: fix uninitialized warning
[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         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_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 (address->family == AF_INET) {
349                 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
350                 if (r < 0) {
351                         log_error("Could not append IFA_BROADCAST attribute: %s",
352                                   strerror(-r));
353                         return r;
354                 }
355         }
356
357         if (address->label) {
358                 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
359                 if (r < 0) {
360                         log_error("Could not append IFA_LABEL attribute: %s",
361                                   strerror(-r));
362                         return r;
363                 }
364         }
365
366         r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
367                                               &address->cinfo);
368         if (r < 0) {
369                 log_error("Could not append IFA_CACHEINFO attribute: %s",
370                           strerror(-r));
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("Could not send rtnetlink message: %s", strerror(-r));
377                 return r;
378         }
379
380         link_ref(link);
381
382         return 0;
383 }
384
385 int config_parse_dns(const char *unit,
386                 const char *filename,
387                 unsigned line,
388                 const char *section,
389                 unsigned section_line,
390                 const char *lvalue,
391                 int ltype,
392                 const char *rvalue,
393                 void *data,
394                 void *userdata) {
395         Network *network = userdata;
396         Address *tail;
397         _cleanup_address_free_ Address *n = NULL;
398         int r;
399
400         assert(filename);
401         assert(section);
402         assert(lvalue);
403         assert(rvalue);
404         assert(network);
405
406         r = address_new_dynamic(&n);
407         if (r < 0)
408                 return r;
409
410         r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
411         if (r < 0) {
412                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
413                            "DNS address is invalid, ignoring assignment: %s", rvalue);
414                 return 0;
415         }
416
417         if (streq(lvalue, "DNS")) {
418                 LIST_FIND_TAIL(addresses, network->dns, tail);
419                 LIST_INSERT_AFTER(addresses, network->dns, tail, n);
420         } else if (streq(lvalue, "NTP")) {
421                 LIST_FIND_TAIL(addresses, network->ntp, tail);
422                 LIST_INSERT_AFTER(addresses, network->ntp, tail, n);
423         } else {
424                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
425                            "Key is invalid, ignoring assignment: %s=%s", lvalue, rvalue);
426                 return 0;
427         }
428
429         n = NULL;
430
431         return 0;
432 }
433
434 int config_parse_broadcast(const char *unit,
435                 const char *filename,
436                 unsigned line,
437                 const char *section,
438                 unsigned section_line,
439                 const char *lvalue,
440                 int ltype,
441                 const char *rvalue,
442                 void *data,
443                 void *userdata) {
444         Network *network = userdata;
445         _cleanup_address_free_ Address *n = NULL;
446         _cleanup_free_ char *address = NULL;
447         int r;
448
449         assert(filename);
450         assert(section);
451         assert(lvalue);
452         assert(rvalue);
453         assert(data);
454
455         r = address_new_static(network, section_line, &n);
456         if (r < 0)
457                 return r;
458
459         if (n->family == AF_INET6) {
460                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
461                            "Broadcast is not valid for IPv6 addresses, "
462                            "ignoring assignment: %s", address);
463                 return 0;
464         }
465
466         r = net_parse_inaddr(address, &n->family, &n->broadcast);
467         if (r < 0) {
468                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
469                            "Broadcast is invalid, ignoring assignment: %s", address);
470                 return 0;
471         }
472
473         n = NULL;
474
475         return 0;
476 }
477
478 int config_parse_address(const char *unit,
479                 const char *filename,
480                 unsigned line,
481                 const char *section,
482                 unsigned section_line,
483                 const char *lvalue,
484                 int ltype,
485                 const char *rvalue,
486                 void *data,
487                 void *userdata) {
488         Network *network = userdata;
489         _cleanup_address_free_ Address *n = NULL;
490         _cleanup_free_ char *address = NULL;
491         const char *e;
492         int r;
493
494         assert(filename);
495         assert(section);
496         assert(lvalue);
497         assert(rvalue);
498         assert(data);
499
500         if (streq(section, "Network")) {
501                 /* we are not in an Address section, so treat
502                  * this as the special '0' section */
503                 section_line = 0;
504         }
505
506         r = address_new_static(network, section_line, &n);
507         if (r < 0)
508                 return r;
509
510         /* Address=address/prefixlen */
511
512         /* prefixlen */
513         e = strchr(rvalue, '/');
514         if (e) {
515                 unsigned i;
516                 r = safe_atou(e + 1, &i);
517                 if (r < 0) {
518                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
519                                    "Interface prefix length is invalid, "
520                                    "ignoring assignment: %s", e + 1);
521                         return 0;
522                 }
523
524                 n->prefixlen = (unsigned char) i;
525
526                 address = strndup(rvalue, e - rvalue);
527                 if (!address)
528                         return log_oom();
529         } else {
530                 address = strdup(rvalue);
531                 if (!address)
532                         return log_oom();
533         }
534
535         r = net_parse_inaddr(address, &n->family, &n->in_addr);
536         if (r < 0) {
537                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
538                            "Address is invalid, ignoring assignment: %s", address);
539                 return 0;
540         }
541
542         if (n->family == AF_INET && !n->broadcast.s_addr)
543                 n->broadcast.s_addr = n->in_addr.in.s_addr |
544                                       htonl(0xfffffffflu >> n->prefixlen);
545
546         n = NULL;
547
548         return 0;
549 }
550
551 int config_parse_label(const char *unit,
552                 const char *filename,
553                 unsigned line,
554                 const char *section,
555                 unsigned section_line,
556                 const char *lvalue,
557                 int ltype,
558                 const char *rvalue,
559                 void *data,
560                 void *userdata) {
561         Network *network = userdata;
562         _cleanup_address_free_ Address *n = NULL;
563         char *label;
564         int r;
565
566         assert(filename);
567         assert(section);
568         assert(lvalue);
569         assert(rvalue);
570         assert(data);
571
572         r = address_new_static(network, section_line, &n);
573         if (r < 0)
574                 return r;
575
576         label = strdup(rvalue);
577         if (!label)
578                 return log_oom();
579
580         if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
581                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
582                            "Interface label is not ASCII clean or is too"
583                            " long, ignoring assignment: %s", rvalue);
584                 free(label);
585                 return 0;
586         }
587
588         free(n->label);
589         if (*label)
590                 n->label = label;
591         else {
592                 free(label);
593                 n->label = NULL;
594         }
595
596         n = NULL;
597
598         return 0;
599 }
600
601 bool address_equal(Address *a1, Address *a2) {
602         /* same object */
603         if (a1 == a2)
604                 return true;
605
606         /* one, but not both, is NULL */
607         if (!a1 || !a2)
608                 return false;
609
610         if (a1->family != a2->family)
611                 return false;
612
613         switch (a1->family) {
614         /* use the same notion of equality as the kernel does */
615         case AF_UNSPEC:
616                 return true;
617
618         case AF_INET:
619                 if (a1->prefixlen != a2->prefixlen)
620                         return false;
621                 else {
622                         uint32_t b1, b2;
623
624                         b1 = be32toh(a1->in_addr.in.s_addr);
625                         b2 = be32toh(a2->in_addr.in.s_addr);
626
627                         return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
628                 }
629
630         case AF_INET6:
631         {
632                 uint64_t *b1, *b2;
633
634                 b1 = (uint64_t*)&a1->in_addr.in6;
635                 b2 = (uint64_t*)&a2->in_addr.in6;
636
637                 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
638         }
639         default:
640                 assert_not_reached("Invalid address family");
641         }
642 }