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