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 "in-addr-util.h"
26 #include "siphash24.h"
28 #include "sd-dhcp-server.h"
29 #include "dhcp-server-internal.h"
30 #include "dhcp-internal.h"
32 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
33 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
35 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
36 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
37 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
38 * accidentally hand it out */
39 int sd_dhcp_server_configure_pool(sd_dhcp_server
*server
, struct in_addr
*address
, unsigned char prefixlen
, uint32_t offset
, uint32_t size
) {
40 struct in_addr netmask_addr
;
42 uint32_t server_off
, broadcast_off
, size_max
;
44 assert_return(server
, -EINVAL
);
45 assert_return(address
, -EINVAL
);
46 assert_return(address
->s_addr
!= INADDR_ANY
, -EINVAL
);
47 assert_return(prefixlen
<= 32, -ERANGE
);
48 assert_return(server
->address
== INADDR_ANY
, -EBUSY
);
50 assert_se(in_addr_prefixlen_to_netmask(&netmask_addr
, prefixlen
));
51 netmask
= netmask_addr
.s_addr
;
53 server_off
= be32toh(address
->s_addr
& ~netmask
);
54 broadcast_off
= be32toh(~netmask
);
56 /* the server address cannot be the subnet address */
57 assert_return(server_off
!= 0, -ERANGE
);
59 /* nor the broadcast address */
60 assert_return(server_off
!= broadcast_off
, -ERANGE
);
62 /* 0 offset means we should set a default, we skip the first (subnet) address
63 and take the next one */
67 size_max
= (broadcast_off
+ 1) /* the number of addresses in the subnet */
68 - offset
/* exclude the addresses before the offset */
69 - 1; /* exclude the last (broadcast) address */
71 /* The pool must contain at least one address */
72 assert_return(size_max
>= 1, -ERANGE
);
75 assert_return(size
<= size_max
, -ERANGE
);
79 server
->bound_leases
= new0(DHCPLease
*, size
);
80 if (!server
->bound_leases
)
83 server
->pool_offset
= offset
;
84 server
->pool_size
= size
;
86 server
->address
= address
->s_addr
;
87 server
->netmask
= netmask
;
88 server
->subnet
= address
->s_addr
& netmask
;
90 if (server_off
>= offset
&& server_off
- offset
< size
)
91 server
->bound_leases
[server_off
- offset
] = &server
->invalid_lease
;
96 bool sd_dhcp_server_is_running(sd_dhcp_server
*server
) {
97 assert_return(server
, false);
99 return !!server
->receive_message
;
102 sd_dhcp_server
*sd_dhcp_server_ref(sd_dhcp_server
*server
) {
107 assert(server
->n_ref
>= 1);
113 void client_id_hash_func(const void *p
, struct siphash
*state
) {
114 const DHCPClientId
*id
= p
;
120 siphash24_compress(&id
->length
, sizeof(id
->length
), state
);
121 siphash24_compress(id
->data
, id
->length
, state
);
124 int client_id_compare_func(const void *_a
, const void *_b
) {
125 const DHCPClientId
*a
, *b
;
130 assert(!a
->length
|| a
->data
);
131 assert(!b
->length
|| b
->data
);
133 if (a
->length
!= b
->length
)
134 return a
->length
< b
->length
? -1 : 1;
136 return memcmp(a
->data
, b
->data
, a
->length
);
139 static const struct hash_ops client_id_hash_ops
= {
140 .hash
= client_id_hash_func
,
141 .compare
= client_id_compare_func
144 static void dhcp_lease_free(DHCPLease
*lease
) {
148 free(lease
->client_id
.data
);
152 sd_dhcp_server
*sd_dhcp_server_unref(sd_dhcp_server
*server
) {
158 assert(server
->n_ref
>= 1);
161 if (server
->n_ref
> 0)
164 log_dhcp_server(server
, "UNREF");
166 sd_dhcp_server_stop(server
);
168 sd_event_unref(server
->event
);
170 free(server
->timezone
);
174 while ((lease
= hashmap_steal_first(server
->leases_by_client_id
)))
175 dhcp_lease_free(lease
);
176 hashmap_free(server
->leases_by_client_id
);
178 free(server
->bound_leases
);
184 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
185 _cleanup_dhcp_server_unref_ 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
,
214 assert_return(server
, -EINVAL
);
215 assert_return(!server
->event
, -EBUSY
);
218 server
->event
= sd_event_ref(event
);
220 r
= sd_event_default(&server
->event
);
225 server
->event_priority
= priority
;
230 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
231 assert_return(server
, -EINVAL
);
233 server
->event
= sd_event_unref(server
->event
);
238 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
239 assert_return(server
, NULL
);
241 return server
->event
;
244 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
245 assert_return(server
, -EINVAL
);
247 server
->receive_message
=
248 sd_event_source_unref(server
->receive_message
);
250 server
->fd_raw
= safe_close(server
->fd_raw
);
251 server
->fd
= safe_close(server
->fd
);
253 log_dhcp_server(server
, "STOPPED");
258 static int dhcp_server_send_unicast_raw(sd_dhcp_server
*server
,
259 DHCPPacket
*packet
, size_t len
) {
260 union sockaddr_union link
= {
261 .ll
.sll_family
= AF_PACKET
,
262 .ll
.sll_protocol
= htons(ETH_P_IP
),
263 .ll
.sll_ifindex
= server
->ifindex
,
264 .ll
.sll_halen
= ETH_ALEN
,
268 assert(server
->ifindex
> 0);
269 assert(server
->address
);
271 assert(len
> sizeof(DHCPPacket
));
273 memcpy(&link
.ll
.sll_addr
, &packet
->dhcp
.chaddr
, ETH_ALEN
);
275 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
277 DHCP_PORT_CLIENT
, len
);
279 return dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
282 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
283 DHCPMessage
*message
, size_t len
) {
284 union sockaddr_union dest
= {
285 .in
.sin_family
= AF_INET
,
286 .in
.sin_port
= htobe16(DHCP_PORT_CLIENT
),
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
;
349 assert(req
->max_optlen
);
350 assert(optoffset
<= req
->max_optlen
);
353 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
354 DHCP_OPTION_SERVER_IDENTIFIER
,
355 4, &server
->address
);
359 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
360 DHCP_OPTION_END
, 0, NULL
);
364 /* RFC 2131 Section 4.1
366 If the ’giaddr’ field in a DHCP message from a client is non-zero,
367 the server sends any return messages to the ’DHCP server’ port on the
368 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
369 field is zero and the ’ciaddr’ field is nonzero, then the server
370 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
371 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
372 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
373 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
374 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
375 messages to the client’s hardware address and ’yiaddr’ address. In
376 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
377 messages to 0xffffffff.
381 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
382 different subnet. The server MUST set the broadcast bit in the
383 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
384 client, because the client may not have a correct network address
385 or subnet mask, and the client may not be answering ARP requests.
387 if (req
->message
->giaddr
) {
388 destination
= req
->message
->giaddr
;
389 if (type
== DHCP_NAK
)
390 packet
->dhcp
.flags
= htobe16(0x8000);
391 } else if (req
->message
->ciaddr
&& type
!= DHCP_NAK
)
392 destination
= req
->message
->ciaddr
;
394 if (destination
!= INADDR_ANY
)
395 return dhcp_server_send_udp(server
, destination
, &packet
->dhcp
,
396 sizeof(DHCPMessage
) + optoffset
);
397 else if (requested_broadcast(req
) || type
== DHCP_NAK
)
398 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
400 sizeof(DHCPMessage
) + optoffset
);
402 /* we cannot send UDP packet to specific MAC address when the
403 address is not yet configured, so must fall back to raw
405 return dhcp_server_send_unicast_raw(server
, packet
,
406 sizeof(DHCPPacket
) + optoffset
);
409 static int server_message_init(sd_dhcp_server
*server
, DHCPPacket
**ret
,
410 uint8_t type
, size_t *_optoffset
,
412 _cleanup_free_ DHCPPacket
*packet
= NULL
;
413 size_t optoffset
= 0;
419 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
, DHCP_NAK
));
421 packet
= malloc0(sizeof(DHCPPacket
) + req
->max_optlen
);
425 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
,
426 be32toh(req
->message
->xid
), type
, ARPHRD_ETHER
,
427 req
->max_optlen
, &optoffset
);
431 packet
->dhcp
.flags
= req
->message
->flags
;
432 packet
->dhcp
.giaddr
= req
->message
->giaddr
;
433 memcpy(&packet
->dhcp
.chaddr
, &req
->message
->chaddr
, ETH_ALEN
);
435 *_optoffset
= optoffset
;
442 static int server_send_offer(sd_dhcp_server
*server
, DHCPRequest
*req
,
444 _cleanup_free_ DHCPPacket
*packet
= NULL
;
449 r
= server_message_init(server
, &packet
, DHCP_OFFER
, &offset
, req
);
453 packet
->dhcp
.yiaddr
= address
;
455 lease_time
= htobe32(req
->lifetime
);
456 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
457 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
462 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
463 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
467 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
468 DHCP_OPTION_ROUTER
, 4, &server
->address
);
472 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_OFFER
, offset
);
479 static int server_send_ack(sd_dhcp_server
*server
, DHCPRequest
*req
,
481 _cleanup_free_ DHCPPacket
*packet
= NULL
;
486 r
= server_message_init(server
, &packet
, DHCP_ACK
, &offset
, req
);
490 packet
->dhcp
.yiaddr
= address
;
492 lease_time
= htobe32(req
->lifetime
);
493 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
494 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
499 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
500 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
504 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
505 DHCP_OPTION_ROUTER
, 4, &server
->address
);
509 if (server
->n_dns
> 0) {
510 r
= dhcp_option_append(
511 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
512 DHCP_OPTION_DOMAIN_NAME_SERVER
,
513 sizeof(struct in_addr
) * server
->n_dns
, server
->dns
);
518 if (server
->n_ntp
> 0) {
519 r
= dhcp_option_append(
520 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
521 DHCP_OPTION_NTP_SERVER
,
522 sizeof(struct in_addr
) * server
->n_ntp
, server
->ntp
);
527 if (server
->timezone
) {
528 r
= dhcp_option_append(
529 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
530 DHCP_OPTION_NEW_TZDB_TIMEZONE
,
531 strlen(server
->timezone
), server
->timezone
);
536 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_ACK
, offset
);
543 static int server_send_nak(sd_dhcp_server
*server
, DHCPRequest
*req
) {
544 _cleanup_free_ DHCPPacket
*packet
= NULL
;
548 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
552 return dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
555 static int server_send_forcerenew(sd_dhcp_server
*server
, be32_t address
,
556 be32_t gateway
, uint8_t chaddr
[]) {
557 _cleanup_free_ DHCPPacket
*packet
= NULL
;
558 size_t optoffset
= 0;
562 assert(address
!= INADDR_ANY
);
565 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
569 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
570 DHCP_FORCERENEW
, ARPHRD_ETHER
,
571 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
575 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
576 &optoffset
, 0, DHCP_OPTION_END
, 0, NULL
);
580 memcpy(&packet
->dhcp
.chaddr
, chaddr
, ETH_ALEN
);
582 r
= dhcp_server_send_udp(server
, address
, &packet
->dhcp
,
583 sizeof(DHCPMessage
) + optoffset
);
590 static int parse_request(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
591 DHCPRequest
*req
= userdata
;
596 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
598 req
->lifetime
= be32toh(*(be32_t
*)option
);
601 case DHCP_OPTION_REQUESTED_IP_ADDRESS
:
603 req
->requested_ip
= *(be32_t
*)option
;
606 case DHCP_OPTION_SERVER_IDENTIFIER
:
608 req
->server_id
= *(be32_t
*)option
;
611 case DHCP_OPTION_CLIENT_IDENTIFIER
:
615 data
= memdup(option
, len
);
619 free(req
->client_id
.data
);
620 req
->client_id
.data
= data
;
621 req
->client_id
.length
= len
;
625 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
627 req
->max_optlen
= be16toh(*(be16_t
*)option
) -
628 - sizeof(DHCPPacket
);
636 static void dhcp_request_free(DHCPRequest
*req
) {
640 free(req
->client_id
.data
);
644 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
645 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
647 static int ensure_sane_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPMessage
*message
) {
651 req
->message
= message
;
653 /* set client id based on MAC address if client did not send an explicit
655 if (!req
->client_id
.data
) {
658 data
= malloc0(ETH_ALEN
+ 1);
662 ((uint8_t*) data
)[0] = 0x01;
663 memcpy((uint8_t*) data
+ 1, &message
->chaddr
, ETH_ALEN
);
665 req
->client_id
.length
= ETH_ALEN
+ 1;
666 req
->client_id
.data
= data
;
669 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
670 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
672 if (req
->lifetime
<= 0)
673 req
->lifetime
= MAX(1ULL, server
->default_lease_time
);
675 if (server
->max_lease_time
> 0 && req
->lifetime
> server
->max_lease_time
)
676 req
->lifetime
= server
->max_lease_time
;
681 static int get_pool_offset(sd_dhcp_server
*server
, be32_t requested_ip
) {
684 if (!server
->pool_size
)
687 if (be32toh(requested_ip
) < (be32toh(server
->subnet
) | server
->pool_offset
) ||
688 be32toh(requested_ip
) >= (be32toh(server
->subnet
) | (server
->pool_offset
+ server
->pool_size
)))
691 return be32toh(requested_ip
& ~server
->netmask
) - server
->pool_offset
;
694 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
696 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
,
698 _cleanup_dhcp_request_free_ DHCPRequest
*req
= NULL
;
699 DHCPLease
*existing_lease
;
705 if (message
->op
!= BOOTREQUEST
||
706 message
->htype
!= ARPHRD_ETHER
||
707 message
->hlen
!= ETHER_ADDR_LEN
)
710 req
= new0(DHCPRequest
, 1);
714 type
= dhcp_option_parse(message
, length
, parse_request
, req
);
718 r
= ensure_sane_request(server
, req
, message
);
720 /* this only fails on critical errors */
723 existing_lease
= hashmap_get(server
->leases_by_client_id
,
728 case DHCP_DISCOVER
: {
729 be32_t address
= INADDR_ANY
;
732 log_dhcp_server(server
, "DISCOVER (0x%x)",
733 be32toh(req
->message
->xid
));
735 if (!server
->pool_size
)
736 /* no pool allocated */
739 /* for now pick a random free address from the pool */
741 address
= existing_lease
->address
;
743 struct siphash state
;
747 /* even with no persistence of leases, we try to offer the same client
748 the same IP address. we do this by using the hash of the client id
749 as the offset into the pool of leases when finding the next free one */
751 siphash24_init(&state
, HASH_KEY
.bytes
);
752 client_id_hash_func(&req
->client_id
, &state
);
753 siphash24_finalize((uint8_t*)&hash
, &state
);
754 next_offer
= hash
% server
->pool_size
;
756 for (i
= 0; i
< server
->pool_size
; i
++) {
757 if (!server
->bound_leases
[next_offer
]) {
758 address
= server
->subnet
| htobe32(server
->pool_offset
+ next_offer
);
761 next_offer
= (next_offer
+ 1) % server
->pool_size
;
765 if (address
== INADDR_ANY
)
766 /* no free addresses left */
769 r
= server_send_offer(server
, req
, address
);
771 /* this only fails on critical errors */
772 log_dhcp_server(server
, "could not send offer: %s",
776 log_dhcp_server(server
, "OFFER (0x%x)",
777 be32toh(req
->message
->xid
));
784 log_dhcp_server(server
, "DECLINE (0x%x)",
785 be32toh(req
->message
->xid
));
787 /* TODO: make sure we don't offer this address again */
793 bool init_reboot
= false;
796 /* see RFC 2131, section 4.3.2 */
798 if (req
->server_id
) {
799 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
800 be32toh(req
->message
->xid
));
803 if (req
->server_id
!= server
->address
)
804 /* client did not pick us */
807 if (req
->message
->ciaddr
)
808 /* this MUST be zero */
811 if (!req
->requested_ip
)
812 /* this must be filled in with the yiaddr
813 from the chosen OFFER */
816 address
= req
->requested_ip
;
817 } else if (req
->requested_ip
) {
818 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
819 be32toh(req
->message
->xid
));
822 if (req
->message
->ciaddr
)
823 /* this MUST be zero */
826 /* TODO: check more carefully if IP is correct */
827 address
= req
->requested_ip
;
830 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
831 be32toh(req
->message
->xid
));
833 /* REBINDING / RENEWING */
834 if (!req
->message
->ciaddr
)
835 /* this MUST be filled in with clients IP address */
838 address
= req
->message
->ciaddr
;
841 pool_offset
= get_pool_offset(server
, address
);
843 /* verify that the requested address is from the pool, and either
844 owned by the current client or free */
845 if (pool_offset
>= 0 &&
846 server
->bound_leases
[pool_offset
] == existing_lease
) {
850 if (!existing_lease
) {
851 lease
= new0(DHCPLease
, 1);
852 lease
->address
= req
->requested_ip
;
853 lease
->client_id
.data
= memdup(req
->client_id
.data
,
854 req
->client_id
.length
);
855 if (!lease
->client_id
.data
) {
859 lease
->client_id
.length
= req
->client_id
.length
;
860 memcpy(&lease
->chaddr
, &req
->message
->chaddr
,
862 lease
->gateway
= req
->message
->giaddr
;
864 lease
= existing_lease
;
866 r
= sd_event_now(server
->event
,
867 clock_boottime_or_monotonic(),
871 dhcp_lease_free(lease
);
875 lease
->expiration
= req
->lifetime
* USEC_PER_SEC
+ time_now
;
877 r
= server_send_ack(server
, req
, address
);
879 /* this only fails on critical errors */
880 log_dhcp_server(server
, "could not send ack: %s",
884 dhcp_lease_free(lease
);
888 log_dhcp_server(server
, "ACK (0x%x)",
889 be32toh(req
->message
->xid
));
891 server
->bound_leases
[pool_offset
] = lease
;
892 hashmap_put(server
->leases_by_client_id
,
893 &lease
->client_id
, lease
);
897 } else if (init_reboot
) {
898 r
= server_send_nak(server
, req
);
900 /* this only fails on critical errors */
901 log_dhcp_server(server
, "could not send nak: %s",
905 log_dhcp_server(server
, "NAK (0x%x)",
906 be32toh(req
->message
->xid
));
917 log_dhcp_server(server
, "RELEASE (0x%x)",
918 be32toh(req
->message
->xid
));
923 if (existing_lease
->address
!= req
->message
->ciaddr
)
926 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
930 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
931 server
->bound_leases
[pool_offset
] = NULL
;
932 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
933 dhcp_lease_free(existing_lease
);
944 static int server_receive_message(sd_event_source
*s
, int fd
,
945 uint32_t revents
, void *userdata
) {
946 _cleanup_free_ DHCPMessage
*message
= NULL
;
947 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))];
948 sd_dhcp_server
*server
= userdata
;
949 struct iovec iov
= {};
950 struct msghdr msg
= {
953 .msg_control
= cmsgbuf
,
954 .msg_controllen
= sizeof(cmsgbuf
),
956 struct cmsghdr
*cmsg
;
961 if (ioctl(fd
, FIONREAD
, &buflen
) < 0)
966 message
= malloc0(buflen
);
970 iov
.iov_base
= message
;
971 iov
.iov_len
= buflen
;
973 len
= recvmsg(fd
, &msg
, 0);
976 else if ((size_t)len
< sizeof(DHCPMessage
))
979 CMSG_FOREACH(cmsg
, &msg
) {
980 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
981 cmsg
->cmsg_type
== IP_PKTINFO
&&
982 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
983 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
985 /* TODO figure out if this can be done as a filter on
986 * the socket, like for IPv6 */
987 if (server
->ifindex
!= info
->ipi_ifindex
)
994 return dhcp_server_handle_message(server
, message
, (size_t)len
);
997 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
1000 assert_return(server
, -EINVAL
);
1001 assert_return(server
->event
, -EINVAL
);
1002 assert_return(!server
->receive_message
, -EBUSY
);
1003 assert_return(server
->fd_raw
== -1, -EBUSY
);
1004 assert_return(server
->fd
== -1, -EBUSY
);
1005 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
1007 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0);
1010 sd_dhcp_server_stop(server
);
1015 r
= dhcp_network_bind_udp_socket(INADDR_ANY
, DHCP_PORT_SERVER
);
1017 sd_dhcp_server_stop(server
);
1022 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
1023 server
->fd
, EPOLLIN
,
1024 server_receive_message
, server
);
1026 sd_dhcp_server_stop(server
);
1030 r
= sd_event_source_set_priority(server
->receive_message
,
1031 server
->event_priority
);
1033 sd_dhcp_server_stop(server
);
1037 log_dhcp_server(server
, "STARTED");
1042 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1046 assert_return(server
, -EINVAL
);
1047 assert(server
->bound_leases
);
1049 for (i
= 0; i
< server
->pool_size
; i
++) {
1050 DHCPLease
*lease
= server
->bound_leases
[i
];
1052 if (!lease
|| lease
== &server
->invalid_lease
)
1055 r
= server_send_forcerenew(server
, lease
->address
,
1061 log_dhcp_server(server
, "FORCERENEW");
1067 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *tz
) {
1070 assert_return(server
, -EINVAL
);
1071 assert_return(timezone_is_valid(tz
), -EINVAL
);
1073 if (streq_ptr(tz
, server
->timezone
))
1076 r
= free_and_strdup(&server
->timezone
, tz
);
1083 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1084 assert_return(server
, -EINVAL
);
1086 if (t
== server
->max_lease_time
)
1089 server
->max_lease_time
= t
;
1093 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1094 assert_return(server
, -EINVAL
);
1096 if (t
== server
->default_lease_time
)
1099 server
->default_lease_time
= t
;
1103 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], unsigned n
) {
1104 assert_return(server
, -EINVAL
);
1105 assert_return(dns
|| n
<= 0, -EINVAL
);
1107 if (server
->n_dns
== n
&&
1108 memcmp(server
->dns
, dns
, sizeof(struct in_addr
) * n
) == 0)
1112 server
->dns
= mfree(server
->dns
);
1117 c
= newdup(struct in_addr
, dns
, n
);
1129 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], unsigned n
) {
1130 assert_return(server
, -EINVAL
);
1131 assert_return(ntp
|| n
<= 0, -EINVAL
);
1133 if (server
->n_ntp
== n
&&
1134 memcmp(server
->ntp
, ntp
, sizeof(struct in_addr
) * n
) == 0)
1138 server
->ntp
= mfree(server
->ntp
);
1143 c
= newdup(struct in_addr
, ntp
, n
);