LCOV - code coverage report
Current view: top level - network - networkd-network.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 132 395 33.4 %
Date: 2015-07-29 18:47:03 Functions: 5 22 22.7 %

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

Generated by: LCOV version 1.11