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
->data
, id
->length
, state
);
123 int client_id_compare_func(const void *_a
, const void *_b
) {
124 const DHCPClientId
*a
, *b
;
129 assert(!a
->length
|| a
->data
);
130 assert(!b
->length
|| b
->data
);
132 if (a
->length
!= b
->length
)
133 return a
->length
< b
->length
? -1 : 1;
135 return memcmp(a
->data
, b
->data
, a
->length
);
138 static const struct hash_ops client_id_hash_ops
= {
139 .hash
= client_id_hash_func
,
140 .compare
= client_id_compare_func
143 static void dhcp_lease_free(DHCPLease
*lease
) {
147 free(lease
->client_id
.data
);
151 sd_dhcp_server
*sd_dhcp_server_unref(sd_dhcp_server
*server
) {
157 assert(server
->n_ref
>= 1);
160 if (server
->n_ref
> 0)
163 log_dhcp_server(server
, "UNREF");
165 sd_dhcp_server_stop(server
);
167 sd_event_unref(server
->event
);
169 free(server
->timezone
);
173 while ((lease
= hashmap_steal_first(server
->leases_by_client_id
)))
174 dhcp_lease_free(lease
);
175 hashmap_free(server
->leases_by_client_id
);
177 free(server
->bound_leases
);
183 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
184 _cleanup_dhcp_server_unref_ sd_dhcp_server
*server
= NULL
;
186 assert_return(ret
, -EINVAL
);
187 assert_return(ifindex
> 0, -EINVAL
);
189 server
= new0(sd_dhcp_server
, 1);
196 server
->address
= htobe32(INADDR_ANY
);
197 server
->netmask
= htobe32(INADDR_ANY
);
198 server
->ifindex
= ifindex
;
199 server
->leases_by_client_id
= hashmap_new(&client_id_hash_ops
);
200 server
->default_lease_time
= DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC
, USEC_PER_SEC
);
201 server
->max_lease_time
= DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC
, USEC_PER_SEC
);
209 int sd_dhcp_server_attach_event(sd_dhcp_server
*server
, sd_event
*event
,
213 assert_return(server
, -EINVAL
);
214 assert_return(!server
->event
, -EBUSY
);
217 server
->event
= sd_event_ref(event
);
219 r
= sd_event_default(&server
->event
);
224 server
->event_priority
= priority
;
229 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
230 assert_return(server
, -EINVAL
);
232 server
->event
= sd_event_unref(server
->event
);
237 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
238 assert_return(server
, NULL
);
240 return server
->event
;
243 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
244 assert_return(server
, -EINVAL
);
246 server
->receive_message
=
247 sd_event_source_unref(server
->receive_message
);
249 server
->fd_raw
= safe_close(server
->fd_raw
);
250 server
->fd
= safe_close(server
->fd
);
252 log_dhcp_server(server
, "STOPPED");
257 static int dhcp_server_send_unicast_raw(sd_dhcp_server
*server
,
258 DHCPPacket
*packet
, size_t len
) {
259 union sockaddr_union link
= {
260 .ll
.sll_family
= AF_PACKET
,
261 .ll
.sll_protocol
= htons(ETH_P_IP
),
262 .ll
.sll_ifindex
= server
->ifindex
,
263 .ll
.sll_halen
= ETH_ALEN
,
267 assert(server
->ifindex
> 0);
268 assert(server
->address
);
270 assert(len
> sizeof(DHCPPacket
));
272 memcpy(&link
.ll
.sll_addr
, &packet
->dhcp
.chaddr
, ETH_ALEN
);
274 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
276 DHCP_PORT_CLIENT
, len
);
278 return dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
281 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
282 DHCPMessage
*message
, size_t len
) {
283 union sockaddr_union dest
= {
284 .in
.sin_family
= AF_INET
,
285 .in
.sin_port
= htobe16(DHCP_PORT_CLIENT
),
286 .in
.sin_addr
.s_addr
= destination
,
292 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))] = {};
293 struct msghdr msg
= {
295 .msg_namelen
= sizeof(dest
.in
),
298 .msg_control
= cmsgbuf
,
299 .msg_controllen
= sizeof(cmsgbuf
),
301 struct cmsghdr
*cmsg
;
302 struct in_pktinfo
*pktinfo
;
306 assert(server
->fd
> 0);
308 assert(len
> sizeof(DHCPMessage
));
310 cmsg
= CMSG_FIRSTHDR(&msg
);
313 cmsg
->cmsg_level
= IPPROTO_IP
;
314 cmsg
->cmsg_type
= IP_PKTINFO
;
315 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
317 /* we attach source interface and address info to the message
318 rather than binding the socket. This will be mostly useful
319 when we gain support for arbitrary number of server addresses
321 pktinfo
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
324 pktinfo
->ipi_ifindex
= server
->ifindex
;
325 pktinfo
->ipi_spec_dst
.s_addr
= server
->address
;
327 r
= sendmsg(server
->fd
, &msg
, 0);
334 static bool requested_broadcast(DHCPRequest
*req
) {
337 return req
->message
->flags
& htobe16(0x8000);
340 int dhcp_server_send_packet(sd_dhcp_server
*server
,
341 DHCPRequest
*req
, DHCPPacket
*packet
,
342 int type
, size_t optoffset
) {
343 be32_t destination
= INADDR_ANY
;
348 assert(req
->max_optlen
);
349 assert(optoffset
<= req
->max_optlen
);
352 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
353 DHCP_OPTION_SERVER_IDENTIFIER
,
354 4, &server
->address
);
358 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
359 DHCP_OPTION_END
, 0, NULL
);
363 /* RFC 2131 Section 4.1
365 If the ’giaddr’ field in a DHCP message from a client is non-zero,
366 the server sends any return messages to the ’DHCP server’ port on the
367 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
368 field is zero and the ’ciaddr’ field is nonzero, then the server
369 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
370 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
371 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
372 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
373 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
374 messages to the client’s hardware address and ’yiaddr’ address. In
375 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
376 messages to 0xffffffff.
380 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
381 different subnet. The server MUST set the broadcast bit in the
382 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
383 client, because the client may not have a correct network address
384 or subnet mask, and the client may not be answering ARP requests.
386 if (req
->message
->giaddr
) {
387 destination
= req
->message
->giaddr
;
388 if (type
== DHCP_NAK
)
389 packet
->dhcp
.flags
= htobe16(0x8000);
390 } else if (req
->message
->ciaddr
&& type
!= DHCP_NAK
)
391 destination
= req
->message
->ciaddr
;
393 if (destination
!= INADDR_ANY
)
394 return dhcp_server_send_udp(server
, destination
, &packet
->dhcp
,
395 sizeof(DHCPMessage
) + optoffset
);
396 else if (requested_broadcast(req
) || type
== DHCP_NAK
)
397 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
399 sizeof(DHCPMessage
) + optoffset
);
401 /* we cannot send UDP packet to specific MAC address when the
402 address is not yet configured, so must fall back to raw
404 return dhcp_server_send_unicast_raw(server
, packet
,
405 sizeof(DHCPPacket
) + optoffset
);
408 static int server_message_init(sd_dhcp_server
*server
, DHCPPacket
**ret
,
409 uint8_t type
, size_t *_optoffset
,
411 _cleanup_free_ DHCPPacket
*packet
= NULL
;
412 size_t optoffset
= 0;
418 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
, DHCP_NAK
));
420 packet
= malloc0(sizeof(DHCPPacket
) + req
->max_optlen
);
424 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
,
425 be32toh(req
->message
->xid
), type
, ARPHRD_ETHER
,
426 req
->max_optlen
, &optoffset
);
430 packet
->dhcp
.flags
= req
->message
->flags
;
431 packet
->dhcp
.giaddr
= req
->message
->giaddr
;
432 memcpy(&packet
->dhcp
.chaddr
, &req
->message
->chaddr
, ETH_ALEN
);
434 *_optoffset
= optoffset
;
441 static int server_send_offer(sd_dhcp_server
*server
, DHCPRequest
*req
,
443 _cleanup_free_ DHCPPacket
*packet
= NULL
;
448 r
= server_message_init(server
, &packet
, DHCP_OFFER
, &offset
, req
);
452 packet
->dhcp
.yiaddr
= address
;
454 lease_time
= htobe32(req
->lifetime
);
455 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
456 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
461 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
462 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
466 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
467 DHCP_OPTION_ROUTER
, 4, &server
->address
);
471 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_OFFER
, offset
);
478 static int server_send_ack(sd_dhcp_server
*server
, DHCPRequest
*req
,
480 _cleanup_free_ DHCPPacket
*packet
= NULL
;
485 r
= server_message_init(server
, &packet
, DHCP_ACK
, &offset
, req
);
489 packet
->dhcp
.yiaddr
= address
;
491 lease_time
= htobe32(req
->lifetime
);
492 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
493 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
498 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
499 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
503 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
504 DHCP_OPTION_ROUTER
, 4, &server
->address
);
508 if (server
->n_dns
> 0) {
509 r
= dhcp_option_append(
510 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
511 DHCP_OPTION_DOMAIN_NAME_SERVER
,
512 sizeof(struct in_addr
) * server
->n_dns
, server
->dns
);
517 if (server
->n_ntp
> 0) {
518 r
= dhcp_option_append(
519 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
520 DHCP_OPTION_NTP_SERVER
,
521 sizeof(struct in_addr
) * server
->n_ntp
, server
->ntp
);
526 if (server
->timezone
) {
527 r
= dhcp_option_append(
528 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
529 DHCP_OPTION_NEW_TZDB_TIMEZONE
,
530 strlen(server
->timezone
), server
->timezone
);
535 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_ACK
, offset
);
542 static int server_send_nak(sd_dhcp_server
*server
, DHCPRequest
*req
) {
543 _cleanup_free_ DHCPPacket
*packet
= NULL
;
547 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
551 return dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
554 static int server_send_forcerenew(sd_dhcp_server
*server
, be32_t address
,
555 be32_t gateway
, uint8_t chaddr
[]) {
556 _cleanup_free_ DHCPPacket
*packet
= NULL
;
557 size_t optoffset
= 0;
561 assert(address
!= INADDR_ANY
);
564 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
568 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
569 DHCP_FORCERENEW
, ARPHRD_ETHER
,
570 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
574 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
575 &optoffset
, 0, DHCP_OPTION_END
, 0, NULL
);
579 memcpy(&packet
->dhcp
.chaddr
, chaddr
, ETH_ALEN
);
581 r
= dhcp_server_send_udp(server
, address
, &packet
->dhcp
,
582 sizeof(DHCPMessage
) + optoffset
);
589 static int parse_request(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
590 DHCPRequest
*req
= userdata
;
595 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
597 req
->lifetime
= be32toh(*(be32_t
*)option
);
600 case DHCP_OPTION_REQUESTED_IP_ADDRESS
:
602 req
->requested_ip
= *(be32_t
*)option
;
605 case DHCP_OPTION_SERVER_IDENTIFIER
:
607 req
->server_id
= *(be32_t
*)option
;
610 case DHCP_OPTION_CLIENT_IDENTIFIER
:
614 data
= memdup(option
, len
);
618 free(req
->client_id
.data
);
619 req
->client_id
.data
= data
;
620 req
->client_id
.length
= len
;
624 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
626 req
->max_optlen
= be16toh(*(be16_t
*)option
) -
627 - sizeof(DHCPPacket
);
635 static void dhcp_request_free(DHCPRequest
*req
) {
639 free(req
->client_id
.data
);
643 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
644 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
646 static int ensure_sane_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPMessage
*message
) {
650 req
->message
= message
;
652 /* set client id based on MAC address if client did not send an explicit
654 if (!req
->client_id
.data
) {
657 data
= malloc0(ETH_ALEN
+ 1);
661 ((uint8_t*) data
)[0] = 0x01;
662 memcpy((uint8_t*) data
+ 1, &message
->chaddr
, ETH_ALEN
);
664 req
->client_id
.length
= ETH_ALEN
+ 1;
665 req
->client_id
.data
= data
;
668 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
669 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
671 if (req
->lifetime
<= 0)
672 req
->lifetime
= MAX(1ULL, server
->default_lease_time
);
674 if (server
->max_lease_time
> 0 && req
->lifetime
> server
->max_lease_time
)
675 req
->lifetime
= server
->max_lease_time
;
680 static int get_pool_offset(sd_dhcp_server
*server
, be32_t requested_ip
) {
683 if (!server
->pool_size
)
686 if (be32toh(requested_ip
) < (be32toh(server
->subnet
) | server
->pool_offset
) ||
687 be32toh(requested_ip
) >= (be32toh(server
->subnet
) | (server
->pool_offset
+ server
->pool_size
)))
690 return be32toh(requested_ip
& ~server
->netmask
) - server
->pool_offset
;
693 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
695 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
,
697 _cleanup_dhcp_request_free_ DHCPRequest
*req
= NULL
;
698 DHCPLease
*existing_lease
;
704 if (message
->op
!= BOOTREQUEST
||
705 message
->htype
!= ARPHRD_ETHER
||
706 message
->hlen
!= ETHER_ADDR_LEN
)
709 req
= new0(DHCPRequest
, 1);
713 type
= dhcp_option_parse(message
, length
, parse_request
, req
);
717 r
= ensure_sane_request(server
, req
, message
);
719 /* this only fails on critical errors */
722 existing_lease
= hashmap_get(server
->leases_by_client_id
,
727 case DHCP_DISCOVER
: {
728 be32_t address
= INADDR_ANY
;
731 log_dhcp_server(server
, "DISCOVER (0x%x)",
732 be32toh(req
->message
->xid
));
734 if (!server
->pool_size
)
735 /* no pool allocated */
738 /* for now pick a random free address from the pool */
740 address
= existing_lease
->address
;
742 struct siphash state
;
745 /* even with no persistence of leases, we try to offer the same client
746 the same IP address. we do this by using the hash of the client id
747 as the offset into the pool of leases when finding the next free one */
749 siphash_init(&state
, HASH_KEY
.bytes
);
750 client_id_hash_func(&req
->client_id
, &state
);
751 next_offer
= siphash24_finalize(&state
) % server
->pool_size
;
753 for (i
= 0; i
< server
->pool_size
; i
++) {
754 if (!server
->bound_leases
[next_offer
]) {
755 address
= server
->subnet
| htobe32(server
->pool_offset
+ next_offer
);
758 next_offer
= (next_offer
+ 1) % server
->pool_size
;
762 if (address
== INADDR_ANY
)
763 /* no free addresses left */
766 r
= server_send_offer(server
, req
, address
);
768 /* this only fails on critical errors */
769 log_dhcp_server(server
, "could not send offer: %s",
773 log_dhcp_server(server
, "OFFER (0x%x)",
774 be32toh(req
->message
->xid
));
781 log_dhcp_server(server
, "DECLINE (0x%x)",
782 be32toh(req
->message
->xid
));
784 /* TODO: make sure we don't offer this address again */
790 bool init_reboot
= false;
793 /* see RFC 2131, section 4.3.2 */
795 if (req
->server_id
) {
796 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
797 be32toh(req
->message
->xid
));
800 if (req
->server_id
!= server
->address
)
801 /* client did not pick us */
804 if (req
->message
->ciaddr
)
805 /* this MUST be zero */
808 if (!req
->requested_ip
)
809 /* this must be filled in with the yiaddr
810 from the chosen OFFER */
813 address
= req
->requested_ip
;
814 } else if (req
->requested_ip
) {
815 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
816 be32toh(req
->message
->xid
));
819 if (req
->message
->ciaddr
)
820 /* this MUST be zero */
823 /* TODO: check more carefully if IP is correct */
824 address
= req
->requested_ip
;
827 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
828 be32toh(req
->message
->xid
));
830 /* REBINDING / RENEWING */
831 if (!req
->message
->ciaddr
)
832 /* this MUST be filled in with clients IP address */
835 address
= req
->message
->ciaddr
;
838 pool_offset
= get_pool_offset(server
, address
);
840 /* verify that the requested address is from the pool, and either
841 owned by the current client or free */
842 if (pool_offset
>= 0 &&
843 server
->bound_leases
[pool_offset
] == existing_lease
) {
847 if (!existing_lease
) {
848 lease
= new0(DHCPLease
, 1);
849 lease
->address
= req
->requested_ip
;
850 lease
->client_id
.data
= memdup(req
->client_id
.data
,
851 req
->client_id
.length
);
852 if (!lease
->client_id
.data
) {
856 lease
->client_id
.length
= req
->client_id
.length
;
857 memcpy(&lease
->chaddr
, &req
->message
->chaddr
,
859 lease
->gateway
= req
->message
->giaddr
;
861 lease
= existing_lease
;
863 r
= sd_event_now(server
->event
,
864 clock_boottime_or_monotonic(),
868 dhcp_lease_free(lease
);
872 lease
->expiration
= req
->lifetime
* USEC_PER_SEC
+ time_now
;
874 r
= server_send_ack(server
, req
, address
);
876 /* this only fails on critical errors */
877 log_dhcp_server(server
, "could not send ack: %s",
881 dhcp_lease_free(lease
);
885 log_dhcp_server(server
, "ACK (0x%x)",
886 be32toh(req
->message
->xid
));
888 server
->bound_leases
[pool_offset
] = lease
;
889 hashmap_put(server
->leases_by_client_id
,
890 &lease
->client_id
, lease
);
894 } else if (init_reboot
) {
895 r
= server_send_nak(server
, req
);
897 /* this only fails on critical errors */
898 log_dhcp_server(server
, "could not send nak: %s",
902 log_dhcp_server(server
, "NAK (0x%x)",
903 be32toh(req
->message
->xid
));
914 log_dhcp_server(server
, "RELEASE (0x%x)",
915 be32toh(req
->message
->xid
));
920 if (existing_lease
->address
!= req
->message
->ciaddr
)
923 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
927 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
928 server
->bound_leases
[pool_offset
] = NULL
;
929 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
930 dhcp_lease_free(existing_lease
);
941 static int server_receive_message(sd_event_source
*s
, int fd
,
942 uint32_t revents
, void *userdata
) {
943 _cleanup_free_ DHCPMessage
*message
= NULL
;
944 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))];
945 sd_dhcp_server
*server
= userdata
;
946 struct iovec iov
= {};
947 struct msghdr msg
= {
950 .msg_control
= cmsgbuf
,
951 .msg_controllen
= sizeof(cmsgbuf
),
953 struct cmsghdr
*cmsg
;
958 if (ioctl(fd
, FIONREAD
, &buflen
) < 0)
963 message
= malloc0(buflen
);
967 iov
.iov_base
= message
;
968 iov
.iov_len
= buflen
;
970 len
= recvmsg(fd
, &msg
, 0);
973 else if ((size_t)len
< sizeof(DHCPMessage
))
976 CMSG_FOREACH(cmsg
, &msg
) {
977 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
978 cmsg
->cmsg_type
== IP_PKTINFO
&&
979 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
980 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
982 /* TODO figure out if this can be done as a filter on
983 * the socket, like for IPv6 */
984 if (server
->ifindex
!= info
->ipi_ifindex
)
991 return dhcp_server_handle_message(server
, message
, (size_t)len
);
994 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
997 assert_return(server
, -EINVAL
);
998 assert_return(server
->event
, -EINVAL
);
999 assert_return(!server
->receive_message
, -EBUSY
);
1000 assert_return(server
->fd_raw
== -1, -EBUSY
);
1001 assert_return(server
->fd
== -1, -EBUSY
);
1002 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
1004 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0);
1007 sd_dhcp_server_stop(server
);
1012 r
= dhcp_network_bind_udp_socket(INADDR_ANY
, DHCP_PORT_SERVER
);
1014 sd_dhcp_server_stop(server
);
1019 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
1020 server
->fd
, EPOLLIN
,
1021 server_receive_message
, server
);
1023 sd_dhcp_server_stop(server
);
1027 r
= sd_event_source_set_priority(server
->receive_message
,
1028 server
->event_priority
);
1030 sd_dhcp_server_stop(server
);
1034 log_dhcp_server(server
, "STARTED");
1039 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1043 assert_return(server
, -EINVAL
);
1044 assert(server
->bound_leases
);
1046 for (i
= 0; i
< server
->pool_size
; i
++) {
1047 DHCPLease
*lease
= server
->bound_leases
[i
];
1049 if (!lease
|| lease
== &server
->invalid_lease
)
1052 r
= server_send_forcerenew(server
, lease
->address
,
1058 log_dhcp_server(server
, "FORCERENEW");
1064 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *tz
) {
1067 assert_return(server
, -EINVAL
);
1068 assert_return(timezone_is_valid(tz
), -EINVAL
);
1070 if (streq_ptr(tz
, server
->timezone
))
1073 r
= free_and_strdup(&server
->timezone
, tz
);
1080 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1081 assert_return(server
, -EINVAL
);
1083 if (t
== server
->max_lease_time
)
1086 server
->max_lease_time
= t
;
1090 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1091 assert_return(server
, -EINVAL
);
1093 if (t
== server
->default_lease_time
)
1096 server
->default_lease_time
= t
;
1100 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], unsigned n
) {
1101 assert_return(server
, -EINVAL
);
1102 assert_return(dns
|| n
<= 0, -EINVAL
);
1104 if (server
->n_dns
== n
&&
1105 memcmp(server
->dns
, dns
, sizeof(struct in_addr
) * n
) == 0)
1109 server
->dns
= mfree(server
->dns
);
1114 c
= newdup(struct in_addr
, dns
, n
);
1126 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], unsigned n
) {
1127 assert_return(server
, -EINVAL
);
1128 assert_return(ntp
|| n
<= 0, -EINVAL
);
1130 if (server
->n_ntp
== n
&&
1131 memcmp(server
->ntp
, ntp
, sizeof(struct in_addr
) * n
) == 0)
1135 server
->ntp
= mfree(server
->ntp
);
1140 c
= newdup(struct in_addr
, ntp
, n
);