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