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 "siphash24.h"
27 #include "sd-dhcp-server.h"
28 #include "dhcp-server-internal.h"
29 #include "dhcp-internal.h"
31 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
32 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
34 int sd_dhcp_server_set_lease_pool(sd_dhcp_server
*server
,
35 struct in_addr
*address
,
37 assert_return(server
, -EINVAL
);
38 assert_return(address
, -EINVAL
);
39 assert_return(address
->s_addr
, -EINVAL
);
40 assert_return(size
, -EINVAL
);
41 assert_return(server
->pool_start
== htobe32(INADDR_ANY
), -EBUSY
);
42 assert_return(!server
->pool_size
, -EBUSY
);
43 assert_return(!server
->bound_leases
, -EBUSY
);
45 server
->bound_leases
= new0(DHCPLease
*, size
);
46 if (!server
->bound_leases
)
49 server
->pool_start
= address
->s_addr
;
50 server
->pool_size
= size
;
55 int sd_dhcp_server_set_address(sd_dhcp_server
*server
, struct in_addr
*address
,
56 unsigned char prefixlen
) {
57 assert_return(server
, -EINVAL
);
58 assert_return(address
, -EINVAL
);
59 assert_return(address
->s_addr
, -EINVAL
);
60 assert_return(prefixlen
<= 32, -ERANGE
);
61 assert_return(server
->address
== htobe32(INADDR_ANY
), -EBUSY
);
62 assert_return(server
->netmask
== htobe32(INADDR_ANY
), -EBUSY
);
64 server
->address
= address
->s_addr
;
65 server
->netmask
= htobe32(0xfffffffflu
<< (32 - prefixlen
));
70 bool sd_dhcp_server_is_running(sd_dhcp_server
*server
) {
71 assert_return(server
, false);
73 return !!server
->receive_message
;
76 sd_dhcp_server
*sd_dhcp_server_ref(sd_dhcp_server
*server
) {
81 assert(server
->n_ref
>= 1);
87 unsigned long client_id_hash_func(const void *p
,
88 const uint8_t hash_key
[HASH_KEY_SIZE
]) {
90 const DHCPClientId
*id
= p
;
96 siphash24((uint8_t*) &u
, id
->data
, id
->length
, hash_key
);
98 return (unsigned long) u
;
101 int client_id_compare_func(const void *_a
, const void *_b
) {
102 const DHCPClientId
*a
, *b
;
107 assert(!a
->length
|| a
->data
);
108 assert(!b
->length
|| b
->data
);
110 if (a
->length
!= b
->length
)
111 return a
->length
< b
->length
? -1 : 1;
113 return memcmp(a
->data
, b
->data
, a
->length
);
116 static const struct hash_ops client_id_hash_ops
= {
117 .hash
= client_id_hash_func
,
118 .compare
= client_id_compare_func
121 static void dhcp_lease_free(DHCPLease
*lease
) {
125 free(lease
->client_id
.data
);
129 sd_dhcp_server
*sd_dhcp_server_unref(sd_dhcp_server
*server
) {
135 assert(server
->n_ref
>= 1);
138 if (server
->n_ref
> 0)
141 log_dhcp_server(server
, "UNREF");
143 sd_dhcp_server_stop(server
);
145 sd_event_unref(server
->event
);
147 free(server
->timezone
);
151 while ((lease
= hashmap_steal_first(server
->leases_by_client_id
)))
152 dhcp_lease_free(lease
);
153 hashmap_free(server
->leases_by_client_id
);
155 free(server
->bound_leases
);
161 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
162 _cleanup_dhcp_server_unref_ sd_dhcp_server
*server
= NULL
;
164 assert_return(ret
, -EINVAL
);
165 assert_return(ifindex
> 0, -EINVAL
);
167 server
= new0(sd_dhcp_server
, 1);
174 server
->address
= htobe32(INADDR_ANY
);
175 server
->netmask
= htobe32(INADDR_ANY
);
176 server
->ifindex
= ifindex
;
177 server
->leases_by_client_id
= hashmap_new(&client_id_hash_ops
);
178 server
->default_lease_time
= DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC
, USEC_PER_SEC
);
179 server
->max_lease_time
= DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC
, USEC_PER_SEC
);
187 int sd_dhcp_server_attach_event(sd_dhcp_server
*server
, sd_event
*event
,
191 assert_return(server
, -EINVAL
);
192 assert_return(!server
->event
, -EBUSY
);
195 server
->event
= sd_event_ref(event
);
197 r
= sd_event_default(&server
->event
);
202 server
->event_priority
= priority
;
207 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
208 assert_return(server
, -EINVAL
);
210 server
->event
= sd_event_unref(server
->event
);
215 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
216 assert_return(server
, NULL
);
218 return server
->event
;
221 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
222 assert_return(server
, -EINVAL
);
224 server
->receive_message
=
225 sd_event_source_unref(server
->receive_message
);
227 server
->fd_raw
= safe_close(server
->fd_raw
);
228 server
->fd
= safe_close(server
->fd
);
230 log_dhcp_server(server
, "STOPPED");
235 static int dhcp_server_send_unicast_raw(sd_dhcp_server
*server
,
236 DHCPPacket
*packet
, size_t len
) {
237 union sockaddr_union link
= {
238 .ll
.sll_family
= AF_PACKET
,
239 .ll
.sll_protocol
= htons(ETH_P_IP
),
240 .ll
.sll_ifindex
= server
->ifindex
,
241 .ll
.sll_halen
= ETH_ALEN
,
245 assert(server
->ifindex
> 0);
246 assert(server
->address
);
248 assert(len
> sizeof(DHCPPacket
));
250 memcpy(&link
.ll
.sll_addr
, &packet
->dhcp
.chaddr
, ETH_ALEN
);
252 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
254 DHCP_PORT_CLIENT
, len
);
256 return dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
259 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
260 DHCPMessage
*message
, size_t len
) {
261 union sockaddr_union dest
= {
262 .in
.sin_family
= AF_INET
,
263 .in
.sin_port
= htobe16(DHCP_PORT_CLIENT
),
264 .in
.sin_addr
.s_addr
= destination
,
270 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))] = {};
271 struct msghdr msg
= {
273 .msg_namelen
= sizeof(dest
.in
),
276 .msg_control
= cmsgbuf
,
277 .msg_controllen
= sizeof(cmsgbuf
),
279 struct cmsghdr
*cmsg
;
280 struct in_pktinfo
*pktinfo
;
284 assert(server
->fd
> 0);
286 assert(len
> sizeof(DHCPMessage
));
288 cmsg
= CMSG_FIRSTHDR(&msg
);
291 cmsg
->cmsg_level
= IPPROTO_IP
;
292 cmsg
->cmsg_type
= IP_PKTINFO
;
293 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
295 /* we attach source interface and address info to the message
296 rather than binding the socket. This will be mostly useful
297 when we gain support for arbitrary number of server addresses
299 pktinfo
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
302 pktinfo
->ipi_ifindex
= server
->ifindex
;
303 pktinfo
->ipi_spec_dst
.s_addr
= server
->address
;
305 r
= sendmsg(server
->fd
, &msg
, 0);
312 static bool requested_broadcast(DHCPRequest
*req
) {
315 return req
->message
->flags
& htobe16(0x8000);
318 int dhcp_server_send_packet(sd_dhcp_server
*server
,
319 DHCPRequest
*req
, DHCPPacket
*packet
,
320 int type
, size_t optoffset
) {
321 be32_t destination
= INADDR_ANY
;
326 assert(req
->max_optlen
);
327 assert(optoffset
<= req
->max_optlen
);
330 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
331 DHCP_OPTION_SERVER_IDENTIFIER
,
332 4, &server
->address
);
336 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
337 DHCP_OPTION_END
, 0, NULL
);
341 /* RFC 2131 Section 4.1
343 If the ’giaddr’ field in a DHCP message from a client is non-zero,
344 the server sends any return messages to the ’DHCP server’ port on the
345 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
346 field is zero and the ’ciaddr’ field is nonzero, then the server
347 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
348 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
349 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
350 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
351 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
352 messages to the client’s hardware address and ’yiaddr’ address. In
353 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
354 messages to 0xffffffff.
358 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
359 different subnet. The server MUST set the broadcast bit in the
360 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
361 client, because the client may not have a correct network address
362 or subnet mask, and the client may not be answering ARP requests.
364 if (req
->message
->giaddr
) {
365 destination
= req
->message
->giaddr
;
366 if (type
== DHCP_NAK
)
367 packet
->dhcp
.flags
= htobe16(0x8000);
368 } else if (req
->message
->ciaddr
&& type
!= DHCP_NAK
)
369 destination
= req
->message
->ciaddr
;
371 if (destination
!= INADDR_ANY
)
372 return dhcp_server_send_udp(server
, destination
, &packet
->dhcp
,
373 sizeof(DHCPMessage
) + optoffset
);
374 else if (requested_broadcast(req
) || type
== DHCP_NAK
)
375 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
377 sizeof(DHCPMessage
) + optoffset
);
379 /* we cannot send UDP packet to specific MAC address when the
380 address is not yet configured, so must fall back to raw
382 return dhcp_server_send_unicast_raw(server
, packet
,
383 sizeof(DHCPPacket
) + optoffset
);
386 static int server_message_init(sd_dhcp_server
*server
, DHCPPacket
**ret
,
387 uint8_t type
, size_t *_optoffset
,
389 _cleanup_free_ DHCPPacket
*packet
= NULL
;
390 size_t optoffset
= 0;
396 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
, DHCP_NAK
));
398 packet
= malloc0(sizeof(DHCPPacket
) + req
->max_optlen
);
402 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
,
403 be32toh(req
->message
->xid
), type
, ARPHRD_ETHER
,
404 req
->max_optlen
, &optoffset
);
408 packet
->dhcp
.flags
= req
->message
->flags
;
409 packet
->dhcp
.giaddr
= req
->message
->giaddr
;
410 memcpy(&packet
->dhcp
.chaddr
, &req
->message
->chaddr
, ETH_ALEN
);
412 *_optoffset
= optoffset
;
419 static int server_send_offer(sd_dhcp_server
*server
, DHCPRequest
*req
,
421 _cleanup_free_ DHCPPacket
*packet
= NULL
;
426 r
= server_message_init(server
, &packet
, DHCP_OFFER
, &offset
, req
);
430 packet
->dhcp
.yiaddr
= address
;
432 lease_time
= htobe32(req
->lifetime
);
433 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
434 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
439 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
440 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
444 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
445 DHCP_OPTION_ROUTER
, 4, &server
->address
);
449 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_OFFER
, offset
);
456 static int server_send_ack(sd_dhcp_server
*server
, DHCPRequest
*req
,
458 _cleanup_free_ DHCPPacket
*packet
= NULL
;
463 r
= server_message_init(server
, &packet
, DHCP_ACK
, &offset
, req
);
467 packet
->dhcp
.yiaddr
= address
;
469 lease_time
= htobe32(req
->lifetime
);
470 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
471 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
476 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
477 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
481 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
482 DHCP_OPTION_ROUTER
, 4, &server
->address
);
486 if (server
->n_dns
> 0) {
487 r
= dhcp_option_append(
488 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
489 DHCP_OPTION_DOMAIN_NAME_SERVER
,
490 sizeof(struct in_addr
) * server
->n_dns
, server
->dns
);
495 if (server
->n_ntp
> 0) {
496 r
= dhcp_option_append(
497 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
498 DHCP_OPTION_NTP_SERVER
,
499 sizeof(struct in_addr
) * server
->n_ntp
, server
->ntp
);
504 if (server
->timezone
) {
505 r
= dhcp_option_append(
506 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
507 DHCP_OPTION_NEW_TZDB_TIMEZONE
,
508 strlen(server
->timezone
), server
->timezone
);
513 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_ACK
, offset
);
520 static int server_send_nak(sd_dhcp_server
*server
, DHCPRequest
*req
) {
521 _cleanup_free_ DHCPPacket
*packet
= NULL
;
525 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
529 return dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
532 static int server_send_forcerenew(sd_dhcp_server
*server
, be32_t address
,
533 be32_t gateway
, uint8_t chaddr
[]) {
534 _cleanup_free_ DHCPPacket
*packet
= NULL
;
535 size_t optoffset
= 0;
539 assert(address
!= INADDR_ANY
);
542 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
546 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
547 DHCP_FORCERENEW
, ARPHRD_ETHER
,
548 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
552 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
553 &optoffset
, 0, DHCP_OPTION_END
, 0, NULL
);
557 memcpy(&packet
->dhcp
.chaddr
, chaddr
, ETH_ALEN
);
559 r
= dhcp_server_send_udp(server
, address
, &packet
->dhcp
,
560 sizeof(DHCPMessage
) + optoffset
);
567 static int parse_request(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
568 DHCPRequest
*req
= userdata
;
573 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
575 req
->lifetime
= be32toh(*(be32_t
*)option
);
578 case DHCP_OPTION_REQUESTED_IP_ADDRESS
:
580 req
->requested_ip
= *(be32_t
*)option
;
583 case DHCP_OPTION_SERVER_IDENTIFIER
:
585 req
->server_id
= *(be32_t
*)option
;
588 case DHCP_OPTION_CLIENT_IDENTIFIER
:
592 data
= memdup(option
, len
);
596 free(req
->client_id
.data
);
597 req
->client_id
.data
= data
;
598 req
->client_id
.length
= len
;
602 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
604 req
->max_optlen
= be16toh(*(be16_t
*)option
) -
605 - sizeof(DHCPPacket
);
613 static void dhcp_request_free(DHCPRequest
*req
) {
617 free(req
->client_id
.data
);
621 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
622 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
624 static int ensure_sane_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPMessage
*message
) {
628 req
->message
= message
;
630 /* set client id based on MAC address if client did not send an explicit
632 if (!req
->client_id
.data
) {
635 data
= malloc0(ETH_ALEN
+ 1);
639 ((uint8_t*) data
)[0] = 0x01;
640 memcpy((uint8_t*) data
+ 1, &message
->chaddr
, ETH_ALEN
);
642 req
->client_id
.length
= ETH_ALEN
+ 1;
643 req
->client_id
.data
= data
;
646 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
647 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
649 if (req
->lifetime
<= 0)
650 req
->lifetime
= MAX(1ULL, server
->default_lease_time
);
652 if (server
->max_lease_time
> 0 && req
->lifetime
> server
->max_lease_time
)
653 req
->lifetime
= server
->max_lease_time
;
658 static int get_pool_offset(sd_dhcp_server
*server
, be32_t requested_ip
) {
661 if (!server
->pool_size
)
664 if (be32toh(requested_ip
) < be32toh(server
->pool_start
) ||
665 be32toh(requested_ip
) >= be32toh(server
->pool_start
) +
669 return be32toh(requested_ip
) - be32toh(server
->pool_start
);
672 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
674 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
,
676 _cleanup_dhcp_request_free_ DHCPRequest
*req
= NULL
;
677 DHCPLease
*existing_lease
;
683 if (message
->op
!= BOOTREQUEST
||
684 message
->htype
!= ARPHRD_ETHER
||
685 message
->hlen
!= ETHER_ADDR_LEN
)
688 req
= new0(DHCPRequest
, 1);
692 type
= dhcp_option_parse(message
, length
, parse_request
, req
);
696 r
= ensure_sane_request(server
, req
, message
);
698 /* this only fails on critical errors */
701 existing_lease
= hashmap_get(server
->leases_by_client_id
,
706 case DHCP_DISCOVER
: {
707 be32_t address
= INADDR_ANY
;
710 log_dhcp_server(server
, "DISCOVER (0x%x)",
711 be32toh(req
->message
->xid
));
713 if (!server
->pool_size
)
714 /* no pool allocated */
717 /* for now pick a random free address from the pool */
719 address
= existing_lease
->address
;
723 /* even with no persistence of leases, we try to offer the same client
724 the same IP address. we do this by using the hash of the client id
725 as the offset into the pool of leases when finding the next free one */
727 next_offer
= client_id_hash_func(&req
->client_id
, HASH_KEY
.bytes
) % server
->pool_size
;
729 for (i
= 0; i
< server
->pool_size
; i
++) {
730 if (!server
->bound_leases
[next_offer
]) {
731 address
= htobe32(be32toh(server
->pool_start
) + next_offer
);
734 next_offer
= (next_offer
+ 1) % server
->pool_size
;
738 if (address
== INADDR_ANY
)
739 /* no free addresses left */
742 r
= server_send_offer(server
, req
, address
);
744 /* this only fails on critical errors */
745 log_dhcp_server(server
, "could not send offer: %s",
749 log_dhcp_server(server
, "OFFER (0x%x)",
750 be32toh(req
->message
->xid
));
757 log_dhcp_server(server
, "DECLINE (0x%x)",
758 be32toh(req
->message
->xid
));
760 /* TODO: make sure we don't offer this address again */
766 bool init_reboot
= false;
769 /* see RFC 2131, section 4.3.2 */
771 if (req
->server_id
) {
772 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
773 be32toh(req
->message
->xid
));
776 if (req
->server_id
!= server
->address
)
777 /* client did not pick us */
780 if (req
->message
->ciaddr
)
781 /* this MUST be zero */
784 if (!req
->requested_ip
)
785 /* this must be filled in with the yiaddr
786 from the chosen OFFER */
789 address
= req
->requested_ip
;
790 } else if (req
->requested_ip
) {
791 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
792 be32toh(req
->message
->xid
));
795 if (req
->message
->ciaddr
)
796 /* this MUST be zero */
799 /* TODO: check more carefully if IP is correct */
800 address
= req
->requested_ip
;
803 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
804 be32toh(req
->message
->xid
));
806 /* REBINDING / RENEWING */
807 if (!req
->message
->ciaddr
)
808 /* this MUST be filled in with clients IP address */
811 address
= req
->message
->ciaddr
;
814 pool_offset
= get_pool_offset(server
, address
);
816 /* verify that the requested address is from the pool, and either
817 owned by the current client or free */
818 if (pool_offset
>= 0 &&
819 server
->bound_leases
[pool_offset
] == existing_lease
) {
823 if (!existing_lease
) {
824 lease
= new0(DHCPLease
, 1);
825 lease
->address
= req
->requested_ip
;
826 lease
->client_id
.data
= memdup(req
->client_id
.data
,
827 req
->client_id
.length
);
828 if (!lease
->client_id
.data
) {
832 lease
->client_id
.length
= req
->client_id
.length
;
833 memcpy(&lease
->chaddr
, &req
->message
->chaddr
,
835 lease
->gateway
= req
->message
->giaddr
;
837 lease
= existing_lease
;
839 r
= sd_event_now(server
->event
,
840 clock_boottime_or_monotonic(),
844 dhcp_lease_free(lease
);
848 lease
->expiration
= req
->lifetime
* USEC_PER_SEC
+ time_now
;
850 r
= server_send_ack(server
, req
, address
);
852 /* this only fails on critical errors */
853 log_dhcp_server(server
, "could not send ack: %s",
857 dhcp_lease_free(lease
);
861 log_dhcp_server(server
, "ACK (0x%x)",
862 be32toh(req
->message
->xid
));
864 server
->bound_leases
[pool_offset
] = lease
;
865 hashmap_put(server
->leases_by_client_id
,
866 &lease
->client_id
, lease
);
870 } else if (init_reboot
) {
871 r
= server_send_nak(server
, req
);
873 /* this only fails on critical errors */
874 log_dhcp_server(server
, "could not send nak: %s",
878 log_dhcp_server(server
, "NAK (0x%x)",
879 be32toh(req
->message
->xid
));
890 log_dhcp_server(server
, "RELEASE (0x%x)",
891 be32toh(req
->message
->xid
));
896 if (existing_lease
->address
!= req
->message
->ciaddr
)
899 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
903 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
904 server
->bound_leases
[pool_offset
] = NULL
;
905 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
906 dhcp_lease_free(existing_lease
);
917 static int server_receive_message(sd_event_source
*s
, int fd
,
918 uint32_t revents
, void *userdata
) {
919 _cleanup_free_ DHCPMessage
*message
= NULL
;
920 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))];
921 sd_dhcp_server
*server
= userdata
;
922 struct iovec iov
= {};
923 struct msghdr msg
= {
926 .msg_control
= cmsgbuf
,
927 .msg_controllen
= sizeof(cmsgbuf
),
929 struct cmsghdr
*cmsg
;
934 if (ioctl(fd
, FIONREAD
, &buflen
) < 0)
939 message
= malloc0(buflen
);
943 iov
.iov_base
= message
;
944 iov
.iov_len
= buflen
;
946 len
= recvmsg(fd
, &msg
, 0);
949 else if ((size_t)len
< sizeof(DHCPMessage
))
952 CMSG_FOREACH(cmsg
, &msg
) {
953 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
954 cmsg
->cmsg_type
== IP_PKTINFO
&&
955 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
956 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
958 /* TODO figure out if this can be done as a filter on
959 * the socket, like for IPv6 */
960 if (server
->ifindex
!= info
->ipi_ifindex
)
967 return dhcp_server_handle_message(server
, message
, (size_t)len
);
970 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
973 assert_return(server
, -EINVAL
);
974 assert_return(server
->event
, -EINVAL
);
975 assert_return(!server
->receive_message
, -EBUSY
);
976 assert_return(server
->fd_raw
== -1, -EBUSY
);
977 assert_return(server
->fd
== -1, -EBUSY
);
978 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
980 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0);
983 sd_dhcp_server_stop(server
);
988 r
= dhcp_network_bind_udp_socket(INADDR_ANY
, DHCP_PORT_SERVER
);
990 sd_dhcp_server_stop(server
);
995 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
997 server_receive_message
, server
);
999 sd_dhcp_server_stop(server
);
1003 r
= sd_event_source_set_priority(server
->receive_message
,
1004 server
->event_priority
);
1006 sd_dhcp_server_stop(server
);
1010 log_dhcp_server(server
, "STARTED");
1015 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1019 assert_return(server
, -EINVAL
);
1020 assert(server
->bound_leases
);
1022 for (i
= 0; i
< server
->pool_size
; i
++) {
1023 DHCPLease
*lease
= server
->bound_leases
[i
];
1028 r
= server_send_forcerenew(server
, lease
->address
,
1034 log_dhcp_server(server
, "FORCERENEW");
1040 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *timezone
) {
1043 assert_return(server
, -EINVAL
);
1044 assert_return(timezone_is_valid(timezone
), -EINVAL
);
1046 if (streq_ptr(timezone
, server
->timezone
))
1049 r
= free_and_strdup(&server
->timezone
, timezone
);
1056 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1057 assert_return(server
, -EINVAL
);
1059 if (t
== server
->max_lease_time
)
1062 server
->max_lease_time
= t
;
1066 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1067 assert_return(server
, -EINVAL
);
1069 if (t
== server
->default_lease_time
)
1072 server
->default_lease_time
= t
;
1076 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], unsigned n
) {
1077 assert_return(server
, -EINVAL
);
1078 assert_return(dns
|| n
<= 0, -EINVAL
);
1080 if (server
->n_dns
== n
&&
1081 memcmp(server
->dns
, dns
, sizeof(struct in_addr
) * n
) == 0)
1085 server
->dns
= mfree(server
->dns
);
1090 c
= newdup(struct in_addr
, dns
, n
);
1102 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], unsigned n
) {
1103 assert_return(server
, -EINVAL
);
1104 assert_return(ntp
|| n
<= 0, -EINVAL
);
1106 if (server
->n_ntp
== n
&&
1107 memcmp(server
->ntp
, ntp
, sizeof(struct in_addr
) * n
) == 0)
1111 server
->ntp
= mfree(server
->ntp
);
1116 c
= newdup(struct in_addr
, ntp
, n
);