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