LCOV - code coverage report
Current view: top level - libsystemd-network - sd-dhcp-lease.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 113 506 22.3 %
Date: 2015-07-29 18:47:03 Functions: 13 35 37.1 %

          Line data    Source code
       1             : /***
       2             :   This file is part of systemd.
       3             : 
       4             :   Copyright (C) 2013 Intel Corporation. All rights reserved.
       5             :   Copyright (C) 2014 Tom Gundersen
       6             : 
       7             :   systemd is free software; you can redistribute it and/or modify it
       8             :   under the terms of the GNU Lesser General Public License as published by
       9             :   the Free Software Foundation; either version 2.1 of the License, or
      10             :   (at your option) any later version.
      11             : 
      12             :   systemd is distributed in the hope that it will be useful, but
      13             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      15             :   Lesser General Public License for more details.
      16             : 
      17             :   You should have received a copy of the GNU Lesser General Public License
      18             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      19             : ***/
      20             : 
      21             : #include <stdlib.h>
      22             : #include <errno.h>
      23             : #include <string.h>
      24             : #include <stdio.h>
      25             : #include <arpa/inet.h>
      26             : 
      27             : #include "fileio.h"
      28             : #include "unaligned.h"
      29             : #include "in-addr-util.h"
      30             : #include "hostname-util.h"
      31             : #include "dhcp-protocol.h"
      32             : #include "dhcp-lease-internal.h"
      33             : #include "sd-dhcp-lease.h"
      34             : #include "network-internal.h"
      35             : #include "dns-domain.h"
      36             : 
      37           1 : int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
      38           1 :         assert_return(lease, -EINVAL);
      39           1 :         assert_return(addr, -EINVAL);
      40             : 
      41           1 :         addr->s_addr = lease->address;
      42             : 
      43           1 :         return 0;
      44             : }
      45             : 
      46           0 : int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
      47           0 :         assert_return(lease, -EINVAL);
      48           0 :         assert_return(lifetime, -EINVAL);
      49             : 
      50           0 :         *lifetime = lease->lifetime;
      51             : 
      52           0 :         return 0;
      53             : }
      54             : 
      55           0 : int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
      56           0 :         assert_return(lease, -EINVAL);
      57           0 :         assert_return(mtu, -EINVAL);
      58             : 
      59           0 :         if (lease->mtu)
      60           0 :                 *mtu = lease->mtu;
      61             :         else
      62           0 :                 return -ENOENT;
      63             : 
      64           0 :         return 0;
      65             : }
      66             : 
      67           0 : int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
      68           0 :         assert_return(lease, -EINVAL);
      69           0 :         assert_return(addr, -EINVAL);
      70             : 
      71           0 :         if (lease->dns_size) {
      72           0 :                 *addr = lease->dns;
      73           0 :                 return lease->dns_size;
      74             :         } else
      75           0 :                 return -ENOENT;
      76             : 
      77             :         return 0;
      78             : }
      79             : 
      80           0 : int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
      81           0 :         assert_return(lease, -EINVAL);
      82           0 :         assert_return(addr, -EINVAL);
      83             : 
      84           0 :         if (lease->ntp_size) {
      85           0 :                 *addr = lease->ntp;
      86           0 :                 return lease->ntp_size;
      87             :         } else
      88           0 :                 return -ENOENT;
      89             : 
      90             :         return 0;
      91             : }
      92             : 
      93           0 : int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
      94           0 :         assert_return(lease, -EINVAL);
      95           0 :         assert_return(domainname, -EINVAL);
      96             : 
      97           0 :         if (lease->domainname)
      98           0 :                 *domainname = lease->domainname;
      99             :         else
     100           0 :                 return -ENOENT;
     101             : 
     102           0 :         return 0;
     103             : }
     104             : 
     105           0 : int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
     106           0 :         assert_return(lease, -EINVAL);
     107           0 :         assert_return(hostname, -EINVAL);
     108             : 
     109           0 :         if (lease->hostname)
     110           0 :                 *hostname = lease->hostname;
     111             :         else
     112           0 :                 return -ENOENT;
     113             : 
     114           0 :         return 0;
     115             : }
     116             : 
     117           0 : int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
     118           0 :         assert_return(lease, -EINVAL);
     119           0 :         assert_return(root_path, -EINVAL);
     120             : 
     121           0 :         if (lease->root_path)
     122           0 :                 *root_path = lease->root_path;
     123             :         else
     124           0 :                 return -ENOENT;
     125             : 
     126           0 :         return 0;
     127             : }
     128             : 
     129           1 : int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
     130           1 :         assert_return(lease, -EINVAL);
     131           1 :         assert_return(addr, -EINVAL);
     132             : 
     133           1 :         if (lease->router != INADDR_ANY)
     134           1 :                 addr->s_addr = lease->router;
     135             :         else
     136           0 :                 return -ENOENT;
     137             : 
     138           1 :         return 0;
     139             : }
     140             : 
     141           1 : int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
     142           1 :         assert_return(lease, -EINVAL);
     143           1 :         assert_return(addr, -EINVAL);
     144             : 
     145           1 :         addr->s_addr = lease->subnet_mask;
     146             : 
     147           1 :         return 0;
     148             : }
     149             : 
     150           0 : int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
     151           0 :         assert_return(lease, -EINVAL);
     152           0 :         assert_return(addr, -EINVAL);
     153             : 
     154           0 :         addr->s_addr = lease->server_address;
     155             : 
     156           0 :         return 0;
     157             : }
     158             : 
     159           0 : int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
     160           0 :         assert_return(lease, -EINVAL);
     161           0 :         assert_return(addr, -EINVAL);
     162             : 
     163           0 :         addr->s_addr = lease->next_server;
     164             : 
     165           0 :         return 0;
     166             : }
     167             : 
     168           0 : int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) {
     169             : 
     170           0 :         assert_return(lease, -EINVAL);
     171           0 :         assert_return(routes, -EINVAL);
     172             : 
     173           0 :         if (lease->static_route_size) {
     174           0 :                 *routes = lease->static_route;
     175           0 :                 return lease->static_route_size;
     176             :         } else
     177           0 :                 return -ENOENT;
     178             : 
     179             :         return 0;
     180             : }
     181             : 
     182           0 : int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data,
     183             :                                       size_t *data_len) {
     184           0 :         assert_return(lease, -EINVAL);
     185           0 :         assert_return(data, -EINVAL);
     186           0 :         assert_return(data_len, -EINVAL);
     187             : 
     188           0 :         if (!lease->vendor_specific)
     189           0 :                 return -ENOENT;
     190             : 
     191           0 :         *data = lease->vendor_specific;
     192           0 :         *data_len = lease->vendor_specific_len;
     193             : 
     194           0 :         return 0;
     195             : }
     196             : 
     197           1 : sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
     198           1 :         if (lease)
     199           1 :                 assert_se(REFCNT_INC(lease->n_ref) >= 2);
     200             : 
     201           1 :         return lease;
     202             : }
     203             : 
     204          11 : sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
     205          11 :         if (lease && REFCNT_DEC(lease->n_ref) == 0) {
     206           2 :                 free(lease->hostname);
     207           2 :                 free(lease->domainname);
     208           2 :                 free(lease->dns);
     209           2 :                 free(lease->ntp);
     210           2 :                 free(lease->static_route);
     211           2 :                 free(lease->client_id);
     212           2 :                 free(lease->vendor_specific);
     213           2 :                 free(lease);
     214             :         }
     215             : 
     216          11 :         return NULL;
     217             : }
     218             : 
     219           2 : static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
     220           2 :         assert(option);
     221           2 :         assert(ret);
     222             : 
     223           2 :         if (len == 4) {
     224           2 :                 *ret = unaligned_read_be32((be32_t*) option);
     225             : 
     226           2 :                 if (*ret < min)
     227           0 :                         *ret = min;
     228             :         }
     229           2 : }
     230             : 
     231           0 : static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
     232           0 :         lease_parse_u32(option, len, (uint32_t *)ret, 0);
     233           0 : }
     234             : 
     235           0 : static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
     236           0 :         assert(option);
     237           0 :         assert(ret);
     238             : 
     239           0 :         if (len == 2) {
     240           0 :                 *ret = unaligned_read_be16((be16_t*) option);
     241             : 
     242           0 :                 if (*ret < min)
     243           0 :                         *ret = min;
     244             :         }
     245           0 : }
     246             : 
     247           6 : static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
     248           6 :         assert(option);
     249           6 :         assert(ret);
     250             : 
     251           6 :         if (len == 4)
     252           6 :                 memcpy(ret, option, 4);
     253           6 : }
     254             : 
     255           0 : static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
     256           0 :         assert(option);
     257           0 :         assert(ret);
     258             : 
     259           0 :         if (len == 1)
     260           0 :                 *ret = !!(*option);
     261           0 : }
     262             : 
     263           0 : static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
     264           0 :         assert(option);
     265           0 :         assert(ret);
     266             : 
     267           0 :         if (len == 1) {
     268           0 :                 *ret = *option;
     269             : 
     270           0 :                 if (*ret < min)
     271           0 :                         *ret = min;
     272             :         }
     273           0 : }
     274             : 
     275           2 : static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
     276           2 :         assert(option);
     277           2 :         assert(ret);
     278             : 
     279           2 :         if (len >= 1) {
     280             :                 char *string;
     281             : 
     282           2 :                 string = strndup((const char *)option, len);
     283           2 :                 if (!string)
     284           0 :                         return -errno;
     285             : 
     286           2 :                 free(*ret);
     287           2 :                 *ret = string;
     288             :         }
     289             : 
     290           2 :         return 0;
     291             : }
     292             : 
     293           2 : static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) {
     294           2 :         assert(option);
     295           2 :         assert(ret);
     296           2 :         assert(ret_size);
     297             : 
     298           2 :         if (len && !(len % (4 * mult))) {
     299             :                 size_t size;
     300             :                 struct in_addr *addresses;
     301             : 
     302           2 :                 size = len / 4;
     303             : 
     304           2 :                 addresses = newdup(struct in_addr, option, size);
     305           2 :                 if (!addresses)
     306           0 :                         return -ENOMEM;
     307             : 
     308           2 :                 free(*ret);
     309           2 :                 *ret = addresses;
     310           2 :                 *ret_size = size;
     311             :         }
     312             : 
     313           2 :         return 0;
     314             : }
     315             : 
     316           2 : static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
     317           2 :         return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
     318             : }
     319             : 
     320           0 : static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
     321           0 :         return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
     322             : }
     323             : 
     324           0 : static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
     325             :         size_t *routes_size, size_t *routes_allocated) {
     326             : 
     327             :         struct in_addr addr;
     328             : 
     329           0 :         assert(option);
     330           0 :         assert(routes);
     331           0 :         assert(routes_size);
     332           0 :         assert(routes_allocated);
     333             : 
     334           0 :         if (!len)
     335           0 :                 return 0;
     336             : 
     337           0 :         if (len % 8 != 0)
     338           0 :                 return -EINVAL;
     339             : 
     340           0 :         if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
     341           0 :                 return -ENOMEM;
     342             : 
     343           0 :         while (len >= 8) {
     344           0 :                 struct sd_dhcp_route *route = *routes + *routes_size;
     345             :                 int r;
     346             : 
     347           0 :                 r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
     348           0 :                 if (r < 0) {
     349           0 :                         log_error("Failed to determine destination prefix length from class based IP, ignoring");
     350           0 :                         continue;
     351             :                 }
     352             : 
     353           0 :                 lease_parse_be32(option, 4, &addr.s_addr);
     354           0 :                 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
     355           0 :                 option += 4;
     356             : 
     357           0 :                 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
     358           0 :                 option += 4;
     359             : 
     360           0 :                 len -= 8;
     361           0 :                 (*routes_size)++;
     362             :         }
     363             : 
     364           0 :         return 0;
     365             : }
     366             : 
     367             : /* parses RFC3442 Classless Static Route Option */
     368           0 : static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
     369             :         size_t *routes_size, size_t *routes_allocated) {
     370             : 
     371           0 :         assert(option);
     372           0 :         assert(routes);
     373           0 :         assert(routes_size);
     374           0 :         assert(routes_allocated);
     375             : 
     376             :         /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)*  */
     377             : 
     378           0 :         while (len > 0) {
     379             :                 uint8_t dst_octets;
     380             :                 struct sd_dhcp_route *route;
     381             : 
     382           0 :                 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
     383           0 :                     return -ENOMEM;
     384             : 
     385           0 :                 route = *routes + *routes_size;
     386             : 
     387           0 :                 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
     388           0 :                 route->dst_prefixlen = *option;
     389           0 :                 option++;
     390           0 :                 len--;
     391             : 
     392             :                 /* can't have more than 4 octets in IPv4 */
     393           0 :                 if (dst_octets > 4 || len < dst_octets)
     394           0 :                         return -EINVAL;
     395             : 
     396           0 :                 route->dst_addr.s_addr = 0;
     397           0 :                 memcpy(&route->dst_addr.s_addr, option, dst_octets);
     398           0 :                 option += dst_octets;
     399           0 :                 len -= dst_octets;
     400             : 
     401           0 :                 if (len < 4)
     402           0 :                         return -EINVAL;
     403             : 
     404           0 :                 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
     405           0 :                 option += 4;
     406           0 :                 len -= 4;
     407             : 
     408           0 :                 (*routes_size)++;
     409             :         }
     410             : 
     411           0 :         return 0;
     412             : }
     413             : 
     414          12 : int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
     415             :                               void *user_data) {
     416          12 :         sd_dhcp_lease *lease = user_data;
     417             :         int r;
     418             : 
     419          12 :         assert(lease);
     420             : 
     421          12 :         switch(code) {
     422             : 
     423             :         case DHCP_OPTION_TIME_OFFSET:
     424           0 :                 lease_parse_s32(option, len, &lease->time_offset);
     425             : 
     426           0 :                 break;
     427             : 
     428             :         case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
     429           0 :                 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
     430             : 
     431           0 :                 break;
     432             : 
     433             :         case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
     434           2 :                 lease_parse_u32(option, len, &lease->lifetime, 1);
     435             : 
     436           2 :                 break;
     437             : 
     438             :         case DHCP_OPTION_SERVER_IDENTIFIER:
     439           2 :                 lease_parse_be32(option, len, &lease->server_address);
     440             : 
     441           2 :                 break;
     442             : 
     443             :         case DHCP_OPTION_SUBNET_MASK:
     444           2 :                 lease_parse_be32(option, len, &lease->subnet_mask);
     445             : 
     446           2 :                 break;
     447             : 
     448             :         case DHCP_OPTION_BROADCAST:
     449           0 :                 lease_parse_be32(option, len, &lease->broadcast);
     450             : 
     451           0 :                 break;
     452             : 
     453             :         case DHCP_OPTION_ROUTER:
     454           2 :                 if(len >= 4)
     455           2 :                         lease_parse_be32(option, 4, &lease->router);
     456             : 
     457           2 :                 break;
     458             : 
     459             :         case DHCP_OPTION_DOMAIN_NAME_SERVER:
     460           0 :                 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
     461           0 :                 if (r < 0)
     462           0 :                         return r;
     463             : 
     464           0 :                 break;
     465             : 
     466             :         case DHCP_OPTION_NTP_SERVER:
     467           2 :                 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
     468           2 :                 if (r < 0)
     469           0 :                         return r;
     470             : 
     471           2 :                 break;
     472             : 
     473             :         case DHCP_OPTION_POLICY_FILTER:
     474           0 :                 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
     475           0 :                 if (r < 0)
     476           0 :                         return r;
     477             : 
     478           0 :                 break;
     479             : 
     480             :         case DHCP_OPTION_STATIC_ROUTE:
     481           0 :                 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
     482             :                         &lease->static_route_allocated);
     483           0 :                 if (r < 0)
     484           0 :                         return r;
     485             : 
     486           0 :                 break;
     487             : 
     488             :         case DHCP_OPTION_INTERFACE_MTU:
     489           0 :                 lease_parse_u16(option, len, &lease->mtu, 68);
     490             : 
     491           0 :                 break;
     492             : 
     493             :         case DHCP_OPTION_INTERFACE_MDR:
     494           0 :                 lease_parse_u16(option, len, &lease->mdr, 576);
     495             : 
     496           0 :                 break;
     497             : 
     498             :         case DHCP_OPTION_INTERFACE_TTL:
     499           0 :                 lease_parse_u8(option, len, &lease->ttl, 1);
     500             : 
     501           0 :                 break;
     502             : 
     503             :         case DHCP_OPTION_BOOT_FILE_SIZE:
     504           0 :                 lease_parse_u16(option, len, &lease->boot_file_size, 0);
     505             : 
     506           0 :                 break;
     507             : 
     508             :         case DHCP_OPTION_DOMAIN_NAME:
     509             :         {
     510           4 :                 _cleanup_free_ char *domainname = NULL;
     511             :                 char *e;
     512             : 
     513           2 :                 r = lease_parse_string(option, len, &domainname);
     514           2 :                 if (r < 0)
     515           0 :                         return r;
     516             : 
     517             :                 /* Chop off trailing dot of domain name that some DHCP
     518             :                  * servers send us back. Internally we want to store
     519             :                  * host names without trailing dots and
     520             :                  * host_name_is_valid() doesn't accept them. */
     521           2 :                 e = endswith(domainname, ".");
     522           2 :                 if (e)
     523           0 :                         *e = 0;
     524             : 
     525           2 :                 if (is_localhost(domainname))
     526           0 :                         break;
     527             : 
     528           2 :                 r = dns_name_is_valid(domainname);
     529           2 :                 if (r <= 0) {
     530           0 :                         if (r < 0)
     531           0 :                                 log_error_errno(r, "Failed to validate domain name: %s: %m", domainname);
     532           0 :                         if (r == 0)
     533           0 :                                 log_warning("Domain name is not valid, ignoring: %s", domainname);
     534           0 :                         break;
     535             :                 }
     536             : 
     537           2 :                 free(lease->domainname);
     538           2 :                 lease->domainname = domainname;
     539           2 :                 domainname = NULL;
     540             : 
     541           2 :                 break;
     542             :         }
     543             :         case DHCP_OPTION_HOST_NAME:
     544             :         {
     545           0 :                 _cleanup_free_ char *hostname = NULL;
     546             :                 char *e;
     547             : 
     548           0 :                 r = lease_parse_string(option, len, &hostname);
     549           0 :                 if (r < 0)
     550           0 :                         return r;
     551             : 
     552           0 :                 e = endswith(hostname, ".");
     553           0 :                 if (e)
     554           0 :                         *e = 0;
     555             : 
     556           0 :                 if (!hostname_is_valid(hostname) || is_localhost(hostname))
     557             :                         break;
     558             : 
     559           0 :                 free(lease->hostname);
     560           0 :                 lease->hostname = hostname;
     561           0 :                 hostname = NULL;
     562             : 
     563           0 :                 break;
     564             :         }
     565             :         case DHCP_OPTION_ROOT_PATH:
     566           0 :                 r = lease_parse_string(option, len, &lease->root_path);
     567           0 :                 if (r < 0)
     568           0 :                         return r;
     569             : 
     570           0 :                 break;
     571             : 
     572             :         case DHCP_OPTION_RENEWAL_T1_TIME:
     573           0 :                 lease_parse_u32(option, len, &lease->t1, 1);
     574             : 
     575           0 :                 break;
     576             : 
     577             :         case DHCP_OPTION_REBINDING_T2_TIME:
     578           0 :                 lease_parse_u32(option, len, &lease->t2, 1);
     579             : 
     580           0 :                 break;
     581             : 
     582             :         case DHCP_OPTION_ENABLE_IP_FORWARDING:
     583           0 :                 lease_parse_bool(option, len, &lease->ip_forward);
     584             : 
     585           0 :                 break;
     586             : 
     587             :         case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
     588           0 :                 lease_parse_bool(option, len, &lease->ip_forward_non_local);
     589             : 
     590           0 :                 break;
     591             : 
     592             :         case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
     593           0 :                 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
     594             :                         &lease->static_route_allocated);
     595           0 :                 if (r < 0)
     596           0 :                         return r;
     597             : 
     598           0 :                 break;
     599             : 
     600             :         case DHCP_OPTION_VENDOR_SPECIFIC:
     601           0 :                 if (len >= 1) {
     602           0 :                         free(lease->vendor_specific);
     603           0 :                         lease->vendor_specific = memdup(option, len);
     604           0 :                         if (!lease->vendor_specific)
     605           0 :                                 return -ENOMEM;
     606           0 :                         lease->vendor_specific_len = len;
     607             :                 }
     608             : 
     609           0 :                break;
     610             :         }
     611             : 
     612          12 :         return 0;
     613             : }
     614             : 
     615           2 : int dhcp_lease_new(sd_dhcp_lease **ret) {
     616             :         sd_dhcp_lease *lease;
     617             : 
     618           2 :         lease = new0(sd_dhcp_lease, 1);
     619           2 :         if (!lease)
     620           0 :                 return -ENOMEM;
     621             : 
     622           2 :         lease->router = INADDR_ANY;
     623           2 :         lease->n_ref = REFCNT_INIT;
     624             : 
     625           2 :         *ret = lease;
     626           2 :         return 0;
     627             : }
     628             : 
     629           0 : int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
     630           0 :         _cleanup_free_ char *temp_path = NULL;
     631           0 :         _cleanup_fclose_ FILE *f = NULL;
     632             :         struct in_addr address;
     633             :         const struct in_addr *addresses;
     634             :         const uint8_t *client_id, *data;
     635             :         size_t client_id_len, data_len;
     636             :         const char *string;
     637             :         uint16_t mtu;
     638             :         struct sd_dhcp_route *routes;
     639             :         int r;
     640             : 
     641           0 :         assert(lease);
     642           0 :         assert(lease_file);
     643             : 
     644           0 :         r = fopen_temporary(lease_file, &f, &temp_path);
     645           0 :         if (r < 0)
     646           0 :                 goto finish;
     647             : 
     648           0 :         fchmod(fileno(f), 0644);
     649             : 
     650           0 :         r = sd_dhcp_lease_get_address(lease, &address);
     651           0 :         if (r < 0)
     652           0 :                 goto finish;
     653             : 
     654           0 :         fprintf(f,
     655             :                 "# This is private data. Do not parse.\n"
     656             :                 "ADDRESS=%s\n", inet_ntoa(address));
     657             : 
     658           0 :         r = sd_dhcp_lease_get_netmask(lease, &address);
     659           0 :         if (r < 0)
     660           0 :                 goto finish;
     661             : 
     662           0 :         fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
     663             : 
     664           0 :         r = sd_dhcp_lease_get_router(lease, &address);
     665           0 :         if (r >= 0)
     666           0 :                 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
     667             : 
     668           0 :         r = sd_dhcp_lease_get_server_identifier(lease, &address);
     669           0 :         if (r >= 0)
     670           0 :                 fprintf(f, "SERVER_ADDRESS=%s\n",
     671             :                         inet_ntoa(address));
     672             : 
     673           0 :         r = sd_dhcp_lease_get_next_server(lease, &address);
     674           0 :         if (r >= 0)
     675           0 :                 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
     676             : 
     677           0 :         r = sd_dhcp_lease_get_mtu(lease, &mtu);
     678           0 :         if (r >= 0)
     679           0 :                 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
     680             : 
     681           0 :         fputs("DNS=", f);
     682           0 :         r = sd_dhcp_lease_get_dns(lease, &addresses);
     683           0 :         if (r >= 0)
     684           0 :                 serialize_in_addrs(f, addresses, r);
     685           0 :         fputs("\n", f);
     686             : 
     687           0 :         fputs("NTP=", f);
     688           0 :         r = sd_dhcp_lease_get_ntp(lease, &addresses);
     689           0 :         if (r >= 0)
     690           0 :                 serialize_in_addrs(f, addresses, r);
     691           0 :         fputs("\n", f);
     692             : 
     693           0 :         r = sd_dhcp_lease_get_domainname(lease, &string);
     694           0 :         if (r >= 0)
     695           0 :                 fprintf(f, "DOMAINNAME=%s\n", string);
     696             : 
     697           0 :         r = sd_dhcp_lease_get_hostname(lease, &string);
     698           0 :         if (r >= 0)
     699           0 :                 fprintf(f, "HOSTNAME=%s\n", string);
     700             : 
     701           0 :         r = sd_dhcp_lease_get_root_path(lease, &string);
     702           0 :         if (r >= 0)
     703           0 :                 fprintf(f, "ROOT_PATH=%s\n", string);
     704             : 
     705           0 :         r = sd_dhcp_lease_get_routes(lease, &routes);
     706           0 :         if (r >= 0)
     707           0 :                 serialize_dhcp_routes(f, "ROUTES", routes, r);
     708             : 
     709           0 :         r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
     710           0 :         if (r >= 0) {
     711           0 :                 _cleanup_free_ char *client_id_hex;
     712             : 
     713           0 :                 client_id_hex = hexmem(client_id, client_id_len);
     714           0 :                 if (!client_id_hex) {
     715           0 :                         r = -ENOMEM;
     716           0 :                         goto finish;
     717             :                 }
     718           0 :                 fprintf(f, "CLIENTID=%s\n", client_id_hex);
     719             :         }
     720             : 
     721           0 :         r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
     722           0 :         if (r >= 0) {
     723           0 :                 _cleanup_free_ char *option_hex = NULL;
     724             : 
     725           0 :                 option_hex = hexmem(data, data_len);
     726           0 :                 if (!option_hex) {
     727           0 :                         r = -ENOMEM;
     728           0 :                         goto finish;
     729             :                 }
     730           0 :                 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
     731             :         }
     732             : 
     733           0 :         r = 0;
     734             : 
     735           0 :         fflush(f);
     736             : 
     737           0 :         if (ferror(f) || rename(temp_path, lease_file) < 0) {
     738           0 :                 r = -errno;
     739           0 :                 unlink(lease_file);
     740           0 :                 unlink(temp_path);
     741             :         }
     742             : 
     743             : finish:
     744           0 :         if (r < 0)
     745           0 :                 log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
     746             : 
     747           0 :         return r;
     748             : }
     749             : 
     750           0 : int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
     751           0 :         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
     752           0 :         _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
     753           0 :                             *server_address = NULL, *next_server = NULL,
     754           0 :                             *dns = NULL, *ntp = NULL, *mtu = NULL,
     755           0 :                             *routes = NULL, *client_id_hex = NULL,
     756           0 :                             *vendor_specific_hex = NULL;
     757             :         struct in_addr addr;
     758             :         int r;
     759             : 
     760           0 :         assert(lease_file);
     761           0 :         assert(ret);
     762             : 
     763           0 :         r = dhcp_lease_new(&lease);
     764           0 :         if (r < 0)
     765           0 :                 return r;
     766             : 
     767           0 :         r = parse_env_file(lease_file, NEWLINE,
     768             :                            "ADDRESS", &address,
     769             :                            "ROUTER", &router,
     770             :                            "NETMASK", &netmask,
     771             :                            "SERVER_IDENTIFIER", &server_address,
     772             :                            "NEXT_SERVER", &next_server,
     773             :                            "DNS", &dns,
     774             :                            "NTP", &ntp,
     775             :                            "MTU", &mtu,
     776           0 :                            "DOMAINNAME", &lease->domainname,
     777           0 :                            "HOSTNAME", &lease->hostname,
     778           0 :                            "ROOT_PATH", &lease->root_path,
     779             :                            "ROUTES", &routes,
     780             :                            "CLIENTID", &client_id_hex,
     781             :                            "VENDOR_SPECIFIC", &vendor_specific_hex,
     782             :                            NULL);
     783           0 :         if (r < 0) {
     784           0 :                 if (r == -ENOENT)
     785           0 :                         return 0;
     786             : 
     787           0 :                 return log_error_errno(r, "Failed to read %s: %m", lease_file);
     788             :         }
     789             : 
     790           0 :         r = inet_pton(AF_INET, address, &addr);
     791           0 :         if (r < 0)
     792           0 :                 return r;
     793             : 
     794           0 :         lease->address = addr.s_addr;
     795             : 
     796           0 :         if (router) {
     797           0 :                 r = inet_pton(AF_INET, router, &addr);
     798           0 :                 if (r < 0)
     799           0 :                         return r;
     800             : 
     801           0 :                 lease->router = addr.s_addr;
     802             :         }
     803             : 
     804           0 :         r = inet_pton(AF_INET, netmask, &addr);
     805           0 :         if (r < 0)
     806           0 :                 return r;
     807             : 
     808           0 :         lease->subnet_mask = addr.s_addr;
     809             : 
     810           0 :         if (server_address) {
     811           0 :                 r = inet_pton(AF_INET, server_address, &addr);
     812           0 :                 if (r < 0)
     813           0 :                         return r;
     814             : 
     815           0 :                 lease->server_address = addr.s_addr;
     816             :         }
     817             : 
     818           0 :         if (next_server) {
     819           0 :                 r = inet_pton(AF_INET, next_server, &addr);
     820           0 :                 if (r < 0)
     821           0 :                         return r;
     822             : 
     823           0 :                 lease->next_server = addr.s_addr;
     824             :         }
     825             : 
     826           0 :         if (dns) {
     827           0 :                 r = deserialize_in_addrs(&lease->dns, dns);
     828           0 :                 if (r < 0)
     829           0 :                         return r;
     830             : 
     831           0 :                 lease->dns_size = r;
     832             :         }
     833             : 
     834           0 :         if (ntp) {
     835           0 :                 r = deserialize_in_addrs(&lease->ntp, ntp);
     836           0 :                 if (r < 0)
     837           0 :                         return r;
     838             : 
     839           0 :                 lease->ntp_size = r;
     840             :         }
     841             : 
     842           0 :         if (mtu) {
     843             :                 uint16_t u;
     844           0 :                 if (sscanf(mtu, "%" SCNu16, &u) > 0)
     845           0 :                         lease->mtu = u;
     846             :         }
     847             : 
     848           0 :         if (routes) {
     849           0 :                 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
     850           0 :                                 &lease->static_route_allocated, routes);
     851           0 :                 if (r < 0)
     852           0 :                     return r;
     853             :         }
     854             : 
     855           0 :         if (client_id_hex) {
     856           0 :                 if (strlen(client_id_hex) % 2)
     857           0 :                         return -EINVAL;
     858             : 
     859           0 :                 r = unhexmem(client_id_hex, strlen(client_id_hex), (void**) &lease->client_id, &lease->client_id_len);
     860           0 :                 if (r < 0)
     861           0 :                         return r;
     862             :         }
     863             : 
     864           0 :         if (vendor_specific_hex) {
     865           0 :                 if (strlen(vendor_specific_hex) % 2)
     866           0 :                         return -EINVAL;
     867             : 
     868           0 :                 r = unhexmem(vendor_specific_hex, strlen(vendor_specific_hex), (void**) &lease->vendor_specific, &lease->vendor_specific_len);
     869           0 :                 if (r < 0)
     870           0 :                         return r;
     871             :         }
     872             : 
     873           0 :         *ret = lease;
     874           0 :         lease = NULL;
     875             : 
     876           0 :         return 0;
     877             : }
     878             : 
     879           0 : int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
     880             :         struct in_addr address;
     881             :         struct in_addr mask;
     882             :         int r;
     883             : 
     884           0 :         assert(lease);
     885             : 
     886           0 :         address.s_addr = lease->address;
     887             : 
     888             :         /* fall back to the default subnet masks based on address class */
     889           0 :         r = in_addr_default_subnet_mask(&address, &mask);
     890           0 :         if (r < 0)
     891           0 :                 return r;
     892             : 
     893           0 :         lease->subnet_mask = mask.s_addr;
     894             : 
     895           0 :         return 0;
     896             : }
     897             : 
     898           0 : int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
     899             :                                 size_t *client_id_len) {
     900           0 :         assert_return(lease, -EINVAL);
     901           0 :         assert_return(client_id, -EINVAL);
     902           0 :         assert_return(client_id_len, -EINVAL);
     903             : 
     904           0 :         *client_id = lease->client_id;
     905           0 :         *client_id_len = lease->client_id_len;
     906           0 :         return 0;
     907             : }
     908             : 
     909           2 : int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
     910             :                              size_t client_id_len) {
     911           2 :         assert_return(lease, -EINVAL);
     912           2 :         assert_return((!client_id && !client_id_len) ||
     913             :                       (client_id && client_id_len), -EINVAL);
     914             : 
     915           2 :         free (lease->client_id);
     916           2 :         lease->client_id = NULL;
     917           2 :         lease->client_id_len = 0;
     918             : 
     919           2 :         if (client_id) {
     920           2 :                 lease->client_id = memdup (client_id, client_id_len);
     921           2 :                 lease->client_id_len = client_id_len;
     922             :         }
     923             : 
     924           2 :         return 0;
     925             : }

Generated by: LCOV version 1.11