2 This file is part of systemd.
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
5 Copyright (C) 2014 Tom Gundersen
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <sys/ioctl.h>
23 #include "sd-dhcp-server.h"
25 #include "alloc-util.h"
26 #include "dhcp-internal.h"
27 #include "dhcp-server-internal.h"
29 #include "in-addr-util.h"
30 #include "siphash24.h"
31 #include "string-util.h"
32 #include "unaligned.h"
34 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
35 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
37 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
38 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
39 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
40 * accidentally hand it out */
41 int sd_dhcp_server_configure_pool(sd_dhcp_server
*server
, struct in_addr
*address
, unsigned char prefixlen
, uint32_t offset
, uint32_t size
) {
42 struct in_addr netmask_addr
;
44 uint32_t server_off
, broadcast_off
, size_max
;
46 assert_return(server
, -EINVAL
);
47 assert_return(address
, -EINVAL
);
48 assert_return(address
->s_addr
!= INADDR_ANY
, -EINVAL
);
49 assert_return(prefixlen
<= 32, -ERANGE
);
50 assert_return(server
->address
== INADDR_ANY
, -EBUSY
);
52 assert_se(in_addr_prefixlen_to_netmask(&netmask_addr
, prefixlen
));
53 netmask
= netmask_addr
.s_addr
;
55 server_off
= be32toh(address
->s_addr
& ~netmask
);
56 broadcast_off
= be32toh(~netmask
);
58 /* the server address cannot be the subnet address */
59 assert_return(server_off
!= 0, -ERANGE
);
61 /* nor the broadcast address */
62 assert_return(server_off
!= broadcast_off
, -ERANGE
);
64 /* 0 offset means we should set a default, we skip the first (subnet) address
65 and take the next one */
69 size_max
= (broadcast_off
+ 1) /* the number of addresses in the subnet */
70 - offset
/* exclude the addresses before the offset */
71 - 1; /* exclude the last (broadcast) address */
73 /* The pool must contain at least one address */
74 assert_return(size_max
>= 1, -ERANGE
);
77 assert_return(size
<= size_max
, -ERANGE
);
81 server
->bound_leases
= new0(DHCPLease
*, size
);
82 if (!server
->bound_leases
)
85 server
->pool_offset
= offset
;
86 server
->pool_size
= size
;
88 server
->address
= address
->s_addr
;
89 server
->netmask
= netmask
;
90 server
->subnet
= address
->s_addr
& netmask
;
92 if (server_off
>= offset
&& server_off
- offset
< size
)
93 server
->bound_leases
[server_off
- offset
] = &server
->invalid_lease
;
98 int sd_dhcp_server_is_running(sd_dhcp_server
*server
) {
99 assert_return(server
, false);
101 return !!server
->receive_message
;
104 sd_dhcp_server
*sd_dhcp_server_ref(sd_dhcp_server
*server
) {
109 assert(server
->n_ref
>= 1);
115 void client_id_hash_func(const void *p
, struct siphash
*state
) {
116 const DHCPClientId
*id
= p
;
122 siphash24_compress(&id
->length
, sizeof(id
->length
), state
);
123 siphash24_compress(id
->data
, id
->length
, state
);
126 int client_id_compare_func(const void *_a
, const void *_b
) {
127 const DHCPClientId
*a
, *b
;
132 assert(!a
->length
|| a
->data
);
133 assert(!b
->length
|| b
->data
);
135 if (a
->length
!= b
->length
)
136 return a
->length
< b
->length
? -1 : 1;
138 return memcmp(a
->data
, b
->data
, a
->length
);
141 static const struct hash_ops client_id_hash_ops
= {
142 .hash
= client_id_hash_func
,
143 .compare
= client_id_compare_func
146 static void dhcp_lease_free(DHCPLease
*lease
) {
150 free(lease
->client_id
.data
);
154 sd_dhcp_server
*sd_dhcp_server_unref(sd_dhcp_server
*server
) {
160 assert(server
->n_ref
>= 1);
163 if (server
->n_ref
> 0)
166 log_dhcp_server(server
, "UNREF");
168 sd_dhcp_server_stop(server
);
170 sd_event_unref(server
->event
);
172 free(server
->timezone
);
176 while ((lease
= hashmap_steal_first(server
->leases_by_client_id
)))
177 dhcp_lease_free(lease
);
178 hashmap_free(server
->leases_by_client_id
);
180 free(server
->bound_leases
);
181 return mfree(server
);
184 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
185 _cleanup_(sd_dhcp_server_unrefp
) sd_dhcp_server
*server
= NULL
;
187 assert_return(ret
, -EINVAL
);
188 assert_return(ifindex
> 0, -EINVAL
);
190 server
= new0(sd_dhcp_server
, 1);
197 server
->address
= htobe32(INADDR_ANY
);
198 server
->netmask
= htobe32(INADDR_ANY
);
199 server
->ifindex
= ifindex
;
200 server
->leases_by_client_id
= hashmap_new(&client_id_hash_ops
);
201 server
->default_lease_time
= DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC
, USEC_PER_SEC
);
202 server
->max_lease_time
= DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC
, USEC_PER_SEC
);
210 int sd_dhcp_server_attach_event(sd_dhcp_server
*server
, sd_event
*event
, int64_t priority
) {
213 assert_return(server
, -EINVAL
);
214 assert_return(!server
->event
, -EBUSY
);
217 server
->event
= sd_event_ref(event
);
219 r
= sd_event_default(&server
->event
);
224 server
->event_priority
= priority
;
229 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
230 assert_return(server
, -EINVAL
);
232 server
->event
= sd_event_unref(server
->event
);
237 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
238 assert_return(server
, NULL
);
240 return server
->event
;
243 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
244 assert_return(server
, -EINVAL
);
246 server
->receive_message
=
247 sd_event_source_unref(server
->receive_message
);
249 server
->fd_raw
= safe_close(server
->fd_raw
);
250 server
->fd
= safe_close(server
->fd
);
252 log_dhcp_server(server
, "STOPPED");
257 static int dhcp_server_send_unicast_raw(sd_dhcp_server
*server
,
258 DHCPPacket
*packet
, size_t len
) {
259 union sockaddr_union link
= {
260 .ll
.sll_family
= AF_PACKET
,
261 .ll
.sll_protocol
= htobe16(ETH_P_IP
),
262 .ll
.sll_ifindex
= server
->ifindex
,
263 .ll
.sll_halen
= ETH_ALEN
,
267 assert(server
->ifindex
> 0);
268 assert(server
->address
);
270 assert(len
> sizeof(DHCPPacket
));
272 memcpy(&link
.ll
.sll_addr
, &packet
->dhcp
.chaddr
, ETH_ALEN
);
274 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
276 DHCP_PORT_CLIENT
, len
);
278 return dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
281 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
282 uint16_t destination_port
,
283 DHCPMessage
*message
, size_t len
) {
284 union sockaddr_union dest
= {
285 .in
.sin_family
= AF_INET
,
286 .in
.sin_port
= htobe16(destination_port
),
287 .in
.sin_addr
.s_addr
= destination
,
293 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))] = {};
294 struct msghdr msg
= {
296 .msg_namelen
= sizeof(dest
.in
),
299 .msg_control
= cmsgbuf
,
300 .msg_controllen
= sizeof(cmsgbuf
),
302 struct cmsghdr
*cmsg
;
303 struct in_pktinfo
*pktinfo
;
307 assert(server
->fd
> 0);
309 assert(len
> sizeof(DHCPMessage
));
311 cmsg
= CMSG_FIRSTHDR(&msg
);
314 cmsg
->cmsg_level
= IPPROTO_IP
;
315 cmsg
->cmsg_type
= IP_PKTINFO
;
316 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
318 /* we attach source interface and address info to the message
319 rather than binding the socket. This will be mostly useful
320 when we gain support for arbitrary number of server addresses
322 pktinfo
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
325 pktinfo
->ipi_ifindex
= server
->ifindex
;
326 pktinfo
->ipi_spec_dst
.s_addr
= server
->address
;
328 r
= sendmsg(server
->fd
, &msg
, 0);
335 static bool requested_broadcast(DHCPRequest
*req
) {
338 return req
->message
->flags
& htobe16(0x8000);
341 int dhcp_server_send_packet(sd_dhcp_server
*server
,
342 DHCPRequest
*req
, DHCPPacket
*packet
,
343 int type
, size_t optoffset
) {
344 be32_t destination
= INADDR_ANY
;
345 uint16_t destination_port
= DHCP_PORT_CLIENT
;
350 assert(req
->max_optlen
);
351 assert(optoffset
<= req
->max_optlen
);
354 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
355 SD_DHCP_OPTION_SERVER_IDENTIFIER
,
356 4, &server
->address
);
360 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
361 SD_DHCP_OPTION_END
, 0, NULL
);
365 /* RFC 2131 Section 4.1
367 If the ’giaddr’ field in a DHCP message from a client is non-zero,
368 the server sends any return messages to the ’DHCP server’ port on the
369 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
370 field is zero and the ’ciaddr’ field is nonzero, then the server
371 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
372 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
373 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
374 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
375 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
376 messages to the client’s hardware address and ’yiaddr’ address. In
377 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
378 messages to 0xffffffff.
382 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
383 different subnet. The server MUST set the broadcast bit in the
384 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
385 client, because the client may not have a correct network address
386 or subnet mask, and the client may not be answering ARP requests.
388 if (req
->message
->giaddr
) {
389 destination
= req
->message
->giaddr
;
390 destination_port
= DHCP_PORT_SERVER
;
391 if (type
== DHCP_NAK
)
392 packet
->dhcp
.flags
= htobe16(0x8000);
393 } else if (req
->message
->ciaddr
&& type
!= DHCP_NAK
)
394 destination
= req
->message
->ciaddr
;
396 if (destination
!= INADDR_ANY
)
397 return dhcp_server_send_udp(server
, destination
,
398 destination_port
, &packet
->dhcp
,
399 sizeof(DHCPMessage
) + optoffset
);
400 else if (requested_broadcast(req
) || type
== DHCP_NAK
)
401 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
402 destination_port
, &packet
->dhcp
,
403 sizeof(DHCPMessage
) + optoffset
);
405 /* we cannot send UDP packet to specific MAC address when the
406 address is not yet configured, so must fall back to raw
408 return dhcp_server_send_unicast_raw(server
, packet
,
409 sizeof(DHCPPacket
) + optoffset
);
412 static int server_message_init(sd_dhcp_server
*server
, DHCPPacket
**ret
,
413 uint8_t type
, size_t *_optoffset
,
415 _cleanup_free_ DHCPPacket
*packet
= NULL
;
416 size_t optoffset
= 0;
422 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
, DHCP_NAK
));
424 packet
= malloc0(sizeof(DHCPPacket
) + req
->max_optlen
);
428 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
,
429 be32toh(req
->message
->xid
), type
, ARPHRD_ETHER
,
430 req
->max_optlen
, &optoffset
);
434 packet
->dhcp
.flags
= req
->message
->flags
;
435 packet
->dhcp
.giaddr
= req
->message
->giaddr
;
436 memcpy(&packet
->dhcp
.chaddr
, &req
->message
->chaddr
, ETH_ALEN
);
438 *_optoffset
= optoffset
;
445 static int server_send_offer(sd_dhcp_server
*server
, DHCPRequest
*req
,
447 _cleanup_free_ DHCPPacket
*packet
= NULL
;
452 r
= server_message_init(server
, &packet
, DHCP_OFFER
, &offset
, req
);
456 packet
->dhcp
.yiaddr
= address
;
458 lease_time
= htobe32(req
->lifetime
);
459 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
460 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
465 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
466 SD_DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
470 if (server
->emit_router
) {
471 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
472 SD_DHCP_OPTION_ROUTER
, 4, &server
->address
);
477 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_OFFER
, offset
);
484 static int server_send_ack(sd_dhcp_server
*server
, DHCPRequest
*req
,
486 _cleanup_free_ DHCPPacket
*packet
= NULL
;
491 r
= server_message_init(server
, &packet
, DHCP_ACK
, &offset
, req
);
495 packet
->dhcp
.yiaddr
= address
;
497 lease_time
= htobe32(req
->lifetime
);
498 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
499 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
504 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
505 SD_DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
509 if (server
->emit_router
) {
510 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
511 SD_DHCP_OPTION_ROUTER
, 4, &server
->address
);
516 if (server
->n_dns
> 0) {
517 r
= dhcp_option_append(
518 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
519 SD_DHCP_OPTION_DOMAIN_NAME_SERVER
,
520 sizeof(struct in_addr
) * server
->n_dns
, server
->dns
);
525 if (server
->n_ntp
> 0) {
526 r
= dhcp_option_append(
527 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
528 SD_DHCP_OPTION_NTP_SERVER
,
529 sizeof(struct in_addr
) * server
->n_ntp
, server
->ntp
);
534 if (server
->timezone
) {
535 r
= dhcp_option_append(
536 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
537 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
,
538 strlen(server
->timezone
), server
->timezone
);
543 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_ACK
, offset
);
550 static int server_send_nak(sd_dhcp_server
*server
, DHCPRequest
*req
) {
551 _cleanup_free_ DHCPPacket
*packet
= NULL
;
555 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
559 return dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
562 static int server_send_forcerenew(sd_dhcp_server
*server
, be32_t address
,
563 be32_t gateway
, uint8_t chaddr
[]) {
564 _cleanup_free_ DHCPPacket
*packet
= NULL
;
565 size_t optoffset
= 0;
569 assert(address
!= INADDR_ANY
);
572 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
576 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
577 DHCP_FORCERENEW
, ARPHRD_ETHER
,
578 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
582 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
583 &optoffset
, 0, SD_DHCP_OPTION_END
, 0, NULL
);
587 memcpy(&packet
->dhcp
.chaddr
, chaddr
, ETH_ALEN
);
589 r
= dhcp_server_send_udp(server
, address
, DHCP_PORT_CLIENT
,
591 sizeof(DHCPMessage
) + optoffset
);
598 static int parse_request(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
599 DHCPRequest
*req
= userdata
;
604 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
606 req
->lifetime
= unaligned_read_be32(option
);
609 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
:
611 memcpy(&req
->requested_ip
, option
, sizeof(be32_t
));
614 case SD_DHCP_OPTION_SERVER_IDENTIFIER
:
616 memcpy(&req
->server_id
, option
, sizeof(be32_t
));
619 case SD_DHCP_OPTION_CLIENT_IDENTIFIER
:
623 data
= memdup(option
, len
);
627 free(req
->client_id
.data
);
628 req
->client_id
.data
= data
;
629 req
->client_id
.length
= len
;
633 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
635 if (len
== 2 && unaligned_read_be16(option
) >= sizeof(DHCPPacket
))
636 req
->max_optlen
= unaligned_read_be16(option
) - sizeof(DHCPPacket
);
644 static void dhcp_request_free(DHCPRequest
*req
) {
648 free(req
->client_id
.data
);
652 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
653 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
655 static int ensure_sane_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPMessage
*message
) {
659 req
->message
= message
;
661 /* set client id based on MAC address if client did not send an explicit
663 if (!req
->client_id
.data
) {
666 data
= malloc0(ETH_ALEN
+ 1);
670 ((uint8_t*) data
)[0] = 0x01;
671 memcpy((uint8_t*) data
+ 1, &message
->chaddr
, ETH_ALEN
);
673 req
->client_id
.length
= ETH_ALEN
+ 1;
674 req
->client_id
.data
= data
;
677 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
678 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
680 if (req
->lifetime
<= 0)
681 req
->lifetime
= MAX(1ULL, server
->default_lease_time
);
683 if (server
->max_lease_time
> 0 && req
->lifetime
> server
->max_lease_time
)
684 req
->lifetime
= server
->max_lease_time
;
689 static int get_pool_offset(sd_dhcp_server
*server
, be32_t requested_ip
) {
692 if (!server
->pool_size
)
695 if (be32toh(requested_ip
) < (be32toh(server
->subnet
) | server
->pool_offset
) ||
696 be32toh(requested_ip
) >= (be32toh(server
->subnet
) | (server
->pool_offset
+ server
->pool_size
)))
699 return be32toh(requested_ip
& ~server
->netmask
) - server
->pool_offset
;
702 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
704 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
,
706 _cleanup_dhcp_request_free_ DHCPRequest
*req
= NULL
;
707 _cleanup_free_
char *error_message
= NULL
;
708 DHCPLease
*existing_lease
;
714 if (message
->op
!= BOOTREQUEST
||
715 message
->htype
!= ARPHRD_ETHER
||
716 message
->hlen
!= ETHER_ADDR_LEN
)
719 req
= new0(DHCPRequest
, 1);
723 type
= dhcp_option_parse(message
, length
, parse_request
, req
, &error_message
);
727 r
= ensure_sane_request(server
, req
, message
);
729 /* this only fails on critical errors */
732 existing_lease
= hashmap_get(server
->leases_by_client_id
,
737 case DHCP_DISCOVER
: {
738 be32_t address
= INADDR_ANY
;
741 log_dhcp_server(server
, "DISCOVER (0x%x)",
742 be32toh(req
->message
->xid
));
744 if (!server
->pool_size
)
745 /* no pool allocated */
748 /* for now pick a random free address from the pool */
750 address
= existing_lease
->address
;
752 struct siphash state
;
756 /* even with no persistence of leases, we try to offer the same client
757 the same IP address. we do this by using the hash of the client id
758 as the offset into the pool of leases when finding the next free one */
760 siphash24_init(&state
, HASH_KEY
.bytes
);
761 client_id_hash_func(&req
->client_id
, &state
);
762 hash
= htole64(siphash24_finalize(&state
));
763 next_offer
= hash
% server
->pool_size
;
765 for (i
= 0; i
< server
->pool_size
; i
++) {
766 if (!server
->bound_leases
[next_offer
]) {
767 address
= server
->subnet
| htobe32(server
->pool_offset
+ next_offer
);
770 next_offer
= (next_offer
+ 1) % server
->pool_size
;
774 if (address
== INADDR_ANY
)
775 /* no free addresses left */
778 r
= server_send_offer(server
, req
, address
);
780 /* this only fails on critical errors */
781 log_dhcp_server(server
, "could not send offer: %s",
785 log_dhcp_server(server
, "OFFER (0x%x)",
786 be32toh(req
->message
->xid
));
793 log_dhcp_server(server
, "DECLINE (0x%x): %s", be32toh(req
->message
->xid
), strna(error_message
));
795 /* TODO: make sure we don't offer this address again */
801 bool init_reboot
= false;
804 /* see RFC 2131, section 4.3.2 */
806 if (req
->server_id
) {
807 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
808 be32toh(req
->message
->xid
));
811 if (req
->server_id
!= server
->address
)
812 /* client did not pick us */
815 if (req
->message
->ciaddr
)
816 /* this MUST be zero */
819 if (!req
->requested_ip
)
820 /* this must be filled in with the yiaddr
821 from the chosen OFFER */
824 address
= req
->requested_ip
;
825 } else if (req
->requested_ip
) {
826 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
827 be32toh(req
->message
->xid
));
830 if (req
->message
->ciaddr
)
831 /* this MUST be zero */
834 /* TODO: check more carefully if IP is correct */
835 address
= req
->requested_ip
;
838 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
839 be32toh(req
->message
->xid
));
841 /* REBINDING / RENEWING */
842 if (!req
->message
->ciaddr
)
843 /* this MUST be filled in with clients IP address */
846 address
= req
->message
->ciaddr
;
849 pool_offset
= get_pool_offset(server
, address
);
851 /* verify that the requested address is from the pool, and either
852 owned by the current client or free */
853 if (pool_offset
>= 0 &&
854 server
->bound_leases
[pool_offset
] == existing_lease
) {
858 if (!existing_lease
) {
859 lease
= new0(DHCPLease
, 1);
860 lease
->address
= req
->requested_ip
;
861 lease
->client_id
.data
= memdup(req
->client_id
.data
,
862 req
->client_id
.length
);
863 if (!lease
->client_id
.data
) {
867 lease
->client_id
.length
= req
->client_id
.length
;
868 memcpy(&lease
->chaddr
, &req
->message
->chaddr
,
870 lease
->gateway
= req
->message
->giaddr
;
872 lease
= existing_lease
;
874 r
= sd_event_now(server
->event
,
875 clock_boottime_or_monotonic(),
879 dhcp_lease_free(lease
);
883 lease
->expiration
= req
->lifetime
* USEC_PER_SEC
+ time_now
;
885 r
= server_send_ack(server
, req
, address
);
887 /* this only fails on critical errors */
888 log_dhcp_server(server
, "could not send ack: %s",
892 dhcp_lease_free(lease
);
896 log_dhcp_server(server
, "ACK (0x%x)",
897 be32toh(req
->message
->xid
));
899 server
->bound_leases
[pool_offset
] = lease
;
900 hashmap_put(server
->leases_by_client_id
,
901 &lease
->client_id
, lease
);
905 } else if (init_reboot
) {
906 r
= server_send_nak(server
, req
);
908 /* this only fails on critical errors */
909 log_dhcp_server(server
, "could not send nak: %s",
913 log_dhcp_server(server
, "NAK (0x%x)",
914 be32toh(req
->message
->xid
));
925 log_dhcp_server(server
, "RELEASE (0x%x)",
926 be32toh(req
->message
->xid
));
931 if (existing_lease
->address
!= req
->message
->ciaddr
)
934 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
938 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
939 server
->bound_leases
[pool_offset
] = NULL
;
940 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
941 dhcp_lease_free(existing_lease
);
952 static int server_receive_message(sd_event_source
*s
, int fd
,
953 uint32_t revents
, void *userdata
) {
954 _cleanup_free_ DHCPMessage
*message
= NULL
;
955 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))];
956 sd_dhcp_server
*server
= userdata
;
957 struct iovec iov
= {};
958 struct msghdr msg
= {
961 .msg_control
= cmsgbuf
,
962 .msg_controllen
= sizeof(cmsgbuf
),
964 struct cmsghdr
*cmsg
;
969 buflen
= next_datagram_size_fd(fd
);
973 message
= malloc(buflen
);
977 iov
.iov_base
= message
;
978 iov
.iov_len
= buflen
;
980 len
= recvmsg(fd
, &msg
, 0);
982 if (errno
== EAGAIN
|| errno
== EINTR
)
986 } else if ((size_t)len
< sizeof(DHCPMessage
))
989 CMSG_FOREACH(cmsg
, &msg
) {
990 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
991 cmsg
->cmsg_type
== IP_PKTINFO
&&
992 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
993 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
995 /* TODO figure out if this can be done as a filter on
996 * the socket, like for IPv6 */
997 if (server
->ifindex
!= info
->ipi_ifindex
)
1004 return dhcp_server_handle_message(server
, message
, (size_t)len
);
1007 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
1010 assert_return(server
, -EINVAL
);
1011 assert_return(server
->event
, -EINVAL
);
1012 assert_return(!server
->receive_message
, -EBUSY
);
1013 assert_return(server
->fd_raw
== -1, -EBUSY
);
1014 assert_return(server
->fd
== -1, -EBUSY
);
1015 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
1017 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0);
1020 sd_dhcp_server_stop(server
);
1025 r
= dhcp_network_bind_udp_socket(INADDR_ANY
, DHCP_PORT_SERVER
);
1027 sd_dhcp_server_stop(server
);
1032 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
1033 server
->fd
, EPOLLIN
,
1034 server_receive_message
, server
);
1036 sd_dhcp_server_stop(server
);
1040 r
= sd_event_source_set_priority(server
->receive_message
,
1041 server
->event_priority
);
1043 sd_dhcp_server_stop(server
);
1047 log_dhcp_server(server
, "STARTED");
1052 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1056 assert_return(server
, -EINVAL
);
1057 assert(server
->bound_leases
);
1059 for (i
= 0; i
< server
->pool_size
; i
++) {
1060 DHCPLease
*lease
= server
->bound_leases
[i
];
1062 if (!lease
|| lease
== &server
->invalid_lease
)
1065 r
= server_send_forcerenew(server
, lease
->address
,
1071 log_dhcp_server(server
, "FORCERENEW");
1077 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *tz
) {
1080 assert_return(server
, -EINVAL
);
1081 assert_return(timezone_is_valid(tz
), -EINVAL
);
1083 if (streq_ptr(tz
, server
->timezone
))
1086 r
= free_and_strdup(&server
->timezone
, tz
);
1093 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1094 assert_return(server
, -EINVAL
);
1096 if (t
== server
->max_lease_time
)
1099 server
->max_lease_time
= t
;
1103 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1104 assert_return(server
, -EINVAL
);
1106 if (t
== server
->default_lease_time
)
1109 server
->default_lease_time
= t
;
1113 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], unsigned n
) {
1114 assert_return(server
, -EINVAL
);
1115 assert_return(dns
|| n
<= 0, -EINVAL
);
1117 if (server
->n_dns
== n
&&
1118 memcmp(server
->dns
, dns
, sizeof(struct in_addr
) * n
) == 0)
1122 server
->dns
= mfree(server
->dns
);
1127 c
= newdup(struct in_addr
, dns
, n
);
1139 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], unsigned n
) {
1140 assert_return(server
, -EINVAL
);
1141 assert_return(ntp
|| n
<= 0, -EINVAL
);
1143 if (server
->n_ntp
== n
&&
1144 memcmp(server
->ntp
, ntp
, sizeof(struct in_addr
) * n
) == 0)
1148 server
->ntp
= mfree(server
->ntp
);
1153 c
= newdup(struct in_addr
, ntp
, n
);
1165 int sd_dhcp_server_set_emit_router(sd_dhcp_server
*server
, int enabled
) {
1166 assert_return(server
, -EINVAL
);
1168 if (enabled
== server
->emit_router
)
1171 server
->emit_router
= enabled
;