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