LCOV - code coverage report
Current view: top level - libsystemd-network - sd-dhcp-lease.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 173 759 22.8 %
Date: 2019-08-22 15:41:25 Functions: 14 43 32.6 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : /***
       3             :   Copyright © 2013 Intel Corporation. All rights reserved.
       4             : ***/
       5             : 
       6             : #include <arpa/inet.h>
       7             : #include <errno.h>
       8             : #include <stdio.h>
       9             : #include <stdlib.h>
      10             : #include <string.h>
      11             : #include <sys/stat.h>
      12             : #include <sys/types.h>
      13             : #include <unistd.h>
      14             : 
      15             : #include "sd-dhcp-lease.h"
      16             : 
      17             : #include "alloc-util.h"
      18             : #include "dhcp-lease-internal.h"
      19             : #include "dhcp-protocol.h"
      20             : #include "dns-domain.h"
      21             : #include "env-file.h"
      22             : #include "fd-util.h"
      23             : #include "fileio.h"
      24             : #include "hexdecoct.h"
      25             : #include "hostname-util.h"
      26             : #include "in-addr-util.h"
      27             : #include "network-internal.h"
      28             : #include "parse-util.h"
      29             : #include "stdio-util.h"
      30             : #include "string-util.h"
      31             : #include "strv.h"
      32             : #include "tmpfile-util.h"
      33             : #include "unaligned.h"
      34             : 
      35           1 : int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
      36           1 :         assert_return(lease, -EINVAL);
      37           1 :         assert_return(addr, -EINVAL);
      38             : 
      39           1 :         if (lease->address == 0)
      40           0 :                 return -ENODATA;
      41             : 
      42           1 :         addr->s_addr = lease->address;
      43           1 :         return 0;
      44             : }
      45             : 
      46           0 : int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
      47           0 :         assert_return(lease, -EINVAL);
      48           0 :         assert_return(addr, -EINVAL);
      49             : 
      50           0 :         if (!lease->have_broadcast)
      51           0 :                 return -ENODATA;
      52             : 
      53           0 :         addr->s_addr = lease->broadcast;
      54           0 :         return 0;
      55             : }
      56             : 
      57           0 : int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
      58           0 :         assert_return(lease, -EINVAL);
      59           0 :         assert_return(lifetime, -EINVAL);
      60             : 
      61           0 :         if (lease->lifetime <= 0)
      62           0 :                 return -ENODATA;
      63             : 
      64           0 :         *lifetime = lease->lifetime;
      65           0 :         return 0;
      66             : }
      67             : 
      68           0 : int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) {
      69           0 :         assert_return(lease, -EINVAL);
      70           0 :         assert_return(t1, -EINVAL);
      71             : 
      72           0 :         if (lease->t1 <= 0)
      73           0 :                 return -ENODATA;
      74             : 
      75           0 :         *t1 = lease->t1;
      76           0 :         return 0;
      77             : }
      78             : 
      79           0 : int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) {
      80           0 :         assert_return(lease, -EINVAL);
      81           0 :         assert_return(t2, -EINVAL);
      82             : 
      83           0 :         if (lease->t2 <= 0)
      84           0 :                 return -ENODATA;
      85             : 
      86           0 :         *t2 = lease->t2;
      87           0 :         return 0;
      88             : }
      89             : 
      90           0 : int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
      91           0 :         assert_return(lease, -EINVAL);
      92           0 :         assert_return(mtu, -EINVAL);
      93             : 
      94           0 :         if (lease->mtu <= 0)
      95           0 :                 return -ENODATA;
      96             : 
      97           0 :         *mtu = lease->mtu;
      98           0 :         return 0;
      99             : }
     100             : 
     101           0 : int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
     102           0 :         assert_return(lease, -EINVAL);
     103           0 :         assert_return(addr, -EINVAL);
     104             : 
     105           0 :         if (lease->dns_size <= 0)
     106           0 :                 return -ENODATA;
     107             : 
     108           0 :         *addr = lease->dns;
     109           0 :         return (int) lease->dns_size;
     110             : }
     111             : 
     112           0 : int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
     113           0 :         assert_return(lease, -EINVAL);
     114           0 :         assert_return(addr, -EINVAL);
     115             : 
     116           0 :         if (lease->ntp_size <= 0)
     117           0 :                 return -ENODATA;
     118             : 
     119           0 :         *addr = lease->ntp;
     120           0 :         return (int) lease->ntp_size;
     121             : }
     122             : 
     123           0 : int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
     124           0 :         assert_return(lease, -EINVAL);
     125           0 :         assert_return(domainname, -EINVAL);
     126             : 
     127           0 :         if (!lease->domainname)
     128           0 :                 return -ENODATA;
     129             : 
     130           0 :         *domainname = lease->domainname;
     131           0 :         return 0;
     132             : }
     133             : 
     134           0 : int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
     135           0 :         assert_return(lease, -EINVAL);
     136           0 :         assert_return(hostname, -EINVAL);
     137             : 
     138           0 :         if (!lease->hostname)
     139           0 :                 return -ENODATA;
     140             : 
     141           0 :         *hostname = lease->hostname;
     142           0 :         return 0;
     143             : }
     144             : 
     145           0 : int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
     146           0 :         assert_return(lease, -EINVAL);
     147           0 :         assert_return(root_path, -EINVAL);
     148             : 
     149           0 :         if (!lease->root_path)
     150           0 :                 return -ENODATA;
     151             : 
     152           0 :         *root_path = lease->root_path;
     153           0 :         return 0;
     154             : }
     155             : 
     156           1 : int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
     157           1 :         assert_return(lease, -EINVAL);
     158           1 :         assert_return(addr, -EINVAL);
     159             : 
     160           1 :         if (lease->router_size <= 0)
     161           0 :                 return -ENODATA;
     162             : 
     163           1 :         *addr = lease->router;
     164           1 :         return (int) lease->router_size;
     165             : }
     166             : 
     167           1 : int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
     168           1 :         assert_return(lease, -EINVAL);
     169           1 :         assert_return(addr, -EINVAL);
     170             : 
     171           1 :         if (!lease->have_subnet_mask)
     172           0 :                 return -ENODATA;
     173             : 
     174           1 :         addr->s_addr = lease->subnet_mask;
     175           1 :         return 0;
     176             : }
     177             : 
     178           0 : int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
     179           0 :         assert_return(lease, -EINVAL);
     180           0 :         assert_return(addr, -EINVAL);
     181             : 
     182           0 :         if (lease->server_address == 0)
     183           0 :                 return -ENODATA;
     184             : 
     185           0 :         addr->s_addr = lease->server_address;
     186           0 :         return 0;
     187             : }
     188             : 
     189           0 : int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
     190           0 :         assert_return(lease, -EINVAL);
     191           0 :         assert_return(addr, -EINVAL);
     192             : 
     193           0 :         if (lease->next_server == 0)
     194           0 :                 return -ENODATA;
     195             : 
     196           0 :         addr->s_addr = lease->next_server;
     197           0 :         return 0;
     198             : }
     199             : 
     200             : /*
     201             :  * The returned routes array must be freed by the caller.
     202             :  * Route objects have the same lifetime of the lease and must not be freed.
     203             :  */
     204           0 : int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
     205             :         sd_dhcp_route **ret;
     206             :         unsigned i;
     207             : 
     208           0 :         assert_return(lease, -EINVAL);
     209           0 :         assert_return(routes, -EINVAL);
     210             : 
     211           0 :         if (lease->static_route_size <= 0)
     212           0 :                 return -ENODATA;
     213             : 
     214           0 :         ret = new(sd_dhcp_route *, lease->static_route_size);
     215           0 :         if (!ret)
     216           0 :                 return -ENOMEM;
     217             : 
     218           0 :         for (i = 0; i < lease->static_route_size; i++)
     219           0 :                 ret[i] = &lease->static_route[i];
     220             : 
     221           0 :         *routes = ret;
     222           0 :         return (int) lease->static_route_size;
     223             : }
     224             : 
     225           0 : int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
     226             :         size_t r;
     227             : 
     228           0 :         assert_return(lease, -EINVAL);
     229           0 :         assert_return(domains, -EINVAL);
     230             : 
     231           0 :         r = strv_length(lease->search_domains);
     232           0 :         if (r > 0) {
     233           0 :                 *domains = lease->search_domains;
     234           0 :                 return (int) r;
     235             :         }
     236             : 
     237           0 :         return -ENODATA;
     238             : }
     239             : 
     240           0 : int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
     241           0 :         assert_return(lease, -EINVAL);
     242           0 :         assert_return(data, -EINVAL);
     243           0 :         assert_return(data_len, -EINVAL);
     244             : 
     245           0 :         if (lease->vendor_specific_len <= 0)
     246           0 :                 return -ENODATA;
     247             : 
     248           0 :         *data = lease->vendor_specific;
     249           0 :         *data_len = lease->vendor_specific_len;
     250           0 :         return 0;
     251             : }
     252             : 
     253           1 : static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
     254           1 :         assert(lease);
     255             : 
     256           1 :         while (lease->private_options) {
     257           0 :                 struct sd_dhcp_raw_option *option = lease->private_options;
     258             : 
     259           0 :                 LIST_REMOVE(options, lease->private_options, option);
     260             : 
     261           0 :                 free(option->data);
     262           0 :                 free(option);
     263             :         }
     264             : 
     265           1 :         free(lease->root_path);
     266           1 :         free(lease->router);
     267           1 :         free(lease->timezone);
     268           1 :         free(lease->hostname);
     269           1 :         free(lease->domainname);
     270           1 :         free(lease->dns);
     271           1 :         free(lease->ntp);
     272           1 :         free(lease->static_route);
     273           1 :         free(lease->client_id);
     274           1 :         free(lease->vendor_specific);
     275           1 :         strv_free(lease->search_domains);
     276           1 :         return mfree(lease);
     277             : }
     278             : 
     279          19 : DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_lease, sd_dhcp_lease, dhcp_lease_free);
     280             : 
     281           1 : static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
     282           1 :         assert(option);
     283           1 :         assert(ret);
     284             : 
     285           1 :         if (len != 4)
     286           0 :                 return -EINVAL;
     287             : 
     288           1 :         *ret = unaligned_read_be32((be32_t*) option);
     289           1 :         if (*ret < min)
     290           0 :                 *ret = min;
     291             : 
     292           1 :         return 0;
     293             : }
     294             : 
     295           0 : static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
     296           0 :         assert(option);
     297           0 :         assert(ret);
     298             : 
     299           0 :         if (len != 2)
     300           0 :                 return -EINVAL;
     301             : 
     302           0 :         *ret = unaligned_read_be16((be16_t*) option);
     303           0 :         if (*ret < min)
     304           0 :                 *ret = min;
     305             : 
     306           0 :         return 0;
     307             : }
     308             : 
     309           2 : static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
     310           2 :         assert(option);
     311           2 :         assert(ret);
     312             : 
     313           2 :         if (len != 4)
     314           0 :                 return -EINVAL;
     315             : 
     316           2 :         memcpy(ret, option, 4);
     317           2 :         return 0;
     318             : }
     319             : 
     320           1 : static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
     321           1 :         assert(option);
     322           1 :         assert(ret);
     323             : 
     324           1 :         if (len <= 0)
     325           0 :                 *ret = mfree(*ret);
     326             :         else {
     327             :                 char *string;
     328             : 
     329             :                 /*
     330             :                  * One trailing NUL byte is OK, we don't mind. See:
     331             :                  * https://github.com/systemd/systemd/issues/1337
     332             :                  */
     333           1 :                 if (memchr(option, 0, len - 1))
     334           0 :                         return -EINVAL;
     335             : 
     336           1 :                 string = memdup_suffix0((const char *) option, len);
     337           1 :                 if (!string)
     338           0 :                         return -ENOMEM;
     339             : 
     340           1 :                 free_and_replace(*ret, string);
     341             :         }
     342             : 
     343           1 :         return 0;
     344             : }
     345             : 
     346           1 : static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
     347           1 :         _cleanup_free_ char *name = NULL, *normalized = NULL;
     348             :         int r;
     349             : 
     350           1 :         assert(option);
     351           1 :         assert(ret);
     352             : 
     353           1 :         r = lease_parse_string(option, len, &name);
     354           1 :         if (r < 0)
     355           0 :                 return r;
     356           1 :         if (!name) {
     357           0 :                 *ret = mfree(*ret);
     358           0 :                 return 0;
     359             :         }
     360             : 
     361           1 :         r = dns_name_normalize(name, 0, &normalized);
     362           1 :         if (r < 0)
     363           0 :                 return r;
     364             : 
     365           1 :         if (is_localhost(normalized))
     366           0 :                 return -EINVAL;
     367             : 
     368           1 :         if (dns_name_is_root(normalized))
     369           0 :                 return -EINVAL;
     370             : 
     371           1 :         free_and_replace(*ret, normalized);
     372             : 
     373           1 :         return 0;
     374             : }
     375             : 
     376           2 : static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
     377           2 :         assert(option);
     378           2 :         assert(ret);
     379           2 :         assert(n_ret);
     380             : 
     381           2 :         if (len <= 0) {
     382           0 :                 *ret = mfree(*ret);
     383           0 :                 *n_ret = 0;
     384             :         } else {
     385             :                 size_t n_addresses;
     386             :                 struct in_addr *addresses;
     387             : 
     388           2 :                 if (len % 4 != 0)
     389           0 :                         return -EINVAL;
     390             : 
     391           2 :                 n_addresses = len / 4;
     392             : 
     393           2 :                 addresses = newdup(struct in_addr, option, n_addresses);
     394           2 :                 if (!addresses)
     395           0 :                         return -ENOMEM;
     396             : 
     397           2 :                 free(*ret);
     398           2 :                 *ret = addresses;
     399           2 :                 *n_ret = n_addresses;
     400             :         }
     401             : 
     402           2 :         return 0;
     403             : }
     404             : 
     405           0 : static int lease_parse_routes(
     406             :                 const uint8_t *option, size_t len,
     407             :                 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
     408             : 
     409             :         struct in_addr addr;
     410             : 
     411           0 :         assert(option || len <= 0);
     412           0 :         assert(routes);
     413           0 :         assert(routes_size);
     414           0 :         assert(routes_allocated);
     415             : 
     416           0 :         if (len <= 0)
     417           0 :                 return 0;
     418             : 
     419           0 :         if (len % 8 != 0)
     420           0 :                 return -EINVAL;
     421             : 
     422           0 :         if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
     423           0 :                 return -ENOMEM;
     424             : 
     425           0 :         while (len >= 8) {
     426           0 :                 struct sd_dhcp_route *route = *routes + *routes_size;
     427             :                 int r;
     428             : 
     429           0 :                 route->option = SD_DHCP_OPTION_STATIC_ROUTE;
     430           0 :                 r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
     431           0 :                 if (r < 0) {
     432           0 :                         log_debug("Failed to determine destination prefix length from class based IP, ignoring");
     433           0 :                         continue;
     434             :                 }
     435             : 
     436           0 :                 assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0);
     437           0 :                 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
     438           0 :                 option += 4;
     439             : 
     440           0 :                 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
     441           0 :                 option += 4;
     442             : 
     443           0 :                 len -= 8;
     444           0 :                 (*routes_size)++;
     445             :         }
     446             : 
     447           0 :         return 0;
     448             : }
     449             : 
     450             : /* parses RFC3442 Classless Static Route Option */
     451           0 : static int lease_parse_classless_routes(
     452             :                 const uint8_t *option, size_t len,
     453             :                 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
     454             : 
     455           0 :         assert(option || len <= 0);
     456           0 :         assert(routes);
     457           0 :         assert(routes_size);
     458           0 :         assert(routes_allocated);
     459             : 
     460           0 :         if (len <= 0)
     461           0 :                 return 0;
     462             : 
     463             :         /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)*  */
     464             : 
     465           0 :         while (len > 0) {
     466             :                 uint8_t dst_octets;
     467             :                 struct sd_dhcp_route *route;
     468             : 
     469           0 :                 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
     470           0 :                         return -ENOMEM;
     471             : 
     472           0 :                 route = *routes + *routes_size;
     473           0 :                 route->option = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE;
     474             : 
     475           0 :                 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
     476           0 :                 route->dst_prefixlen = *option;
     477           0 :                 option++;
     478           0 :                 len--;
     479             : 
     480             :                 /* can't have more than 4 octets in IPv4 */
     481           0 :                 if (dst_octets > 4 || len < dst_octets)
     482           0 :                         return -EINVAL;
     483             : 
     484           0 :                 route->dst_addr.s_addr = 0;
     485           0 :                 memcpy(&route->dst_addr.s_addr, option, dst_octets);
     486           0 :                 option += dst_octets;
     487           0 :                 len -= dst_octets;
     488             : 
     489           0 :                 if (len < 4)
     490           0 :                         return -EINVAL;
     491             : 
     492           0 :                 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
     493           0 :                 option += 4;
     494           0 :                 len -= 4;
     495             : 
     496           0 :                 (*routes_size)++;
     497             :         }
     498             : 
     499           0 :         return 0;
     500             : }
     501             : 
     502           6 : int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
     503           6 :         sd_dhcp_lease *lease = userdata;
     504             :         int r;
     505             : 
     506           6 :         assert(lease);
     507             : 
     508           6 :         switch(code) {
     509             : 
     510           1 :         case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
     511           1 :                 r = lease_parse_u32(option, len, &lease->lifetime, 1);
     512           1 :                 if (r < 0)
     513           0 :                         log_debug_errno(r, "Failed to parse lease time, ignoring: %m");
     514             : 
     515           1 :                 break;
     516             : 
     517           1 :         case SD_DHCP_OPTION_SERVER_IDENTIFIER:
     518           1 :                 r = lease_parse_be32(option, len, &lease->server_address);
     519           1 :                 if (r < 0)
     520           0 :                         log_debug_errno(r, "Failed to parse server identifier, ignoring: %m");
     521             : 
     522           1 :                 break;
     523             : 
     524           1 :         case SD_DHCP_OPTION_SUBNET_MASK:
     525           1 :                 r = lease_parse_be32(option, len, &lease->subnet_mask);
     526           1 :                 if (r < 0)
     527           0 :                         log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m");
     528             :                 else
     529           1 :                         lease->have_subnet_mask = true;
     530           1 :                 break;
     531             : 
     532           0 :         case SD_DHCP_OPTION_BROADCAST:
     533           0 :                 r = lease_parse_be32(option, len, &lease->broadcast);
     534           0 :                 if (r < 0)
     535           0 :                         log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m");
     536             :                 else
     537           0 :                         lease->have_broadcast = true;
     538           0 :                 break;
     539             : 
     540           1 :         case SD_DHCP_OPTION_ROUTER:
     541           1 :                 r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size);
     542           1 :                 if (r < 0)
     543           0 :                         log_debug_errno(r, "Failed to parse router addresses, ignoring: %m");
     544           1 :                 break;
     545             : 
     546           0 :         case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
     547           0 :                 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
     548           0 :                 if (r < 0)
     549           0 :                         log_debug_errno(r, "Failed to parse DNS server, ignoring: %m");
     550           0 :                 break;
     551             : 
     552           1 :         case SD_DHCP_OPTION_NTP_SERVER:
     553           1 :                 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
     554           1 :                 if (r < 0)
     555           0 :                         log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
     556           1 :                 break;
     557             : 
     558           0 :         case SD_DHCP_OPTION_STATIC_ROUTE:
     559           0 :                 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated);
     560           0 :                 if (r < 0)
     561           0 :                         log_debug_errno(r, "Failed to parse static routes, ignoring: %m");
     562           0 :                 break;
     563             : 
     564           0 :         case SD_DHCP_OPTION_INTERFACE_MTU:
     565           0 :                 r = lease_parse_u16(option, len, &lease->mtu, 68);
     566           0 :                 if (r < 0)
     567           0 :                         log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
     568           0 :                 if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
     569           0 :                         log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
     570           0 :                         lease->mtu = DHCP_DEFAULT_MIN_SIZE;
     571             :                 }
     572             : 
     573           0 :                 break;
     574             : 
     575           1 :         case SD_DHCP_OPTION_DOMAIN_NAME:
     576           1 :                 r = lease_parse_domain(option, len, &lease->domainname);
     577           1 :                 if (r < 0) {
     578           0 :                         log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
     579           0 :                         return 0;
     580             :                 }
     581             : 
     582           1 :                 break;
     583             : 
     584           0 :         case SD_DHCP_OPTION_DOMAIN_SEARCH_LIST:
     585           0 :                 r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains);
     586           0 :                 if (r < 0)
     587           0 :                         log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m");
     588           0 :                 break;
     589             : 
     590           0 :         case SD_DHCP_OPTION_HOST_NAME:
     591           0 :                 r = lease_parse_domain(option, len, &lease->hostname);
     592           0 :                 if (r < 0) {
     593           0 :                         log_debug_errno(r, "Failed to parse host name, ignoring: %m");
     594           0 :                         return 0;
     595             :                 }
     596             : 
     597           0 :                 break;
     598             : 
     599           0 :         case SD_DHCP_OPTION_ROOT_PATH:
     600           0 :                 r = lease_parse_string(option, len, &lease->root_path);
     601           0 :                 if (r < 0)
     602           0 :                         log_debug_errno(r, "Failed to parse root path, ignoring: %m");
     603           0 :                 break;
     604             : 
     605           0 :         case SD_DHCP_OPTION_RENEWAL_T1_TIME:
     606           0 :                 r = lease_parse_u32(option, len, &lease->t1, 1);
     607           0 :                 if (r < 0)
     608           0 :                         log_debug_errno(r, "Failed to parse T1 time, ignoring: %m");
     609           0 :                 break;
     610             : 
     611           0 :         case SD_DHCP_OPTION_REBINDING_T2_TIME:
     612           0 :                 r = lease_parse_u32(option, len, &lease->t2, 1);
     613           0 :                 if (r < 0)
     614           0 :                         log_debug_errno(r, "Failed to parse T2 time, ignoring: %m");
     615           0 :                 break;
     616             : 
     617           0 :         case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
     618           0 :                 r = lease_parse_classless_routes(
     619             :                                 option, len,
     620             :                                 &lease->static_route,
     621             :                                 &lease->static_route_size,
     622             :                                 &lease->static_route_allocated);
     623           0 :                 if (r < 0)
     624           0 :                         log_debug_errno(r, "Failed to parse classless routes, ignoring: %m");
     625           0 :                 break;
     626             : 
     627           0 :         case SD_DHCP_OPTION_NEW_TZDB_TIMEZONE: {
     628           0 :                 _cleanup_free_ char *tz = NULL;
     629             : 
     630           0 :                 r = lease_parse_string(option, len, &tz);
     631           0 :                 if (r < 0) {
     632           0 :                         log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
     633           0 :                         return 0;
     634             :                 }
     635             : 
     636           0 :                 if (!timezone_is_valid(tz, LOG_DEBUG)) {
     637           0 :                         log_debug_errno(r, "Timezone is not valid, ignoring: %m");
     638           0 :                         return 0;
     639             :                 }
     640             : 
     641           0 :                 free_and_replace(lease->timezone, tz);
     642             : 
     643           0 :                 break;
     644             :         }
     645             : 
     646           0 :         case SD_DHCP_OPTION_VENDOR_SPECIFIC:
     647             : 
     648           0 :                 if (len <= 0)
     649           0 :                         lease->vendor_specific = mfree(lease->vendor_specific);
     650             :                 else {
     651             :                         void *p;
     652             : 
     653           0 :                         p = memdup(option, len);
     654           0 :                         if (!p)
     655           0 :                                 return -ENOMEM;
     656             : 
     657           0 :                         free(lease->vendor_specific);
     658           0 :                         lease->vendor_specific = p;
     659             :                 }
     660             : 
     661           0 :                 lease->vendor_specific_len = len;
     662           0 :                 break;
     663             : 
     664           0 :         case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST:
     665           0 :                 r = dhcp_lease_insert_private_option(lease, code, option, len);
     666           0 :                 if (r < 0)
     667           0 :                         return r;
     668             : 
     669           0 :                 break;
     670             : 
     671           0 :         default:
     672           0 :                 log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code);
     673           0 :                 break;
     674             :         }
     675             : 
     676           6 :         return 0;
     677             : }
     678             : 
     679             : /* Parses compressed domain names. */
     680           7 : int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains) {
     681           7 :         _cleanup_strv_free_ char **names = NULL;
     682           7 :         size_t pos = 0, cnt = 0;
     683             :         int r;
     684             : 
     685           7 :         assert(domains);
     686           7 :         assert_return(option && len > 0, -ENODATA);
     687             : 
     688          13 :         while (pos < len) {
     689          10 :                 _cleanup_free_ char *name = NULL;
     690          10 :                 size_t n = 0, allocated = 0;
     691          10 :                 size_t jump_barrier = pos, next_chunk = 0;
     692          10 :                 bool first = true;
     693             : 
     694          16 :                 for (;;) {
     695             :                         uint8_t c;
     696          26 :                         c = option[pos++];
     697             : 
     698          26 :                         if (c == 0) {
     699             :                                 /* End of name */
     700           8 :                                 break;
     701          18 :                         } else if (c <= 63) {
     702             :                                 const char *label;
     703             : 
     704             :                                 /* Literal label */
     705          15 :                                 label = (const char*) (option + pos);
     706          15 :                                 pos += c;
     707          15 :                                 if (pos >= len)
     708           1 :                                         return -EBADMSG;
     709             : 
     710          14 :                                 if (!GREEDY_REALLOC(name, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
     711           0 :                                         return -ENOMEM;
     712             : 
     713          14 :                                 if (first)
     714           9 :                                         first = false;
     715             :                                 else
     716           5 :                                         name[n++] = '.';
     717             : 
     718          14 :                                 r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX);
     719          14 :                                 if (r < 0)
     720           0 :                                         return r;
     721             : 
     722          14 :                                 n += r;
     723           3 :                         } else if ((c & 0xc0) == 0xc0) {
     724             :                                 /* Pointer */
     725             : 
     726             :                                 uint8_t d;
     727             :                                 uint16_t ptr;
     728             : 
     729           3 :                                 if (pos >= len)
     730           0 :                                         return -EBADMSG;
     731             : 
     732           3 :                                 d = option[pos++];
     733           3 :                                 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
     734             : 
     735             :                                 /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
     736           3 :                                 if (ptr >= jump_barrier)
     737           1 :                                         return -EBADMSG;
     738           2 :                                 jump_barrier = ptr;
     739             : 
     740             :                                 /* Save current location so we don't end up re-parsing what's parsed so far. */
     741           2 :                                 if (next_chunk == 0)
     742           2 :                                         next_chunk = pos;
     743             : 
     744           2 :                                 pos = ptr;
     745             :                         } else
     746           0 :                                 return -EBADMSG;
     747             :                 }
     748             : 
     749           8 :                 if (!GREEDY_REALLOC(name, allocated, n + 1))
     750           0 :                         return -ENOMEM;
     751           8 :                 name[n] = 0;
     752             : 
     753           8 :                 r = strv_extend(&names, name);
     754           8 :                 if (r < 0)
     755           0 :                         return r;
     756             : 
     757           8 :                 cnt++;
     758             : 
     759           8 :                 if (next_chunk != 0)
     760           2 :                       pos = next_chunk;
     761             :         }
     762             : 
     763           3 :         *domains = TAKE_PTR(names);
     764             : 
     765           3 :         return cnt;
     766             : }
     767             : 
     768           0 : int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) {
     769             :         struct sd_dhcp_raw_option *cur, *option;
     770             : 
     771           0 :         assert(lease);
     772             : 
     773           0 :         LIST_FOREACH(options, cur, lease->private_options) {
     774           0 :                 if (tag < cur->tag)
     775           0 :                         break;
     776           0 :                 if (tag == cur->tag) {
     777           0 :                         log_debug("Ignoring duplicate option, tagged %i.", tag);
     778           0 :                         return 0;
     779             :                 }
     780             :         }
     781             : 
     782           0 :         option = new(struct sd_dhcp_raw_option, 1);
     783           0 :         if (!option)
     784           0 :                 return -ENOMEM;
     785             : 
     786           0 :         option->tag = tag;
     787           0 :         option->length = len;
     788           0 :         option->data = memdup(data, len);
     789           0 :         if (!option->data) {
     790           0 :                 free(option);
     791           0 :                 return -ENOMEM;
     792             :         }
     793             : 
     794           0 :         LIST_INSERT_BEFORE(options, lease->private_options, cur, option);
     795           0 :         return 0;
     796             : }
     797             : 
     798           1 : int dhcp_lease_new(sd_dhcp_lease **ret) {
     799             :         sd_dhcp_lease *lease;
     800             : 
     801           1 :         lease = new0(sd_dhcp_lease, 1);
     802           1 :         if (!lease)
     803           0 :                 return -ENOMEM;
     804             : 
     805           1 :         lease->n_ref = 1;
     806             : 
     807           1 :         *ret = lease;
     808           1 :         return 0;
     809             : }
     810             : 
     811           0 : int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
     812           0 :         _cleanup_free_ char *temp_path = NULL;
     813           0 :         _cleanup_fclose_ FILE *f = NULL;
     814             :         struct sd_dhcp_raw_option *option;
     815             :         struct in_addr address;
     816             :         const struct in_addr *addresses;
     817             :         const void *client_id, *data;
     818             :         size_t client_id_len, data_len;
     819             :         char sbuf[INET_ADDRSTRLEN];
     820             :         const char *string;
     821             :         uint16_t mtu;
     822           0 :         _cleanup_free_ sd_dhcp_route **routes = NULL;
     823           0 :         char **search_domains = NULL;
     824             :         uint32_t t1, t2, lifetime;
     825             :         int r;
     826             : 
     827           0 :         assert(lease);
     828           0 :         assert(lease_file);
     829             : 
     830           0 :         r = fopen_temporary(lease_file, &f, &temp_path);
     831           0 :         if (r < 0)
     832           0 :                 goto fail;
     833             : 
     834           0 :         (void) fchmod(fileno(f), 0644);
     835             : 
     836           0 :         fprintf(f,
     837             :                 "# This is private data. Do not parse.\n");
     838             : 
     839           0 :         r = sd_dhcp_lease_get_address(lease, &address);
     840           0 :         if (r >= 0)
     841           0 :                 fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
     842             : 
     843           0 :         r = sd_dhcp_lease_get_netmask(lease, &address);
     844           0 :         if (r >= 0)
     845           0 :                 fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
     846             : 
     847           0 :         r = sd_dhcp_lease_get_router(lease, &addresses);
     848           0 :         if (r > 0) {
     849           0 :                 fputs("ROUTER=", f);
     850           0 :                 serialize_in_addrs(f, addresses, r, false, NULL);
     851           0 :                 fputc('\n', f);
     852             :         }
     853             : 
     854           0 :         r = sd_dhcp_lease_get_server_identifier(lease, &address);
     855           0 :         if (r >= 0)
     856           0 :                 fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
     857             : 
     858           0 :         r = sd_dhcp_lease_get_next_server(lease, &address);
     859           0 :         if (r >= 0)
     860           0 :                 fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
     861             : 
     862           0 :         r = sd_dhcp_lease_get_broadcast(lease, &address);
     863           0 :         if (r >= 0)
     864           0 :                 fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
     865             : 
     866           0 :         r = sd_dhcp_lease_get_mtu(lease, &mtu);
     867           0 :         if (r >= 0)
     868           0 :                 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
     869             : 
     870           0 :         r = sd_dhcp_lease_get_t1(lease, &t1);
     871           0 :         if (r >= 0)
     872           0 :                 fprintf(f, "T1=%" PRIu32 "\n", t1);
     873             : 
     874           0 :         r = sd_dhcp_lease_get_t2(lease, &t2);
     875           0 :         if (r >= 0)
     876           0 :                 fprintf(f, "T2=%" PRIu32 "\n", t2);
     877             : 
     878           0 :         r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
     879           0 :         if (r >= 0)
     880           0 :                 fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime);
     881             : 
     882           0 :         r = sd_dhcp_lease_get_dns(lease, &addresses);
     883           0 :         if (r > 0) {
     884           0 :                 fputs("DNS=", f);
     885           0 :                 serialize_in_addrs(f, addresses, r, false, NULL);
     886           0 :                 fputc('\n', f);
     887             :         }
     888             : 
     889           0 :         r = sd_dhcp_lease_get_ntp(lease, &addresses);
     890           0 :         if (r > 0) {
     891           0 :                 fputs("NTP=", f);
     892           0 :                 serialize_in_addrs(f, addresses, r, false, NULL);
     893           0 :                 fputc('\n', f);
     894             :         }
     895             : 
     896           0 :         r = sd_dhcp_lease_get_domainname(lease, &string);
     897           0 :         if (r >= 0)
     898           0 :                 fprintf(f, "DOMAINNAME=%s\n", string);
     899             : 
     900           0 :         r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
     901           0 :         if (r > 0) {
     902           0 :                 fputs("DOMAIN_SEARCH_LIST=", f);
     903           0 :                 fputstrv(f, search_domains, NULL, NULL);
     904           0 :                 fputc('\n', f);
     905             :         }
     906             : 
     907           0 :         r = sd_dhcp_lease_get_hostname(lease, &string);
     908           0 :         if (r >= 0)
     909           0 :                 fprintf(f, "HOSTNAME=%s\n", string);
     910             : 
     911           0 :         r = sd_dhcp_lease_get_root_path(lease, &string);
     912           0 :         if (r >= 0)
     913           0 :                 fprintf(f, "ROOT_PATH=%s\n", string);
     914             : 
     915           0 :         r = sd_dhcp_lease_get_routes(lease, &routes);
     916           0 :         if (r > 0)
     917           0 :                 serialize_dhcp_routes(f, "ROUTES", routes, r);
     918             : 
     919           0 :         r = sd_dhcp_lease_get_timezone(lease, &string);
     920           0 :         if (r >= 0)
     921           0 :                 fprintf(f, "TIMEZONE=%s\n", string);
     922             : 
     923           0 :         r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
     924           0 :         if (r >= 0) {
     925           0 :                 _cleanup_free_ char *client_id_hex = NULL;
     926             : 
     927           0 :                 client_id_hex = hexmem(client_id, client_id_len);
     928           0 :                 if (!client_id_hex) {
     929           0 :                         r = -ENOMEM;
     930           0 :                         goto fail;
     931             :                 }
     932           0 :                 fprintf(f, "CLIENTID=%s\n", client_id_hex);
     933             :         }
     934             : 
     935           0 :         r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
     936           0 :         if (r >= 0) {
     937           0 :                 _cleanup_free_ char *option_hex = NULL;
     938             : 
     939           0 :                 option_hex = hexmem(data, data_len);
     940           0 :                 if (!option_hex) {
     941           0 :                         r = -ENOMEM;
     942           0 :                         goto fail;
     943             :                 }
     944           0 :                 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
     945             :         }
     946             : 
     947           0 :         LIST_FOREACH(options, option, lease->private_options) {
     948             :                 char key[STRLEN("OPTION_000")+1];
     949             : 
     950           0 :                 xsprintf(key, "OPTION_%" PRIu8, option->tag);
     951           0 :                 r = serialize_dhcp_option(f, key, option->data, option->length);
     952           0 :                 if (r < 0)
     953           0 :                         goto fail;
     954             :         }
     955             : 
     956           0 :         r = fflush_and_check(f);
     957           0 :         if (r < 0)
     958           0 :                 goto fail;
     959             : 
     960           0 :         if (rename(temp_path, lease_file) < 0) {
     961           0 :                 r = -errno;
     962           0 :                 goto fail;
     963             :         }
     964             : 
     965           0 :         return 0;
     966             : 
     967           0 : fail:
     968           0 :         if (temp_path)
     969           0 :                 (void) unlink(temp_path);
     970             : 
     971           0 :         return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
     972             : }
     973             : 
     974           0 : int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
     975             : 
     976           0 :         _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
     977             :         _cleanup_free_ char
     978           0 :                 *address = NULL,
     979           0 :                 *router = NULL,
     980           0 :                 *netmask = NULL,
     981           0 :                 *server_address = NULL,
     982           0 :                 *next_server = NULL,
     983           0 :                 *broadcast = NULL,
     984           0 :                 *dns = NULL,
     985           0 :                 *ntp = NULL,
     986           0 :                 *mtu = NULL,
     987           0 :                 *routes = NULL,
     988           0 :                 *domains = NULL,
     989           0 :                 *client_id_hex = NULL,
     990           0 :                 *vendor_specific_hex = NULL,
     991           0 :                 *lifetime = NULL,
     992           0 :                 *t1 = NULL,
     993           0 :                 *t2 = NULL,
     994           0 :                 *options[SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1] = {};
     995             : 
     996             :         int r, i;
     997             : 
     998           0 :         assert(lease_file);
     999           0 :         assert(ret);
    1000             : 
    1001           0 :         r = dhcp_lease_new(&lease);
    1002           0 :         if (r < 0)
    1003           0 :                 return r;
    1004             : 
    1005           0 :         r = parse_env_file(NULL, lease_file,
    1006             :                            "ADDRESS", &address,
    1007             :                            "ROUTER", &router,
    1008             :                            "NETMASK", &netmask,
    1009             :                            "SERVER_IDENTIFIER", &server_address,
    1010             :                            "NEXT_SERVER", &next_server,
    1011             :                            "BROADCAST", &broadcast,
    1012             :                            "DNS", &dns,
    1013             :                            "NTP", &ntp,
    1014             :                            "MTU", &mtu,
    1015             :                            "DOMAINNAME", &lease->domainname,
    1016             :                            "HOSTNAME", &lease->hostname,
    1017             :                            "DOMAIN_SEARCH_LIST", &domains,
    1018             :                            "ROOT_PATH", &lease->root_path,
    1019             :                            "ROUTES", &routes,
    1020             :                            "CLIENTID", &client_id_hex,
    1021             :                            "TIMEZONE", &lease->timezone,
    1022             :                            "VENDOR_SPECIFIC", &vendor_specific_hex,
    1023             :                            "LIFETIME", &lifetime,
    1024             :                            "T1", &t1,
    1025             :                            "T2", &t2,
    1026             :                            "OPTION_224", &options[0],
    1027             :                            "OPTION_225", &options[1],
    1028             :                            "OPTION_226", &options[2],
    1029             :                            "OPTION_227", &options[3],
    1030             :                            "OPTION_228", &options[4],
    1031             :                            "OPTION_229", &options[5],
    1032             :                            "OPTION_230", &options[6],
    1033             :                            "OPTION_231", &options[7],
    1034             :                            "OPTION_232", &options[8],
    1035             :                            "OPTION_233", &options[9],
    1036             :                            "OPTION_234", &options[10],
    1037             :                            "OPTION_235", &options[11],
    1038             :                            "OPTION_236", &options[12],
    1039             :                            "OPTION_237", &options[13],
    1040             :                            "OPTION_238", &options[14],
    1041             :                            "OPTION_239", &options[15],
    1042             :                            "OPTION_240", &options[16],
    1043             :                            "OPTION_241", &options[17],
    1044             :                            "OPTION_242", &options[18],
    1045             :                            "OPTION_243", &options[19],
    1046             :                            "OPTION_244", &options[20],
    1047             :                            "OPTION_245", &options[21],
    1048             :                            "OPTION_246", &options[22],
    1049             :                            "OPTION_247", &options[23],
    1050             :                            "OPTION_248", &options[24],
    1051             :                            "OPTION_249", &options[25],
    1052             :                            "OPTION_250", &options[26],
    1053             :                            "OPTION_251", &options[27],
    1054             :                            "OPTION_252", &options[28],
    1055             :                            "OPTION_253", &options[29],
    1056             :                            "OPTION_254", &options[30]);
    1057           0 :         if (r < 0)
    1058           0 :                 return r;
    1059             : 
    1060           0 :         if (address) {
    1061           0 :                 r = inet_pton(AF_INET, address, &lease->address);
    1062           0 :                 if (r <= 0)
    1063           0 :                         log_debug("Failed to parse address %s, ignoring.", address);
    1064             :         }
    1065             : 
    1066           0 :         if (router) {
    1067           0 :                 r = deserialize_in_addrs(&lease->router, router);
    1068           0 :                 if (r < 0)
    1069           0 :                         log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router);
    1070             :                 else
    1071           0 :                         lease->router_size = r;
    1072             :         }
    1073             : 
    1074           0 :         if (netmask) {
    1075           0 :                 r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
    1076           0 :                 if (r <= 0)
    1077           0 :                         log_debug("Failed to parse netmask %s, ignoring.", netmask);
    1078             :                 else
    1079           0 :                         lease->have_subnet_mask = true;
    1080             :         }
    1081             : 
    1082           0 :         if (server_address) {
    1083           0 :                 r = inet_pton(AF_INET, server_address, &lease->server_address);
    1084           0 :                 if (r <= 0)
    1085           0 :                         log_debug("Failed to parse server address %s, ignoring.", server_address);
    1086             :         }
    1087             : 
    1088           0 :         if (next_server) {
    1089           0 :                 r = inet_pton(AF_INET, next_server, &lease->next_server);
    1090           0 :                 if (r <= 0)
    1091           0 :                         log_debug("Failed to parse next server %s, ignoring.", next_server);
    1092             :         }
    1093             : 
    1094           0 :         if (broadcast) {
    1095           0 :                 r = inet_pton(AF_INET, broadcast, &lease->broadcast);
    1096           0 :                 if (r <= 0)
    1097           0 :                         log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
    1098             :                 else
    1099           0 :                         lease->have_broadcast = true;
    1100             :         }
    1101             : 
    1102           0 :         if (dns) {
    1103           0 :                 r = deserialize_in_addrs(&lease->dns, dns);
    1104           0 :                 if (r < 0)
    1105           0 :                         log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns);
    1106             :                 else
    1107           0 :                         lease->dns_size = r;
    1108             :         }
    1109             : 
    1110           0 :         if (ntp) {
    1111           0 :                 r = deserialize_in_addrs(&lease->ntp, ntp);
    1112           0 :                 if (r < 0)
    1113           0 :                         log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp);
    1114             :                 else
    1115           0 :                         lease->ntp_size = r;
    1116             :         }
    1117             : 
    1118           0 :         if (mtu) {
    1119           0 :                 r = safe_atou16(mtu, &lease->mtu);
    1120           0 :                 if (r < 0)
    1121           0 :                         log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu);
    1122             :         }
    1123             : 
    1124           0 :         if (domains) {
    1125           0 :                 _cleanup_strv_free_ char **a = NULL;
    1126           0 :                 a = strv_split(domains, " ");
    1127           0 :                 if (!a)
    1128           0 :                         return -ENOMEM;
    1129             : 
    1130           0 :                 if (!strv_isempty(a)) {
    1131           0 :                         lease->search_domains = a;
    1132           0 :                         a = NULL;
    1133             :                 }
    1134             :         }
    1135             : 
    1136           0 :         if (routes) {
    1137           0 :                 r = deserialize_dhcp_routes(
    1138           0 :                                 &lease->static_route,
    1139           0 :                                 &lease->static_route_size,
    1140           0 :                                 &lease->static_route_allocated,
    1141             :                                 routes);
    1142           0 :                 if (r < 0)
    1143           0 :                         log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes);
    1144             :         }
    1145             : 
    1146           0 :         if (lifetime) {
    1147           0 :                 r = safe_atou32(lifetime, &lease->lifetime);
    1148           0 :                 if (r < 0)
    1149           0 :                         log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime);
    1150             :         }
    1151             : 
    1152           0 :         if (t1) {
    1153           0 :                 r = safe_atou32(t1, &lease->t1);
    1154           0 :                 if (r < 0)
    1155           0 :                         log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1);
    1156             :         }
    1157             : 
    1158           0 :         if (t2) {
    1159           0 :                 r = safe_atou32(t2, &lease->t2);
    1160           0 :                 if (r < 0)
    1161           0 :                         log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2);
    1162             :         }
    1163             : 
    1164           0 :         if (client_id_hex) {
    1165           0 :                 r = unhexmem(client_id_hex, (size_t) -1, &lease->client_id, &lease->client_id_len);
    1166           0 :                 if (r < 0)
    1167           0 :                         log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
    1168             :         }
    1169             : 
    1170           0 :         if (vendor_specific_hex) {
    1171           0 :                 r = unhexmem(vendor_specific_hex, (size_t) -1, &lease->vendor_specific, &lease->vendor_specific_len);
    1172           0 :                 if (r < 0)
    1173           0 :                         log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
    1174             :         }
    1175             : 
    1176           0 :         for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) {
    1177           0 :                 _cleanup_free_ void *data = NULL;
    1178             :                 size_t len;
    1179             : 
    1180           0 :                 if (!options[i])
    1181           0 :                         continue;
    1182             : 
    1183           0 :                 r = unhexmem(options[i], (size_t) -1, &data, &len);
    1184           0 :                 if (r < 0) {
    1185           0 :                         log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
    1186           0 :                         continue;
    1187             :                 }
    1188             : 
    1189           0 :                 r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len);
    1190           0 :                 if (r < 0)
    1191           0 :                         return r;
    1192             :         }
    1193             : 
    1194           0 :         *ret = TAKE_PTR(lease);
    1195             : 
    1196           0 :         return 0;
    1197             : }
    1198             : 
    1199           0 : int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
    1200             :         struct in_addr address, mask;
    1201             :         int r;
    1202             : 
    1203           0 :         assert(lease);
    1204             : 
    1205           0 :         if (lease->address == 0)
    1206           0 :                 return -ENODATA;
    1207             : 
    1208           0 :         address.s_addr = lease->address;
    1209             : 
    1210             :         /* fall back to the default subnet masks based on address class */
    1211           0 :         r = in4_addr_default_subnet_mask(&address, &mask);
    1212           0 :         if (r < 0)
    1213           0 :                 return r;
    1214             : 
    1215           0 :         lease->subnet_mask = mask.s_addr;
    1216           0 :         lease->have_subnet_mask = true;
    1217             : 
    1218           0 :         return 0;
    1219             : }
    1220             : 
    1221           0 : int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
    1222           0 :         assert_return(lease, -EINVAL);
    1223           0 :         assert_return(client_id, -EINVAL);
    1224           0 :         assert_return(client_id_len, -EINVAL);
    1225             : 
    1226           0 :         if (!lease->client_id)
    1227           0 :                 return -ENODATA;
    1228             : 
    1229           0 :         *client_id = lease->client_id;
    1230           0 :         *client_id_len = lease->client_id_len;
    1231             : 
    1232           0 :         return 0;
    1233             : }
    1234             : 
    1235           1 : int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) {
    1236           1 :         assert_return(lease, -EINVAL);
    1237           1 :         assert_return(client_id || client_id_len <= 0, -EINVAL);
    1238             : 
    1239           1 :         if (client_id_len <= 0)
    1240           0 :                 lease->client_id = mfree(lease->client_id);
    1241             :         else {
    1242             :                 void *p;
    1243             : 
    1244           1 :                 p = memdup(client_id, client_id_len);
    1245           1 :                 if (!p)
    1246           0 :                         return -ENOMEM;
    1247             : 
    1248           1 :                 free(lease->client_id);
    1249           1 :                 lease->client_id = p;
    1250           1 :                 lease->client_id_len = client_id_len;
    1251             :         }
    1252             : 
    1253           1 :         return 0;
    1254             : }
    1255             : 
    1256           0 : int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
    1257           0 :         assert_return(lease, -EINVAL);
    1258           0 :         assert_return(tz, -EINVAL);
    1259             : 
    1260           0 :         if (!lease->timezone)
    1261           0 :                 return -ENODATA;
    1262             : 
    1263           0 :         *tz = lease->timezone;
    1264           0 :         return 0;
    1265             : }
    1266             : 
    1267           0 : int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) {
    1268           0 :         assert_return(route, -EINVAL);
    1269           0 :         assert_return(destination, -EINVAL);
    1270             : 
    1271           0 :         *destination = route->dst_addr;
    1272           0 :         return 0;
    1273             : }
    1274             : 
    1275           0 : int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) {
    1276           0 :         assert_return(route, -EINVAL);
    1277           0 :         assert_return(length, -EINVAL);
    1278             : 
    1279           0 :         *length = route->dst_prefixlen;
    1280           0 :         return 0;
    1281             : }
    1282             : 
    1283           0 : int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) {
    1284           0 :         assert_return(route, -EINVAL);
    1285           0 :         assert_return(gateway, -EINVAL);
    1286             : 
    1287           0 :         *gateway = route->gw_addr;
    1288           0 :         return 0;
    1289             : }
    1290             : 
    1291           0 : int sd_dhcp_route_get_option(sd_dhcp_route *route) {
    1292           0 :         assert_return(route, -EINVAL);
    1293             : 
    1294           0 :         return route->option;
    1295             : }

Generated by: LCOV version 1.14