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