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