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