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