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 unsigned long client_id_hash_func(const void *p
,
114 const uint8_t hash_key
[HASH_KEY_SIZE
]) {
116 const DHCPClientId
*id
= p
;
122 siphash24((uint8_t*) &u
, id
->data
, id
->length
, hash_key
);
124 return (unsigned long) u
;
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_dhcp_server_unref_ 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 DHCP_OPTION_SERVER_IDENTIFIER
,
358 4, &server
->address
);
362 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
363 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 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
465 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
466 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
470 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
471 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 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
502 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
503 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
507 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
508 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 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 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 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, 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 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
601 req
->lifetime
= be32toh(*(be32_t
*)option
);
604 case DHCP_OPTION_REQUESTED_IP_ADDRESS
:
606 req
->requested_ip
= *(be32_t
*)option
;
609 case DHCP_OPTION_SERVER_IDENTIFIER
:
611 req
->server_id
= *(be32_t
*)option
;
614 case 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 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 DHCPLease
*existing_lease
;
708 if (message
->op
!= BOOTREQUEST
||
709 message
->htype
!= ARPHRD_ETHER
||
710 message
->hlen
!= ETHER_ADDR_LEN
)
713 req
= new0(DHCPRequest
, 1);
717 type
= dhcp_option_parse(message
, length
, parse_request
, req
);
721 r
= ensure_sane_request(server
, req
, message
);
723 /* this only fails on critical errors */
726 existing_lease
= hashmap_get(server
->leases_by_client_id
,
731 case DHCP_DISCOVER
: {
732 be32_t address
= INADDR_ANY
;
735 log_dhcp_server(server
, "DISCOVER (0x%x)",
736 be32toh(req
->message
->xid
));
738 if (!server
->pool_size
)
739 /* no pool allocated */
742 /* for now pick a random free address from the pool */
744 address
= existing_lease
->address
;
748 /* even with no persistence of leases, we try to offer the same client
749 the same IP address. we do this by using the hash of the client id
750 as the offset into the pool of leases when finding the next free one */
752 next_offer
= client_id_hash_func(&req
->client_id
, HASH_KEY
.bytes
) % server
->pool_size
;
754 for (i
= 0; i
< server
->pool_size
; i
++) {
755 if (!server
->bound_leases
[next_offer
]) {
756 address
= server
->subnet
| htobe32(server
->pool_offset
+ next_offer
);
759 next_offer
= (next_offer
+ 1) % server
->pool_size
;
763 if (address
== INADDR_ANY
)
764 /* no free addresses left */
767 r
= server_send_offer(server
, req
, address
);
769 /* this only fails on critical errors */
770 log_dhcp_server(server
, "could not send offer: %s",
774 log_dhcp_server(server
, "OFFER (0x%x)",
775 be32toh(req
->message
->xid
));
782 log_dhcp_server(server
, "DECLINE (0x%x)",
783 be32toh(req
->message
->xid
));
785 /* TODO: make sure we don't offer this address again */
791 bool init_reboot
= false;
794 /* see RFC 2131, section 4.3.2 */
796 if (req
->server_id
) {
797 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
798 be32toh(req
->message
->xid
));
801 if (req
->server_id
!= server
->address
)
802 /* client did not pick us */
805 if (req
->message
->ciaddr
)
806 /* this MUST be zero */
809 if (!req
->requested_ip
)
810 /* this must be filled in with the yiaddr
811 from the chosen OFFER */
814 address
= req
->requested_ip
;
815 } else if (req
->requested_ip
) {
816 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
817 be32toh(req
->message
->xid
));
820 if (req
->message
->ciaddr
)
821 /* this MUST be zero */
824 /* TODO: check more carefully if IP is correct */
825 address
= req
->requested_ip
;
828 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
829 be32toh(req
->message
->xid
));
831 /* REBINDING / RENEWING */
832 if (!req
->message
->ciaddr
)
833 /* this MUST be filled in with clients IP address */
836 address
= req
->message
->ciaddr
;
839 pool_offset
= get_pool_offset(server
, address
);
841 /* verify that the requested address is from the pool, and either
842 owned by the current client or free */
843 if (pool_offset
>= 0 &&
844 server
->bound_leases
[pool_offset
] == existing_lease
) {
848 if (!existing_lease
) {
849 lease
= new0(DHCPLease
, 1);
850 lease
->address
= req
->requested_ip
;
851 lease
->client_id
.data
= memdup(req
->client_id
.data
,
852 req
->client_id
.length
);
853 if (!lease
->client_id
.data
) {
857 lease
->client_id
.length
= req
->client_id
.length
;
858 memcpy(&lease
->chaddr
, &req
->message
->chaddr
,
860 lease
->gateway
= req
->message
->giaddr
;
862 lease
= existing_lease
;
864 r
= sd_event_now(server
->event
,
865 clock_boottime_or_monotonic(),
869 dhcp_lease_free(lease
);
873 lease
->expiration
= req
->lifetime
* USEC_PER_SEC
+ time_now
;
875 r
= server_send_ack(server
, req
, address
);
877 /* this only fails on critical errors */
878 log_dhcp_server(server
, "could not send ack: %s",
882 dhcp_lease_free(lease
);
886 log_dhcp_server(server
, "ACK (0x%x)",
887 be32toh(req
->message
->xid
));
889 server
->bound_leases
[pool_offset
] = lease
;
890 hashmap_put(server
->leases_by_client_id
,
891 &lease
->client_id
, lease
);
895 } else if (init_reboot
) {
896 r
= server_send_nak(server
, req
);
898 /* this only fails on critical errors */
899 log_dhcp_server(server
, "could not send nak: %s",
903 log_dhcp_server(server
, "NAK (0x%x)",
904 be32toh(req
->message
->xid
));
915 log_dhcp_server(server
, "RELEASE (0x%x)",
916 be32toh(req
->message
->xid
));
921 if (existing_lease
->address
!= req
->message
->ciaddr
)
924 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
928 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
929 server
->bound_leases
[pool_offset
] = NULL
;
930 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
931 dhcp_lease_free(existing_lease
);
942 static int server_receive_message(sd_event_source
*s
, int fd
,
943 uint32_t revents
, void *userdata
) {
944 _cleanup_free_ DHCPMessage
*message
= NULL
;
945 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))];
946 sd_dhcp_server
*server
= userdata
;
947 struct iovec iov
= {};
948 struct msghdr msg
= {
951 .msg_control
= cmsgbuf
,
952 .msg_controllen
= sizeof(cmsgbuf
),
954 struct cmsghdr
*cmsg
;
959 if (ioctl(fd
, FIONREAD
, &buflen
) < 0)
964 message
= malloc0(buflen
);
968 iov
.iov_base
= message
;
969 iov
.iov_len
= buflen
;
971 len
= recvmsg(fd
, &msg
, 0);
974 else if ((size_t)len
< sizeof(DHCPMessage
))
977 CMSG_FOREACH(cmsg
, &msg
) {
978 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
979 cmsg
->cmsg_type
== IP_PKTINFO
&&
980 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
981 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
983 /* TODO figure out if this can be done as a filter on
984 * the socket, like for IPv6 */
985 if (server
->ifindex
!= info
->ipi_ifindex
)
992 return dhcp_server_handle_message(server
, message
, (size_t)len
);
995 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
998 assert_return(server
, -EINVAL
);
999 assert_return(server
->event
, -EINVAL
);
1000 assert_return(!server
->receive_message
, -EBUSY
);
1001 assert_return(server
->fd_raw
== -1, -EBUSY
);
1002 assert_return(server
->fd
== -1, -EBUSY
);
1003 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
1005 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0);
1008 sd_dhcp_server_stop(server
);
1013 r
= dhcp_network_bind_udp_socket(INADDR_ANY
, DHCP_PORT_SERVER
);
1015 sd_dhcp_server_stop(server
);
1020 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
1021 server
->fd
, EPOLLIN
,
1022 server_receive_message
, server
);
1024 sd_dhcp_server_stop(server
);
1028 r
= sd_event_source_set_priority(server
->receive_message
,
1029 server
->event_priority
);
1031 sd_dhcp_server_stop(server
);
1035 log_dhcp_server(server
, "STARTED");
1040 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1044 assert_return(server
, -EINVAL
);
1045 assert(server
->bound_leases
);
1047 for (i
= 0; i
< server
->pool_size
; i
++) {
1048 DHCPLease
*lease
= server
->bound_leases
[i
];
1050 if (!lease
|| lease
== &server
->invalid_lease
)
1053 r
= server_send_forcerenew(server
, lease
->address
,
1059 log_dhcp_server(server
, "FORCERENEW");
1065 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *tz
) {
1068 assert_return(server
, -EINVAL
);
1069 assert_return(timezone_is_valid(tz
), -EINVAL
);
1071 if (streq_ptr(tz
, server
->timezone
))
1074 r
= free_and_strdup(&server
->timezone
, tz
);
1081 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1082 assert_return(server
, -EINVAL
);
1084 if (t
== server
->max_lease_time
)
1087 server
->max_lease_time
= t
;
1091 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1092 assert_return(server
, -EINVAL
);
1094 if (t
== server
->default_lease_time
)
1097 server
->default_lease_time
= t
;
1101 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], unsigned n
) {
1102 assert_return(server
, -EINVAL
);
1103 assert_return(dns
|| n
<= 0, -EINVAL
);
1105 if (server
->n_dns
== n
&&
1106 memcmp(server
->dns
, dns
, sizeof(struct in_addr
) * n
) == 0)
1110 server
->dns
= mfree(server
->dns
);
1115 c
= newdup(struct in_addr
, dns
, n
);
1127 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], unsigned n
) {
1128 assert_return(server
, -EINVAL
);
1129 assert_return(ntp
|| n
<= 0, -EINVAL
);
1131 if (server
->n_ntp
== n
&&
1132 memcmp(server
->ntp
, ntp
, sizeof(struct in_addr
) * n
) == 0)
1136 server
->ntp
= mfree(server
->ntp
);
1141 c
= newdup(struct in_addr
, ntp
, n
);