LCOV - code coverage report
Current view: top level - libsystemd-network - sd-dhcp-client.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 338 979 34.5 %
Date: 2019-08-22 15:41:25 Functions: 30 57 52.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 <errno.h>
       7             : #include <net/ethernet.h>
       8             : #include <net/if_arp.h>
       9             : #include <stdio.h>
      10             : #include <stdlib.h>
      11             : #include <string.h>
      12             : #include <sys/ioctl.h>
      13             : #include <linux/if_infiniband.h>
      14             : 
      15             : #include "sd-dhcp-client.h"
      16             : 
      17             : #include "alloc-util.h"
      18             : #include "async.h"
      19             : #include "dhcp-identifier.h"
      20             : #include "dhcp-internal.h"
      21             : #include "dhcp-lease-internal.h"
      22             : #include "dhcp-protocol.h"
      23             : #include "dns-domain.h"
      24             : #include "event-util.h"
      25             : #include "hostname-util.h"
      26             : #include "io-util.h"
      27             : #include "memory-util.h"
      28             : #include "random-util.h"
      29             : #include "string-util.h"
      30             : #include "strv.h"
      31             : 
      32             : #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN)  /* Arbitrary limit */
      33             : #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
      34             : 
      35             : #define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
      36             : #define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
      37             : 
      38             : struct sd_dhcp_client {
      39             :         unsigned n_ref;
      40             : 
      41             :         DHCPState state;
      42             :         sd_event *event;
      43             :         int event_priority;
      44             :         sd_event_source *timeout_resend;
      45             :         int ifindex;
      46             :         int fd;
      47             :         uint16_t port;
      48             :         union sockaddr_union link;
      49             :         sd_event_source *receive_message;
      50             :         bool request_broadcast;
      51             :         uint8_t *req_opts;
      52             :         size_t req_opts_allocated;
      53             :         size_t req_opts_size;
      54             :         bool anonymize;
      55             :         be32_t last_addr;
      56             :         uint8_t mac_addr[MAX_MAC_ADDR_LEN];
      57             :         size_t mac_addr_len;
      58             :         uint16_t arp_type;
      59             :         struct {
      60             :                 uint8_t type;
      61             :                 union {
      62             :                         struct {
      63             :                                 /* 0: Generic (non-LL) (RFC 2132) */
      64             :                                 uint8_t data[MAX_CLIENT_ID_LEN];
      65             :                         } _packed_ gen;
      66             :                         struct {
      67             :                                 /* 1: Ethernet Link-Layer (RFC 2132) */
      68             :                                 uint8_t haddr[ETH_ALEN];
      69             :                         } _packed_ eth;
      70             :                         struct {
      71             :                                 /* 2 - 254: ARP/Link-Layer (RFC 2132) */
      72             :                                 uint8_t haddr[0];
      73             :                         } _packed_ ll;
      74             :                         struct {
      75             :                                 /* 255: Node-specific (RFC 4361) */
      76             :                                 be32_t iaid;
      77             :                                 struct duid duid;
      78             :                         } _packed_ ns;
      79             :                         struct {
      80             :                                 uint8_t data[MAX_CLIENT_ID_LEN];
      81             :                         } _packed_ raw;
      82             :                 };
      83             :         } _packed_ client_id;
      84             :         size_t client_id_len;
      85             :         char *hostname;
      86             :         char *vendor_class_identifier;
      87             :         char **user_class;
      88             :         uint32_t mtu;
      89             :         uint32_t xid;
      90             :         usec_t start_time;
      91             :         uint64_t attempt;
      92             :         uint64_t max_attempts;
      93             :         usec_t request_sent;
      94             :         sd_event_source *timeout_t1;
      95             :         sd_event_source *timeout_t2;
      96             :         sd_event_source *timeout_expire;
      97             :         sd_dhcp_client_callback_t callback;
      98             :         void *userdata;
      99             :         sd_dhcp_lease *lease;
     100             :         usec_t start_delay;
     101             : };
     102             : 
     103             : static const uint8_t default_req_opts[] = {
     104             :         SD_DHCP_OPTION_SUBNET_MASK,
     105             :         SD_DHCP_OPTION_ROUTER,
     106             :         SD_DHCP_OPTION_HOST_NAME,
     107             :         SD_DHCP_OPTION_DOMAIN_NAME,
     108             :         SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
     109             : };
     110             : 
     111             : /* RFC7844 section 3:
     112             :    MAY contain the Parameter Request List option.
     113             :    RFC7844 section 3.6:
     114             :    The client intending to protect its privacy SHOULD only request a
     115             :    minimal number of options in the PRL and SHOULD also randomly shuffle
     116             :    the ordering of option codes in the PRL.  If this random ordering
     117             :    cannot be implemented, the client MAY order the option codes in the
     118             :    PRL by option code number (lowest to highest).
     119             : */
     120             : /* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
     121             : static const uint8_t default_req_opts_anonymize[] = {
     122             :         SD_DHCP_OPTION_SUBNET_MASK,                     /* 1 */
     123             :         SD_DHCP_OPTION_ROUTER,                          /* 3 */
     124             :         SD_DHCP_OPTION_DOMAIN_NAME_SERVER,              /* 6 */
     125             :         SD_DHCP_OPTION_DOMAIN_NAME,                     /* 15 */
     126             :         SD_DHCP_OPTION_ROUTER_DISCOVER,                 /* 31 */
     127             :         SD_DHCP_OPTION_STATIC_ROUTE,                    /* 33 */
     128             :         SD_DHCP_OPTION_VENDOR_SPECIFIC,                 /* 43 */
     129             :         SD_DHCP_OPTION_NETBIOS_NAMESERVER,              /* 44 */
     130             :         SD_DHCP_OPTION_NETBIOS_NODETYPE,                /* 46 */
     131             :         SD_DHCP_OPTION_NETBIOS_SCOPE,                   /* 47 */
     132             :         SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE,          /* 121 */
     133             :         SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE,  /* 249 */
     134             :         SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY,     /* 252 */
     135             : };
     136             : 
     137             : static int client_receive_message_raw(
     138             :                 sd_event_source *s,
     139             :                 int fd,
     140             :                 uint32_t revents,
     141             :                 void *userdata);
     142             : static int client_receive_message_udp(
     143             :                 sd_event_source *s,
     144             :                 int fd,
     145             :                 uint32_t revents,
     146             :                 void *userdata);
     147             : static void client_stop(sd_dhcp_client *client, int error);
     148             : 
     149           2 : int sd_dhcp_client_set_callback(
     150             :                 sd_dhcp_client *client,
     151             :                 sd_dhcp_client_callback_t cb,
     152             :                 void *userdata) {
     153             : 
     154           2 :         assert_return(client, -EINVAL);
     155             : 
     156           2 :         client->callback = cb;
     157           2 :         client->userdata = userdata;
     158             : 
     159           2 :         return 0;
     160             : }
     161             : 
     162           0 : int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
     163           0 :         assert_return(client, -EINVAL);
     164             : 
     165           0 :         client->request_broadcast = !!broadcast;
     166             : 
     167           0 :         return 0;
     168             : }
     169             : 
     170          21 : int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
     171             :         size_t i;
     172             : 
     173          21 :         assert_return(client, -EINVAL);
     174          20 :         assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
     175             : 
     176          20 :         switch(option) {
     177             : 
     178           6 :         case SD_DHCP_OPTION_PAD:
     179             :         case SD_DHCP_OPTION_OVERLOAD:
     180             :         case SD_DHCP_OPTION_MESSAGE_TYPE:
     181             :         case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
     182             :         case SD_DHCP_OPTION_END:
     183           6 :                 return -EINVAL;
     184             : 
     185          14 :         default:
     186          14 :                 break;
     187             :         }
     188             : 
     189          98 :         for (i = 0; i < client->req_opts_size; i++)
     190          93 :                 if (client->req_opts[i] == option)
     191           9 :                         return -EEXIST;
     192             : 
     193           5 :         if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
     194             :                             client->req_opts_size + 1))
     195           0 :                 return -ENOMEM;
     196             : 
     197           5 :         client->req_opts[client->req_opts_size++] = option;
     198             : 
     199           5 :         return 0;
     200             : }
     201             : 
     202           1 : int sd_dhcp_client_set_request_address(
     203             :                 sd_dhcp_client *client,
     204             :                 const struct in_addr *last_addr) {
     205             : 
     206           1 :         assert_return(client, -EINVAL);
     207           0 :         assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
     208             : 
     209           0 :         if (last_addr)
     210           0 :                 client->last_addr = last_addr->s_addr;
     211             :         else
     212           0 :                 client->last_addr = INADDR_ANY;
     213             : 
     214           0 :         return 0;
     215             : }
     216             : 
     217           8 : int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
     218             : 
     219           8 :         assert_return(client, -EINVAL);
     220           7 :         assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
     221           7 :         assert_return(ifindex > 0, -EINVAL);
     222             : 
     223           4 :         client->ifindex = ifindex;
     224           4 :         return 0;
     225             : }
     226             : 
     227           2 : int sd_dhcp_client_set_mac(
     228             :                 sd_dhcp_client *client,
     229             :                 const uint8_t *addr,
     230             :                 size_t addr_len,
     231             :                 uint16_t arp_type) {
     232             : 
     233           4 :         DHCP_CLIENT_DONT_DESTROY(client);
     234           2 :         bool need_restart = false;
     235             : 
     236           2 :         assert_return(client, -EINVAL);
     237           2 :         assert_return(addr, -EINVAL);
     238           2 :         assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
     239           2 :         assert_return(arp_type > 0, -EINVAL);
     240             : 
     241           2 :         if (arp_type == ARPHRD_ETHER)
     242           2 :                 assert_return(addr_len == ETH_ALEN, -EINVAL);
     243           0 :         else if (arp_type == ARPHRD_INFINIBAND)
     244           0 :                 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
     245             :         else
     246           0 :                 return -EINVAL;
     247             : 
     248           2 :         if (client->mac_addr_len == addr_len &&
     249           0 :             memcmp(&client->mac_addr, addr, addr_len) == 0)
     250           0 :                 return 0;
     251             : 
     252           2 :         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
     253           0 :                 log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting");
     254           0 :                 need_restart = true;
     255           0 :                 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
     256             :         }
     257             : 
     258           2 :         memcpy(&client->mac_addr, addr, addr_len);
     259           2 :         client->mac_addr_len = addr_len;
     260           2 :         client->arp_type = arp_type;
     261             : 
     262           2 :         if (need_restart && client->state != DHCP_STATE_STOPPED)
     263           0 :                 sd_dhcp_client_start(client);
     264             : 
     265           2 :         return 0;
     266             : }
     267             : 
     268           0 : int sd_dhcp_client_get_client_id(
     269             :                 sd_dhcp_client *client,
     270             :                 uint8_t *type,
     271             :                 const uint8_t **data,
     272             :                 size_t *data_len) {
     273             : 
     274           0 :         assert_return(client, -EINVAL);
     275           0 :         assert_return(type, -EINVAL);
     276           0 :         assert_return(data, -EINVAL);
     277           0 :         assert_return(data_len, -EINVAL);
     278             : 
     279           0 :         *type = 0;
     280           0 :         *data = NULL;
     281           0 :         *data_len = 0;
     282           0 :         if (client->client_id_len) {
     283           0 :                 *type = client->client_id.type;
     284           0 :                 *data = client->client_id.raw.data;
     285           0 :                 *data_len = client->client_id_len - sizeof(client->client_id.type);
     286             :         }
     287             : 
     288           0 :         return 0;
     289             : }
     290             : 
     291           0 : int sd_dhcp_client_set_client_id(
     292             :                 sd_dhcp_client *client,
     293             :                 uint8_t type,
     294             :                 const uint8_t *data,
     295             :                 size_t data_len) {
     296             : 
     297           0 :         DHCP_CLIENT_DONT_DESTROY(client);
     298           0 :         bool need_restart = false;
     299             : 
     300           0 :         assert_return(client, -EINVAL);
     301           0 :         assert_return(data, -EINVAL);
     302           0 :         assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
     303             : 
     304           0 :         if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
     305           0 :             client->client_id.type == type &&
     306           0 :             memcmp(&client->client_id.raw.data, data, data_len) == 0)
     307           0 :                 return 0;
     308             : 
     309             :         /* For hardware types, log debug message about unexpected data length.
     310             :          *
     311             :          * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
     312             :          * last last 8 bytes of the address are stable and suitable to put into
     313             :          * the client-id. The caller is advised to account for that. */
     314           0 :         if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) ||
     315           0 :             (type == ARPHRD_INFINIBAND && data_len != 8))
     316           0 :                 log_dhcp_client(client, "Changing client ID to hardware type %u with "
     317             :                                 "unexpected address length %zu",
     318             :                                 type, data_len);
     319             : 
     320           0 :         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
     321           0 :                 log_dhcp_client(client, "Changing client ID on running DHCP "
     322             :                                 "client, restarting");
     323           0 :                 need_restart = true;
     324           0 :                 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
     325             :         }
     326             : 
     327           0 :         client->client_id.type = type;
     328           0 :         memcpy(&client->client_id.raw.data, data, data_len);
     329           0 :         client->client_id_len = data_len + sizeof (client->client_id.type);
     330             : 
     331           0 :         if (need_restart && client->state != DHCP_STATE_STOPPED)
     332           0 :                 sd_dhcp_client_start(client);
     333             : 
     334           0 :         return 0;
     335             : }
     336             : 
     337             : /**
     338             :  * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
     339             :  * without further modification. Otherwise, if duid_type is supported, DUID
     340             :  * is set based on that type. Otherwise, an error is returned.
     341             :  */
     342           0 : static int dhcp_client_set_iaid_duid_internal(
     343             :                 sd_dhcp_client *client,
     344             :                 bool iaid_append,
     345             :                 bool iaid_set,
     346             :                 uint32_t iaid,
     347             :                 uint16_t duid_type,
     348             :                 const void *duid,
     349             :                 size_t duid_len,
     350             :                 usec_t llt_time) {
     351             : 
     352           0 :         DHCP_CLIENT_DONT_DESTROY(client);
     353             :         int r;
     354             :         size_t len;
     355             : 
     356           0 :         assert_return(client, -EINVAL);
     357           0 :         assert_return(duid_len == 0 || duid, -EINVAL);
     358             : 
     359           0 :         if (duid) {
     360           0 :                 r = dhcp_validate_duid_len(duid_type, duid_len, true);
     361           0 :                 if (r < 0)
     362           0 :                         return r;
     363             :         }
     364             : 
     365           0 :         zero(client->client_id);
     366           0 :         client->client_id.type = 255;
     367             : 
     368           0 :         if (iaid_append) {
     369           0 :                 if (iaid_set)
     370           0 :                         client->client_id.ns.iaid = htobe32(iaid);
     371             :                 else {
     372           0 :                         r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
     373             :                                                      client->mac_addr_len,
     374             :                                                      true,
     375           0 :                                                      &client->client_id.ns.iaid);
     376           0 :                         if (r < 0)
     377           0 :                                 return r;
     378             :                 }
     379             :         }
     380             : 
     381           0 :         if (duid) {
     382           0 :                 client->client_id.ns.duid.type = htobe16(duid_type);
     383           0 :                 memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
     384           0 :                 len = sizeof(client->client_id.ns.duid.type) + duid_len;
     385             :         } else
     386           0 :                 switch (duid_type) {
     387           0 :                 case DUID_TYPE_LLT:
     388           0 :                         if (client->mac_addr_len == 0)
     389           0 :                                 return -EOPNOTSUPP;
     390             : 
     391           0 :                         r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
     392           0 :                         if (r < 0)
     393           0 :                                 return r;
     394           0 :                         break;
     395           0 :                 case DUID_TYPE_EN:
     396           0 :                         r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
     397           0 :                         if (r < 0)
     398           0 :                                 return r;
     399           0 :                         break;
     400           0 :                 case DUID_TYPE_LL:
     401           0 :                         if (client->mac_addr_len == 0)
     402           0 :                                 return -EOPNOTSUPP;
     403             : 
     404           0 :                         r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
     405           0 :                         if (r < 0)
     406           0 :                                 return r;
     407           0 :                         break;
     408           0 :                 case DUID_TYPE_UUID:
     409           0 :                         r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len);
     410           0 :                         if (r < 0)
     411           0 :                                 return r;
     412           0 :                         break;
     413           0 :                 default:
     414           0 :                         return -EINVAL;
     415             :                 }
     416             : 
     417           0 :         client->client_id_len = sizeof(client->client_id.type) + len +
     418           0 :                                 (iaid_append ? sizeof(client->client_id.ns.iaid) : 0);
     419             : 
     420           0 :         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
     421           0 :                 log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : "");
     422           0 :                 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
     423           0 :                 sd_dhcp_client_start(client);
     424             :         }
     425             : 
     426           0 :         return 0;
     427             : }
     428             : 
     429           0 : int sd_dhcp_client_set_iaid_duid(
     430             :                 sd_dhcp_client *client,
     431             :                 bool iaid_set,
     432             :                 uint32_t iaid,
     433             :                 uint16_t duid_type,
     434             :                 const void *duid,
     435             :                 size_t duid_len) {
     436           0 :         return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, duid_type, duid, duid_len, 0);
     437             : }
     438             : 
     439           0 : int sd_dhcp_client_set_iaid_duid_llt(
     440             :                 sd_dhcp_client *client,
     441             :                 bool iaid_set,
     442             :                 uint32_t iaid,
     443             :                 usec_t llt_time) {
     444           0 :         return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time);
     445             : }
     446             : 
     447           0 : int sd_dhcp_client_set_duid(
     448             :                 sd_dhcp_client *client,
     449             :                 uint16_t duid_type,
     450             :                 const void *duid,
     451             :                 size_t duid_len) {
     452           0 :         return dhcp_client_set_iaid_duid_internal(client, false, false, 0, duid_type, duid, duid_len, 0);
     453             : }
     454             : 
     455           0 : int sd_dhcp_client_set_duid_llt(
     456             :                 sd_dhcp_client *client,
     457             :                 usec_t llt_time) {
     458           0 :         return dhcp_client_set_iaid_duid_internal(client, false, false, 0, DUID_TYPE_LLT, NULL, 0, llt_time);
     459             : }
     460             : 
     461           5 : int sd_dhcp_client_set_hostname(
     462             :                 sd_dhcp_client *client,
     463             :                 const char *hostname) {
     464             : 
     465           5 :         assert_return(client, -EINVAL);
     466             : 
     467             :         /* Make sure hostnames qualify as DNS and as Linux hostnames */
     468           5 :         if (hostname &&
     469           4 :             !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0))
     470           2 :                 return -EINVAL;
     471             : 
     472           3 :         return free_and_strdup(&client->hostname, hostname);
     473             : }
     474             : 
     475           0 : int sd_dhcp_client_set_vendor_class_identifier(
     476             :                 sd_dhcp_client *client,
     477             :                 const char *vci) {
     478             : 
     479           0 :         assert_return(client, -EINVAL);
     480             : 
     481           0 :         return free_and_strdup(&client->vendor_class_identifier, vci);
     482             : }
     483             : 
     484           0 : int sd_dhcp_client_set_user_class(
     485             :                 sd_dhcp_client *client,
     486             :                 const char* const* user_class) {
     487             : 
     488           0 :         _cleanup_strv_free_ char **s = NULL;
     489             :         char **p;
     490             : 
     491           0 :         STRV_FOREACH(p, (char **) user_class)
     492           0 :                 if (strlen(*p) > 255)
     493           0 :                         return -ENAMETOOLONG;
     494             : 
     495           0 :         s = strv_copy((char **) user_class);
     496           0 :         if (!s)
     497           0 :                 return -ENOMEM;
     498             : 
     499           0 :         client->user_class = TAKE_PTR(s);
     500             : 
     501           0 :         return 0;
     502             : }
     503             : 
     504           0 : int sd_dhcp_client_set_client_port(
     505             :                 sd_dhcp_client *client,
     506             :                 uint16_t port) {
     507             : 
     508           0 :         assert_return(client, -EINVAL);
     509             : 
     510           0 :         client->port = port;
     511             : 
     512           0 :         return 0;
     513             : }
     514             : 
     515           0 : int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
     516           0 :         assert_return(client, -EINVAL);
     517           0 :         assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
     518             : 
     519           0 :         client->mtu = mtu;
     520             : 
     521           0 :         return 0;
     522             : }
     523             : 
     524           0 : int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) {
     525           0 :         assert_return(client, -EINVAL);
     526             : 
     527           0 :         client->max_attempts = max_attempts;
     528             : 
     529           0 :         return 0;
     530             : }
     531             : 
     532           1 : int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
     533           1 :         assert_return(client, -EINVAL);
     534             : 
     535           1 :         if (!IN_SET(client->state, DHCP_STATE_SELECTING, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING))
     536           0 :                 return -EADDRNOTAVAIL;
     537             : 
     538           1 :         if (ret)
     539           1 :                 *ret = client->lease;
     540             : 
     541           1 :         return 0;
     542             : }
     543             : 
     544           3 : static int client_notify(sd_dhcp_client *client, int event) {
     545           3 :         assert(client);
     546             : 
     547           3 :         if (client->callback)
     548           1 :                 return client->callback(client, event, client->userdata);
     549             : 
     550           2 :         return 0;
     551             : }
     552             : 
     553           8 : static int client_initialize(sd_dhcp_client *client) {
     554           8 :         assert_return(client, -EINVAL);
     555             : 
     556           8 :         client->receive_message = sd_event_source_unref(client->receive_message);
     557             : 
     558           8 :         client->fd = asynchronous_close(client->fd);
     559             : 
     560           8 :         (void) event_source_disable(client->timeout_resend);
     561           8 :         (void) event_source_disable(client->timeout_t1);
     562           8 :         (void) event_source_disable(client->timeout_t2);
     563           8 :         (void) event_source_disable(client->timeout_expire);
     564             : 
     565           8 :         client->attempt = 0;
     566             : 
     567           8 :         client->state = DHCP_STATE_INIT;
     568           8 :         client->xid = 0;
     569             : 
     570           8 :         client->lease = sd_dhcp_lease_unref(client->lease);
     571             : 
     572           8 :         return 0;
     573             : }
     574             : 
     575           2 : static void client_stop(sd_dhcp_client *client, int error) {
     576           2 :         assert(client);
     577             : 
     578           2 :         if (error < 0)
     579           0 :                 log_dhcp_client_errno(client, error, "STOPPED: %m");
     580           2 :         else if (error == SD_DHCP_CLIENT_EVENT_STOP)
     581           2 :                 log_dhcp_client(client, "STOPPED");
     582             :         else
     583           0 :                 log_dhcp_client(client, "STOPPED: Unknown event");
     584             : 
     585           2 :         client_notify(client, error);
     586             : 
     587           2 :         client_initialize(client);
     588           2 : }
     589             : 
     590           2 : static int client_message_init(
     591             :                 sd_dhcp_client *client,
     592             :                 DHCPPacket **ret,
     593             :                 uint8_t type,
     594             :                 size_t *_optlen,
     595             :                 size_t *_optoffset) {
     596             : 
     597           2 :         _cleanup_free_ DHCPPacket *packet = NULL;
     598             :         size_t optlen, optoffset, size;
     599             :         be16_t max_size;
     600             :         usec_t time_now;
     601             :         uint16_t secs;
     602             :         int r;
     603             : 
     604           2 :         assert(client);
     605           2 :         assert(client->start_time);
     606           2 :         assert(ret);
     607           2 :         assert(_optlen);
     608           2 :         assert(_optoffset);
     609           2 :         assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE));
     610             : 
     611           2 :         optlen = DHCP_MIN_OPTIONS_SIZE;
     612           2 :         size = sizeof(DHCPPacket) + optlen;
     613             : 
     614           2 :         packet = malloc0(size);
     615           2 :         if (!packet)
     616           0 :                 return -ENOMEM;
     617             : 
     618           2 :         r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
     619           2 :                               client->arp_type, optlen, &optoffset);
     620           2 :         if (r < 0)
     621           0 :                 return r;
     622             : 
     623             :         /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
     624             :            refuse to issue an DHCP lease if 'secs' is set to zero */
     625           2 :         r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
     626           2 :         if (r < 0)
     627           0 :                 return r;
     628           2 :         assert(time_now >= client->start_time);
     629             : 
     630             :         /* seconds between sending first and last DISCOVER
     631             :          * must always be strictly positive to deal with broken servers */
     632           2 :         secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
     633           2 :         packet->dhcp.secs = htobe16(secs);
     634             : 
     635             :         /* RFC2132 section 4.1
     636             :            A client that cannot receive unicast IP datagrams until its protocol
     637             :            software has been configured with an IP address SHOULD set the
     638             :            BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
     639             :            DHCPREQUEST messages that client sends.  The BROADCAST bit will
     640             :            provide a hint to the DHCP server and BOOTP relay agent to broadcast
     641             :            any messages to the client on the client's subnet.
     642             : 
     643             :            Note: some interfaces needs this to be enabled, but some networks
     644             :            needs this to be disabled as broadcasts are filteretd, so this
     645             :            needs to be configurable */
     646           2 :         if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
     647           0 :                 packet->dhcp.flags = htobe16(0x8000);
     648             : 
     649             :         /* RFC2132 section 4.1.1:
     650             :            The client MUST include its hardware address in the ’chaddr’ field, if
     651             :            necessary for delivery of DHCP reply messages.  Non-Ethernet
     652             :            interfaces will leave 'chaddr' empty and use the client identifier
     653             :            instead (eg, RFC 4390 section 2.1).
     654             :          */
     655           2 :         if (client->arp_type == ARPHRD_ETHER)
     656           2 :                 memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
     657             : 
     658             :         /* If no client identifier exists, construct an RFC 4361-compliant one */
     659           2 :         if (client->client_id_len == 0) {
     660             :                 size_t duid_len;
     661             : 
     662           2 :                 client->client_id.type = 255;
     663             : 
     664           2 :                 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
     665           2 :                                              true, &client->client_id.ns.iaid);
     666           2 :                 if (r < 0)
     667           0 :                         return r;
     668             : 
     669           2 :                 r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
     670           2 :                 if (r < 0)
     671           0 :                         return r;
     672             : 
     673           2 :                 client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
     674             :         }
     675             : 
     676             :         /* Some DHCP servers will refuse to issue an DHCP lease if the Client
     677             :            Identifier option is not set */
     678           2 :         if (client->client_id_len) {
     679           2 :                 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
     680             :                                        SD_DHCP_OPTION_CLIENT_IDENTIFIER,
     681             :                                        client->client_id_len,
     682           2 :                                        &client->client_id);
     683           2 :                 if (r < 0)
     684           0 :                         return r;
     685             :         }
     686             : 
     687             :         /* RFC2131 section 3.5:
     688             :            in its initial DHCPDISCOVER or DHCPREQUEST message, a
     689             :            client may provide the server with a list of specific
     690             :            parameters the client is interested in. If the client
     691             :            includes a list of parameters in a DHCPDISCOVER message,
     692             :            it MUST include that list in any subsequent DHCPREQUEST
     693             :            messages.
     694             :          */
     695             : 
     696             :         /* RFC7844 section 3:
     697             :            MAY contain the Parameter Request List option. */
     698             :         /* NOTE: in case that there would be an option to do not send
     699             :          * any PRL at all, the size should be checked before sending */
     700           2 :         if (client->req_opts_size > 0 && type != DHCP_RELEASE) {
     701           2 :                 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
     702             :                                        SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
     703           2 :                                        client->req_opts_size, client->req_opts);
     704           2 :                 if (r < 0)
     705           0 :                         return r;
     706             :         }
     707             : 
     708             :         /* RFC2131 section 3.5:
     709             :            The client SHOULD include the ’maximum DHCP message size’ option to
     710             :            let the server know how large the server may make its DHCP messages.
     711             : 
     712             :            Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
     713             :            than the defined default size unless the Maximum Message Size option
     714             :            is explicitly set
     715             : 
     716             :            RFC3442 "Requirements to Avoid Sizing Constraints":
     717             :            Because a full routing table can be quite large, the standard 576
     718             :            octet maximum size for a DHCP message may be too short to contain
     719             :            some legitimate Classless Static Route options.  Because of this,
     720             :            clients implementing the Classless Static Route option SHOULD send a
     721             :            Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
     722             :            stack is capable of receiving larger IP datagrams.  In this case, the
     723             :            client SHOULD set the value of this option to at least the MTU of the
     724             :            interface that the client is configuring.  The client MAY set the
     725             :            value of this option higher, up to the size of the largest UDP packet
     726             :            it is prepared to accept.  (Note that the value specified in the
     727             :            Maximum DHCP Message Size option is the total maximum packet size,
     728             :            including IP and UDP headers.)
     729             :          */
     730             :         /* RFC7844 section 3:
     731             :            SHOULD NOT contain any other option. */
     732           2 :         if (!client->anonymize && type != DHCP_RELEASE) {
     733           2 :                 max_size = htobe16(size);
     734           2 :                 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
     735             :                                        SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
     736             :                                        2, &max_size);
     737           2 :                 if (r < 0)
     738           0 :                         return r;
     739             :         }
     740             : 
     741           2 :         *_optlen = optlen;
     742           2 :         *_optoffset = optoffset;
     743           2 :         *ret = TAKE_PTR(packet);
     744             : 
     745           2 :         return 0;
     746             : }
     747             : 
     748           0 : static int client_append_fqdn_option(
     749             :                 DHCPMessage *message,
     750             :                 size_t optlen,
     751             :                 size_t *optoffset,
     752             :                 const char *fqdn) {
     753             : 
     754             :         uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
     755             :         int r;
     756             : 
     757           0 :         buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
     758             :                     DHCP_FQDN_FLAG_E;  /* Canonical wire format */
     759           0 :         buffer[1] = 0;                 /* RCODE1 (deprecated) */
     760           0 :         buffer[2] = 0;                 /* RCODE2 (deprecated) */
     761             : 
     762           0 :         r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);
     763           0 :         if (r > 0)
     764           0 :                 r = dhcp_option_append(message, optlen, optoffset, 0,
     765           0 :                                        SD_DHCP_OPTION_FQDN, 3 + r, buffer);
     766             : 
     767           0 :         return r;
     768             : }
     769             : 
     770           2 : static int dhcp_client_send_raw(
     771             :                 sd_dhcp_client *client,
     772             :                 DHCPPacket *packet,
     773             :                 size_t len) {
     774             : 
     775           2 :         dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
     776             :                                       INADDR_BROADCAST, DHCP_PORT_SERVER, len);
     777             : 
     778           2 :         return dhcp_network_send_raw_socket(client->fd, &client->link,
     779             :                                             packet, len);
     780             : }
     781             : 
     782           2 : static int client_send_discover(sd_dhcp_client *client) {
     783           2 :         _cleanup_free_ DHCPPacket *discover = NULL;
     784             :         size_t optoffset, optlen;
     785             :         int r;
     786             : 
     787           2 :         assert(client);
     788           2 :         assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
     789             : 
     790           2 :         r = client_message_init(client, &discover, DHCP_DISCOVER,
     791             :                                 &optlen, &optoffset);
     792           2 :         if (r < 0)
     793           0 :                 return r;
     794             : 
     795             :         /* the client may suggest values for the network address
     796             :            and lease time in the DHCPDISCOVER message. The client may include
     797             :            the ’requested IP address’ option to suggest that a particular IP
     798             :            address be assigned, and may include the ’IP address lease time’
     799             :            option to suggest the lease time it would like.
     800             :          */
     801           2 :         if (client->last_addr != INADDR_ANY) {
     802           0 :                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
     803             :                                        SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
     804           0 :                                        4, &client->last_addr);
     805           0 :                 if (r < 0)
     806           0 :                         return r;
     807             :         }
     808             : 
     809           2 :         if (client->hostname) {
     810             :                 /* According to RFC 4702 "clients that send the Client FQDN option in
     811             :                    their messages MUST NOT also send the Host Name option". Just send
     812             :                    one of the two depending on the hostname type.
     813             :                 */
     814           0 :                 if (dns_name_is_single_label(client->hostname)) {
     815             :                         /* it is unclear from RFC 2131 if client should send hostname in
     816             :                            DHCPDISCOVER but dhclient does and so we do as well
     817             :                         */
     818           0 :                         r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
     819             :                                                SD_DHCP_OPTION_HOST_NAME,
     820           0 :                                                strlen(client->hostname), client->hostname);
     821             :                 } else
     822           0 :                         r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
     823           0 :                                                       client->hostname);
     824           0 :                 if (r < 0)
     825           0 :                         return r;
     826             :         }
     827             : 
     828           2 :         if (client->vendor_class_identifier) {
     829           0 :                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
     830             :                                        SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
     831           0 :                                        strlen(client->vendor_class_identifier),
     832           0 :                                        client->vendor_class_identifier);
     833           0 :                 if (r < 0)
     834           0 :                         return r;
     835             :         }
     836             : 
     837           2 :         if (client->user_class) {
     838           0 :                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
     839             :                                        SD_DHCP_OPTION_USER_CLASS,
     840           0 :                                        strv_length(client->user_class),
     841           0 :                                        client->user_class);
     842           0 :                 if (r < 0)
     843           0 :                         return r;
     844             :         }
     845             : 
     846           2 :         r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
     847             :                                SD_DHCP_OPTION_END, 0, NULL);
     848           2 :         if (r < 0)
     849           0 :                 return r;
     850             : 
     851             :         /* We currently ignore:
     852             :            The client SHOULD wait a random time between one and ten seconds to
     853             :            desynchronize the use of DHCP at startup.
     854             :          */
     855           2 :         r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
     856           2 :         if (r < 0)
     857           0 :                 return r;
     858             : 
     859           2 :         log_dhcp_client(client, "DISCOVER");
     860             : 
     861           2 :         return 0;
     862             : }
     863             : 
     864           0 : static int client_send_release(sd_dhcp_client *client) {
     865           0 :         _cleanup_free_ DHCPPacket *release = NULL;
     866             :         size_t optoffset, optlen;
     867             :         int r;
     868             : 
     869           0 :         assert(client);
     870           0 :         assert(!IN_SET(client->state, DHCP_STATE_STOPPED));
     871             : 
     872           0 :         r = client_message_init(client, &release, DHCP_RELEASE,
     873             :                                 &optlen, &optoffset);
     874           0 :         if (r < 0)
     875           0 :                 return r;
     876             : 
     877             :         /* Fill up release IP and MAC */
     878           0 :         release->dhcp.ciaddr = client->lease->address;
     879           0 :         memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
     880             : 
     881           0 :         r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
     882             :                                SD_DHCP_OPTION_END, 0, NULL);
     883           0 :         if (r < 0)
     884           0 :                 return r;
     885             : 
     886           0 :         r = dhcp_network_send_udp_socket(client->fd,
     887           0 :                                          client->lease->server_address,
     888             :                                          DHCP_PORT_SERVER,
     889           0 :                                          &release->dhcp,
     890             :                                          sizeof(DHCPMessage) + optoffset);
     891           0 :         if (r < 0)
     892           0 :                 return r;
     893             : 
     894           0 :         log_dhcp_client(client, "RELEASE");
     895             : 
     896           0 :         return 0;
     897             : }
     898             : 
     899           0 : static int client_send_request(sd_dhcp_client *client) {
     900           0 :         _cleanup_free_ DHCPPacket *request = NULL;
     901             :         size_t optoffset, optlen;
     902             :         int r;
     903             : 
     904           0 :         assert(client);
     905             : 
     906           0 :         r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset);
     907           0 :         if (r < 0)
     908           0 :                 return r;
     909             : 
     910           0 :         switch (client->state) {
     911             :         /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
     912             :            SELECTING should be REQUESTING)
     913             :          */
     914             : 
     915           0 :         case DHCP_STATE_REQUESTING:
     916             :                 /* Client inserts the address of the selected server in ’server
     917             :                    identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
     918             :                    filled in with the yiaddr value from the chosen DHCPOFFER.
     919             :                  */
     920             : 
     921           0 :                 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
     922             :                                        SD_DHCP_OPTION_SERVER_IDENTIFIER,
     923           0 :                                        4, &client->lease->server_address);
     924           0 :                 if (r < 0)
     925           0 :                         return r;
     926             : 
     927           0 :                 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
     928             :                                        SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
     929           0 :                                        4, &client->lease->address);
     930           0 :                 if (r < 0)
     931           0 :                         return r;
     932             : 
     933           0 :                 break;
     934             : 
     935           0 :         case DHCP_STATE_INIT_REBOOT:
     936             :                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
     937             :                    option MUST be filled in with client’s notion of its previously
     938             :                    assigned address. ’ciaddr’ MUST be zero.
     939             :                  */
     940           0 :                 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
     941             :                                        SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
     942           0 :                                        4, &client->last_addr);
     943           0 :                 if (r < 0)
     944           0 :                         return r;
     945           0 :                 break;
     946             : 
     947           0 :         case DHCP_STATE_RENEWING:
     948             :                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
     949             :                    option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
     950             :                    client’s IP address.
     951             :                 */
     952             : 
     953             :         case DHCP_STATE_REBINDING:
     954             :                 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
     955             :                    option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
     956             :                    client’s IP address.
     957             : 
     958             :                    This message MUST be broadcast to the 0xffffffff IP broadcast address.
     959             :                  */
     960           0 :                 request->dhcp.ciaddr = client->lease->address;
     961             : 
     962           0 :                 break;
     963             : 
     964           0 :         case DHCP_STATE_INIT:
     965             :         case DHCP_STATE_SELECTING:
     966             :         case DHCP_STATE_REBOOTING:
     967             :         case DHCP_STATE_BOUND:
     968             :         case DHCP_STATE_STOPPED:
     969           0 :                 return -EINVAL;
     970             :         }
     971             : 
     972           0 :         if (client->hostname) {
     973           0 :                 if (dns_name_is_single_label(client->hostname))
     974           0 :                         r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
     975             :                                                SD_DHCP_OPTION_HOST_NAME,
     976           0 :                                                strlen(client->hostname), client->hostname);
     977             :                 else
     978           0 :                         r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
     979           0 :                                                       client->hostname);
     980           0 :                 if (r < 0)
     981           0 :                         return r;
     982             :         }
     983             : 
     984           0 :         if (client->vendor_class_identifier) {
     985           0 :                 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
     986             :                                        SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
     987           0 :                                        strlen(client->vendor_class_identifier),
     988           0 :                                        client->vendor_class_identifier);
     989           0 :                 if (r < 0)
     990           0 :                         return r;
     991             :         }
     992             : 
     993           0 :         r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
     994             :                                SD_DHCP_OPTION_END, 0, NULL);
     995           0 :         if (r < 0)
     996           0 :                 return r;
     997             : 
     998           0 :         if (client->state == DHCP_STATE_RENEWING) {
     999           0 :                 r = dhcp_network_send_udp_socket(client->fd,
    1000           0 :                                                  client->lease->server_address,
    1001             :                                                  DHCP_PORT_SERVER,
    1002           0 :                                                  &request->dhcp,
    1003             :                                                  sizeof(DHCPMessage) + optoffset);
    1004             :         } else {
    1005           0 :                 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
    1006             :         }
    1007           0 :         if (r < 0)
    1008           0 :                 return r;
    1009             : 
    1010           0 :         switch (client->state) {
    1011             : 
    1012           0 :         case DHCP_STATE_REQUESTING:
    1013           0 :                 log_dhcp_client(client, "REQUEST (requesting)");
    1014           0 :                 break;
    1015             : 
    1016           0 :         case DHCP_STATE_INIT_REBOOT:
    1017           0 :                 log_dhcp_client(client, "REQUEST (init-reboot)");
    1018           0 :                 break;
    1019             : 
    1020           0 :         case DHCP_STATE_RENEWING:
    1021           0 :                 log_dhcp_client(client, "REQUEST (renewing)");
    1022           0 :                 break;
    1023             : 
    1024           0 :         case DHCP_STATE_REBINDING:
    1025           0 :                 log_dhcp_client(client, "REQUEST (rebinding)");
    1026           0 :                 break;
    1027             : 
    1028           0 :         default:
    1029           0 :                 log_dhcp_client(client, "REQUEST (invalid)");
    1030           0 :                 break;
    1031             :         }
    1032             : 
    1033           0 :         return 0;
    1034             : }
    1035             : 
    1036             : static int client_start(sd_dhcp_client *client);
    1037             : 
    1038           2 : static int client_timeout_resend(
    1039             :                 sd_event_source *s,
    1040             :                 uint64_t usec,
    1041             :                 void *userdata) {
    1042             : 
    1043           2 :         sd_dhcp_client *client = userdata;
    1044           4 :         DHCP_CLIENT_DONT_DESTROY(client);
    1045           2 :         usec_t next_timeout = 0;
    1046             :         uint64_t time_now;
    1047             :         uint32_t time_left;
    1048             :         int r;
    1049             : 
    1050           2 :         assert(s);
    1051           2 :         assert(client);
    1052           2 :         assert(client->event);
    1053             : 
    1054           2 :         r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
    1055           2 :         if (r < 0)
    1056           0 :                 goto error;
    1057             : 
    1058           2 :         switch (client->state) {
    1059             : 
    1060           0 :         case DHCP_STATE_RENEWING:
    1061             : 
    1062           0 :                 time_left = (client->lease->t2 - client->lease->t1) / 2;
    1063           0 :                 if (time_left < 60)
    1064           0 :                         time_left = 60;
    1065             : 
    1066           0 :                 next_timeout = time_now + time_left * USEC_PER_SEC;
    1067             : 
    1068           0 :                 break;
    1069             : 
    1070           0 :         case DHCP_STATE_REBINDING:
    1071             : 
    1072           0 :                 time_left = (client->lease->lifetime - client->lease->t2) / 2;
    1073           0 :                 if (time_left < 60)
    1074           0 :                         time_left = 60;
    1075             : 
    1076           0 :                 next_timeout = time_now + time_left * USEC_PER_SEC;
    1077           0 :                 break;
    1078             : 
    1079           0 :         case DHCP_STATE_REBOOTING:
    1080             :                 /* start over as we did not receive a timely ack or nak */
    1081           0 :                 r = client_initialize(client);
    1082           0 :                 if (r < 0)
    1083           0 :                         goto error;
    1084             : 
    1085           0 :                 r = client_start(client);
    1086           0 :                 if (r < 0)
    1087           0 :                         goto error;
    1088             :                 else {
    1089           0 :                         log_dhcp_client(client, "REBOOTED");
    1090           0 :                         return 0;
    1091             :                 }
    1092             : 
    1093           2 :         case DHCP_STATE_INIT:
    1094             :         case DHCP_STATE_INIT_REBOOT:
    1095             :         case DHCP_STATE_SELECTING:
    1096             :         case DHCP_STATE_REQUESTING:
    1097             :         case DHCP_STATE_BOUND:
    1098             : 
    1099           2 :                 if (client->attempt < client->max_attempts)
    1100           2 :                         client->attempt++;
    1101             :                 else
    1102           0 :                         goto error;
    1103             : 
    1104           2 :                 next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
    1105             : 
    1106           2 :                 break;
    1107             : 
    1108           0 :         case DHCP_STATE_STOPPED:
    1109           0 :                 r = -EINVAL;
    1110           0 :                 goto error;
    1111             :         }
    1112             : 
    1113           2 :         next_timeout += (random_u32() & 0x1fffff);
    1114             : 
    1115           2 :         r = event_reset_time(client->event, &client->timeout_resend,
    1116             :                              clock_boottime_or_monotonic(),
    1117             :                              next_timeout, 10 * USEC_PER_MSEC,
    1118             :                              client_timeout_resend, client,
    1119           2 :                              client->event_priority, "dhcp4-resend-timer", true);
    1120           2 :         if (r < 0)
    1121           0 :                 goto error;
    1122             : 
    1123           2 :         switch (client->state) {
    1124           2 :         case DHCP_STATE_INIT:
    1125           2 :                 r = client_send_discover(client);
    1126           2 :                 if (r >= 0) {
    1127           2 :                         client->state = DHCP_STATE_SELECTING;
    1128           2 :                         client->attempt = 0;
    1129           0 :                 } else if (client->attempt >= client->max_attempts)
    1130           0 :                         goto error;
    1131             : 
    1132           2 :                 break;
    1133             : 
    1134           0 :         case DHCP_STATE_SELECTING:
    1135           0 :                 r = client_send_discover(client);
    1136           0 :                 if (r < 0 && client->attempt >= client->max_attempts)
    1137           0 :                         goto error;
    1138             : 
    1139           0 :                 break;
    1140             : 
    1141           0 :         case DHCP_STATE_INIT_REBOOT:
    1142             :         case DHCP_STATE_REQUESTING:
    1143             :         case DHCP_STATE_RENEWING:
    1144             :         case DHCP_STATE_REBINDING:
    1145           0 :                 r = client_send_request(client);
    1146           0 :                 if (r < 0 && client->attempt >= client->max_attempts)
    1147           0 :                          goto error;
    1148             : 
    1149           0 :                 if (client->state == DHCP_STATE_INIT_REBOOT)
    1150           0 :                         client->state = DHCP_STATE_REBOOTING;
    1151             : 
    1152           0 :                 client->request_sent = time_now;
    1153             : 
    1154           0 :                 break;
    1155             : 
    1156           0 :         case DHCP_STATE_REBOOTING:
    1157             :         case DHCP_STATE_BOUND:
    1158             : 
    1159           0 :                 break;
    1160             : 
    1161           0 :         case DHCP_STATE_STOPPED:
    1162           0 :                 r = -EINVAL;
    1163           0 :                 goto error;
    1164             :         }
    1165             : 
    1166           2 :         return 0;
    1167             : 
    1168           0 : error:
    1169           0 :         client_stop(client, r);
    1170             : 
    1171             :         /* Errors were dealt with when stopping the client, don't spill
    1172             :            errors into the event loop handler */
    1173           0 :         return 0;
    1174             : }
    1175             : 
    1176           2 : static int client_initialize_io_events(
    1177             :                 sd_dhcp_client *client,
    1178             :                 sd_event_io_handler_t io_callback) {
    1179             : 
    1180             :         int r;
    1181             : 
    1182           2 :         assert(client);
    1183           2 :         assert(client->event);
    1184             : 
    1185           2 :         r = sd_event_add_io(client->event, &client->receive_message,
    1186             :                             client->fd, EPOLLIN, io_callback,
    1187             :                             client);
    1188           2 :         if (r < 0)
    1189           0 :                 goto error;
    1190             : 
    1191           2 :         r = sd_event_source_set_priority(client->receive_message,
    1192           2 :                                          client->event_priority);
    1193           2 :         if (r < 0)
    1194           0 :                 goto error;
    1195             : 
    1196           2 :         r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
    1197           2 :         if (r < 0)
    1198           0 :                 goto error;
    1199             : 
    1200           2 : error:
    1201           2 :         if (r < 0)
    1202           0 :                 client_stop(client, r);
    1203             : 
    1204           2 :         return 0;
    1205             : }
    1206             : 
    1207           2 : static int client_initialize_time_events(sd_dhcp_client *client) {
    1208           2 :         uint64_t usec = 0;
    1209             :         int r;
    1210             : 
    1211           2 :         assert(client);
    1212           2 :         assert(client->event);
    1213             : 
    1214           2 :         if (client->start_delay) {
    1215           0 :                 assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
    1216           0 :                 usec += client->start_delay;
    1217             :         }
    1218             : 
    1219           2 :         r = event_reset_time(client->event, &client->timeout_resend,
    1220             :                              clock_boottime_or_monotonic(),
    1221             :                              usec, 0,
    1222             :                              client_timeout_resend, client,
    1223           2 :                              client->event_priority, "dhcp4-resend-timer", true);
    1224           2 :         if (r < 0)
    1225           0 :                 client_stop(client, r);
    1226             : 
    1227           2 :         return 0;
    1228             : 
    1229             : }
    1230             : 
    1231           2 : static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
    1232           2 :         client_initialize_io_events(client, io_callback);
    1233           2 :         client_initialize_time_events(client);
    1234             : 
    1235           2 :         return 0;
    1236             : }
    1237             : 
    1238           2 : static int client_start_delayed(sd_dhcp_client *client) {
    1239             :         int r;
    1240             : 
    1241           2 :         assert_return(client, -EINVAL);
    1242           2 :         assert_return(client->event, -EINVAL);
    1243           2 :         assert_return(client->ifindex > 0, -EINVAL);
    1244           2 :         assert_return(client->fd < 0, -EBUSY);
    1245           2 :         assert_return(client->xid == 0, -EINVAL);
    1246           2 :         assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY);
    1247             : 
    1248           2 :         client->xid = random_u32();
    1249             : 
    1250           6 :         r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
    1251           2 :                                          client->xid, client->mac_addr,
    1252           2 :                                          client->mac_addr_len, client->arp_type, client->port);
    1253           2 :         if (r < 0) {
    1254           0 :                 client_stop(client, r);
    1255           0 :                 return r;
    1256             :         }
    1257           2 :         client->fd = r;
    1258             : 
    1259           2 :         if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT))
    1260           2 :                 client->start_time = now(clock_boottime_or_monotonic());
    1261             : 
    1262           2 :         return client_initialize_events(client, client_receive_message_raw);
    1263             : }
    1264             : 
    1265           2 : static int client_start(sd_dhcp_client *client) {
    1266           2 :         client->start_delay = 0;
    1267           2 :         return client_start_delayed(client);
    1268             : }
    1269             : 
    1270           0 : static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
    1271           0 :         sd_dhcp_client *client = userdata;
    1272           0 :         DHCP_CLIENT_DONT_DESTROY(client);
    1273             : 
    1274           0 :         log_dhcp_client(client, "EXPIRED");
    1275             : 
    1276           0 :         client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
    1277             : 
    1278             :         /* lease was lost, start over if not freed or stopped in callback */
    1279           0 :         if (client->state != DHCP_STATE_STOPPED) {
    1280           0 :                 client_initialize(client);
    1281           0 :                 client_start(client);
    1282             :         }
    1283             : 
    1284           0 :         return 0;
    1285             : }
    1286             : 
    1287           0 : static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
    1288           0 :         sd_dhcp_client *client = userdata;
    1289           0 :         DHCP_CLIENT_DONT_DESTROY(client);
    1290             :         int r;
    1291             : 
    1292           0 :         assert(client);
    1293             : 
    1294           0 :         client->receive_message = sd_event_source_unref(client->receive_message);
    1295           0 :         client->fd = asynchronous_close(client->fd);
    1296             : 
    1297           0 :         client->state = DHCP_STATE_REBINDING;
    1298           0 :         client->attempt = 0;
    1299             : 
    1300           0 :         r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
    1301           0 :                                          client->xid, client->mac_addr,
    1302           0 :                                          client->mac_addr_len, client->arp_type,
    1303           0 :                                          client->port);
    1304           0 :         if (r < 0) {
    1305           0 :                 client_stop(client, r);
    1306           0 :                 return 0;
    1307             :         }
    1308           0 :         client->fd = r;
    1309             : 
    1310           0 :         return client_initialize_events(client, client_receive_message_raw);
    1311             : }
    1312             : 
    1313           0 : static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
    1314           0 :         sd_dhcp_client *client = userdata;
    1315           0 :         DHCP_CLIENT_DONT_DESTROY(client);
    1316             : 
    1317           0 :         client->state = DHCP_STATE_RENEWING;
    1318           0 :         client->attempt = 0;
    1319             : 
    1320           0 :         return client_initialize_time_events(client);
    1321             : }
    1322             : 
    1323           1 : static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
    1324           1 :         _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
    1325             :         int r;
    1326             : 
    1327           1 :         r = dhcp_lease_new(&lease);
    1328           1 :         if (r < 0)
    1329           0 :                 return r;
    1330             : 
    1331           1 :         if (client->client_id_len) {
    1332           2 :                 r = dhcp_lease_set_client_id(lease,
    1333           1 :                                              (uint8_t *) &client->client_id,
    1334             :                                              client->client_id_len);
    1335           1 :                 if (r < 0)
    1336           0 :                         return r;
    1337             :         }
    1338             : 
    1339           1 :         r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
    1340           1 :         if (r != DHCP_OFFER) {
    1341           0 :                 log_dhcp_client(client, "received message was not an OFFER, ignoring");
    1342           0 :                 return -ENOMSG;
    1343             :         }
    1344             : 
    1345           1 :         lease->next_server = offer->siaddr;
    1346           1 :         lease->address = offer->yiaddr;
    1347             : 
    1348           1 :         if (lease->address == 0 ||
    1349           1 :             lease->server_address == 0 ||
    1350           1 :             lease->lifetime == 0) {
    1351           0 :                 log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring");
    1352           0 :                 return -ENOMSG;
    1353             :         }
    1354             : 
    1355           1 :         if (!lease->have_subnet_mask) {
    1356           0 :                 r = dhcp_lease_set_default_subnet_mask(lease);
    1357           0 :                 if (r < 0) {
    1358           0 :                         log_dhcp_client(client,
    1359             :                                         "received lease lacks subnet mask, "
    1360             :                                         "and a fallback one cannot be generated, ignoring");
    1361           0 :                         return -ENOMSG;
    1362             :                 }
    1363             :         }
    1364             : 
    1365           1 :         sd_dhcp_lease_unref(client->lease);
    1366           1 :         client->lease = TAKE_PTR(lease);
    1367             : 
    1368           1 :         if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
    1369           0 :                 return -ENOMSG;
    1370             : 
    1371           1 :         log_dhcp_client(client, "OFFER");
    1372             : 
    1373           1 :         return 0;
    1374             : }
    1375             : 
    1376           0 : static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
    1377             :         int r;
    1378             : 
    1379           0 :         r = dhcp_option_parse(force, len, NULL, NULL, NULL);
    1380           0 :         if (r != DHCP_FORCERENEW)
    1381           0 :                 return -ENOMSG;
    1382             : 
    1383           0 :         log_dhcp_client(client, "FORCERENEW");
    1384             : 
    1385           0 :         return 0;
    1386             : }
    1387             : 
    1388           0 : static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) {
    1389           0 :         if (a->address != b->address)
    1390           0 :                 return false;
    1391             : 
    1392           0 :         if (a->subnet_mask != b->subnet_mask)
    1393           0 :                 return false;
    1394             : 
    1395           0 :         if (a->router_size != b->router_size)
    1396           0 :                 return false;
    1397             : 
    1398           0 :         for (size_t i = 0; i < a->router_size; i++)
    1399           0 :                 if (a->router[i].s_addr != b->router[i].s_addr)
    1400           0 :                         return false;
    1401             : 
    1402           0 :         return true;
    1403             : }
    1404             : 
    1405           0 : static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
    1406           0 :         _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
    1407           0 :         _cleanup_free_ char *error_message = NULL;
    1408             :         int r;
    1409             : 
    1410           0 :         r = dhcp_lease_new(&lease);
    1411           0 :         if (r < 0)
    1412           0 :                 return r;
    1413             : 
    1414           0 :         if (client->client_id_len) {
    1415           0 :                 r = dhcp_lease_set_client_id(lease,
    1416           0 :                                              (uint8_t *) &client->client_id,
    1417             :                                              client->client_id_len);
    1418           0 :                 if (r < 0)
    1419           0 :                         return r;
    1420             :         }
    1421             : 
    1422           0 :         r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
    1423           0 :         if (r == DHCP_NAK) {
    1424           0 :                 log_dhcp_client(client, "NAK: %s", strna(error_message));
    1425           0 :                 return -EADDRNOTAVAIL;
    1426             :         }
    1427             : 
    1428           0 :         if (r != DHCP_ACK) {
    1429           0 :                 log_dhcp_client(client, "received message was not an ACK, ignoring");
    1430           0 :                 return -ENOMSG;
    1431             :         }
    1432             : 
    1433           0 :         lease->next_server = ack->siaddr;
    1434             : 
    1435           0 :         lease->address = ack->yiaddr;
    1436             : 
    1437           0 :         if (lease->address == INADDR_ANY ||
    1438           0 :             lease->server_address == INADDR_ANY ||
    1439           0 :             lease->lifetime == 0) {
    1440           0 :                 log_dhcp_client(client, "received lease lacks address, server "
    1441             :                                 "address or lease lifetime, ignoring");
    1442           0 :                 return -ENOMSG;
    1443             :         }
    1444             : 
    1445           0 :         if (lease->subnet_mask == INADDR_ANY) {
    1446           0 :                 r = dhcp_lease_set_default_subnet_mask(lease);
    1447           0 :                 if (r < 0) {
    1448           0 :                         log_dhcp_client(client,
    1449             :                                         "received lease lacks subnet mask, "
    1450             :                                         "and a fallback one cannot be generated, ignoring");
    1451           0 :                         return -ENOMSG;
    1452             :                 }
    1453             :         }
    1454             : 
    1455           0 :         r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
    1456           0 :         if (client->lease) {
    1457           0 :                 if (lease_equal(client->lease, lease))
    1458           0 :                         r = SD_DHCP_CLIENT_EVENT_RENEW;
    1459             :                 else
    1460           0 :                         r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
    1461             : 
    1462           0 :                 client->lease = sd_dhcp_lease_unref(client->lease);
    1463             :         }
    1464             : 
    1465           0 :         client->lease = TAKE_PTR(lease);
    1466             : 
    1467           0 :         log_dhcp_client(client, "ACK");
    1468             : 
    1469           0 :         return r;
    1470             : }
    1471             : 
    1472           0 : static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
    1473           0 :         assert(client);
    1474           0 :         assert(client->request_sent);
    1475           0 :         assert(lifetime > 0);
    1476             : 
    1477           0 :         if (lifetime > 3)
    1478           0 :                 lifetime -= 3;
    1479             :         else
    1480           0 :                 lifetime = 0;
    1481             : 
    1482           0 :         return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
    1483           0 :                 + (random_u32() & 0x1fffff);
    1484             : }
    1485             : 
    1486           0 : static int client_set_lease_timeouts(sd_dhcp_client *client) {
    1487             :         usec_t time_now;
    1488             :         uint64_t lifetime_timeout;
    1489             :         uint64_t t2_timeout;
    1490             :         uint64_t t1_timeout;
    1491             :         char time_string[FORMAT_TIMESPAN_MAX];
    1492             :         int r;
    1493             : 
    1494           0 :         assert(client);
    1495           0 :         assert(client->event);
    1496           0 :         assert(client->lease);
    1497           0 :         assert(client->lease->lifetime);
    1498             : 
    1499             :         /* don't set timers for infinite leases */
    1500           0 :         if (client->lease->lifetime == 0xffffffff) {
    1501           0 :                 (void) event_source_disable(client->timeout_t1);
    1502           0 :                 (void) event_source_disable(client->timeout_t2);
    1503           0 :                 (void) event_source_disable(client->timeout_expire);
    1504             : 
    1505           0 :                 return 0;
    1506             :         }
    1507             : 
    1508           0 :         r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
    1509           0 :         if (r < 0)
    1510           0 :                 return r;
    1511           0 :         assert(client->request_sent <= time_now);
    1512             : 
    1513             :         /* convert the various timeouts from relative (secs) to absolute (usecs) */
    1514           0 :         lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
    1515           0 :         if (client->lease->t1 > 0 && client->lease->t2 > 0) {
    1516             :                 /* both T1 and T2 are given */
    1517           0 :                 if (client->lease->t1 < client->lease->t2 &&
    1518           0 :                     client->lease->t2 < client->lease->lifetime) {
    1519             :                         /* they are both valid */
    1520           0 :                         t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
    1521           0 :                         t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
    1522             :                 } else {
    1523             :                         /* discard both */
    1524           0 :                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
    1525           0 :                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
    1526           0 :                         t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
    1527           0 :                         client->lease->t1 = client->lease->lifetime / 2;
    1528             :                 }
    1529           0 :         } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
    1530             :                 /* only T2 is given, and it is valid */
    1531           0 :                 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
    1532           0 :                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
    1533           0 :                 client->lease->t1 = client->lease->lifetime / 2;
    1534           0 :                 if (t2_timeout <= t1_timeout) {
    1535             :                         /* the computed T1 would be invalid, so discard T2 */
    1536           0 :                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
    1537           0 :                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
    1538             :                 }
    1539           0 :         } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
    1540             :                 /* only T1 is given, and it is valid */
    1541           0 :                 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
    1542           0 :                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
    1543           0 :                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
    1544           0 :                 if (t2_timeout <= t1_timeout) {
    1545             :                         /* the computed T2 would be invalid, so discard T1 */
    1546           0 :                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
    1547           0 :                         client->lease->t2 = client->lease->lifetime / 2;
    1548             :                 }
    1549             :         } else {
    1550             :                 /* fall back to the default timeouts */
    1551           0 :                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
    1552           0 :                 client->lease->t1 = client->lease->lifetime / 2;
    1553           0 :                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
    1554           0 :                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
    1555             :         }
    1556             : 
    1557             :         /* arm lifetime timeout */
    1558           0 :         r = event_reset_time(client->event, &client->timeout_expire,
    1559             :                              clock_boottime_or_monotonic(),
    1560             :                              lifetime_timeout, 10 * USEC_PER_MSEC,
    1561             :                              client_timeout_expire, client,
    1562           0 :                              client->event_priority, "dhcp4-lifetime", true);
    1563           0 :         if (r < 0)
    1564           0 :                 return r;
    1565             : 
    1566           0 :         log_dhcp_client(client, "lease expires in %s",
    1567             :                         format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
    1568             : 
    1569             :         /* don't arm earlier timeouts if this has already expired */
    1570           0 :         if (lifetime_timeout <= time_now)
    1571           0 :                 return 0;
    1572             : 
    1573             :         /* arm T2 timeout */
    1574           0 :         r = event_reset_time(client->event, &client->timeout_t2,
    1575             :                              clock_boottime_or_monotonic(),
    1576             :                              t2_timeout, 10 * USEC_PER_MSEC,
    1577             :                              client_timeout_t2, client,
    1578           0 :                              client->event_priority, "dhcp4-t2-timeout", true);
    1579           0 :         if (r < 0)
    1580           0 :                 return r;
    1581             : 
    1582           0 :         log_dhcp_client(client, "T2 expires in %s",
    1583             :                         format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
    1584             : 
    1585             :         /* don't arm earlier timeout if this has already expired */
    1586           0 :         if (t2_timeout <= time_now)
    1587           0 :                 return 0;
    1588             : 
    1589             :         /* arm T1 timeout */
    1590           0 :         r = event_reset_time(client->event, &client->timeout_t1,
    1591             :                              clock_boottime_or_monotonic(),
    1592             :                              t1_timeout, 10 * USEC_PER_MSEC,
    1593             :                              client_timeout_t1, client,
    1594           0 :                              client->event_priority, "dhcp4-t1-timer", true);
    1595           0 :         if (r < 0)
    1596           0 :                 return r;
    1597             : 
    1598           0 :         log_dhcp_client(client, "T1 expires in %s",
    1599             :                         format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
    1600             : 
    1601           0 :         return 0;
    1602             : }
    1603             : 
    1604           1 : static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
    1605           2 :         DHCP_CLIENT_DONT_DESTROY(client);
    1606             :         char time_string[FORMAT_TIMESPAN_MAX];
    1607           1 :         int r = 0, notify_event = 0;
    1608             : 
    1609           1 :         assert(client);
    1610           1 :         assert(client->event);
    1611           1 :         assert(message);
    1612             : 
    1613           1 :         switch (client->state) {
    1614           1 :         case DHCP_STATE_SELECTING:
    1615             : 
    1616           1 :                 r = client_handle_offer(client, message, len);
    1617           1 :                 if (r >= 0) {
    1618             : 
    1619           1 :                         client->state = DHCP_STATE_REQUESTING;
    1620           1 :                         client->attempt = 0;
    1621             : 
    1622           1 :                         r = event_reset_time(client->event, &client->timeout_resend,
    1623             :                                              clock_boottime_or_monotonic(),
    1624             :                                              0, 0,
    1625             :                                              client_timeout_resend, client,
    1626           1 :                                              client->event_priority, "dhcp4-resend-timer", true);
    1627           1 :                         if (r < 0)
    1628           0 :                                 goto error;
    1629           0 :                 } else if (r == -ENOMSG)
    1630             :                         /* invalid message, let's ignore it */
    1631           0 :                         return 0;
    1632             : 
    1633           1 :                 break;
    1634             : 
    1635           0 :         case DHCP_STATE_REBOOTING:
    1636             :         case DHCP_STATE_REQUESTING:
    1637             :         case DHCP_STATE_RENEWING:
    1638             :         case DHCP_STATE_REBINDING:
    1639             : 
    1640           0 :                 r = client_handle_ack(client, message, len);
    1641           0 :                 if (r >= 0) {
    1642           0 :                         client->start_delay = 0;
    1643           0 :                         (void) event_source_disable(client->timeout_resend);
    1644           0 :                         client->receive_message =
    1645           0 :                                 sd_event_source_unref(client->receive_message);
    1646           0 :                         client->fd = asynchronous_close(client->fd);
    1647             : 
    1648           0 :                         if (IN_SET(client->state, DHCP_STATE_REQUESTING,
    1649             :                                    DHCP_STATE_REBOOTING))
    1650           0 :                                 notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
    1651           0 :                         else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
    1652           0 :                                 notify_event = r;
    1653             : 
    1654           0 :                         client->state = DHCP_STATE_BOUND;
    1655           0 :                         client->attempt = 0;
    1656             : 
    1657           0 :                         client->last_addr = client->lease->address;
    1658             : 
    1659           0 :                         r = client_set_lease_timeouts(client);
    1660           0 :                         if (r < 0) {
    1661           0 :                                 log_dhcp_client(client, "could not set lease timeouts");
    1662           0 :                                 goto error;
    1663             :                         }
    1664             : 
    1665           0 :                         r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port);
    1666           0 :                         if (r < 0) {
    1667           0 :                                 log_dhcp_client(client, "could not bind UDP socket");
    1668           0 :                                 goto error;
    1669             :                         }
    1670             : 
    1671           0 :                         client->fd = r;
    1672             : 
    1673           0 :                         client_initialize_io_events(client, client_receive_message_udp);
    1674             : 
    1675           0 :                         if (notify_event) {
    1676           0 :                                 client_notify(client, notify_event);
    1677           0 :                                 if (client->state == DHCP_STATE_STOPPED)
    1678           0 :                                         return 0;
    1679             :                         }
    1680             : 
    1681           0 :                 } else if (r == -EADDRNOTAVAIL) {
    1682             :                         /* got a NAK, let's restart the client */
    1683           0 :                         client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
    1684             : 
    1685           0 :                         r = client_initialize(client);
    1686           0 :                         if (r < 0)
    1687           0 :                                 goto error;
    1688             : 
    1689           0 :                         r = client_start_delayed(client);
    1690           0 :                         if (r < 0)
    1691           0 :                                 goto error;
    1692             : 
    1693           0 :                         log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
    1694             :                                                                                 client->start_delay, USEC_PER_SEC));
    1695             : 
    1696           0 :                         client->start_delay = CLAMP(client->start_delay * 2,
    1697             :                                                     RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
    1698             : 
    1699           0 :                         return 0;
    1700           0 :                 } else if (r == -ENOMSG)
    1701             :                         /* invalid message, let's ignore it */
    1702           0 :                         return 0;
    1703             : 
    1704           0 :                 break;
    1705             : 
    1706           0 :         case DHCP_STATE_BOUND:
    1707           0 :                 r = client_handle_forcerenew(client, message, len);
    1708           0 :                 if (r >= 0) {
    1709           0 :                         r = client_timeout_t1(NULL, 0, client);
    1710           0 :                         if (r < 0)
    1711           0 :                                 goto error;
    1712           0 :                 } else if (r == -ENOMSG)
    1713             :                         /* invalid message, let's ignore it */
    1714           0 :                         return 0;
    1715             : 
    1716           0 :                 break;
    1717             : 
    1718           0 :         case DHCP_STATE_INIT:
    1719             :         case DHCP_STATE_INIT_REBOOT:
    1720             : 
    1721           0 :                 break;
    1722             : 
    1723           0 :         case DHCP_STATE_STOPPED:
    1724           0 :                 r = -EINVAL;
    1725           0 :                 goto error;
    1726             :         }
    1727             : 
    1728           1 : error:
    1729           1 :         if (r < 0)
    1730           0 :                 client_stop(client, r);
    1731             : 
    1732           1 :         return r;
    1733             : }
    1734             : 
    1735           0 : static int client_receive_message_udp(
    1736             :                 sd_event_source *s,
    1737             :                 int fd,
    1738             :                 uint32_t revents,
    1739             :                 void *userdata) {
    1740             : 
    1741           0 :         sd_dhcp_client *client = userdata;
    1742           0 :         _cleanup_free_ DHCPMessage *message = NULL;
    1743           0 :         const uint8_t *expected_chaddr = NULL;
    1744           0 :         uint8_t expected_hlen = 0;
    1745             :         ssize_t len, buflen;
    1746             : 
    1747           0 :         assert(s);
    1748           0 :         assert(client);
    1749             : 
    1750           0 :         buflen = next_datagram_size_fd(fd);
    1751           0 :         if (buflen == -ENETDOWN) {
    1752             :                 /* the link is down. Don't return an error or the I/O event
    1753             :                    source will be disconnected and we won't be able to receive
    1754             :                    packets again when the link comes back. */
    1755           0 :                 return 0;
    1756             :         }
    1757           0 :         if (buflen < 0)
    1758           0 :                 return buflen;
    1759             : 
    1760           0 :         message = malloc0(buflen);
    1761           0 :         if (!message)
    1762           0 :                 return -ENOMEM;
    1763             : 
    1764           0 :         len = recv(fd, message, buflen, 0);
    1765           0 :         if (len < 0) {
    1766             :                 /* see comment above for why we shouldn't error out on ENETDOWN. */
    1767           0 :                 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
    1768           0 :                         return 0;
    1769             : 
    1770           0 :                 return log_dhcp_client_errno(client, errno,
    1771             :                                              "Could not receive message from UDP socket: %m");
    1772             :         }
    1773           0 :         if ((size_t) len < sizeof(DHCPMessage)) {
    1774           0 :                 log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
    1775           0 :                 return 0;
    1776             :         }
    1777             : 
    1778           0 :         if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
    1779           0 :                 log_dhcp_client(client, "Not a DHCP message: ignoring");
    1780           0 :                 return 0;
    1781             :         }
    1782             : 
    1783           0 :         if (message->op != BOOTREPLY) {
    1784           0 :                 log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
    1785           0 :                 return 0;
    1786             :         }
    1787             : 
    1788           0 :         if (message->htype != client->arp_type) {
    1789           0 :                 log_dhcp_client(client, "Packet type does not match client type");
    1790           0 :                 return 0;
    1791             :         }
    1792             : 
    1793           0 :         if (client->arp_type == ARPHRD_ETHER) {
    1794           0 :                 expected_hlen = ETH_ALEN;
    1795           0 :                 expected_chaddr = &client->mac_addr[0];
    1796             :         }
    1797             : 
    1798           0 :         if (message->hlen != expected_hlen) {
    1799           0 :                 log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
    1800           0 :                 return 0;
    1801             :         }
    1802             : 
    1803           0 :         if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) {
    1804           0 :                 log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
    1805           0 :                 return 0;
    1806             :         }
    1807             : 
    1808           0 :         if (client->state != DHCP_STATE_BOUND &&
    1809           0 :             be32toh(message->xid) != client->xid) {
    1810             :                 /* in BOUND state, we may receive FORCERENEW with xid set by server,
    1811             :                    so ignore the xid in this case */
    1812           0 :                 log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
    1813             :                                 be32toh(message->xid), client->xid);
    1814           0 :                 return 0;
    1815             :         }
    1816             : 
    1817           0 :         return client_handle_message(client, message, len);
    1818             : }
    1819             : 
    1820           1 : static int client_receive_message_raw(
    1821             :                 sd_event_source *s,
    1822             :                 int fd,
    1823             :                 uint32_t revents,
    1824             :                 void *userdata) {
    1825             : 
    1826           1 :         sd_dhcp_client *client = userdata;
    1827           1 :         _cleanup_free_ DHCPPacket *packet = NULL;
    1828             :         uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
    1829           1 :         struct iovec iov = {};
    1830           1 :         struct msghdr msg = {
    1831             :                 .msg_iov = &iov,
    1832             :                 .msg_iovlen = 1,
    1833             :                 .msg_control = cmsgbuf,
    1834             :                 .msg_controllen = sizeof(cmsgbuf),
    1835             :         };
    1836             :         struct cmsghdr *cmsg;
    1837           1 :         bool checksum = true;
    1838             :         ssize_t buflen, len;
    1839             :         int r;
    1840             : 
    1841           1 :         assert(s);
    1842           1 :         assert(client);
    1843             : 
    1844           1 :         buflen = next_datagram_size_fd(fd);
    1845           1 :         if (buflen == -ENETDOWN)
    1846           0 :                 return 0;
    1847           1 :         if (buflen < 0)
    1848           0 :                 return buflen;
    1849             : 
    1850           1 :         packet = malloc0(buflen);
    1851           1 :         if (!packet)
    1852           0 :                 return -ENOMEM;
    1853             : 
    1854           1 :         iov = IOVEC_MAKE(packet, buflen);
    1855             : 
    1856           1 :         len = recvmsg(fd, &msg, 0);
    1857           1 :         if (len < 0) {
    1858           0 :                 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
    1859           0 :                         return 0;
    1860             : 
    1861           0 :                 return log_dhcp_client_errno(client, errno,
    1862             :                                              "Could not receive message from raw socket: %m");
    1863           1 :         } else if ((size_t)len < sizeof(DHCPPacket))
    1864           0 :                 return 0;
    1865             : 
    1866           1 :         CMSG_FOREACH(cmsg, &msg)
    1867           0 :                 if (cmsg->cmsg_level == SOL_PACKET &&
    1868           0 :                     cmsg->cmsg_type == PACKET_AUXDATA &&
    1869           0 :                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
    1870           0 :                         struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
    1871             : 
    1872           0 :                         checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
    1873           0 :                         break;
    1874             :                 }
    1875             : 
    1876           1 :         r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
    1877           1 :         if (r < 0)
    1878           0 :                 return 0;
    1879             : 
    1880           1 :         len -= DHCP_IP_UDP_SIZE;
    1881             : 
    1882           1 :         return client_handle_message(client, &packet->dhcp, len);
    1883             : }
    1884             : 
    1885           2 : int sd_dhcp_client_start(sd_dhcp_client *client) {
    1886             :         int r;
    1887             : 
    1888           2 :         assert_return(client, -EINVAL);
    1889             : 
    1890           2 :         r = client_initialize(client);
    1891           2 :         if (r < 0)
    1892           0 :                 return r;
    1893             : 
    1894             :         /* RFC7844 section 3.3:
    1895             :            SHOULD perform a complete four-way handshake, starting with a
    1896             :            DHCPDISCOVER, to obtain a new address lease.  If the client can
    1897             :            ascertain that this is exactly the same network to which it was
    1898             :            previously connected, and if the link-layer address did not change,
    1899             :            the client MAY issue a DHCPREQUEST to try to reclaim the current
    1900             :            address. */
    1901           2 :         if (client->last_addr && !client->anonymize)
    1902           0 :                 client->state = DHCP_STATE_INIT_REBOOT;
    1903             : 
    1904           2 :         r = client_start(client);
    1905           2 :         if (r >= 0)
    1906           2 :                 log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
    1907             : 
    1908           2 :         return r;
    1909             : }
    1910             : 
    1911           0 : int sd_dhcp_client_send_release(sd_dhcp_client *client) {
    1912           0 :         assert_return(client, -EINVAL);
    1913             : 
    1914           0 :         client_send_release(client);
    1915             : 
    1916           0 :         return 0;
    1917             : }
    1918             : 
    1919           2 : int sd_dhcp_client_stop(sd_dhcp_client *client) {
    1920           4 :         DHCP_CLIENT_DONT_DESTROY(client);
    1921             : 
    1922           2 :         assert_return(client, -EINVAL);
    1923             : 
    1924           2 :         client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
    1925           2 :         client->state = DHCP_STATE_STOPPED;
    1926             : 
    1927           2 :         return 0;
    1928             : }
    1929             : 
    1930           4 : int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
    1931             :         int r;
    1932             : 
    1933           4 :         assert_return(client, -EINVAL);
    1934           4 :         assert_return(!client->event, -EBUSY);
    1935             : 
    1936           4 :         if (event)
    1937           4 :                 client->event = sd_event_ref(event);
    1938             :         else {
    1939           0 :                 r = sd_event_default(&client->event);
    1940           0 :                 if (r < 0)
    1941           0 :                         return 0;
    1942             :         }
    1943             : 
    1944           4 :         client->event_priority = priority;
    1945             : 
    1946           4 :         return 0;
    1947             : }
    1948             : 
    1949           4 : int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
    1950           4 :         assert_return(client, -EINVAL);
    1951             : 
    1952           4 :         client->event = sd_event_unref(client->event);
    1953             : 
    1954           4 :         return 0;
    1955             : }
    1956             : 
    1957           0 : sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
    1958           0 :         assert_return(client, NULL);
    1959             : 
    1960           0 :         return client->event;
    1961             : }
    1962             : 
    1963           4 : static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
    1964           4 :         assert(client);
    1965             : 
    1966           4 :         log_dhcp_client(client, "FREE");
    1967             : 
    1968           4 :         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
    1969           4 :         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
    1970           4 :         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
    1971           4 :         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
    1972             : 
    1973           4 :         client_initialize(client);
    1974             : 
    1975           4 :         sd_dhcp_client_detach_event(client);
    1976             : 
    1977           4 :         sd_dhcp_lease_unref(client->lease);
    1978             : 
    1979           4 :         free(client->req_opts);
    1980           4 :         free(client->hostname);
    1981           4 :         free(client->vendor_class_identifier);
    1982           4 :         client->user_class = strv_free(client->user_class);
    1983           4 :         return mfree(client);
    1984             : }
    1985             : 
    1986          24 : DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
    1987             : 
    1988           4 : int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
    1989           4 :         _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
    1990             : 
    1991           4 :         assert_return(ret, -EINVAL);
    1992             : 
    1993           4 :         client = new(sd_dhcp_client, 1);
    1994           4 :         if (!client)
    1995           0 :                 return -ENOMEM;
    1996             : 
    1997           8 :         *client = (sd_dhcp_client) {
    1998             :                 .n_ref = 1,
    1999             :                 .state = DHCP_STATE_INIT,
    2000             :                 .ifindex = -1,
    2001             :                 .fd = -1,
    2002             :                 .mtu = DHCP_DEFAULT_MIN_SIZE,
    2003             :                 .port = DHCP_PORT_CLIENT,
    2004           4 :                 .anonymize = !!anonymize,
    2005             :                 .max_attempts = (uint64_t) -1,
    2006             :         };
    2007             :         /* NOTE: this could be moved to a function. */
    2008           4 :         if (anonymize) {
    2009           1 :                 client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
    2010           1 :                 client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
    2011             :         } else {
    2012           3 :                 client->req_opts_size = ELEMENTSOF(default_req_opts);
    2013           3 :                 client->req_opts = memdup(default_req_opts, client->req_opts_size);
    2014             :         }
    2015           4 :         if (!client->req_opts)
    2016           0 :                 return -ENOMEM;
    2017             : 
    2018           4 :         *ret = TAKE_PTR(client);
    2019             : 
    2020           4 :         return 0;
    2021             : }

Generated by: LCOV version 1.14