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