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