]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-server.c
sd-dhcp-server: support IPv6 only mode
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-server.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
b44cd882 2/***
810adae9 3 Copyright © 2013 Intel Corporation. All rights reserved.
b44cd882
TG
4***/
5
ddb82ec2 6#include <net/if_arp.h>
ff734080
TG
7#include <sys/ioctl.h>
8
b44cd882 9#include "sd-dhcp-server.h"
6e86b24d 10#include "sd-id128.h"
07630cea 11
b5efdb8a 12#include "alloc-util.h"
ff734080 13#include "dhcp-internal.h"
07630cea 14#include "dhcp-server-internal.h"
6278e428 15#include "dns-domain.h"
3ffd4af2 16#include "fd-util.h"
07630cea 17#include "in-addr-util.h"
cb310866 18#include "io-util.h"
54d95d02 19#include "memory-util.h"
61a9fa8f 20#include "network-common.h"
ebffea2a 21#include "ordered-set.h"
07630cea
LP
22#include "siphash24.h"
23#include "string-util.h"
9ae84244 24#include "unaligned.h"
d5e5cd5c 25#include "utf8.h"
b44cd882 26
586ac6f7
LP
27#define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
28#define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
4dc35568 29
aca607d1 30DHCPLease *dhcp_lease_free(DHCPLease *lease) {
45a9eac9 31 if (!lease)
6121fc30 32 return NULL;
45a9eac9 33
b713a99b 34 if (lease->server) {
8a7d048d
YW
35 hashmap_remove_value(lease->server->bound_leases_by_address, UINT32_TO_PTR(lease->address), lease);
36 hashmap_remove_value(lease->server->bound_leases_by_client_id, &lease->client_id, lease);
37 hashmap_remove_value(lease->server->static_leases_by_address, UINT32_TO_PTR(lease->address), lease);
38 hashmap_remove_value(lease->server->static_leases_by_client_id, &lease->client_id, lease);
b713a99b
YW
39 }
40
45a9eac9 41 free(lease->client_id.data);
930133d5 42 free(lease->hostname);
6121fc30 43 return mfree(lease);
45a9eac9
RM
44}
45
99634696
TG
46/* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
47 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
48 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
49 * accidentally hand it out */
90810f7a
LP
50int sd_dhcp_server_configure_pool(
51 sd_dhcp_server *server,
52 const struct in_addr *address,
53 unsigned char prefixlen,
54 uint32_t offset,
55 uint32_t size) {
56
99634696
TG
57 struct in_addr netmask_addr;
58 be32_t netmask;
59 uint32_t server_off, broadcast_off, size_max;
60
2dead812
TG
61 assert_return(server, -EINVAL);
62 assert_return(address, -EINVAL);
99634696
TG
63 assert_return(address->s_addr != INADDR_ANY, -EINVAL);
64 assert_return(prefixlen <= 32, -ERANGE);
99634696 65
5a941f5f 66 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
99634696
TG
67 netmask = netmask_addr.s_addr;
68
69 server_off = be32toh(address->s_addr & ~netmask);
70 broadcast_off = be32toh(~netmask);
71
72 /* the server address cannot be the subnet address */
73 assert_return(server_off != 0, -ERANGE);
74
75 /* nor the broadcast address */
76 assert_return(server_off != broadcast_off, -ERANGE);
77
78 /* 0 offset means we should set a default, we skip the first (subnet) address
79 and take the next one */
80 if (offset == 0)
81 offset = 1;
82
83 size_max = (broadcast_off + 1) /* the number of addresses in the subnet */
84 - offset /* exclude the addresses before the offset */
85 - 1; /* exclude the last (broadcast) address */
86
87 /* The pool must contain at least one address */
88 assert_return(size_max >= 1, -ERANGE);
89
90 if (size != 0)
91 assert_return(size <= size_max, -ERANGE);
92 else
93 size = size_max;
87322b3a 94
45a9eac9 95 if (server->address != address->s_addr || server->netmask != netmask || server->pool_size != size || server->pool_offset != offset) {
45a9eac9 96
45a9eac9
RM
97 server->pool_offset = offset;
98 server->pool_size = size;
2dead812 99
45a9eac9
RM
100 server->address = address->s_addr;
101 server->netmask = netmask;
102 server->subnet = address->s_addr & netmask;
99634696 103
45a9eac9 104 /* Drop any leases associated with the old address range */
b713a99b
YW
105 hashmap_clear(server->bound_leases_by_address);
106 hashmap_clear(server->bound_leases_by_client_id);
36d35f22
MAL
107
108 if (server->callback)
109 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
45a9eac9 110 }
20af7091
TG
111
112 return 0;
113}
114
04c01369 115int sd_dhcp_server_is_running(sd_dhcp_server *server) {
75677581 116 assert_return(server, false);
7c16313f
TG
117
118 return !!server->receive_message;
119}
120
c95df587
YA
121int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server) {
122 assert_return(server, -EINVAL);
123
124 return in4_addr_is_set(&server->relay_target);
125}
126
7a08d314 127void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
87322b3a 128 assert(id);
a2a80192 129 assert(id->length > 0);
87322b3a
TG
130 assert(id->data);
131
1e2527a6 132 siphash24_compress(&id->length, sizeof(id->length), state);
b826ab58 133 siphash24_compress(id->data, id->length, state);
87322b3a
TG
134}
135
7a08d314 136int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
a0edd02e 137 int r;
87322b3a 138
a2a80192
YW
139 assert(a->length > 0);
140 assert(a->data);
141 assert(b->length > 0);
142 assert(b->data);
87322b3a 143
a0edd02e
FB
144 r = CMP(a->length, b->length);
145 if (r != 0)
146 return r;
87322b3a
TG
147
148 return memcmp(a->data, b->data, a->length);
149}
150
cedf6a8d
YW
151DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
152 dhcp_lease_hash_ops,
153 DHCPClientId,
154 client_id_hash_func,
155 client_id_compare_func,
156 DHCPLease,
157 dhcp_lease_free);
d5099efc 158
8301aa0b 159static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
8301aa0b 160 assert(server);
ff734080 161
3bdace9b 162 sd_dhcp_server_stop(server);
87322b3a 163
3bdace9b
LP
164 sd_event_unref(server->event);
165
6278e428
YW
166 free(server->boot_server_name);
167 free(server->boot_filename);
8eb9058d 168 free(server->timezone);
ddb82ec2 169
2324fd3a 170 for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
ddb82ec2 171 free(server->servers[i].addr);
8eb9058d 172
b713a99b
YW
173 server->bound_leases_by_address = hashmap_free(server->bound_leases_by_address);
174 server->bound_leases_by_client_id = hashmap_free(server->bound_leases_by_client_id);
175 server->static_leases_by_address = hashmap_free(server->static_leases_by_address);
176 server->static_leases_by_client_id = hashmap_free(server->static_leases_by_client_id);
3bdace9b 177
ebffea2a
SS
178 ordered_set_free(server->extra_options);
179 ordered_set_free(server->vendor_options);
564ca984 180
11c38d3e
YA
181 free(server->agent_circuit_id);
182 free(server->agent_remote_id);
183
61a9fa8f 184 free(server->ifname);
6b430fdb 185 return mfree(server);
b44cd882
TG
186}
187
8301aa0b
YW
188DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server, sd_dhcp_server, dhcp_server_free);
189
3a864fe4 190int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
4afd3348 191 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
b44cd882
TG
192
193 assert_return(ret, -EINVAL);
3a864fe4 194 assert_return(ifindex > 0, -EINVAL);
b44cd882 195
61a9fa8f 196 server = new(sd_dhcp_server, 1);
b44cd882
TG
197 if (!server)
198 return -ENOMEM;
199
61a9fa8f
YW
200 *server = (sd_dhcp_server) {
201 .n_ref = 1,
254d1313
ZJS
202 .fd_raw = -EBADF,
203 .fd = -EBADF,
204 .fd_broadcast = -EBADF,
61a9fa8f
YW
205 .address = htobe32(INADDR_ANY),
206 .netmask = htobe32(INADDR_ANY),
207 .ifindex = ifindex,
21b6b87e 208 .bind_to_interface = true,
a0007611
YW
209 .default_lease_time = DHCP_DEFAULT_LEASE_TIME_USEC,
210 .max_lease_time = DHCP_MAX_LEASE_TIME_USEC,
61a9fa8f 211 };
357e1b17 212
1cc6c93a 213 *ret = TAKE_PTR(server);
b44cd882
TG
214
215 return 0;
216}
217
61a9fa8f
YW
218int sd_dhcp_server_set_ifname(sd_dhcp_server *server, const char *ifname) {
219 assert_return(server, -EINVAL);
220 assert_return(ifname, -EINVAL);
221
222 if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
223 return -EINVAL;
224
225 return free_and_strdup(&server->ifname, ifname);
226}
227
5977b71f
YW
228int sd_dhcp_server_get_ifname(sd_dhcp_server *server, const char **ret) {
229 int r;
230
231 assert_return(server, -EINVAL);
61a9fa8f 232
5977b71f
YW
233 r = get_ifname(server->ifindex, &server->ifname);
234 if (r < 0)
235 return r;
236
237 if (ret)
238 *ret = server->ifname;
239
240 return 0;
61a9fa8f
YW
241}
242
32d20645 243int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
b44cd882
TG
244 int r;
245
246 assert_return(server, -EINVAL);
247 assert_return(!server->event, -EBUSY);
248
249 if (event)
250 server->event = sd_event_ref(event);
251 else {
252 r = sd_event_default(&server->event);
253 if (r < 0)
254 return r;
255 }
256
257 server->event_priority = priority;
258
259 return 0;
260}
261
262int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
263 assert_return(server, -EINVAL);
264
265 server->event = sd_event_unref(server->event);
266
267 return 0;
268}
269
270sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
271 assert_return(server, NULL);
272
273 return server->event;
274}
ff734080 275
6278e428 276int sd_dhcp_server_set_boot_server_address(sd_dhcp_server *server, const struct in_addr *address) {
d5e5cd5c
YW
277 assert_return(server, -EINVAL);
278
6278e428
YW
279 if (address)
280 server->boot_server_address = *address;
d5e5cd5c 281 else
6278e428 282 server->boot_server_address = (struct in_addr) {};
d5e5cd5c
YW
283
284 return 0;
285}
286
6278e428
YW
287int sd_dhcp_server_set_boot_server_name(sd_dhcp_server *server, const char *name) {
288 int r;
289
290 assert_return(server, -EINVAL);
291
292 if (name) {
293 r = dns_name_is_valid(name);
294 if (r < 0)
295 return r;
296 if (r == 0)
297 return -EINVAL;
298 }
299
300 return free_and_strdup(&server->boot_server_name, name);
301}
302
303int sd_dhcp_server_set_boot_filename(sd_dhcp_server *server, const char *filename) {
d5e5cd5c
YW
304 assert_return(server, -EINVAL);
305
1aaab936 306 if (filename && (!string_is_safe(filename) || !ascii_is_valid(filename)))
d5e5cd5c
YW
307 return -EINVAL;
308
6278e428 309 return free_and_strdup(&server->boot_filename, filename);
d5e5cd5c
YW
310}
311
ff734080 312int sd_dhcp_server_stop(sd_dhcp_server *server) {
0a195d41
YW
313 bool running;
314
c8bae363
YW
315 if (!server)
316 return 0;
ff734080 317
0a195d41
YW
318 running = sd_dhcp_server_is_running(server);
319
eb2f7502
YW
320 server->receive_message = sd_event_source_disable_unref(server->receive_message);
321 server->receive_broadcast = sd_event_source_disable_unref(server->receive_broadcast);
ff734080 322
8de4a226 323 server->fd_raw = safe_close(server->fd_raw);
ff734080 324 server->fd = safe_close(server->fd);
21b6b87e 325 server->fd_broadcast = safe_close(server->fd_broadcast);
ff734080 326
0a195d41
YW
327 if (running)
328 log_dhcp_server(server, "STOPPED");
ff734080
TG
329
330 return 0;
331}
332
14bd102e
SS
333static bool dhcp_request_contains(DHCPRequest *req, uint8_t option) {
334 assert(req);
335
336 if (!req->parameter_request_list)
337 return false;
338
339 return memchr(req->parameter_request_list, option, req->parameter_request_list_len);
340}
341
54d95d02
YW
342static int dhcp_server_send_unicast_raw(
343 sd_dhcp_server *server,
344 uint8_t hlen,
345 const uint8_t *chaddr,
346 DHCPPacket *packet,
347 size_t len) {
348
969b009d
TG
349 union sockaddr_union link = {
350 .ll.sll_family = AF_PACKET,
8e38570e 351 .ll.sll_protocol = htobe16(ETH_P_IP),
b3ec603c 352 .ll.sll_ifindex = server->ifindex,
54d95d02 353 .ll.sll_halen = hlen,
969b009d 354 };
969b009d
TG
355
356 assert(server);
b3ec603c 357 assert(server->ifindex > 0);
6277e48f 358 assert(server->address != 0);
54d95d02
YW
359 assert(hlen > 0);
360 assert(chaddr);
969b009d
TG
361 assert(packet);
362 assert(len > sizeof(DHCPPacket));
363
54d95d02 364 memcpy(link.ll.sll_addr, chaddr, hlen);
969b009d 365
71df50a9
YW
366 if (len > UINT16_MAX)
367 return -EOVERFLOW;
368
969b009d 369 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
a6f1e036 370 packet->dhcp.yiaddr,
afe42aef 371 DHCP_PORT_CLIENT, len, -1);
969b009d 372
b3ec603c 373 return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
969b009d
TG
374}
375
376static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
8eb7b6a5 377 uint16_t destination_port,
969b009d
TG
378 DHCPMessage *message, size_t len) {
379 union sockaddr_union dest = {
380 .in.sin_family = AF_INET,
8eb7b6a5 381 .in.sin_port = htobe16(destination_port),
969b009d
TG
382 .in.sin_addr.s_addr = destination,
383 };
384 struct iovec iov = {
385 .iov_base = message,
386 .iov_len = len,
387 };
fb29cdbe 388 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control = {};
969b009d
TG
389 struct msghdr msg = {
390 .msg_name = &dest,
391 .msg_namelen = sizeof(dest.in),
392 .msg_iov = &iov,
393 .msg_iovlen = 1,
969b009d
TG
394 };
395 struct cmsghdr *cmsg;
396 struct in_pktinfo *pktinfo;
969b009d
TG
397
398 assert(server);
4c9cb12c 399 assert(server->fd >= 0);
969b009d 400 assert(message);
b52031db 401 assert(len >= sizeof(DHCPMessage));
969b009d 402
21b6b87e
YA
403 if (server->bind_to_interface) {
404 msg.msg_control = &control;
405 msg.msg_controllen = sizeof(control);
969b009d 406
21b6b87e
YA
407 cmsg = CMSG_FIRSTHDR(&msg);
408 assert(cmsg);
969b009d 409
21b6b87e
YA
410 cmsg->cmsg_level = IPPROTO_IP;
411 cmsg->cmsg_type = IP_PKTINFO;
412 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
969b009d 413
21b6b87e
YA
414 /* we attach source interface and address info to the message
415 rather than binding the socket. This will be mostly useful
416 when we gain support for arbitrary number of server addresses
417 */
b5d39bb3 418 pktinfo = CMSG_TYPED_DATA(cmsg, struct in_pktinfo);
21b6b87e
YA
419 assert(pktinfo);
420
421 pktinfo->ipi_ifindex = server->ifindex;
422 pktinfo->ipi_spec_dst.s_addr = server->address;
423 }
969b009d 424
0f01c1f9 425 if (sendmsg(server->fd, &msg, 0) < 0)
969b009d
TG
426 return -errno;
427
428 return 0;
429}
430
c95df587
YA
431static bool requested_broadcast(DHCPMessage *message) {
432 assert(message);
433 return message->flags & htobe16(0x8000);
434}
969b009d 435
54d95d02
YW
436static int dhcp_server_send(
437 sd_dhcp_server *server,
438 uint8_t hlen,
439 const uint8_t *chaddr,
440 be32_t destination,
441 uint16_t destination_port,
442 DHCPPacket *packet,
443 size_t optoffset,
444 bool l2_broadcast) {
445
c95df587
YA
446 if (destination != INADDR_ANY)
447 return dhcp_server_send_udp(server, destination,
448 destination_port, &packet->dhcp,
449 sizeof(DHCPMessage) + optoffset);
450 else if (l2_broadcast)
451 return dhcp_server_send_udp(server, INADDR_BROADCAST,
452 destination_port, &packet->dhcp,
453 sizeof(DHCPMessage) + optoffset);
454 else
455 /* we cannot send UDP packet to specific MAC address when the
456 address is not yet configured, so must fall back to raw
457 packets */
54d95d02 458 return dhcp_server_send_unicast_raw(server, hlen, chaddr, packet,
c95df587 459 sizeof(DHCPPacket) + optoffset);
969b009d
TG
460}
461
462int dhcp_server_send_packet(sd_dhcp_server *server,
463 DHCPRequest *req, DHCPPacket *packet,
464 int type, size_t optoffset) {
465 be32_t destination = INADDR_ANY;
8eb7b6a5 466 uint16_t destination_port = DHCP_PORT_CLIENT;
969b009d
TG
467 int r;
468
469 assert(server);
470 assert(req);
6277e48f 471 assert(req->max_optlen > 0);
11c38d3e 472 assert(req->message);
969b009d
TG
473 assert(optoffset <= req->max_optlen);
474 assert(packet);
475
476 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
22805d92 477 SD_DHCP_OPTION_SERVER_IDENTIFIER,
969b009d
TG
478 4, &server->address);
479 if (r < 0)
480 return r;
481
11c38d3e
YA
482 if (req->agent_info_option) {
483 size_t opt_full_length = *(req->agent_info_option + 1) + 2;
484 /* there must be space left for SD_DHCP_OPTION_END */
485 if (optoffset + opt_full_length < req->max_optlen) {
486 memcpy(packet->dhcp.options + optoffset, req->agent_info_option, opt_full_length);
487 optoffset += opt_full_length;
488 }
489 }
490
969b009d 491 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
22805d92 492 SD_DHCP_OPTION_END, 0, NULL);
969b009d
TG
493 if (r < 0)
494 return r;
495
496 /* RFC 2131 Section 4.1
497
498 If the ’giaddr’ field in a DHCP message from a client is non-zero,
499 the server sends any return messages to the ’DHCP server’ port on the
500 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
501 field is zero and the ’ciaddr’ field is nonzero, then the server
502 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
503 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
504 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
505 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
506 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
507 messages to the client’s hardware address and ’yiaddr’ address. In
508 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
509 messages to 0xffffffff.
510
511 Section 4.3.2
512
513 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
514 different subnet. The server MUST set the broadcast bit in the
515 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
516 client, because the client may not have a correct network address
517 or subnet mask, and the client may not be answering ARP requests.
518 */
6277e48f 519 if (req->message->giaddr != 0) {
969b009d 520 destination = req->message->giaddr;
8eb7b6a5 521 destination_port = DHCP_PORT_SERVER;
969b009d
TG
522 if (type == DHCP_NAK)
523 packet->dhcp.flags = htobe16(0x8000);
6277e48f 524 } else if (req->message->ciaddr != 0 && type != DHCP_NAK)
969b009d
TG
525 destination = req->message->ciaddr;
526
c95df587 527 bool l2_broadcast = requested_broadcast(req->message) || type == DHCP_NAK;
54d95d02
YW
528 return dhcp_server_send(server, req->message->hlen, req->message->chaddr,
529 destination, destination_port, packet, optoffset, l2_broadcast);
969b009d
TG
530}
531
48be485b
YW
532static int server_message_init(
533 sd_dhcp_server *server,
534 DHCPPacket **ret,
535 uint8_t type,
536 size_t *ret_optoffset,
537 DHCPRequest *req) {
538
4dc35568 539 _cleanup_free_ DHCPPacket *packet = NULL;
1231c4d2 540 size_t optoffset = 0;
4dc35568
TG
541 int r;
542
543 assert(server);
544 assert(ret);
48be485b 545 assert(ret_optoffset);
bd57b450 546 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
48be485b 547 assert(req);
4dc35568
TG
548
549 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
550 if (!packet)
551 return -ENOMEM;
552
a6f1e036 553 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
97fa338d
YW
554 be32toh(req->message->xid), type,
555 req->message->htype, req->message->hlen, req->message->chaddr,
76253e73 556 req->max_optlen, &optoffset);
4dc35568
TG
557 if (r < 0)
558 return r;
559
560 packet->dhcp.flags = req->message->flags;
561 packet->dhcp.giaddr = req->message->giaddr;
4dc35568 562
48be485b 563 *ret_optoffset = optoffset;
1cc6c93a 564 *ret = TAKE_PTR(packet);
4dc35568
TG
565
566 return 0;
567}
568
986c0edf 569static int server_send_offer_or_ack(
ddb82ec2
LP
570 sd_dhcp_server *server,
571 DHCPRequest *req,
986c0edf
YW
572 be32_t address,
573 uint8_t type) {
ddb82ec2 574
0c3ea0c2
YW
575 static const uint8_t option_map[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = {
576 [SD_DHCP_LEASE_DNS] = SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
577 [SD_DHCP_LEASE_NTP] = SD_DHCP_OPTION_NTP_SERVER,
578 [SD_DHCP_LEASE_SIP] = SD_DHCP_OPTION_SIP_SERVER,
579 [SD_DHCP_LEASE_POP3] = SD_DHCP_OPTION_POP3_SERVER,
580 [SD_DHCP_LEASE_SMTP] = SD_DHCP_OPTION_SMTP_SERVER,
581 [SD_DHCP_LEASE_LPR] = SD_DHCP_OPTION_LPR_SERVER,
582 };
583
2dead812 584 _cleanup_free_ DHCPPacket *packet = NULL;
7354900d 585 sd_dhcp_option *j;
986c0edf 586 be32_t lease_time;
564ca984 587 size_t offset;
2dead812
TG
588 int r;
589
986c0edf
YW
590 assert(server);
591 assert(req);
592 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK));
593
594 r = server_message_init(server, &packet, type, &offset, req);
2dead812
TG
595 if (r < 0)
596 return r;
597
598 packet->dhcp.yiaddr = address;
6278e428 599 packet->dhcp.siaddr = server->boot_server_address.s_addr;
2dead812 600
a0007611 601 lease_time = usec_to_be32_sec(req->lifetime);
2dead812 602 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
22805d92 603 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
a6f1e036 604 &lease_time);
2dead812
TG
605 if (r < 0)
606 return r;
607
59b8f6b6 608 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
22805d92 609 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
59b8f6b6
TG
610 if (r < 0)
611 return r;
612
77ff6022
CG
613 if (server->emit_router) {
614 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
59aa6220
YW
615 SD_DHCP_OPTION_ROUTER, 4,
616 in4_addr_is_set(&server->router_address) ?
617 &server->router_address.s_addr :
618 &server->address);
77ff6022
CG
619 if (r < 0)
620 return r;
621 }
59b8f6b6 622
6278e428 623 if (server->boot_server_name) {
d5e5cd5c 624 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
6278e428
YW
625 SD_DHCP_OPTION_BOOT_SERVER_NAME,
626 strlen(server->boot_server_name), server->boot_server_name);
d5e5cd5c
YW
627 if (r < 0)
628 return r;
6278e428 629 }
d5e5cd5c 630
6278e428 631 if (server->boot_filename) {
d5e5cd5c 632 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
6278e428
YW
633 SD_DHCP_OPTION_BOOT_FILENAME,
634 strlen(server->boot_filename), server->boot_filename);
d5e5cd5c
YW
635 if (r < 0)
636 return r;
637 }
638
0c3ea0c2
YW
639 for (sd_dhcp_lease_server_type_t k = 0; k < _SD_DHCP_LEASE_SERVER_TYPE_MAX; k++) {
640 if (server->servers[k].size <= 0)
641 continue;
2c649ca1 642
0c3ea0c2
YW
643 r = dhcp_option_append(
644 &packet->dhcp, req->max_optlen, &offset, 0,
645 option_map[k],
646 sizeof(struct in_addr) * server->servers[k].size,
647 server->servers[k].addr);
648 if (r < 0)
649 return r;
650 }
50018bfa 651
0c3ea0c2
YW
652 if (server->timezone) {
653 r = dhcp_option_append(
654 &packet->dhcp, req->max_optlen, &offset, 0,
655 SD_DHCP_OPTION_TZDB_TIMEZONE,
656 strlen(server->timezone), server->timezone);
657 if (r < 0)
658 return r;
8eb9058d
LP
659 }
660
14bd102e
SS
661 /* RFC 8925 section 3.3. DHCPv4 Server Behavior
662 * The server MUST NOT include the IPv6-Only Preferred option in the DHCPOFFER or DHCPACK message if
663 * the option was not present in the Parameter Request List sent by the client. */
664 if (dhcp_request_contains(req, SD_DHCP_OPTION_IPV6_ONLY_PREFERRED) &&
665 server->ipv6_only_preferred_usec > 0) {
666 be32_t sec = usec_to_be32_sec(server->ipv6_only_preferred_usec);
667
668 r = dhcp_option_append(
669 &packet->dhcp, req->max_optlen, &offset, 0,
670 SD_DHCP_OPTION_IPV6_ONLY_PREFERRED,
671 sizeof(sec), &sec);
672 if (r < 0)
673 return r;
674 }
675
ebffea2a 676 ORDERED_SET_FOREACH(j, server->extra_options) {
7354900d
DW
677 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
678 j->option, j->length, j->data);
679 if (r < 0)
680 return r;
681 }
682
ebffea2a 683 if (!ordered_set_isempty(server->vendor_options)) {
564ca984
SS
684 r = dhcp_option_append(
685 &packet->dhcp, req->max_optlen, &offset, 0,
686 SD_DHCP_OPTION_VENDOR_SPECIFIC,
ebffea2a 687 ordered_set_size(server->vendor_options), server->vendor_options);
564ca984
SS
688 if (r < 0)
689 return r;
690 }
691
4f9dcf3d 692 return dhcp_server_send_packet(server, req, packet, type, offset);
2dead812
TG
693}
694
eb5bff9c 695static int server_send_nak_or_ignore(sd_dhcp_server *server, bool init_reboot, DHCPRequest *req) {
bd57b450
TG
696 _cleanup_free_ DHCPPacket *packet = NULL;
697 size_t offset;
698 int r;
699
eb5bff9c
YW
700 /* When a request is refused, RFC 2131, section 4.3.2 mentioned we should send NAK when the
701 * client is in INITREBOOT. If the client is in other state, there is nothing mentioned in the
702 * RFC whether we should send NAK or not. Hence, let's silently ignore the request. */
703
704 if (!init_reboot)
705 return 0;
706
bd57b450
TG
707 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
708 if (r < 0)
eb5bff9c
YW
709 return log_dhcp_server_errno(server, r, "Failed to create NAK message: %m");
710
711 r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
712 if (r < 0)
713 return log_dhcp_server_errno(server, r, "Could not send NAK message: %m");
bd57b450 714
eb5bff9c
YW
715 log_dhcp_server(server, "NAK (0x%x)", be32toh(req->message->xid));
716 return DHCP_NAK;
bd57b450
TG
717}
718
54d95d02
YW
719static int server_send_forcerenew(
720 sd_dhcp_server *server,
721 be32_t address,
722 be32_t gateway,
723 uint8_t htype,
724 uint8_t hlen,
725 const uint8_t *chaddr) {
726
52750344
TG
727 _cleanup_free_ DHCPPacket *packet = NULL;
728 size_t optoffset = 0;
729 int r;
730
731 assert(server);
732 assert(address != INADDR_ANY);
733 assert(chaddr);
734
735 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
736 if (!packet)
737 return -ENOMEM;
738
739 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
54d95d02 740 DHCP_FORCERENEW, htype, hlen, chaddr,
76253e73 741 DHCP_MIN_OPTIONS_SIZE, &optoffset);
52750344
TG
742 if (r < 0)
743 return r;
744
745 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
22805d92 746 &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
52750344
TG
747 if (r < 0)
748 return r;
749
4f9dcf3d
YW
750 return dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
751 &packet->dhcp,
752 sizeof(DHCPMessage) + optoffset);
52750344
TG
753}
754
b3ec603c 755static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
99534007 756 DHCPRequest *req = ASSERT_PTR(userdata);
930133d5 757 int r;
816e2e7a 758
79893116 759 switch (code) {
22805d92 760 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
c7d9ffe6 761 if (len == 4)
a0007611 762 req->lifetime = unaligned_be32_sec_to_usec(option, /* max_as_infinity = */ true);
c7d9ffe6
TG
763
764 break;
22805d92 765 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
2dead812 766 if (len == 4)
9ae84244 767 memcpy(&req->requested_ip, option, sizeof(be32_t));
2dead812
TG
768
769 break;
22805d92 770 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
816e2e7a 771 if (len == 4)
9ae84244 772 memcpy(&req->server_id, option, sizeof(be32_t));
816e2e7a
TG
773
774 break;
22805d92 775 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
816e2e7a
TG
776 if (len >= 2) {
777 uint8_t *data;
778
779 data = memdup(option, len);
780 if (!data)
781 return -ENOMEM;
782
255d4933 783 free_and_replace(req->client_id.data, data);
816e2e7a
TG
784 req->client_id.length = len;
785 }
786
787 break;
22805d92 788 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
76a9d0f1
LP
789
790 if (len == 2 && unaligned_read_be16(option) >= sizeof(DHCPPacket))
9ae84244 791 req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket);
816e2e7a 792
11c38d3e
YA
793 break;
794 case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION:
795 req->agent_info_option = (uint8_t*)option - 2;
796
930133d5
RH
797 break;
798 case SD_DHCP_OPTION_HOST_NAME:
799 r = dhcp_option_parse_string(option, len, &req->hostname);
800 if (r < 0) {
801 log_debug_errno(r, "Failed to parse hostname, ignoring: %m");
802 return 0;
803 }
804
14bd102e
SS
805 break;
806 case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
807 req->parameter_request_list = option;
808 req->parameter_request_list_len = len;
816e2e7a
TG
809 break;
810 }
811
812 return 0;
813}
814
75db809a 815static DHCPRequest* dhcp_request_free(DHCPRequest *req) {
816e2e7a 816 if (!req)
75db809a 817 return NULL;
816e2e7a
TG
818
819 free(req->client_id.data);
930133d5 820 free(req->hostname);
75db809a 821 return mfree(req);
816e2e7a
TG
822}
823
824DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
816e2e7a 825
586ac6f7 826static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
816e2e7a
TG
827 assert(req);
828 assert(message);
829
830 req->message = message;
831
ab4f9eeb
YW
832 if (message->hlen > sizeof(message->chaddr))
833 return -EBADMSG;
834
54d95d02 835 /* set client id based on MAC address if client did not send an explicit one */
816e2e7a 836 if (!req->client_id.data) {
2cb66bbd 837 uint8_t *data;
816e2e7a 838
54d95d02
YW
839 if (message->hlen == 0)
840 return -EBADMSG;
841
842 data = new0(uint8_t, message->hlen + 1);
816e2e7a
TG
843 if (!data)
844 return -ENOMEM;
845
2cb66bbd 846 data[0] = 0x01;
54d95d02 847 memcpy(data + 1, message->chaddr, message->hlen);
9a0f246f 848
54d95d02 849 req->client_id.length = message->hlen + 1;
816e2e7a 850 req->client_id.data = data;
816e2e7a
TG
851 }
852
54d95d02
YW
853 if (message->hlen == 0 || memeqzero(message->chaddr, message->hlen)) {
854 /* See RFC2131 section 4.1.1.
855 * hlen and chaddr may not be set for non-ethernet interface.
856 * Let's try to retrieve it from the client ID. */
857
858 if (!req->client_id.data)
859 return -EBADMSG;
860
861 if (req->client_id.length <= 1 || req->client_id.length > sizeof(message->chaddr) + 1)
862 return -EBADMSG;
863
864 if (req->client_id.data[0] != 0x01)
865 return -EBADMSG;
866
867 message->hlen = req->client_id.length - 1;
868 memcpy(message->chaddr, req->client_id.data + 1, message->hlen);
869 }
870
816e2e7a
TG
871 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
872 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
873
9a0f246f 874 if (req->lifetime <= 0)
a0007611 875 req->lifetime = MAX(USEC_PER_SEC, server->default_lease_time);
586ac6f7
LP
876
877 if (server->max_lease_time > 0 && req->lifetime > server->max_lease_time)
878 req->lifetime = server->max_lease_time;
c7d9ffe6 879
816e2e7a
TG
880 return 0;
881}
882
5cc8be89 883static bool address_is_in_pool(sd_dhcp_server *server, be32_t address) {
87322b3a
TG
884 assert(server);
885
6277e48f 886 if (server->pool_size == 0)
5cc8be89 887 return false;
87322b3a 888
9e0cb8b6
YW
889 if (address == server->address)
890 return false;
891
5cc8be89
YW
892 if (be32toh(address) < (be32toh(server->subnet) | server->pool_offset) ||
893 be32toh(address) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
894 return false;
87322b3a 895
bd1a3eb6
YW
896 if (hashmap_contains(server->static_leases_by_address, UINT32_TO_PTR(address)))
897 return false;
898
5cc8be89 899 return true;
87322b3a
TG
900}
901
11c38d3e
YA
902static int append_agent_information_option(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t size) {
903 int r;
904 size_t offset;
905
906 assert(server);
907 assert(message);
908
909 r = dhcp_option_find_option(message->options, opt_length, SD_DHCP_OPTION_END, &offset);
910 if (r < 0)
911 return r;
912
913 r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION, 0, server);
914 if (r < 0)
915 return r;
916
917 r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_END, 0, NULL);
918 if (r < 0)
919 return r;
920 return offset;
921}
922
923static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t buflen) {
c95df587 924 _cleanup_free_ DHCPPacket *packet = NULL;
11c38d3e 925 int r;
c95df587
YA
926
927 assert(server);
928 assert(message);
929 assert(sd_dhcp_server_is_in_relay_mode(server));
930
54d95d02
YW
931 if (message->hlen == 0 || message->hlen > sizeof(message->chaddr) || memeqzero(message->chaddr, message->hlen))
932 return log_dhcp_server_errno(server, SYNTHETIC_ERRNO(EBADMSG),
933 "(relay agent) received message without/invalid hardware address, discarding.");
934
c95df587
YA
935 if (message->op == BOOTREQUEST) {
936 log_dhcp_server(server, "(relay agent) BOOTREQUEST (0x%x)", be32toh(message->xid));
937 if (message->hops >= 16)
938 return -ETIME;
939 message->hops++;
940
941 /* https://tools.ietf.org/html/rfc1542#section-4.1.1 */
942 if (message->giaddr == 0)
943 message->giaddr = server->address;
944
11c38d3e
YA
945 if (server->agent_circuit_id || server->agent_remote_id) {
946 r = append_agent_information_option(server, message, opt_length, buflen - sizeof(DHCPMessage));
947 if (r < 0)
948 return log_dhcp_server_errno(server, r, "could not append relay option: %m");
949 opt_length = r;
950 }
951
c95df587
YA
952 return dhcp_server_send_udp(server, server->relay_target.s_addr, DHCP_PORT_SERVER, message, sizeof(DHCPMessage) + opt_length);
953 } else if (message->op == BOOTREPLY) {
954 log_dhcp_server(server, "(relay agent) BOOTREPLY (0x%x)", be32toh(message->xid));
11c38d3e 955 if (message->giaddr != server->address)
c95df587 956 return log_dhcp_server_errno(server, SYNTHETIC_ERRNO(EBADMSG),
11c38d3e 957 "(relay agent) BOOTREPLY giaddr mismatch, discarding");
c95df587
YA
958
959 int message_type = dhcp_option_parse(message, sizeof(DHCPMessage) + opt_length, NULL, NULL, NULL);
960 if (message_type < 0)
961 return message_type;
962
963 packet = malloc0(sizeof(DHCPPacket) + opt_length);
964 if (!packet)
965 return -ENOMEM;
966 memcpy(&packet->dhcp, message, sizeof(DHCPMessage) + opt_length);
967
11c38d3e
YA
968 r = dhcp_option_remove_option(packet->dhcp.options, opt_length, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION);
969 if (r > 0)
970 opt_length = r;
971
c95df587
YA
972 bool l2_broadcast = requested_broadcast(message) || message_type == DHCP_NAK;
973 const be32_t destination = message_type == DHCP_NAK ? INADDR_ANY : message->ciaddr;
54d95d02 974 return dhcp_server_send(server, message->hlen, message->chaddr, destination, DHCP_PORT_CLIENT, packet, opt_length, l2_broadcast);
c95df587
YA
975 }
976 return -EBADMSG;
977}
978
930133d5 979static int prepare_new_lease(DHCPLease **ret_lease, be32_t address, DHCPRequest *req, usec_t expiration) {
65a0ef23 980 _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
981
930133d5
RH
982 assert(ret_lease);
983 assert(address != 0);
984 assert(req);
985 assert(expiration != 0);
986
65a0ef23 987 lease = new(DHCPLease, 1);
988 if (!lease)
989 return -ENOMEM;
990
991 *lease = (DHCPLease) {
992 .address = address,
930133d5
RH
993 .client_id.length = req->client_id.length,
994 .htype = req->message->htype,
995 .hlen = req->message->hlen,
996 .gateway = req->message->giaddr,
65a0ef23 997 .expiration = expiration,
998 };
930133d5 999 lease->client_id.data = memdup(req->client_id.data, req->client_id.length);
65a0ef23 1000 if (!lease->client_id.data)
1001 return -ENOMEM;
1002
930133d5
RH
1003 memcpy(lease->chaddr, req->message->chaddr, req->message->hlen);
1004
1005 if (req->hostname) {
1006 lease->hostname = strdup(req->hostname);
1007 if (!lease->hostname)
1008 return -ENOMEM;
1009 }
65a0ef23 1010
1011 *ret_lease = TAKE_PTR(lease);
1012
1013 return 0;
1014}
1015
8b572f7a
YW
1016static int server_ack_request(sd_dhcp_server *server, DHCPRequest *req, DHCPLease *existing_lease, be32_t address) {
1017 usec_t time_now, expiration;
1018 int r;
1019
1020 assert(server);
1021 assert(req);
1022 assert(address != 0);
1023
ba4e0427 1024 r = sd_event_now(server->event, CLOCK_BOOTTIME, &time_now);
8b572f7a
YW
1025 if (r < 0)
1026 return r;
1027
a0007611 1028 expiration = usec_add(req->lifetime, time_now);
8b572f7a
YW
1029
1030 if (existing_lease) {
1031 assert(existing_lease->server);
1032 assert(existing_lease->address == address);
1033 existing_lease->expiration = expiration;
1034
1035 } else {
1036 _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
1037
930133d5 1038 r = prepare_new_lease(&lease, address, req, expiration);
8b572f7a
YW
1039 if (r < 0)
1040 return log_dhcp_server_errno(server, r, "Failed to create new lease: %m");
1041
1042 lease->server = server; /* This must be set just before hashmap_put(). */
1043
1044 r = hashmap_ensure_put(&server->bound_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
1045 if (r < 0)
1046 return log_dhcp_server_errno(server, r, "Could not save lease: %m");
1047
1048 r = hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
1049 if (r < 0)
1050 return log_dhcp_server_errno(server, r, "Could not save lease: %m");
1051
1052 TAKE_PTR(lease);
1053 }
1054
1055 r = server_send_offer_or_ack(server, req, address, DHCP_ACK);
1056 if (r < 0)
1057 return log_dhcp_server_errno(server, r, "Could not send ACK: %m");
1058
1059 log_dhcp_server(server, "ACK (0x%x)", be32toh(req->message->xid));
1060
1061 if (server->callback)
1062 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
1063
1064 return DHCP_ACK;
1065}
1066
d635a7f9
THJ
1067static int dhcp_server_cleanup_expired_leases(sd_dhcp_server *server) {
1068 DHCPLease *lease;
1069 usec_t time_now;
1070 int r;
1071
1072 assert(server);
1073
ba4e0427 1074 r = sd_event_now(server->event, CLOCK_BOOTTIME, &time_now);
d635a7f9
THJ
1075 if (r < 0)
1076 return r;
1077
4f9dcf3d 1078 HASHMAP_FOREACH(lease, server->bound_leases_by_client_id)
d635a7f9
THJ
1079 if (lease->expiration < time_now) {
1080 log_dhcp_server(server, "CLEAN (0x%x)", be32toh(lease->address));
1081 dhcp_lease_free(lease);
1082 }
d635a7f9
THJ
1083
1084 return 0;
1085}
1086
cb3c06a0
THJ
1087static bool address_available(sd_dhcp_server *server, be32_t address) {
1088 assert(server);
1089
1090 if (hashmap_contains(server->bound_leases_by_address, UINT32_TO_PTR(address)) ||
1091 hashmap_contains(server->static_leases_by_address, UINT32_TO_PTR(address)) ||
1092 address == server->address)
1093 return false;
1094
1095 return true;
1096}
1097
4646cdaa
RM
1098static int server_get_static_lease(sd_dhcp_server *server, const DHCPRequest *req, DHCPLease **ret) {
1099 DHCPLease *static_lease;
1100 _cleanup_free_ uint8_t *data = NULL;
1101
1102 assert(server);
1103 assert(req);
1104 assert(ret);
1105
1106 static_lease = hashmap_get(server->static_leases_by_client_id, &req->client_id);
1107 if (static_lease) {
1108 *ret = static_lease;
1109 return 0;
1110 }
1111
1112 /* when no lease is found based on the client id fall back to chaddr */
1113 data = new(uint8_t, req->message->hlen + 1);
1114 if (!data)
1115 return -ENOMEM;
1116
1117 /* set client id type to 1: Ethernet Link-Layer (RFC 2132) */
1118 data[0] = 0x01;
1119 memcpy(data + 1, req->message->chaddr, req->message->hlen);
1120
1121 static_lease = hashmap_get(server->static_leases_by_client_id,
1122 &(DHCPClientId) {
1123 .length = req->message->hlen + 1,
1124 .data = data,
1125 });
1126
1127 *ret = static_lease;
1128
1129 return 0;
1130}
1131
83cedf7a
TG
1132#define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
1133
65a0ef23 1134int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length) {
8e766630 1135 _cleanup_(dhcp_request_freep) DHCPRequest *req = NULL;
f693e9b3 1136 _cleanup_free_ char *error_message = NULL;
65a0ef23 1137 DHCPLease *existing_lease, *static_lease;
816e2e7a 1138 int type, r;
be077570
TG
1139
1140 assert(server);
1141 assert(message);
1142
54d95d02 1143 if (message->op != BOOTREQUEST)
be077570
TG
1144 return 0;
1145
816e2e7a
TG
1146 req = new0(DHCPRequest, 1);
1147 if (!req)
1148 return -ENOMEM;
1149
f693e9b3 1150 type = dhcp_option_parse(message, length, parse_request, req, &error_message);
be077570 1151 if (type < 0)
809da721 1152 return type;
be077570 1153
586ac6f7 1154 r = ensure_sane_request(server, req, message);
816e2e7a 1155 if (r < 0)
816e2e7a
TG
1156 return r;
1157
d635a7f9
THJ
1158 r = dhcp_server_cleanup_expired_leases(server);
1159 if (r < 0)
1160 return r;
1161
b713a99b 1162 existing_lease = hashmap_get(server->bound_leases_by_client_id, &req->client_id);
4646cdaa
RM
1163 r = server_get_static_lease(server, req, &static_lease);
1164 if (r < 0)
1165 return r;
87322b3a 1166
79893116 1167 switch (type) {
9a0f246f
LP
1168
1169 case DHCP_DISCOVER: {
87322b3a 1170 be32_t address = INADDR_ANY;
2dead812 1171
65a0ef23 1172 log_dhcp_server(server, "DISCOVER (0x%x)", be32toh(req->message->xid));
4dc35568 1173
6277e48f 1174 if (server->pool_size == 0)
2dead812
TG
1175 /* no pool allocated */
1176 return 0;
1177
87322b3a 1178 /* for now pick a random free address from the pool */
65a0ef23 1179 if (static_lease)
1180 address = static_lease->address;
1181 else if (existing_lease)
87322b3a
TG
1182 address = existing_lease->address;
1183 else {
b826ab58 1184 struct siphash state;
0cb3c286 1185 uint64_t hash;
83cedf7a
TG
1186
1187 /* even with no persistence of leases, we try to offer the same client
1188 the same IP address. we do this by using the hash of the client id
1189 as the offset into the pool of leases when finding the next free one */
1190
0cb3c286 1191 siphash24_init(&state, HASH_KEY.bytes);
b826ab58 1192 client_id_hash_func(&req->client_id, &state);
933f9cae 1193 hash = htole64(siphash24_finalize(&state));
6408ba5f 1194
b713a99b
YW
1195 for (unsigned i = 0; i < server->pool_size; i++) {
1196 be32_t tmp_address;
1197
1198 tmp_address = server->subnet | htobe32(server->pool_offset + (hash + i) % server->pool_size);
cb3c06a0 1199 if (address_available(server, tmp_address)) {
b713a99b
YW
1200 address = tmp_address;
1201 break;
1202 }
87322b3a
TG
1203 }
1204 }
1205
1206 if (address == INADDR_ANY)
1207 /* no free addresses left */
1208 return 0;
2dead812 1209
986c0edf 1210 r = server_send_offer_or_ack(server, req, address, DHCP_OFFER);
6e741541 1211 if (r < 0)
4dc35568 1212 /* this only fails on critical errors */
6e741541 1213 return log_dhcp_server_errno(server, r, "Could not send offer: %m");
be077570 1214
6e741541
LP
1215 log_dhcp_server(server, "OFFER (0x%x)", be32toh(req->message->xid));
1216 return DHCP_OFFER;
4dc35568 1217 }
5b34277c 1218 case DHCP_DECLINE:
f693e9b3 1219 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
5b34277c
TG
1220
1221 /* TODO: make sure we don't offer this address again */
1222
1223 return 1;
1224
9a0f246f 1225 case DHCP_REQUEST: {
2dead812 1226 be32_t address;
bd57b450 1227 bool init_reboot = false;
2dead812
TG
1228
1229 /* see RFC 2131, section 4.3.2 */
1230
6277e48f 1231 if (req->server_id != 0) {
2dead812
TG
1232 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
1233 be32toh(req->message->xid));
1234
1235 /* SELECTING */
1236 if (req->server_id != server->address)
1237 /* client did not pick us */
1238 return 0;
1239
6277e48f 1240 if (req->message->ciaddr != 0)
2dead812
TG
1241 /* this MUST be zero */
1242 return 0;
1243
6277e48f 1244 if (req->requested_ip == 0)
2dead812
TG
1245 /* this must be filled in with the yiaddr
1246 from the chosen OFFER */
1247 return 0;
1248
1249 address = req->requested_ip;
6277e48f 1250 } else if (req->requested_ip != 0) {
2dead812
TG
1251 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
1252 be32toh(req->message->xid));
1253
1254 /* INIT-REBOOT */
6277e48f 1255 if (req->message->ciaddr != 0)
2dead812
TG
1256 /* this MUST be zero */
1257 return 0;
1258
bd57b450 1259 /* TODO: check more carefully if IP is correct */
2dead812 1260 address = req->requested_ip;
bd57b450 1261 init_reboot = true;
2dead812
TG
1262 } else {
1263 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
1264 be32toh(req->message->xid));
1265
1266 /* REBINDING / RENEWING */
6277e48f 1267 if (req->message->ciaddr == 0)
2dead812
TG
1268 /* this MUST be filled in with clients IP address */
1269 return 0;
1270
1271 address = req->message->ciaddr;
1272 }
1273
cb3c06a0
THJ
1274 /* disallow our own address */
1275 if (address == server->address)
1276 return 0;
1277
e2ba4080
YW
1278 if (static_lease) {
1279 /* Found a static lease for the client ID. */
1280
1281 if (static_lease->address != address)
1282 /* The client requested an address which is different from the static lease. Refuse. */
1283 return server_send_nak_or_ignore(server, init_reboot, req);
1284
8b572f7a 1285 return server_ack_request(server, req, existing_lease, address);
5cc8be89 1286 }
65a0ef23 1287
7e98fe05
YW
1288 if (address_is_in_pool(server, address)) {
1289 /* The requested address is in the pool. */
1290
1291 if (existing_lease && existing_lease->address != address)
1292 /* We previously assigned an address, but the client requested another one. Refuse. */
1293 return server_send_nak_or_ignore(server, init_reboot, req);
1294
8b572f7a 1295 return server_ack_request(server, req, existing_lease, address);
bd57b450 1296 }
2dead812 1297
eb5bff9c 1298 return server_send_nak_or_ignore(server, init_reboot, req);
2dead812 1299 }
9a0f246f 1300
500792d8 1301 case DHCP_RELEASE: {
500792d8
TG
1302 log_dhcp_server(server, "RELEASE (0x%x)",
1303 be32toh(req->message->xid));
1304
1305 if (!existing_lease)
1306 return 0;
1307
1308 if (existing_lease->address != req->message->ciaddr)
1309 return 0;
1310
b713a99b 1311 dhcp_lease_free(existing_lease);
36d35f22 1312
b713a99b
YW
1313 if (server->callback)
1314 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
500792d8 1315
c3922c0c
LP
1316 return 0;
1317 }}
4dc35568
TG
1318
1319 return 0;
be077570
TG
1320}
1321
11c38d3e
YA
1322static size_t relay_agent_information_length(const char* agent_circuit_id, const char* agent_remote_id) {
1323 size_t sum = 0;
1324 if (agent_circuit_id)
1325 sum += 2 + strlen(agent_circuit_id);
1326 if (agent_remote_id)
1327 sum += 2 + strlen(agent_remote_id);
1328 return sum;
1329}
1330
ff734080
TG
1331static int server_receive_message(sd_event_source *s, int fd,
1332 uint32_t revents, void *userdata) {
be077570 1333 _cleanup_free_ DHCPMessage *message = NULL;
fb29cdbe 1334 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control;
99534007 1335 sd_dhcp_server *server = ASSERT_PTR(userdata);
ff734080
TG
1336 struct iovec iov = {};
1337 struct msghdr msg = {
1338 .msg_iov = &iov,
1339 .msg_iovlen = 1,
fb29cdbe
LP
1340 .msg_control = &control,
1341 .msg_controllen = sizeof(control),
ff734080 1342 };
11c38d3e 1343 ssize_t datagram_size, len;
57027d03 1344 int r;
ff734080 1345
11c38d3e 1346 datagram_size = next_datagram_size_fd(fd);
1f2db2e3
ZJS
1347 if (ERRNO_IS_NEG_TRANSIENT(datagram_size) || ERRNO_IS_NEG_DISCONNECT(datagram_size))
1348 return 0;
ab8a8a4e 1349 if (datagram_size < 0) {
ab8a8a4e
YW
1350 log_dhcp_server_errno(server, datagram_size, "Failed to determine datagram size to read, ignoring: %m");
1351 return 0;
1352 }
11c38d3e
YA
1353
1354 size_t buflen = datagram_size;
1355 if (sd_dhcp_server_is_in_relay_mode(server))
19cc6d5e 1356 /* Preallocate the additional size for DHCP Relay Agent Information Option if needed */
11c38d3e 1357 buflen += relay_agent_information_length(server->agent_circuit_id, server->agent_remote_id) + 2;
ff734080 1358
0d43d2fc 1359 message = malloc(buflen);
ff734080
TG
1360 if (!message)
1361 return -ENOMEM;
1362
11c38d3e 1363 iov = IOVEC_MAKE(message, datagram_size);
ff734080 1364
2efa5bc6 1365 len = recvmsg_safe(fd, &msg, 0);
1f2db2e3
ZJS
1366 if (ERRNO_IS_NEG_TRANSIENT(len) || ERRNO_IS_NEG_DISCONNECT(len))
1367 return 0;
8add30a0 1368 if (len < 0) {
ab8a8a4e
YW
1369 log_dhcp_server_errno(server, len, "Could not receive message, ignoring: %m");
1370 return 0;
8add30a0
YW
1371 }
1372
2efa5bc6 1373 if ((size_t) len < sizeof(DHCPMessage))
be077570 1374 return 0;
ff734080 1375
1ebb0953
YW
1376 /* TODO figure out if this can be done as a filter on the socket, like for IPv6 */
1377 struct in_pktinfo *info = CMSG_FIND_DATA(&msg, IPPROTO_IP, IP_PKTINFO, struct in_pktinfo);
1378 if (info && info->ipi_ifindex != server->ifindex)
1379 return 0;
3a864fe4 1380
c95df587 1381 if (sd_dhcp_server_is_in_relay_mode(server)) {
11c38d3e 1382 r = dhcp_server_relay_message(server, message, len - sizeof(DHCPMessage), buflen);
c95df587 1383 if (r < 0)
ab8a8a4e 1384 log_dhcp_server_errno(server, r, "Couldn't relay message, ignoring: %m");
c95df587
YA
1385 } else {
1386 r = dhcp_server_handle_message(server, message, (size_t) len);
1387 if (r < 0)
ab8a8a4e 1388 log_dhcp_server_errno(server, r, "Couldn't process incoming message, ignoring: %m");
c95df587 1389 }
57027d03 1390 return 0;
ff734080
TG
1391}
1392
c0fdc91e
YW
1393static void dhcp_server_update_lease_servers(sd_dhcp_server *server) {
1394 assert(server);
1395 assert(server->address != 0);
1396
1397 /* Convert null address -> server address */
1398
1399 for (sd_dhcp_lease_server_type_t k = 0; k < _SD_DHCP_LEASE_SERVER_TYPE_MAX; k++)
1400 for (size_t i = 0; i < server->servers[k].size; i++)
1401 if (in4_addr_is_null(&server->servers[k].addr[i]))
1402 server->servers[k].addr[i].s_addr = server->address;
1403}
1404
ff734080
TG
1405int sd_dhcp_server_start(sd_dhcp_server *server) {
1406 int r;
1407
1408 assert_return(server, -EINVAL);
1409 assert_return(server->event, -EINVAL);
b27e5d53
YW
1410
1411 if (sd_dhcp_server_is_running(server))
1412 return 0;
1413
ff734080 1414 assert_return(!server->receive_message, -EBUSY);
cfcbb135
LP
1415 assert_return(server->fd_raw < 0, -EBUSY);
1416 assert_return(server->fd < 0, -EBUSY);
20af7091 1417 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
ff734080 1418
c0fdc91e
YW
1419 dhcp_server_update_lease_servers(server);
1420
3e29b889 1421 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
8de4a226
TG
1422 if (r < 0) {
1423 r = -errno;
21b6b87e 1424 goto on_error;
8de4a226
TG
1425 }
1426 server->fd_raw = r;
1427
21b6b87e
YA
1428 if (server->bind_to_interface)
1429 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER, -1);
1430 else
1431 r = dhcp_network_bind_udp_socket(0, server->address, DHCP_PORT_SERVER, -1);
1432 if (r < 0)
1433 goto on_error;
ff734080
TG
1434 server->fd = r;
1435
1436 r = sd_event_add_io(server->event, &server->receive_message,
1437 server->fd, EPOLLIN,
1438 server_receive_message, server);
21b6b87e
YA
1439 if (r < 0)
1440 goto on_error;
ff734080
TG
1441
1442 r = sd_event_source_set_priority(server->receive_message,
1443 server->event_priority);
21b6b87e
YA
1444 if (r < 0)
1445 goto on_error;
1446
1447 if (!server->bind_to_interface) {
1448 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_BROADCAST, DHCP_PORT_SERVER, -1);
1449 if (r < 0)
1450 goto on_error;
1451
1452 server->fd_broadcast = r;
1453
1454 r = sd_event_add_io(server->event, &server->receive_broadcast,
1455 server->fd_broadcast, EPOLLIN,
1456 server_receive_message, server);
1457 if (r < 0)
1458 goto on_error;
1459
1460 r = sd_event_source_set_priority(server->receive_broadcast,
1461 server->event_priority);
1462 if (r < 0)
1463 goto on_error;
ff734080
TG
1464 }
1465
1466 log_dhcp_server(server, "STARTED");
1467
1468 return 0;
21b6b87e
YA
1469
1470on_error:
37e21980
YW
1471 sd_dhcp_server_stop(server);
1472 return r;
ff734080 1473}
52750344
TG
1474
1475int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
b713a99b 1476 DHCPLease *lease;
9ef648cc 1477 int r = 0;
52750344
TG
1478
1479 assert_return(server, -EINVAL);
52750344 1480
b713a99b 1481 log_dhcp_server(server, "FORCERENEW");
6408ba5f 1482
9ef648cc
ZJS
1483 HASHMAP_FOREACH(lease, server->bound_leases_by_client_id)
1484 RET_GATHER(r,
1485 server_send_forcerenew(server, lease->address, lease->gateway,
1486 lease->htype, lease->hlen, lease->chaddr));
52750344
TG
1487 return r;
1488}
8eb9058d 1489
21b6b87e
YA
1490int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server *server, int enabled) {
1491 assert_return(server, -EINVAL);
1492 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1493
1494 if (!!enabled == server->bind_to_interface)
1495 return 0;
1496
1497 server->bind_to_interface = enabled;
1498
1499 return 1;
1500}
1501
64d6c229 1502int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
8eb9058d
LP
1503 int r;
1504
1505 assert_return(server, -EINVAL);
089fb865 1506 assert_return(timezone_is_valid(tz, LOG_DEBUG), -EINVAL);
8eb9058d 1507
64d6c229 1508 if (streq_ptr(tz, server->timezone))
8eb9058d
LP
1509 return 0;
1510
64d6c229 1511 r = free_and_strdup(&server->timezone, tz);
8eb9058d
LP
1512 if (r < 0)
1513 return r;
1514
1515 return 1;
1516}
586ac6f7 1517
a0007611 1518int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint64_t t) {
586ac6f7
LP
1519 assert_return(server, -EINVAL);
1520
586ac6f7 1521 server->max_lease_time = t;
a0007611 1522 return 0;
586ac6f7
LP
1523}
1524
a0007611 1525int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint64_t t) {
586ac6f7
LP
1526 assert_return(server, -EINVAL);
1527
586ac6f7 1528 server->default_lease_time = t;
a0007611 1529 return 0;
586ac6f7 1530}
1a04db0f 1531
14bd102e
SS
1532int sd_dhcp_server_set_ipv6_only_preferred_usec(sd_dhcp_server *server, uint64_t t) {
1533 assert_return(server, -EINVAL);
1534
1535 /* When 0 is set, disables the IPv6 only mode. */
1536
1537 /* Refuse too short timespan unless test mode is enabled. */
1538 if (t > 0 && t < MIN_V6ONLY_WAIT_USEC && !network_test_mode_enabled())
1539 return -EINVAL;
1540
1541 server->ipv6_only_preferred_usec = t;
1542 return 0;
1543}
1544
c8407baf
ZJS
1545int sd_dhcp_server_set_servers(
1546 sd_dhcp_server *server,
2324fd3a 1547 sd_dhcp_lease_server_type_t what,
c8407baf 1548 const struct in_addr addresses[],
90810f7a 1549 size_t n_addresses) {
1a04db0f 1550
ddb82ec2
LP
1551 struct in_addr *c = NULL;
1552
1a04db0f 1553 assert_return(server, -EINVAL);
c0fdc91e 1554 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
c8407baf 1555 assert_return(addresses || n_addresses == 0, -EINVAL);
ddb82ec2
LP
1556 assert_return(what >= 0, -EINVAL);
1557 assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL);
1a04db0f 1558
ddb82ec2
LP
1559 if (server->servers[what].size == n_addresses &&
1560 memcmp(server->servers[what].addr, addresses, sizeof(struct in_addr) * n_addresses) == 0)
f678ac7e
SS
1561 return 0;
1562
c8407baf
ZJS
1563 if (n_addresses > 0) {
1564 c = newdup(struct in_addr, addresses, n_addresses);
f678ac7e
SS
1565 if (!c)
1566 return -ENOMEM;
f678ac7e
SS
1567 }
1568
c997f51c 1569 free_and_replace(server->servers[what].addr, c);
ddb82ec2 1570 server->servers[what].size = n_addresses;
f678ac7e
SS
1571 return 1;
1572}
1573
90810f7a 1574int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], size_t n) {
ddb82ec2 1575 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_DNS, dns, n);
c8407baf 1576}
90810f7a 1577int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], size_t n) {
ddb82ec2 1578 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_NTP, ntp, n);
c8407baf 1579}
90810f7a 1580int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], size_t n) {
ddb82ec2 1581 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SIP, sip, n);
c8407baf 1582}
90810f7a 1583int sd_dhcp_server_set_pop3(sd_dhcp_server *server, const struct in_addr pop3[], size_t n) {
ddb82ec2 1584 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_POP3, pop3, n);
c8407baf 1585}
90810f7a 1586int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp[], size_t n) {
ddb82ec2 1587 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SMTP, smtp, n);
2c649ca1 1588}
90810f7a 1589int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], size_t n) {
ddb82ec2 1590 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_LPR, lpr, n);
50018bfa 1591}
2c649ca1 1592
59aa6220 1593int sd_dhcp_server_set_router(sd_dhcp_server *server, const struct in_addr *router) {
77ff6022
CG
1594 assert_return(server, -EINVAL);
1595
59aa6220
YW
1596 /* router is NULL: router option will not be appended.
1597 * router is null address (0.0.0.0): the server address will be used as the router address.
0b75493d 1598 * otherwise: the specified address will be used as the router address. */
77ff6022 1599
59aa6220
YW
1600 server->emit_router = router;
1601 if (router)
1602 server->router_address = *router;
77ff6022 1603
59aa6220 1604 return 0;
77ff6022 1605}
564ca984 1606
461dbb2f 1607int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v) {
564ca984
SS
1608 int r;
1609
1610 assert_return(server, -EINVAL);
1611 assert_return(v, -EINVAL);
1612
ebffea2a 1613 r = ordered_set_ensure_put(&server->extra_options, &dhcp_option_hash_ops, v);
7354900d
DW
1614 if (r < 0)
1615 return r;
1616
1617 sd_dhcp_option_ref(v);
1618 return 0;
1619}
1620
1621int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v) {
1622 int r;
1623
1624 assert_return(server, -EINVAL);
1625 assert_return(v, -EINVAL);
1626
ebffea2a 1627 r = ordered_set_ensure_put(&server->vendor_options, &dhcp_option_hash_ops, v);
564ca984
SS
1628 if (r < 0)
1629 return r;
1630
461dbb2f 1631 sd_dhcp_option_ref(v);
564ca984
SS
1632
1633 return 1;
1634}
5b03043a
MAL
1635
1636int sd_dhcp_server_set_callback(sd_dhcp_server *server, sd_dhcp_server_callback_t cb, void *userdata) {
1637 assert_return(server, -EINVAL);
1638
1639 server->callback = cb;
1640 server->callback_userdata = userdata;
1641
1642 return 0;
1643}
c95df587 1644
11c38d3e 1645int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addr *address) {
c95df587
YA
1646 assert_return(server, -EINVAL);
1647 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1648
1649 if (memcmp(address, &server->relay_target, sizeof(struct in_addr)) == 0)
1650 return 0;
1651
1652 server->relay_target = *address;
1653 return 1;
1654}
11c38d3e
YA
1655
1656int sd_dhcp_server_set_relay_agent_information(
1657 sd_dhcp_server *server,
1658 const char *agent_circuit_id,
1659 const char *agent_remote_id) {
1660 _cleanup_free_ char *circuit_id_dup = NULL, *remote_id_dup = NULL;
1661
1662 assert_return(server, -EINVAL);
1663
1664 if (relay_agent_information_length(agent_circuit_id, agent_remote_id) > UINT8_MAX)
1665 return -ENOBUFS;
1666
1667 if (agent_circuit_id) {
1668 circuit_id_dup = strdup(agent_circuit_id);
1669 if (!circuit_id_dup)
1670 return -ENOMEM;
1671 }
1672
1673 if (agent_remote_id) {
1674 remote_id_dup = strdup(agent_remote_id);
1675 if (!remote_id_dup)
1676 return -ENOMEM;
1677 }
1678
1679 free_and_replace(server->agent_circuit_id, circuit_id_dup);
1680 free_and_replace(server->agent_remote_id, remote_id_dup);
1681 return 0;
1682}
65a0ef23 1683
1684int sd_dhcp_server_set_static_lease(
1685 sd_dhcp_server *server,
1686 const struct in_addr *address,
1687 uint8_t *client_id,
1688 size_t client_id_size) {
1689
b713a99b 1690 _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
65a0ef23 1691 int r;
1692
1693 assert_return(server, -EINVAL);
1694 assert_return(client_id, -EINVAL);
a2a80192 1695 assert_return(client_id_size > 0, -EINVAL);
65a0ef23 1696 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1697
1698 /* Static lease with an empty or omitted address is a valid entry,
f4759ae0 1699 * the server removes any static lease with the specified mac address. */
65a0ef23 1700 if (!address || address->s_addr == 0) {
b713a99b 1701 DHCPClientId c;
65a0ef23 1702
65a0ef23 1703 c = (DHCPClientId) {
1704 .length = client_id_size,
f4759ae0 1705 .data = client_id,
65a0ef23 1706 };
1707
8a7d048d 1708 dhcp_lease_free(hashmap_get(server->static_leases_by_client_id, &c));
65a0ef23 1709 return 0;
1710 }
1711
65a0ef23 1712 lease = new(DHCPLease, 1);
1713 if (!lease)
1714 return -ENOMEM;
1715
1716 *lease = (DHCPLease) {
1717 .address = address->s_addr,
1718 .client_id.length = client_id_size,
65a0ef23 1719 };
1720 lease->client_id.data = memdup(client_id, client_id_size);
1721 if (!lease->client_id.data)
1722 return -ENOMEM;
1723
8a7d048d
YW
1724 lease->server = server; /* This must be set just before hashmap_put(). */
1725
65a0ef23 1726 r = hashmap_ensure_put(&server->static_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
b713a99b
YW
1727 if (r < 0)
1728 return r;
1729 r = hashmap_ensure_put(&server->static_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
65a0ef23 1730 if (r < 0)
1731 return r;
1732
1733 TAKE_PTR(lease);
1734 return 0;
1735}