2 This file is part of systemd.
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
5 Copyright (C) 2014 Tom Gundersen
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <sys/ioctl.h>
23 #include "sd-dhcp-server.h"
25 #include "alloc-util.h"
26 #include "dhcp-internal.h"
27 #include "dhcp-server-internal.h"
29 #include "in-addr-util.h"
30 #include "siphash24.h"
31 #include "string-util.h"
32 #include "unaligned.h"
34 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
35 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
37 static void dhcp_lease_free(DHCPLease
*lease
) {
41 free(lease
->client_id
.data
);
45 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
46 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
47 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
48 * accidentally hand it out */
49 int sd_dhcp_server_configure_pool(sd_dhcp_server
*server
, struct in_addr
*address
, unsigned char prefixlen
, uint32_t offset
, uint32_t size
) {
50 struct in_addr netmask_addr
;
52 uint32_t server_off
, broadcast_off
, size_max
;
54 assert_return(server
, -EINVAL
);
55 assert_return(address
, -EINVAL
);
56 assert_return(address
->s_addr
!= INADDR_ANY
, -EINVAL
);
57 assert_return(prefixlen
<= 32, -ERANGE
);
59 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr
, prefixlen
));
60 netmask
= netmask_addr
.s_addr
;
62 server_off
= be32toh(address
->s_addr
& ~netmask
);
63 broadcast_off
= be32toh(~netmask
);
65 /* the server address cannot be the subnet address */
66 assert_return(server_off
!= 0, -ERANGE
);
68 /* nor the broadcast address */
69 assert_return(server_off
!= broadcast_off
, -ERANGE
);
71 /* 0 offset means we should set a default, we skip the first (subnet) address
72 and take the next one */
76 size_max
= (broadcast_off
+ 1) /* the number of addresses in the subnet */
77 - offset
/* exclude the addresses before the offset */
78 - 1; /* exclude the last (broadcast) address */
80 /* The pool must contain at least one address */
81 assert_return(size_max
>= 1, -ERANGE
);
84 assert_return(size
<= size_max
, -ERANGE
);
88 if (server
->address
!= address
->s_addr
|| server
->netmask
!= netmask
|| server
->pool_size
!= size
|| server
->pool_offset
!= offset
) {
91 free(server
->bound_leases
);
92 server
->bound_leases
= new0(DHCPLease
*, size
);
93 if (!server
->bound_leases
)
96 server
->pool_offset
= offset
;
97 server
->pool_size
= size
;
99 server
->address
= address
->s_addr
;
100 server
->netmask
= netmask
;
101 server
->subnet
= address
->s_addr
& netmask
;
103 if (server_off
>= offset
&& server_off
- offset
< size
)
104 server
->bound_leases
[server_off
- offset
] = &server
->invalid_lease
;
106 /* Drop any leases associated with the old address range */
107 while ((lease
= hashmap_steal_first(server
->leases_by_client_id
)))
108 dhcp_lease_free(lease
);
114 int sd_dhcp_server_is_running(sd_dhcp_server
*server
) {
115 assert_return(server
, false);
117 return !!server
->receive_message
;
120 sd_dhcp_server
*sd_dhcp_server_ref(sd_dhcp_server
*server
) {
125 assert(server
->n_ref
>= 1);
131 void client_id_hash_func(const void *p
, struct siphash
*state
) {
132 const DHCPClientId
*id
= p
;
138 siphash24_compress(&id
->length
, sizeof(id
->length
), state
);
139 siphash24_compress(id
->data
, id
->length
, state
);
142 int client_id_compare_func(const void *_a
, const void *_b
) {
143 const DHCPClientId
*a
, *b
;
148 assert(!a
->length
|| a
->data
);
149 assert(!b
->length
|| b
->data
);
151 if (a
->length
!= b
->length
)
152 return a
->length
< b
->length
? -1 : 1;
154 return memcmp(a
->data
, b
->data
, a
->length
);
157 static const struct hash_ops client_id_hash_ops
= {
158 .hash
= client_id_hash_func
,
159 .compare
= client_id_compare_func
162 sd_dhcp_server
*sd_dhcp_server_unref(sd_dhcp_server
*server
) {
168 assert(server
->n_ref
>= 1);
171 if (server
->n_ref
> 0)
174 log_dhcp_server(server
, "UNREF");
176 sd_dhcp_server_stop(server
);
178 sd_event_unref(server
->event
);
180 free(server
->timezone
);
184 while ((lease
= hashmap_steal_first(server
->leases_by_client_id
)))
185 dhcp_lease_free(lease
);
186 hashmap_free(server
->leases_by_client_id
);
188 free(server
->bound_leases
);
189 return mfree(server
);
192 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
193 _cleanup_(sd_dhcp_server_unrefp
) sd_dhcp_server
*server
= NULL
;
195 assert_return(ret
, -EINVAL
);
196 assert_return(ifindex
> 0, -EINVAL
);
198 server
= new0(sd_dhcp_server
, 1);
205 server
->address
= htobe32(INADDR_ANY
);
206 server
->netmask
= htobe32(INADDR_ANY
);
207 server
->ifindex
= ifindex
;
209 server
->leases_by_client_id
= hashmap_new(&client_id_hash_ops
);
210 if (!server
->leases_by_client_id
)
213 server
->default_lease_time
= DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC
, USEC_PER_SEC
);
214 server
->max_lease_time
= DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC
, USEC_PER_SEC
);
222 int sd_dhcp_server_attach_event(sd_dhcp_server
*server
, sd_event
*event
, int64_t priority
) {
225 assert_return(server
, -EINVAL
);
226 assert_return(!server
->event
, -EBUSY
);
229 server
->event
= sd_event_ref(event
);
231 r
= sd_event_default(&server
->event
);
236 server
->event_priority
= priority
;
241 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
242 assert_return(server
, -EINVAL
);
244 server
->event
= sd_event_unref(server
->event
);
249 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
250 assert_return(server
, NULL
);
252 return server
->event
;
255 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
256 assert_return(server
, -EINVAL
);
258 server
->receive_message
=
259 sd_event_source_unref(server
->receive_message
);
261 server
->fd_raw
= safe_close(server
->fd_raw
);
262 server
->fd
= safe_close(server
->fd
);
264 log_dhcp_server(server
, "STOPPED");
269 static int dhcp_server_send_unicast_raw(sd_dhcp_server
*server
,
270 DHCPPacket
*packet
, size_t len
) {
271 union sockaddr_union link
= {
272 .ll
.sll_family
= AF_PACKET
,
273 .ll
.sll_protocol
= htobe16(ETH_P_IP
),
274 .ll
.sll_ifindex
= server
->ifindex
,
275 .ll
.sll_halen
= ETH_ALEN
,
279 assert(server
->ifindex
> 0);
280 assert(server
->address
);
282 assert(len
> sizeof(DHCPPacket
));
284 memcpy(&link
.ll
.sll_addr
, &packet
->dhcp
.chaddr
, ETH_ALEN
);
286 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
288 DHCP_PORT_CLIENT
, len
);
290 return dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
293 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
294 uint16_t destination_port
,
295 DHCPMessage
*message
, size_t len
) {
296 union sockaddr_union dest
= {
297 .in
.sin_family
= AF_INET
,
298 .in
.sin_port
= htobe16(destination_port
),
299 .in
.sin_addr
.s_addr
= destination
,
305 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))] = {};
306 struct msghdr msg
= {
308 .msg_namelen
= sizeof(dest
.in
),
311 .msg_control
= cmsgbuf
,
312 .msg_controllen
= sizeof(cmsgbuf
),
314 struct cmsghdr
*cmsg
;
315 struct in_pktinfo
*pktinfo
;
319 assert(server
->fd
> 0);
321 assert(len
> sizeof(DHCPMessage
));
323 cmsg
= CMSG_FIRSTHDR(&msg
);
326 cmsg
->cmsg_level
= IPPROTO_IP
;
327 cmsg
->cmsg_type
= IP_PKTINFO
;
328 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
330 /* we attach source interface and address info to the message
331 rather than binding the socket. This will be mostly useful
332 when we gain support for arbitrary number of server addresses
334 pktinfo
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
337 pktinfo
->ipi_ifindex
= server
->ifindex
;
338 pktinfo
->ipi_spec_dst
.s_addr
= server
->address
;
340 r
= sendmsg(server
->fd
, &msg
, 0);
347 static bool requested_broadcast(DHCPRequest
*req
) {
350 return req
->message
->flags
& htobe16(0x8000);
353 int dhcp_server_send_packet(sd_dhcp_server
*server
,
354 DHCPRequest
*req
, DHCPPacket
*packet
,
355 int type
, size_t optoffset
) {
356 be32_t destination
= INADDR_ANY
;
357 uint16_t destination_port
= DHCP_PORT_CLIENT
;
362 assert(req
->max_optlen
);
363 assert(optoffset
<= req
->max_optlen
);
366 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
367 SD_DHCP_OPTION_SERVER_IDENTIFIER
,
368 4, &server
->address
);
372 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
373 SD_DHCP_OPTION_END
, 0, NULL
);
377 /* RFC 2131 Section 4.1
379 If the ’giaddr’ field in a DHCP message from a client is non-zero,
380 the server sends any return messages to the ’DHCP server’ port on the
381 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
382 field is zero and the ’ciaddr’ field is nonzero, then the server
383 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
384 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
385 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
386 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
387 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
388 messages to the client’s hardware address and ’yiaddr’ address. In
389 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
390 messages to 0xffffffff.
394 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
395 different subnet. The server MUST set the broadcast bit in the
396 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
397 client, because the client may not have a correct network address
398 or subnet mask, and the client may not be answering ARP requests.
400 if (req
->message
->giaddr
) {
401 destination
= req
->message
->giaddr
;
402 destination_port
= DHCP_PORT_SERVER
;
403 if (type
== DHCP_NAK
)
404 packet
->dhcp
.flags
= htobe16(0x8000);
405 } else if (req
->message
->ciaddr
&& type
!= DHCP_NAK
)
406 destination
= req
->message
->ciaddr
;
408 if (destination
!= INADDR_ANY
)
409 return dhcp_server_send_udp(server
, destination
,
410 destination_port
, &packet
->dhcp
,
411 sizeof(DHCPMessage
) + optoffset
);
412 else if (requested_broadcast(req
) || type
== DHCP_NAK
)
413 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
414 destination_port
, &packet
->dhcp
,
415 sizeof(DHCPMessage
) + optoffset
);
417 /* we cannot send UDP packet to specific MAC address when the
418 address is not yet configured, so must fall back to raw
420 return dhcp_server_send_unicast_raw(server
, packet
,
421 sizeof(DHCPPacket
) + optoffset
);
424 static int server_message_init(sd_dhcp_server
*server
, DHCPPacket
**ret
,
425 uint8_t type
, size_t *_optoffset
,
427 _cleanup_free_ DHCPPacket
*packet
= NULL
;
428 size_t optoffset
= 0;
434 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
, DHCP_NAK
));
436 packet
= malloc0(sizeof(DHCPPacket
) + req
->max_optlen
);
440 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
,
441 be32toh(req
->message
->xid
), type
, ARPHRD_ETHER
,
442 req
->max_optlen
, &optoffset
);
446 packet
->dhcp
.flags
= req
->message
->flags
;
447 packet
->dhcp
.giaddr
= req
->message
->giaddr
;
448 memcpy(&packet
->dhcp
.chaddr
, &req
->message
->chaddr
, ETH_ALEN
);
450 *_optoffset
= optoffset
;
457 static int server_send_offer(sd_dhcp_server
*server
, DHCPRequest
*req
,
459 _cleanup_free_ DHCPPacket
*packet
= NULL
;
464 r
= server_message_init(server
, &packet
, DHCP_OFFER
, &offset
, req
);
468 packet
->dhcp
.yiaddr
= address
;
470 lease_time
= htobe32(req
->lifetime
);
471 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
472 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
477 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
478 SD_DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
482 if (server
->emit_router
) {
483 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
484 SD_DHCP_OPTION_ROUTER
, 4, &server
->address
);
489 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_OFFER
, offset
);
496 static int server_send_ack(sd_dhcp_server
*server
, DHCPRequest
*req
,
498 _cleanup_free_ DHCPPacket
*packet
= NULL
;
503 r
= server_message_init(server
, &packet
, DHCP_ACK
, &offset
, req
);
507 packet
->dhcp
.yiaddr
= address
;
509 lease_time
= htobe32(req
->lifetime
);
510 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
511 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
516 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
517 SD_DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
521 if (server
->emit_router
) {
522 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
523 SD_DHCP_OPTION_ROUTER
, 4, &server
->address
);
528 if (server
->n_dns
> 0) {
529 r
= dhcp_option_append(
530 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
531 SD_DHCP_OPTION_DOMAIN_NAME_SERVER
,
532 sizeof(struct in_addr
) * server
->n_dns
, server
->dns
);
537 if (server
->n_ntp
> 0) {
538 r
= dhcp_option_append(
539 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
540 SD_DHCP_OPTION_NTP_SERVER
,
541 sizeof(struct in_addr
) * server
->n_ntp
, server
->ntp
);
546 if (server
->timezone
) {
547 r
= dhcp_option_append(
548 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
549 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
,
550 strlen(server
->timezone
), server
->timezone
);
555 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_ACK
, offset
);
562 static int server_send_nak(sd_dhcp_server
*server
, DHCPRequest
*req
) {
563 _cleanup_free_ DHCPPacket
*packet
= NULL
;
567 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
571 return dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
574 static int server_send_forcerenew(sd_dhcp_server
*server
, be32_t address
,
575 be32_t gateway
, uint8_t chaddr
[]) {
576 _cleanup_free_ DHCPPacket
*packet
= NULL
;
577 size_t optoffset
= 0;
581 assert(address
!= INADDR_ANY
);
584 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
588 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
589 DHCP_FORCERENEW
, ARPHRD_ETHER
,
590 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
594 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
595 &optoffset
, 0, SD_DHCP_OPTION_END
, 0, NULL
);
599 memcpy(&packet
->dhcp
.chaddr
, chaddr
, ETH_ALEN
);
601 r
= dhcp_server_send_udp(server
, address
, DHCP_PORT_CLIENT
,
603 sizeof(DHCPMessage
) + optoffset
);
610 static int parse_request(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
611 DHCPRequest
*req
= userdata
;
616 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
618 req
->lifetime
= unaligned_read_be32(option
);
621 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
:
623 memcpy(&req
->requested_ip
, option
, sizeof(be32_t
));
626 case SD_DHCP_OPTION_SERVER_IDENTIFIER
:
628 memcpy(&req
->server_id
, option
, sizeof(be32_t
));
631 case SD_DHCP_OPTION_CLIENT_IDENTIFIER
:
635 data
= memdup(option
, len
);
639 free(req
->client_id
.data
);
640 req
->client_id
.data
= data
;
641 req
->client_id
.length
= len
;
645 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
647 if (len
== 2 && unaligned_read_be16(option
) >= sizeof(DHCPPacket
))
648 req
->max_optlen
= unaligned_read_be16(option
) - sizeof(DHCPPacket
);
656 static void dhcp_request_free(DHCPRequest
*req
) {
660 free(req
->client_id
.data
);
664 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
665 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
667 static int ensure_sane_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPMessage
*message
) {
671 req
->message
= message
;
673 /* set client id based on MAC address if client did not send an explicit
675 if (!req
->client_id
.data
) {
678 data
= malloc0(ETH_ALEN
+ 1);
682 ((uint8_t*) data
)[0] = 0x01;
683 memcpy((uint8_t*) data
+ 1, &message
->chaddr
, ETH_ALEN
);
685 req
->client_id
.length
= ETH_ALEN
+ 1;
686 req
->client_id
.data
= data
;
689 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
690 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
692 if (req
->lifetime
<= 0)
693 req
->lifetime
= MAX(1ULL, server
->default_lease_time
);
695 if (server
->max_lease_time
> 0 && req
->lifetime
> server
->max_lease_time
)
696 req
->lifetime
= server
->max_lease_time
;
701 static int get_pool_offset(sd_dhcp_server
*server
, be32_t requested_ip
) {
704 if (!server
->pool_size
)
707 if (be32toh(requested_ip
) < (be32toh(server
->subnet
) | server
->pool_offset
) ||
708 be32toh(requested_ip
) >= (be32toh(server
->subnet
) | (server
->pool_offset
+ server
->pool_size
)))
711 return be32toh(requested_ip
& ~server
->netmask
) - server
->pool_offset
;
714 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
716 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
,
718 _cleanup_dhcp_request_free_ DHCPRequest
*req
= NULL
;
719 _cleanup_free_
char *error_message
= NULL
;
720 DHCPLease
*existing_lease
;
726 if (message
->op
!= BOOTREQUEST
||
727 message
->htype
!= ARPHRD_ETHER
||
728 message
->hlen
!= ETHER_ADDR_LEN
)
731 req
= new0(DHCPRequest
, 1);
735 type
= dhcp_option_parse(message
, length
, parse_request
, req
, &error_message
);
739 r
= ensure_sane_request(server
, req
, message
);
741 /* this only fails on critical errors */
744 existing_lease
= hashmap_get(server
->leases_by_client_id
,
749 case DHCP_DISCOVER
: {
750 be32_t address
= INADDR_ANY
;
753 log_dhcp_server(server
, "DISCOVER (0x%x)",
754 be32toh(req
->message
->xid
));
756 if (!server
->pool_size
)
757 /* no pool allocated */
760 /* for now pick a random free address from the pool */
762 address
= existing_lease
->address
;
764 struct siphash state
;
768 /* even with no persistence of leases, we try to offer the same client
769 the same IP address. we do this by using the hash of the client id
770 as the offset into the pool of leases when finding the next free one */
772 siphash24_init(&state
, HASH_KEY
.bytes
);
773 client_id_hash_func(&req
->client_id
, &state
);
774 hash
= htole64(siphash24_finalize(&state
));
775 next_offer
= hash
% server
->pool_size
;
777 for (i
= 0; i
< server
->pool_size
; i
++) {
778 if (!server
->bound_leases
[next_offer
]) {
779 address
= server
->subnet
| htobe32(server
->pool_offset
+ next_offer
);
782 next_offer
= (next_offer
+ 1) % server
->pool_size
;
786 if (address
== INADDR_ANY
)
787 /* no free addresses left */
790 r
= server_send_offer(server
, req
, address
);
792 /* this only fails on critical errors */
793 log_dhcp_server(server
, "could not send offer: %s",
797 log_dhcp_server(server
, "OFFER (0x%x)",
798 be32toh(req
->message
->xid
));
805 log_dhcp_server(server
, "DECLINE (0x%x): %s", be32toh(req
->message
->xid
), strna(error_message
));
807 /* TODO: make sure we don't offer this address again */
813 bool init_reboot
= false;
816 /* see RFC 2131, section 4.3.2 */
818 if (req
->server_id
) {
819 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
820 be32toh(req
->message
->xid
));
823 if (req
->server_id
!= server
->address
)
824 /* client did not pick us */
827 if (req
->message
->ciaddr
)
828 /* this MUST be zero */
831 if (!req
->requested_ip
)
832 /* this must be filled in with the yiaddr
833 from the chosen OFFER */
836 address
= req
->requested_ip
;
837 } else if (req
->requested_ip
) {
838 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
839 be32toh(req
->message
->xid
));
842 if (req
->message
->ciaddr
)
843 /* this MUST be zero */
846 /* TODO: check more carefully if IP is correct */
847 address
= req
->requested_ip
;
850 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
851 be32toh(req
->message
->xid
));
853 /* REBINDING / RENEWING */
854 if (!req
->message
->ciaddr
)
855 /* this MUST be filled in with clients IP address */
858 address
= req
->message
->ciaddr
;
861 pool_offset
= get_pool_offset(server
, address
);
863 /* verify that the requested address is from the pool, and either
864 owned by the current client or free */
865 if (pool_offset
>= 0 &&
866 server
->bound_leases
[pool_offset
] == existing_lease
) {
870 if (!existing_lease
) {
871 lease
= new0(DHCPLease
, 1);
874 lease
->address
= address
;
875 lease
->client_id
.data
= memdup(req
->client_id
.data
,
876 req
->client_id
.length
);
877 if (!lease
->client_id
.data
) {
881 lease
->client_id
.length
= req
->client_id
.length
;
882 memcpy(&lease
->chaddr
, &req
->message
->chaddr
,
884 lease
->gateway
= req
->message
->giaddr
;
886 lease
= existing_lease
;
888 r
= sd_event_now(server
->event
,
889 clock_boottime_or_monotonic(),
893 dhcp_lease_free(lease
);
897 lease
->expiration
= req
->lifetime
* USEC_PER_SEC
+ time_now
;
899 r
= server_send_ack(server
, req
, address
);
901 /* this only fails on critical errors */
902 log_dhcp_server(server
, "could not send ack: %s",
906 dhcp_lease_free(lease
);
910 log_dhcp_server(server
, "ACK (0x%x)",
911 be32toh(req
->message
->xid
));
913 server
->bound_leases
[pool_offset
] = lease
;
914 hashmap_put(server
->leases_by_client_id
,
915 &lease
->client_id
, lease
);
919 } else if (init_reboot
) {
920 r
= server_send_nak(server
, req
);
922 /* this only fails on critical errors */
923 log_dhcp_server(server
, "could not send nak: %s",
927 log_dhcp_server(server
, "NAK (0x%x)",
928 be32toh(req
->message
->xid
));
939 log_dhcp_server(server
, "RELEASE (0x%x)",
940 be32toh(req
->message
->xid
));
945 if (existing_lease
->address
!= req
->message
->ciaddr
)
948 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
952 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
953 server
->bound_leases
[pool_offset
] = NULL
;
954 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
955 dhcp_lease_free(existing_lease
);
966 static int server_receive_message(sd_event_source
*s
, int fd
,
967 uint32_t revents
, void *userdata
) {
968 _cleanup_free_ DHCPMessage
*message
= NULL
;
969 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))];
970 sd_dhcp_server
*server
= userdata
;
971 struct iovec iov
= {};
972 struct msghdr msg
= {
975 .msg_control
= cmsgbuf
,
976 .msg_controllen
= sizeof(cmsgbuf
),
978 struct cmsghdr
*cmsg
;
983 buflen
= next_datagram_size_fd(fd
);
987 message
= malloc(buflen
);
991 iov
.iov_base
= message
;
992 iov
.iov_len
= buflen
;
994 len
= recvmsg(fd
, &msg
, 0);
996 if (IN_SET(errno
, EAGAIN
, EINTR
))
1000 } else if ((size_t)len
< sizeof(DHCPMessage
))
1003 CMSG_FOREACH(cmsg
, &msg
) {
1004 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
1005 cmsg
->cmsg_type
== IP_PKTINFO
&&
1006 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
1007 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
1009 /* TODO figure out if this can be done as a filter on
1010 * the socket, like for IPv6 */
1011 if (server
->ifindex
!= info
->ipi_ifindex
)
1018 return dhcp_server_handle_message(server
, message
, (size_t)len
);
1021 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
1024 assert_return(server
, -EINVAL
);
1025 assert_return(server
->event
, -EINVAL
);
1026 assert_return(!server
->receive_message
, -EBUSY
);
1027 assert_return(server
->fd_raw
== -1, -EBUSY
);
1028 assert_return(server
->fd
== -1, -EBUSY
);
1029 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
1031 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0);
1034 sd_dhcp_server_stop(server
);
1039 r
= dhcp_network_bind_udp_socket(server
->ifindex
, INADDR_ANY
, DHCP_PORT_SERVER
);
1041 sd_dhcp_server_stop(server
);
1046 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
1047 server
->fd
, EPOLLIN
,
1048 server_receive_message
, server
);
1050 sd_dhcp_server_stop(server
);
1054 r
= sd_event_source_set_priority(server
->receive_message
,
1055 server
->event_priority
);
1057 sd_dhcp_server_stop(server
);
1061 log_dhcp_server(server
, "STARTED");
1066 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1070 assert_return(server
, -EINVAL
);
1071 assert(server
->bound_leases
);
1073 for (i
= 0; i
< server
->pool_size
; i
++) {
1074 DHCPLease
*lease
= server
->bound_leases
[i
];
1076 if (!lease
|| lease
== &server
->invalid_lease
)
1079 r
= server_send_forcerenew(server
, lease
->address
,
1085 log_dhcp_server(server
, "FORCERENEW");
1091 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *tz
) {
1094 assert_return(server
, -EINVAL
);
1095 assert_return(timezone_is_valid(tz
), -EINVAL
);
1097 if (streq_ptr(tz
, server
->timezone
))
1100 r
= free_and_strdup(&server
->timezone
, tz
);
1107 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1108 assert_return(server
, -EINVAL
);
1110 if (t
== server
->max_lease_time
)
1113 server
->max_lease_time
= t
;
1117 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1118 assert_return(server
, -EINVAL
);
1120 if (t
== server
->default_lease_time
)
1123 server
->default_lease_time
= t
;
1127 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], unsigned n
) {
1128 assert_return(server
, -EINVAL
);
1129 assert_return(dns
|| n
<= 0, -EINVAL
);
1131 if (server
->n_dns
== n
&&
1132 memcmp(server
->dns
, dns
, sizeof(struct in_addr
) * n
) == 0)
1136 server
->dns
= mfree(server
->dns
);
1141 c
= newdup(struct in_addr
, dns
, n
);
1153 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], unsigned n
) {
1154 assert_return(server
, -EINVAL
);
1155 assert_return(ntp
|| n
<= 0, -EINVAL
);
1157 if (server
->n_ntp
== n
&&
1158 memcmp(server
->ntp
, ntp
, sizeof(struct in_addr
) * n
) == 0)
1162 server
->ntp
= mfree(server
->ntp
);
1167 c
= newdup(struct in_addr
, ntp
, n
);
1179 int sd_dhcp_server_set_emit_router(sd_dhcp_server
*server
, int enabled
) {
1180 assert_return(server
, -EINVAL
);
1182 if (enabled
== server
->emit_router
)
1185 server
->emit_router
= enabled
;