1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2013 Intel Corporation. All rights reserved.
7 Copyright (C) 2014 Tom Gundersen
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/ioctl.h>
25 #include "sd-dhcp-server.h"
27 #include "alloc-util.h"
28 #include "dhcp-internal.h"
29 #include "dhcp-server-internal.h"
31 #include "in-addr-util.h"
32 #include "siphash24.h"
33 #include "string-util.h"
35 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
36 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
38 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
39 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
40 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
41 * accidentally hand it out */
42 int sd_dhcp_server_configure_pool(sd_dhcp_server
*server
, struct in_addr
*address
, unsigned char prefixlen
, uint32_t offset
, uint32_t size
) {
43 struct in_addr netmask_addr
;
45 uint32_t server_off
, broadcast_off
, size_max
;
47 assert_return(server
, -EINVAL
);
48 assert_return(address
, -EINVAL
);
49 assert_return(address
->s_addr
!= INADDR_ANY
, -EINVAL
);
50 assert_return(prefixlen
<= 32, -ERANGE
);
51 assert_return(server
->address
== INADDR_ANY
, -EBUSY
);
53 assert_se(in_addr_prefixlen_to_netmask(&netmask_addr
, prefixlen
));
54 netmask
= netmask_addr
.s_addr
;
56 server_off
= be32toh(address
->s_addr
& ~netmask
);
57 broadcast_off
= be32toh(~netmask
);
59 /* the server address cannot be the subnet address */
60 assert_return(server_off
!= 0, -ERANGE
);
62 /* nor the broadcast address */
63 assert_return(server_off
!= broadcast_off
, -ERANGE
);
65 /* 0 offset means we should set a default, we skip the first (subnet) address
66 and take the next one */
70 size_max
= (broadcast_off
+ 1) /* the number of addresses in the subnet */
71 - offset
/* exclude the addresses before the offset */
72 - 1; /* exclude the last (broadcast) address */
74 /* The pool must contain at least one address */
75 assert_return(size_max
>= 1, -ERANGE
);
78 assert_return(size
<= size_max
, -ERANGE
);
82 server
->bound_leases
= new0(DHCPLease
*, size
);
83 if (!server
->bound_leases
)
86 server
->pool_offset
= offset
;
87 server
->pool_size
= size
;
89 server
->address
= address
->s_addr
;
90 server
->netmask
= netmask
;
91 server
->subnet
= address
->s_addr
& netmask
;
93 if (server_off
>= offset
&& server_off
- offset
< size
)
94 server
->bound_leases
[server_off
- offset
] = &server
->invalid_lease
;
99 int sd_dhcp_server_is_running(sd_dhcp_server
*server
) {
100 assert_return(server
, false);
102 return !!server
->receive_message
;
105 sd_dhcp_server
*sd_dhcp_server_ref(sd_dhcp_server
*server
) {
110 assert(server
->n_ref
>= 1);
116 void client_id_hash_func(const void *p
, struct siphash
*state
) {
117 const DHCPClientId
*id
= p
;
123 siphash24_compress(&id
->length
, sizeof(id
->length
), state
);
124 siphash24_compress(id
->data
, id
->length
, state
);
127 int client_id_compare_func(const void *_a
, const void *_b
) {
128 const DHCPClientId
*a
, *b
;
133 assert(!a
->length
|| a
->data
);
134 assert(!b
->length
|| b
->data
);
136 if (a
->length
!= b
->length
)
137 return a
->length
< b
->length
? -1 : 1;
139 return memcmp(a
->data
, b
->data
, a
->length
);
142 static const struct hash_ops client_id_hash_ops
= {
143 .hash
= client_id_hash_func
,
144 .compare
= client_id_compare_func
147 static void dhcp_lease_free(DHCPLease
*lease
) {
151 free(lease
->client_id
.data
);
155 sd_dhcp_server
*sd_dhcp_server_unref(sd_dhcp_server
*server
) {
161 assert(server
->n_ref
>= 1);
164 if (server
->n_ref
> 0)
167 log_dhcp_server(server
, "UNREF");
169 sd_dhcp_server_stop(server
);
171 sd_event_unref(server
->event
);
173 free(server
->timezone
);
177 while ((lease
= hashmap_steal_first(server
->leases_by_client_id
)))
178 dhcp_lease_free(lease
);
179 hashmap_free(server
->leases_by_client_id
);
181 free(server
->bound_leases
);
187 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
188 _cleanup_(sd_dhcp_server_unrefp
) sd_dhcp_server
*server
= NULL
;
190 assert_return(ret
, -EINVAL
);
191 assert_return(ifindex
> 0, -EINVAL
);
193 server
= new0(sd_dhcp_server
, 1);
200 server
->address
= htobe32(INADDR_ANY
);
201 server
->netmask
= htobe32(INADDR_ANY
);
202 server
->ifindex
= ifindex
;
203 server
->leases_by_client_id
= hashmap_new(&client_id_hash_ops
);
204 server
->default_lease_time
= DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC
, USEC_PER_SEC
);
205 server
->max_lease_time
= DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC
, USEC_PER_SEC
);
213 int sd_dhcp_server_attach_event(sd_dhcp_server
*server
, sd_event
*event
,
217 assert_return(server
, -EINVAL
);
218 assert_return(!server
->event
, -EBUSY
);
221 server
->event
= sd_event_ref(event
);
223 r
= sd_event_default(&server
->event
);
228 server
->event_priority
= priority
;
233 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
234 assert_return(server
, -EINVAL
);
236 server
->event
= sd_event_unref(server
->event
);
241 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
242 assert_return(server
, NULL
);
244 return server
->event
;
247 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
248 assert_return(server
, -EINVAL
);
250 server
->receive_message
=
251 sd_event_source_unref(server
->receive_message
);
253 server
->fd_raw
= safe_close(server
->fd_raw
);
254 server
->fd
= safe_close(server
->fd
);
256 log_dhcp_server(server
, "STOPPED");
261 static int dhcp_server_send_unicast_raw(sd_dhcp_server
*server
,
262 DHCPPacket
*packet
, size_t len
) {
263 union sockaddr_union link
= {
264 .ll
.sll_family
= AF_PACKET
,
265 .ll
.sll_protocol
= htons(ETH_P_IP
),
266 .ll
.sll_ifindex
= server
->ifindex
,
267 .ll
.sll_halen
= ETH_ALEN
,
271 assert(server
->ifindex
> 0);
272 assert(server
->address
);
274 assert(len
> sizeof(DHCPPacket
));
276 memcpy(&link
.ll
.sll_addr
, &packet
->dhcp
.chaddr
, ETH_ALEN
);
278 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
280 DHCP_PORT_CLIENT
, len
);
282 return dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
285 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
286 DHCPMessage
*message
, size_t len
) {
287 union sockaddr_union dest
= {
288 .in
.sin_family
= AF_INET
,
289 .in
.sin_port
= htobe16(DHCP_PORT_CLIENT
),
290 .in
.sin_addr
.s_addr
= destination
,
296 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))] = {};
297 struct msghdr msg
= {
299 .msg_namelen
= sizeof(dest
.in
),
302 .msg_control
= cmsgbuf
,
303 .msg_controllen
= sizeof(cmsgbuf
),
305 struct cmsghdr
*cmsg
;
306 struct in_pktinfo
*pktinfo
;
310 assert(server
->fd
> 0);
312 assert(len
> sizeof(DHCPMessage
));
314 cmsg
= CMSG_FIRSTHDR(&msg
);
317 cmsg
->cmsg_level
= IPPROTO_IP
;
318 cmsg
->cmsg_type
= IP_PKTINFO
;
319 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
321 /* we attach source interface and address info to the message
322 rather than binding the socket. This will be mostly useful
323 when we gain support for arbitrary number of server addresses
325 pktinfo
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
328 pktinfo
->ipi_ifindex
= server
->ifindex
;
329 pktinfo
->ipi_spec_dst
.s_addr
= server
->address
;
331 r
= sendmsg(server
->fd
, &msg
, 0);
338 static bool requested_broadcast(DHCPRequest
*req
) {
341 return req
->message
->flags
& htobe16(0x8000);
344 int dhcp_server_send_packet(sd_dhcp_server
*server
,
345 DHCPRequest
*req
, DHCPPacket
*packet
,
346 int type
, size_t optoffset
) {
347 be32_t destination
= INADDR_ANY
;
352 assert(req
->max_optlen
);
353 assert(optoffset
<= req
->max_optlen
);
356 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
357 SD_DHCP_OPTION_SERVER_IDENTIFIER
,
358 4, &server
->address
);
362 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
363 SD_DHCP_OPTION_END
, 0, NULL
);
367 /* RFC 2131 Section 4.1
369 If the ’giaddr’ field in a DHCP message from a client is non-zero,
370 the server sends any return messages to the ’DHCP server’ port on the
371 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
372 field is zero and the ’ciaddr’ field is nonzero, then the server
373 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
374 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
375 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
376 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
377 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
378 messages to the client’s hardware address and ’yiaddr’ address. In
379 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
380 messages to 0xffffffff.
384 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
385 different subnet. The server MUST set the broadcast bit in the
386 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
387 client, because the client may not have a correct network address
388 or subnet mask, and the client may not be answering ARP requests.
390 if (req
->message
->giaddr
) {
391 destination
= req
->message
->giaddr
;
392 if (type
== DHCP_NAK
)
393 packet
->dhcp
.flags
= htobe16(0x8000);
394 } else if (req
->message
->ciaddr
&& type
!= DHCP_NAK
)
395 destination
= req
->message
->ciaddr
;
397 if (destination
!= INADDR_ANY
)
398 return dhcp_server_send_udp(server
, destination
, &packet
->dhcp
,
399 sizeof(DHCPMessage
) + optoffset
);
400 else if (requested_broadcast(req
) || type
== DHCP_NAK
)
401 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
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 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
471 SD_DHCP_OPTION_ROUTER
, 4, &server
->address
);
475 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_OFFER
, offset
);
482 static int server_send_ack(sd_dhcp_server
*server
, DHCPRequest
*req
,
484 _cleanup_free_ DHCPPacket
*packet
= NULL
;
489 r
= server_message_init(server
, &packet
, DHCP_ACK
, &offset
, req
);
493 packet
->dhcp
.yiaddr
= address
;
495 lease_time
= htobe32(req
->lifetime
);
496 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
497 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
502 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
503 SD_DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
507 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
508 SD_DHCP_OPTION_ROUTER
, 4, &server
->address
);
512 if (server
->n_dns
> 0) {
513 r
= dhcp_option_append(
514 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
515 SD_DHCP_OPTION_DOMAIN_NAME_SERVER
,
516 sizeof(struct in_addr
) * server
->n_dns
, server
->dns
);
521 if (server
->n_ntp
> 0) {
522 r
= dhcp_option_append(
523 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
524 SD_DHCP_OPTION_NTP_SERVER
,
525 sizeof(struct in_addr
) * server
->n_ntp
, server
->ntp
);
530 if (server
->timezone
) {
531 r
= dhcp_option_append(
532 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
533 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
,
534 strlen(server
->timezone
), server
->timezone
);
539 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_ACK
, offset
);
546 static int server_send_nak(sd_dhcp_server
*server
, DHCPRequest
*req
) {
547 _cleanup_free_ DHCPPacket
*packet
= NULL
;
551 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
555 return dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
558 static int server_send_forcerenew(sd_dhcp_server
*server
, be32_t address
,
559 be32_t gateway
, uint8_t chaddr
[]) {
560 _cleanup_free_ DHCPPacket
*packet
= NULL
;
561 size_t optoffset
= 0;
565 assert(address
!= INADDR_ANY
);
568 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
572 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
573 DHCP_FORCERENEW
, ARPHRD_ETHER
,
574 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
578 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
579 &optoffset
, 0, SD_DHCP_OPTION_END
, 0, NULL
);
583 memcpy(&packet
->dhcp
.chaddr
, chaddr
, ETH_ALEN
);
585 r
= dhcp_server_send_udp(server
, address
, &packet
->dhcp
,
586 sizeof(DHCPMessage
) + optoffset
);
593 static int parse_request(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
594 DHCPRequest
*req
= userdata
;
599 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
601 req
->lifetime
= be32toh(*(be32_t
*)option
);
604 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
:
606 req
->requested_ip
= *(be32_t
*)option
;
609 case SD_DHCP_OPTION_SERVER_IDENTIFIER
:
611 req
->server_id
= *(be32_t
*)option
;
614 case SD_DHCP_OPTION_CLIENT_IDENTIFIER
:
618 data
= memdup(option
, len
);
622 free(req
->client_id
.data
);
623 req
->client_id
.data
= data
;
624 req
->client_id
.length
= len
;
628 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
630 req
->max_optlen
= be16toh(*(be16_t
*)option
) -
631 - sizeof(DHCPPacket
);
639 static void dhcp_request_free(DHCPRequest
*req
) {
643 free(req
->client_id
.data
);
647 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
648 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
650 static int ensure_sane_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPMessage
*message
) {
654 req
->message
= message
;
656 /* set client id based on MAC address if client did not send an explicit
658 if (!req
->client_id
.data
) {
661 data
= malloc0(ETH_ALEN
+ 1);
665 ((uint8_t*) data
)[0] = 0x01;
666 memcpy((uint8_t*) data
+ 1, &message
->chaddr
, ETH_ALEN
);
668 req
->client_id
.length
= ETH_ALEN
+ 1;
669 req
->client_id
.data
= data
;
672 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
673 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
675 if (req
->lifetime
<= 0)
676 req
->lifetime
= MAX(1ULL, server
->default_lease_time
);
678 if (server
->max_lease_time
> 0 && req
->lifetime
> server
->max_lease_time
)
679 req
->lifetime
= server
->max_lease_time
;
684 static int get_pool_offset(sd_dhcp_server
*server
, be32_t requested_ip
) {
687 if (!server
->pool_size
)
690 if (be32toh(requested_ip
) < (be32toh(server
->subnet
) | server
->pool_offset
) ||
691 be32toh(requested_ip
) >= (be32toh(server
->subnet
) | (server
->pool_offset
+ server
->pool_size
)))
694 return be32toh(requested_ip
& ~server
->netmask
) - server
->pool_offset
;
697 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
699 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
,
701 _cleanup_dhcp_request_free_ DHCPRequest
*req
= NULL
;
702 _cleanup_free_
char *error_message
= NULL
;
703 DHCPLease
*existing_lease
;
709 if (message
->op
!= BOOTREQUEST
||
710 message
->htype
!= ARPHRD_ETHER
||
711 message
->hlen
!= ETHER_ADDR_LEN
)
714 req
= new0(DHCPRequest
, 1);
718 type
= dhcp_option_parse(message
, length
, parse_request
, req
, &error_message
);
722 r
= ensure_sane_request(server
, req
, message
);
724 /* this only fails on critical errors */
727 existing_lease
= hashmap_get(server
->leases_by_client_id
,
732 case DHCP_DISCOVER
: {
733 be32_t address
= INADDR_ANY
;
736 log_dhcp_server(server
, "DISCOVER (0x%x)",
737 be32toh(req
->message
->xid
));
739 if (!server
->pool_size
)
740 /* no pool allocated */
743 /* for now pick a random free address from the pool */
745 address
= existing_lease
->address
;
747 struct siphash state
;
751 /* even with no persistence of leases, we try to offer the same client
752 the same IP address. we do this by using the hash of the client id
753 as the offset into the pool of leases when finding the next free one */
755 siphash24_init(&state
, HASH_KEY
.bytes
);
756 client_id_hash_func(&req
->client_id
, &state
);
757 hash
= htole64(siphash24_finalize(&state
));
758 next_offer
= hash
% server
->pool_size
;
760 for (i
= 0; i
< server
->pool_size
; i
++) {
761 if (!server
->bound_leases
[next_offer
]) {
762 address
= server
->subnet
| htobe32(server
->pool_offset
+ next_offer
);
765 next_offer
= (next_offer
+ 1) % server
->pool_size
;
769 if (address
== INADDR_ANY
)
770 /* no free addresses left */
773 r
= server_send_offer(server
, req
, address
);
775 /* this only fails on critical errors */
776 log_dhcp_server(server
, "could not send offer: %s",
780 log_dhcp_server(server
, "OFFER (0x%x)",
781 be32toh(req
->message
->xid
));
788 log_dhcp_server(server
, "DECLINE (0x%x): %s", be32toh(req
->message
->xid
), strna(error_message
));
790 /* TODO: make sure we don't offer this address again */
796 bool init_reboot
= false;
799 /* see RFC 2131, section 4.3.2 */
801 if (req
->server_id
) {
802 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
803 be32toh(req
->message
->xid
));
806 if (req
->server_id
!= server
->address
)
807 /* client did not pick us */
810 if (req
->message
->ciaddr
)
811 /* this MUST be zero */
814 if (!req
->requested_ip
)
815 /* this must be filled in with the yiaddr
816 from the chosen OFFER */
819 address
= req
->requested_ip
;
820 } else if (req
->requested_ip
) {
821 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
822 be32toh(req
->message
->xid
));
825 if (req
->message
->ciaddr
)
826 /* this MUST be zero */
829 /* TODO: check more carefully if IP is correct */
830 address
= req
->requested_ip
;
833 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
834 be32toh(req
->message
->xid
));
836 /* REBINDING / RENEWING */
837 if (!req
->message
->ciaddr
)
838 /* this MUST be filled in with clients IP address */
841 address
= req
->message
->ciaddr
;
844 pool_offset
= get_pool_offset(server
, address
);
846 /* verify that the requested address is from the pool, and either
847 owned by the current client or free */
848 if (pool_offset
>= 0 &&
849 server
->bound_leases
[pool_offset
] == existing_lease
) {
853 if (!existing_lease
) {
854 lease
= new0(DHCPLease
, 1);
855 lease
->address
= req
->requested_ip
;
856 lease
->client_id
.data
= memdup(req
->client_id
.data
,
857 req
->client_id
.length
);
858 if (!lease
->client_id
.data
) {
862 lease
->client_id
.length
= req
->client_id
.length
;
863 memcpy(&lease
->chaddr
, &req
->message
->chaddr
,
865 lease
->gateway
= req
->message
->giaddr
;
867 lease
= existing_lease
;
869 r
= sd_event_now(server
->event
,
870 clock_boottime_or_monotonic(),
874 dhcp_lease_free(lease
);
878 lease
->expiration
= req
->lifetime
* USEC_PER_SEC
+ time_now
;
880 r
= server_send_ack(server
, req
, address
);
882 /* this only fails on critical errors */
883 log_dhcp_server(server
, "could not send ack: %s",
887 dhcp_lease_free(lease
);
891 log_dhcp_server(server
, "ACK (0x%x)",
892 be32toh(req
->message
->xid
));
894 server
->bound_leases
[pool_offset
] = lease
;
895 hashmap_put(server
->leases_by_client_id
,
896 &lease
->client_id
, lease
);
900 } else if (init_reboot
) {
901 r
= server_send_nak(server
, req
);
903 /* this only fails on critical errors */
904 log_dhcp_server(server
, "could not send nak: %s",
908 log_dhcp_server(server
, "NAK (0x%x)",
909 be32toh(req
->message
->xid
));
920 log_dhcp_server(server
, "RELEASE (0x%x)",
921 be32toh(req
->message
->xid
));
926 if (existing_lease
->address
!= req
->message
->ciaddr
)
929 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
933 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
934 server
->bound_leases
[pool_offset
] = NULL
;
935 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
936 dhcp_lease_free(existing_lease
);
947 static int server_receive_message(sd_event_source
*s
, int fd
,
948 uint32_t revents
, void *userdata
) {
949 _cleanup_free_ DHCPMessage
*message
= NULL
;
950 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))];
951 sd_dhcp_server
*server
= userdata
;
952 struct iovec iov
= {};
953 struct msghdr msg
= {
956 .msg_control
= cmsgbuf
,
957 .msg_controllen
= sizeof(cmsgbuf
),
959 struct cmsghdr
*cmsg
;
964 if (ioctl(fd
, FIONREAD
, &buflen
) < 0)
969 message
= malloc(buflen
);
973 iov
.iov_base
= message
;
974 iov
.iov_len
= buflen
;
976 len
= recvmsg(fd
, &msg
, 0);
978 if (errno
== EAGAIN
|| errno
== EINTR
)
982 } else if ((size_t)len
< sizeof(DHCPMessage
))
985 CMSG_FOREACH(cmsg
, &msg
) {
986 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
987 cmsg
->cmsg_type
== IP_PKTINFO
&&
988 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
989 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
991 /* TODO figure out if this can be done as a filter on
992 * the socket, like for IPv6 */
993 if (server
->ifindex
!= info
->ipi_ifindex
)
1000 return dhcp_server_handle_message(server
, message
, (size_t)len
);
1003 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
1006 assert_return(server
, -EINVAL
);
1007 assert_return(server
->event
, -EINVAL
);
1008 assert_return(!server
->receive_message
, -EBUSY
);
1009 assert_return(server
->fd_raw
== -1, -EBUSY
);
1010 assert_return(server
->fd
== -1, -EBUSY
);
1011 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
1013 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0);
1016 sd_dhcp_server_stop(server
);
1021 r
= dhcp_network_bind_udp_socket(INADDR_ANY
, DHCP_PORT_SERVER
);
1023 sd_dhcp_server_stop(server
);
1028 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
1029 server
->fd
, EPOLLIN
,
1030 server_receive_message
, server
);
1032 sd_dhcp_server_stop(server
);
1036 r
= sd_event_source_set_priority(server
->receive_message
,
1037 server
->event_priority
);
1039 sd_dhcp_server_stop(server
);
1043 log_dhcp_server(server
, "STARTED");
1048 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1052 assert_return(server
, -EINVAL
);
1053 assert(server
->bound_leases
);
1055 for (i
= 0; i
< server
->pool_size
; i
++) {
1056 DHCPLease
*lease
= server
->bound_leases
[i
];
1058 if (!lease
|| lease
== &server
->invalid_lease
)
1061 r
= server_send_forcerenew(server
, lease
->address
,
1067 log_dhcp_server(server
, "FORCERENEW");
1073 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *tz
) {
1076 assert_return(server
, -EINVAL
);
1077 assert_return(timezone_is_valid(tz
), -EINVAL
);
1079 if (streq_ptr(tz
, server
->timezone
))
1082 r
= free_and_strdup(&server
->timezone
, tz
);
1089 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1090 assert_return(server
, -EINVAL
);
1092 if (t
== server
->max_lease_time
)
1095 server
->max_lease_time
= t
;
1099 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1100 assert_return(server
, -EINVAL
);
1102 if (t
== server
->default_lease_time
)
1105 server
->default_lease_time
= t
;
1109 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], unsigned n
) {
1110 assert_return(server
, -EINVAL
);
1111 assert_return(dns
|| n
<= 0, -EINVAL
);
1113 if (server
->n_dns
== n
&&
1114 memcmp(server
->dns
, dns
, sizeof(struct in_addr
) * n
) == 0)
1118 server
->dns
= mfree(server
->dns
);
1123 c
= newdup(struct in_addr
, dns
, n
);
1135 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], unsigned n
) {
1136 assert_return(server
, -EINVAL
);
1137 assert_return(ntp
|| n
<= 0, -EINVAL
);
1139 if (server
->n_ntp
== n
&&
1140 memcmp(server
->ntp
, ntp
, sizeof(struct in_addr
) * n
) == 0)
1144 server
->ntp
= mfree(server
->ntp
);
1149 c
= newdup(struct in_addr
, ntp
, n
);