chiark / gitweb /
c6cf00a5e5f63fe0a03641a0dc0392a2516f26f5
[elogind.git] / src / network / networkd-network.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 <ctype.h>
23 #include <net/if.h>
24
25 #include "conf-files.h"
26 #include "conf-parser.h"
27 #include "util.h"
28 #include "networkd.h"
29 #include "networkd-netdev.h"
30 #include "networkd-link.h"
31 #include "network-internal.h"
32
33 static int network_load_one(Manager *manager, const char *filename) {
34         _cleanup_network_free_ Network *network = NULL;
35         _cleanup_fclose_ FILE *file = NULL;
36         char *d;
37         Route *route;
38         Address *address;
39         int r;
40
41         assert(manager);
42         assert(filename);
43
44         file = fopen(filename, "re");
45         if (!file) {
46                 if (errno == ENOENT)
47                         return 0;
48                 else
49                         return -errno;
50         }
51
52         if (null_or_empty_fd(fileno(file))) {
53                 log_debug("Skipping empty file: %s", filename);
54                 return 0;
55         }
56
57         network = new0(Network, 1);
58         if (!network)
59                 return log_oom();
60
61         network->manager = manager;
62
63         LIST_HEAD_INIT(network->static_addresses);
64         LIST_HEAD_INIT(network->static_routes);
65         LIST_HEAD_INIT(network->static_fdb_entries);
66
67         network->stacked_netdevs = hashmap_new(&string_hash_ops);
68         if (!network->stacked_netdevs)
69                 return log_oom();
70
71         network->addresses_by_section = hashmap_new(NULL);
72         if (!network->addresses_by_section)
73                 return log_oom();
74
75         network->routes_by_section = hashmap_new(NULL);
76         if (!network->routes_by_section)
77                 return log_oom();
78
79         network->fdb_entries_by_section = hashmap_new(NULL);
80         if (!network->fdb_entries_by_section)
81                 return log_oom();
82
83         network->filename = strdup(filename);
84         if (!network->filename)
85                 return log_oom();
86
87         network->name = strdup(basename(filename));
88         if (!network->name)
89                 return log_oom();
90
91         d = strrchr(network->name, '.');
92         if (!d)
93                 return -EINVAL;
94
95         assert(streq(d, ".network"));
96
97         *d = '\0';
98
99         network->dhcp = ADDRESS_FAMILY_NO;
100         network->dhcp_ntp = true;
101         network->dhcp_dns = true;
102         network->dhcp_hostname = true;
103         network->dhcp_routes = true;
104         network->dhcp_sendhost = true;
105         network->dhcp_route_metric = DHCP_ROUTE_METRIC;
106
107         network->llmnr = LLMNR_SUPPORT_YES;
108
109         network->link_local = ADDRESS_FAMILY_IPV6;
110
111         r = config_parse(NULL, filename, file,
112                          "Match\0"
113                          "Link\0"
114                          "Network\0"
115                          "Address\0"
116                          "Route\0"
117                          "DHCP\0"
118                          "DHCPv4\0"
119                          "Bridge\0"
120                          "BridgeFDB\0",
121                          config_item_perf_lookup, network_network_gperf_lookup,
122                          false, false, true, network);
123         if (r < 0)
124                 return r;
125
126         /* IPMasquerade=yes implies IPForward=yes */
127         if (network->ip_masquerade)
128                 network->ip_forward |= ADDRESS_FAMILY_IPV4;
129
130         LIST_PREPEND(networks, manager->networks, network);
131
132         r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
133         if (r < 0)
134                 return r;
135
136         r = hashmap_put(manager->networks_by_name, network->name, network);
137         if (r < 0)
138                 return r;
139
140         LIST_FOREACH(routes, route, network->static_routes) {
141                 if (!route->family) {
142                         log_warning("Route section without Gateway field configured in %s. "
143                                     "Ignoring", filename);
144                         return 0;
145                 }
146         }
147
148         LIST_FOREACH(addresses, address, network->static_addresses) {
149                 if (!address->family) {
150                         log_warning("Address section without Address field configured in %s. "
151                                     "Ignoring", filename);
152                         return 0;
153                 }
154         }
155
156         network = NULL;
157
158         return 0;
159 }
160
161 int network_load(Manager *manager) {
162         Network *network;
163         _cleanup_strv_free_ char **files = NULL;
164         char **f;
165         int r;
166
167         assert(manager);
168
169         while ((network = manager->networks))
170                 network_free(network);
171
172         r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
173         if (r < 0)
174                 return log_error_errno(r, "Failed to enumerate network files: %m");
175
176         STRV_FOREACH_BACKWARDS(f, files) {
177                 r = network_load_one(manager, *f);
178                 if (r < 0)
179                         return r;
180         }
181
182         return 0;
183 }
184
185 void network_free(Network *network) {
186         NetDev *netdev;
187         Route *route;
188         Address *address;
189         FdbEntry *fdb_entry;
190         Iterator i;
191
192         if (!network)
193                 return;
194
195         free(network->filename);
196
197         free(network->match_mac);
198         strv_free(network->match_path);
199         strv_free(network->match_driver);
200         strv_free(network->match_type);
201         strv_free(network->match_name);
202
203         free(network->description);
204         free(network->dhcp_vendor_class_identifier);
205
206         free(network->mac);
207
208         strv_free(network->ntp);
209         strv_free(network->dns);
210         strv_free(network->domains);
211
212         netdev_unref(network->bridge);
213
214         netdev_unref(network->bond);
215
216         HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
217                 hashmap_remove(network->stacked_netdevs, netdev->ifname);
218                 netdev_unref(netdev);
219         }
220         hashmap_free(network->stacked_netdevs);
221
222         while ((route = network->static_routes))
223                 route_free(route);
224
225         while ((address = network->static_addresses))
226                 address_free(address);
227
228         while ((fdb_entry = network->static_fdb_entries))
229                 fdb_entry_free(fdb_entry);
230
231         hashmap_free(network->addresses_by_section);
232         hashmap_free(network->routes_by_section);
233         hashmap_free(network->fdb_entries_by_section);
234
235         if (network->manager) {
236                 if (network->manager->networks)
237                         LIST_REMOVE(networks, network->manager->networks, network);
238
239                 if (network->manager->networks_by_name)
240                         hashmap_remove(network->manager->networks_by_name, network->name);
241         }
242
243         free(network->name);
244
245         condition_free_list(network->match_host);
246         condition_free_list(network->match_virt);
247         condition_free_list(network->match_kernel);
248         condition_free_list(network->match_arch);
249
250         free(network);
251 }
252
253 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
254         Network *network;
255
256         assert(manager);
257         assert(name);
258         assert(ret);
259
260         network = hashmap_get(manager->networks_by_name, name);
261         if (!network)
262                 return -ENOENT;
263
264         *ret = network;
265
266         return 0;
267 }
268
269 int network_get(Manager *manager, struct udev_device *device,
270                 const char *ifname, const struct ether_addr *address,
271                 Network **ret) {
272         Network *network;
273
274         assert(manager);
275         assert(ret);
276
277         LIST_FOREACH(networks, network, manager->networks) {
278                 if (net_match_config(network->match_mac, network->match_path,
279                                      network->match_driver, network->match_type,
280                                      network->match_name, network->match_host,
281                                      network->match_virt, network->match_kernel,
282                                      network->match_arch,
283                                      address,
284                                      udev_device_get_property_value(device, "ID_PATH"),
285                                      udev_device_get_driver(udev_device_get_parent(device)),
286                                      udev_device_get_property_value(device, "ID_NET_DRIVER"),
287                                      udev_device_get_devtype(device),
288                                      ifname)) {
289                         if (network->match_name) {
290                                 const char *attr;
291                                 uint8_t name_assign_type = NET_NAME_UNKNOWN;
292
293                                 attr = udev_device_get_sysattr_value(device, "name_assign_type");
294                                 if (attr)
295                                         (void)safe_atou8(attr, &name_assign_type);
296
297                                 if (name_assign_type == NET_NAME_ENUM)
298                                         log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
299                                                     IFNAMSIZ, ifname, network->filename);
300                                 else
301                                         log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
302                         } else
303                                 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
304
305                         *ret = network;
306                         return 0;
307                 }
308         }
309
310         *ret = NULL;
311
312         return -ENOENT;
313 }
314
315 int network_apply(Manager *manager, Network *network, Link *link) {
316         int r;
317
318         link->network = network;
319
320         if (network->ipv4ll_route) {
321                 Route *route;
322
323                 r = route_new_static(network, 0, &route);
324                 if (r < 0)
325                         return r;
326
327                 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
328                 if (r == 0)
329                         return -EINVAL;
330                 if (r < 0)
331                         return -errno;
332
333                 route->family = AF_INET;
334                 route->dst_prefixlen = 16;
335                 route->scope = RT_SCOPE_LINK;
336                 route->metrics = IPV4LL_ROUTE_METRIC;
337                 route->protocol = RTPROT_STATIC;
338         }
339
340         if (network->dns || network->ntp) {
341                 r = link_save(link);
342                 if (r < 0)
343                         return r;
344         }
345
346         return 0;
347 }
348
349 int config_parse_netdev(const char *unit,
350                 const char *filename,
351                 unsigned line,
352                 const char *section,
353                 unsigned section_line,
354                 const char *lvalue,
355                 int ltype,
356                 const char *rvalue,
357                 void *data,
358                 void *userdata) {
359         Network *network = userdata;
360         _cleanup_free_ char *kind_string = NULL;
361         char *p;
362         NetDev *netdev;
363         NetDevKind kind;
364         int r;
365
366         assert(filename);
367         assert(lvalue);
368         assert(rvalue);
369         assert(data);
370
371         kind_string = strdup(lvalue);
372         if (!kind_string)
373                 return log_oom();
374
375         /* the keys are CamelCase versions of the kind */
376         for (p = kind_string; *p; p++)
377                 *p = tolower(*p);
378
379         kind = netdev_kind_from_string(kind_string);
380         if (kind == _NETDEV_KIND_INVALID) {
381                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
382                            "Invalid NetDev kind: %s", lvalue);
383                 return 0;
384         }
385
386         r = netdev_get(network->manager, rvalue, &netdev);
387         if (r < 0) {
388                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
389                            "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
390                 return 0;
391         }
392
393         if (netdev->kind != kind) {
394                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
395                            "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
396                 return 0;
397         }
398
399         switch (kind) {
400         case NETDEV_KIND_BRIDGE:
401                 network->bridge = netdev;
402
403                 break;
404         case NETDEV_KIND_BOND:
405                 network->bond = netdev;
406
407                 break;
408         case NETDEV_KIND_VLAN:
409         case NETDEV_KIND_MACVLAN:
410         case NETDEV_KIND_IPVLAN:
411         case NETDEV_KIND_VXLAN:
412                 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
413                 if (r < 0) {
414                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
415                                    "Can not add VLAN '%s' to network: %s",
416                                    rvalue, strerror(-r));
417                         return 0;
418                 }
419
420                 break;
421         default:
422                 assert_not_reached("Can not parse NetDev");
423         }
424
425         netdev_ref(netdev);
426
427         return 0;
428 }
429
430 int config_parse_domains(const char *unit,
431                          const char *filename,
432                          unsigned line,
433                          const char *section,
434                          unsigned section_line,
435                          const char *lvalue,
436                          int ltype,
437                          const char *rvalue,
438                          void *data,
439                          void *userdata) {
440         Network *network = userdata;
441         char ***domains = data;
442         char **domain;
443         int r;
444
445         r = config_parse_strv(unit, filename, line, section, section_line,
446                               lvalue, ltype, rvalue, domains, userdata);
447         if (r < 0)
448                 return r;
449
450         strv_uniq(*domains);
451         network->wildcard_domain = !!strv_find(*domains, "*");
452
453         STRV_FOREACH(domain, *domains) {
454                 if (is_localhost(*domain))
455                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
456                 else if (!hostname_is_valid(*domain)) {
457                         if (!streq(*domain, "*"))
458                                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "domain name is not valid, ignoring assignment: %s", *domain);
459                 } else
460                         continue;
461
462                 strv_remove(*domains, *domain);
463
464                 /* We removed one entry, make sure we don't skip the next one */
465                 domain--;
466         }
467
468         return 0;
469 }
470
471 int config_parse_tunnel(const char *unit,
472                         const char *filename,
473                         unsigned line,
474                         const char *section,
475                         unsigned section_line,
476                         const char *lvalue,
477                         int ltype,
478                         const char *rvalue,
479                         void *data,
480                         void *userdata) {
481         Network *network = userdata;
482         NetDev *netdev;
483         int r;
484
485         assert(filename);
486         assert(lvalue);
487         assert(rvalue);
488         assert(data);
489
490         r = netdev_get(network->manager, rvalue, &netdev);
491         if (r < 0) {
492                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
493                            "Tunnel is invalid, ignoring assignment: %s", rvalue);
494                 return 0;
495         }
496
497         if (netdev->kind != NETDEV_KIND_IPIP &&
498             netdev->kind != NETDEV_KIND_SIT &&
499             netdev->kind != NETDEV_KIND_GRE &&
500             netdev->kind != NETDEV_KIND_GRETAP &&
501             netdev->kind != NETDEV_KIND_IP6GRE &&
502             netdev->kind != NETDEV_KIND_IP6GRETAP &&
503             netdev->kind != NETDEV_KIND_VTI &&
504             netdev->kind != NETDEV_KIND_IP6TNL
505             ) {
506                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
507                            "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
508                 return 0;
509         }
510
511         r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
512         if (r < 0) {
513                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
514                            "Can not add VLAN '%s' to network: %s",
515                            rvalue, strerror(-r));
516                 return 0;
517         }
518
519         netdev_ref(netdev);
520
521         return 0;
522 }
523
524 int config_parse_ipv4ll(
525                 const char* unit,
526                 const char *filename,
527                 unsigned line,
528                 const char *section,
529                 unsigned section_line,
530                 const char *lvalue,
531                 int ltype,
532                 const char *rvalue,
533                 void *data,
534                 void *userdata) {
535
536         AddressFamilyBoolean *link_local = data;
537
538         assert(filename);
539         assert(lvalue);
540         assert(rvalue);
541         assert(data);
542
543         /* Note that this is mostly like
544          * config_parse_address_family_boolean(), except that it
545          * applies only to IPv4 */
546
547         if (parse_boolean(rvalue))
548                 *link_local |= ADDRESS_FAMILY_IPV4;
549         else
550                 *link_local &= ~ADDRESS_FAMILY_IPV4;
551
552         return 0;
553 }
554
555 int config_parse_dhcp(
556                 const char* unit,
557                 const char *filename,
558                 unsigned line,
559                 const char *section,
560                 unsigned section_line,
561                 const char *lvalue,
562                 int ltype,
563                 const char *rvalue,
564                 void *data,
565                 void *userdata) {
566
567         AddressFamilyBoolean *dhcp = data, s;
568
569         assert(filename);
570         assert(lvalue);
571         assert(rvalue);
572         assert(data);
573
574         /* Note that this is mostly like
575          * config_parse_address_family_boolean(), except that it
576          * understands some old names for the enum values */
577
578         s = address_family_boolean_from_string(rvalue);
579         if (s < 0) {
580
581                 /* Previously, we had a slightly different enum here,
582                  * support its values for compatbility. */
583
584                 if (streq(rvalue, "none"))
585                         s = ADDRESS_FAMILY_NO;
586                 else if (streq(rvalue, "v4"))
587                         s = ADDRESS_FAMILY_IPV4;
588                 else if (streq(rvalue, "v6"))
589                         s = ADDRESS_FAMILY_IPV6;
590                 else if (streq(rvalue, "both"))
591                         s = ADDRESS_FAMILY_YES;
592                 else {
593                         log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
594                         return 0;
595                 }
596         }
597
598         *dhcp = s;
599         return 0;
600 }
601
602 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
603         [LLMNR_SUPPORT_NO] = "no",
604         [LLMNR_SUPPORT_YES] = "yes",
605         [LLMNR_SUPPORT_RESOLVE] = "resolve",
606 };
607
608 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
609
610 int config_parse_llmnr(
611                 const char* unit,
612                 const char *filename,
613                 unsigned line,
614                 const char *section,
615                 unsigned section_line,
616                 const char *lvalue,
617                 int ltype,
618                 const char *rvalue,
619                 void *data,
620                 void *userdata) {
621
622         LLMNRSupport *llmnr = data;
623         int k;
624
625         assert(filename);
626         assert(lvalue);
627         assert(rvalue);
628         assert(llmnr);
629
630         /* Our enum shall be a superset of booleans, hence first try
631          * to parse as boolean, and then as enum */
632
633         k = parse_boolean(rvalue);
634         if (k > 0)
635                 *llmnr = LLMNR_SUPPORT_YES;
636         else if (k == 0)
637                 *llmnr = LLMNR_SUPPORT_NO;
638         else {
639                 LLMNRSupport s;
640
641                 s = llmnr_support_from_string(rvalue);
642                 if (s < 0){
643                         log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);
644                         return 0;
645                 }
646
647                 *llmnr = s;
648         }
649
650         return 0;
651 }
652
653 int config_parse_ipv6token(
654                 const char* unit,
655                 const char *filename,
656                 unsigned line,
657                 const char *section,
658                 unsigned section_line,
659                 const char *lvalue,
660                 int ltype,
661                 const char *rvalue,
662                 void *data,
663                 void *userdata) {
664
665         union in_addr_union buffer;
666         struct in6_addr *token = data;
667         int r;
668
669         assert(filename);
670         assert(lvalue);
671         assert(rvalue);
672         assert(token);
673
674         r = in_addr_from_string(AF_INET6, rvalue, &buffer);
675         if (r < 0) {
676                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
677                 return 0;
678         }
679
680         r = in_addr_is_null(AF_INET6, &buffer);
681         if (r < 0) {
682                 log_syntax(unit, LOG_ERR, filename, line, -r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
683                 return 0;
684         }
685
686         if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
687                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
688                 return 0;
689         }
690
691         *token = buffer.in6;
692
693         return 0;
694 }