chiark / gitweb /
install: improve paths we show the user when enabling/disabling
[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 int address_configure(Address *address, Link *link,
232                       sd_rtnl_message_handler_t callback) {
233         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
234         int r;
235
236         assert(address);
237         assert(address->family == AF_INET || address->family == AF_INET6);
238         assert(link);
239         assert(link->ifindex > 0);
240         assert(link->manager);
241         assert(link->manager->rtnl);
242
243         r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
244                                      link->ifindex, address->family);
245         if (r < 0) {
246                 log_error("Could not allocate RTM_NEWADDR message: %s",
247                           strerror(-r));
248                 return r;
249         }
250
251         r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
252         if (r < 0) {
253                 log_error("Could not set prefixlen: %s", strerror(-r));
254                 return r;
255         }
256
257         r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
258         if (r < 0) {
259                 log_error("Could not set flags: %s", strerror(-r));
260                 return r;
261         }
262
263         r = sd_rtnl_message_addr_set_scope(req, address->scope);
264         if (r < 0) {
265                 log_error("Could not set scope: %s", strerror(-r));
266                 return r;
267         }
268
269         if (address->family == AF_INET)
270                 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
271         else if (address->family == AF_INET6)
272                 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
273         if (r < 0) {
274                 log_error("Could not append IFA_LOCAL attribute: %s",
275                           strerror(-r));
276                 return r;
277         }
278
279         if (address->family == AF_INET) {
280                 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
281                 if (r < 0) {
282                         log_error("Could not append IFA_BROADCAST attribute: %s",
283                                   strerror(-r));
284                         return r;
285                 }
286         }
287
288         if (address->label) {
289                 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
290                 if (r < 0) {
291                         log_error("Could not append IFA_LABEL attribute: %s",
292                                   strerror(-r));
293                         return r;
294                 }
295         }
296
297         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
298         if (r < 0) {
299                 log_error("Could not send rtnetlink message: %s", strerror(-r));
300                 return r;
301         }
302
303         return 0;
304 }
305
306 int config_parse_dns(const char *unit,
307                 const char *filename,
308                 unsigned line,
309                 const char *section,
310                 unsigned section_line,
311                 const char *lvalue,
312                 int ltype,
313                 const char *rvalue,
314                 void *data,
315                 void *userdata) {
316         Network *network = userdata;
317         Address *tail;
318         _cleanup_address_free_ Address *n = NULL;
319         int r;
320
321         assert(filename);
322         assert(section);
323         assert(lvalue);
324         assert(rvalue);
325         assert(network);
326
327         r = address_new_dynamic(&n);
328         if (r < 0)
329                 return r;
330
331         r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
332         if (r < 0) {
333                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
334                            "DNS address is invalid, ignoring assignment: %s", rvalue);
335                 return 0;
336         }
337
338         if (streq(lvalue, "DNS")) {
339                 LIST_FIND_TAIL(addresses, network->dns, tail);
340                 LIST_INSERT_AFTER(addresses, network->dns, tail, n);
341         } else if (streq(lvalue, "NTP")) {
342                 LIST_FIND_TAIL(addresses, network->ntp, tail);
343                 LIST_INSERT_AFTER(addresses, network->ntp, tail, n);
344         } else {
345                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
346                            "Key is invalid, ignoring assignment: %s=%s", lvalue, rvalue);
347                 return 0;
348         }
349
350         n = NULL;
351
352         return 0;
353 }
354
355 int config_parse_broadcast(const char *unit,
356                 const char *filename,
357                 unsigned line,
358                 const char *section,
359                 unsigned section_line,
360                 const char *lvalue,
361                 int ltype,
362                 const char *rvalue,
363                 void *data,
364                 void *userdata) {
365         Network *network = userdata;
366         _cleanup_address_free_ Address *n = NULL;
367         _cleanup_free_ char *address = NULL;
368         int r;
369
370         assert(filename);
371         assert(section);
372         assert(lvalue);
373         assert(rvalue);
374         assert(data);
375
376         r = address_new_static(network, section_line, &n);
377         if (r < 0)
378                 return r;
379
380         if (n->family == AF_INET6) {
381                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
382                            "Broadcast is not valid for IPv6 addresses, "
383                            "ignoring assignment: %s", address);
384                 return 0;
385         }
386
387         r = net_parse_inaddr(address, &n->family, &n->broadcast);
388         if (r < 0) {
389                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
390                            "Broadcast is invalid, ignoring assignment: %s", address);
391                 return 0;
392         }
393
394         n = NULL;
395
396         return 0;
397 }
398
399 int config_parse_address(const char *unit,
400                 const char *filename,
401                 unsigned line,
402                 const char *section,
403                 unsigned section_line,
404                 const char *lvalue,
405                 int ltype,
406                 const char *rvalue,
407                 void *data,
408                 void *userdata) {
409         Network *network = userdata;
410         _cleanup_address_free_ Address *n = NULL;
411         _cleanup_free_ char *address = NULL;
412         const char *e;
413         int r;
414
415         assert(filename);
416         assert(section);
417         assert(lvalue);
418         assert(rvalue);
419         assert(data);
420
421         if (streq(section, "Network")) {
422                 /* we are not in an Address section, so treat
423                  * this as the special '0' section */
424                 section_line = 0;
425         }
426
427         r = address_new_static(network, section_line, &n);
428         if (r < 0)
429                 return r;
430
431         /* Address=address/prefixlen */
432
433         /* prefixlen */
434         e = strchr(rvalue, '/');
435         if (e) {
436                 unsigned i;
437                 r = safe_atou(e + 1, &i);
438                 if (r < 0) {
439                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
440                                    "Interface prefix length is invalid, "
441                                    "ignoring assignment: %s", e + 1);
442                         return 0;
443                 }
444
445                 n->prefixlen = (unsigned char) i;
446
447                 address = strndup(rvalue, e - rvalue);
448                 if (!address)
449                         return log_oom();
450         } else {
451                 address = strdup(rvalue);
452                 if (!address)
453                         return log_oom();
454         }
455
456         r = net_parse_inaddr(address, &n->family, &n->in_addr);
457         if (r < 0) {
458                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
459                            "Address is invalid, ignoring assignment: %s", address);
460                 return 0;
461         }
462
463         if (n->family == AF_INET && !n->broadcast.s_addr)
464                 n->broadcast.s_addr = n->in_addr.in.s_addr |
465                                       htonl(0xfffffffflu >> n->prefixlen);
466
467         n = NULL;
468
469         return 0;
470 }
471
472 int config_parse_label(const char *unit,
473                 const char *filename,
474                 unsigned line,
475                 const char *section,
476                 unsigned section_line,
477                 const char *lvalue,
478                 int ltype,
479                 const char *rvalue,
480                 void *data,
481                 void *userdata) {
482         Network *network = userdata;
483         _cleanup_address_free_ Address *n = NULL;
484         char *label;
485         int r;
486
487         assert(filename);
488         assert(section);
489         assert(lvalue);
490         assert(rvalue);
491         assert(data);
492
493         r = address_new_static(network, section_line, &n);
494         if (r < 0)
495                 return r;
496
497         label = strdup(rvalue);
498         if (!label)
499                 return log_oom();
500
501         if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
502                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
503                            "Interface label is not ASCII clean or is too"
504                            " long, ignoring assignment: %s", rvalue);
505                 free(label);
506                 return 0;
507         }
508
509         free(n->label);
510         if (*label)
511                 n->label = label;
512         else {
513                 free(label);
514                 n->label = NULL;
515         }
516
517         n = NULL;
518
519         return 0;
520 }
521
522 bool address_equal(Address *a1, Address *a2) {
523         /* same object */
524         if (a1 == a2)
525                 return true;
526
527         /* one, but not both, is NULL */
528         if (!a1 || !a2)
529                 return false;
530
531         if (a1->family != a2->family)
532                 return false;
533
534         switch (a1->family) {
535         /* use the same notion of equality as the kernel does */
536         case AF_UNSPEC:
537                 return true;
538
539         case AF_INET:
540                 if (a1->prefixlen != a2->prefixlen)
541                         return false;
542                 else {
543                         uint32_t b1, b2;
544
545                         b1 = be32toh(a1->in_addr.in.s_addr);
546                         b2 = be32toh(a2->in_addr.in.s_addr);
547
548                         return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
549                 }
550
551         case AF_INET6:
552         {
553                 uint64_t *b1, *b2;
554
555                 b1 = (uint64_t*)&a1->in_addr.in6;
556                 b2 = (uint64_t*)&a2->in_addr.in6;
557
558                 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
559         }
560         default:
561                 assert_not_reached("Invalid address family");
562         }
563 }