1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2013 Intel Corporation. All rights reserved.
6 #include <net/if_arp.h>
9 #include "sd-dhcp-server.h"
12 #include "alloc-util.h"
13 #include "dhcp-internal.h"
14 #include "dhcp-server-internal.h"
16 #include "in-addr-util.h"
18 #include "network-common.h"
19 #include "ordered-set.h"
20 #include "siphash24.h"
21 #include "string-util.h"
22 #include "unaligned.h"
24 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
25 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
27 static DHCPLease
*dhcp_lease_free(DHCPLease
*lease
) {
31 free(lease
->client_id
.data
);
35 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease
*, dhcp_lease_free
);
37 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
38 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
39 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
40 * accidentally hand it out */
41 int sd_dhcp_server_configure_pool(
42 sd_dhcp_server
*server
,
43 const struct in_addr
*address
,
44 unsigned char prefixlen
,
48 struct in_addr netmask_addr
;
50 uint32_t server_off
, broadcast_off
, size_max
;
52 assert_return(server
, -EINVAL
);
53 assert_return(address
, -EINVAL
);
54 assert_return(address
->s_addr
!= INADDR_ANY
, -EINVAL
);
55 assert_return(prefixlen
<= 32, -ERANGE
);
57 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr
, prefixlen
));
58 netmask
= netmask_addr
.s_addr
;
60 server_off
= be32toh(address
->s_addr
& ~netmask
);
61 broadcast_off
= be32toh(~netmask
);
63 /* the server address cannot be the subnet address */
64 assert_return(server_off
!= 0, -ERANGE
);
66 /* nor the broadcast address */
67 assert_return(server_off
!= broadcast_off
, -ERANGE
);
69 /* 0 offset means we should set a default, we skip the first (subnet) address
70 and take the next one */
74 size_max
= (broadcast_off
+ 1) /* the number of addresses in the subnet */
75 - offset
/* exclude the addresses before the offset */
76 - 1; /* exclude the last (broadcast) address */
78 /* The pool must contain at least one address */
79 assert_return(size_max
>= 1, -ERANGE
);
82 assert_return(size
<= size_max
, -ERANGE
);
86 if (server
->address
!= address
->s_addr
|| server
->netmask
!= netmask
|| server
->pool_size
!= size
|| server
->pool_offset
!= offset
) {
88 free(server
->bound_leases
);
89 server
->bound_leases
= new0(DHCPLease
*, size
);
90 if (!server
->bound_leases
)
93 server
->pool_offset
= offset
;
94 server
->pool_size
= size
;
96 server
->address
= address
->s_addr
;
97 server
->netmask
= netmask
;
98 server
->subnet
= address
->s_addr
& netmask
;
100 if (server_off
>= offset
&& server_off
- offset
< size
)
101 server
->bound_leases
[server_off
- offset
] = &server
->invalid_lease
;
103 /* Drop any leases associated with the old address range */
104 hashmap_clear(server
->leases_by_client_id
);
106 if (server
->callback
)
107 server
->callback(server
, SD_DHCP_SERVER_EVENT_LEASE_CHANGED
, server
->callback_userdata
);
113 int sd_dhcp_server_is_running(sd_dhcp_server
*server
) {
114 assert_return(server
, false);
116 return !!server
->receive_message
;
119 int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server
*server
) {
120 assert_return(server
, -EINVAL
);
122 return in4_addr_is_set(&server
->relay_target
);
125 void client_id_hash_func(const DHCPClientId
*id
, struct siphash
*state
) {
130 siphash24_compress(&id
->length
, sizeof(id
->length
), state
);
131 siphash24_compress(id
->data
, id
->length
, state
);
134 int client_id_compare_func(const DHCPClientId
*a
, const DHCPClientId
*b
) {
137 assert(!a
->length
|| a
->data
);
138 assert(!b
->length
|| b
->data
);
140 r
= CMP(a
->length
, b
->length
);
144 return memcmp(a
->data
, b
->data
, a
->length
);
147 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(dhcp_lease_hash_ops
, DHCPClientId
, client_id_hash_func
, client_id_compare_func
,
148 DHCPLease
, dhcp_lease_free
);
150 static sd_dhcp_server
*dhcp_server_free(sd_dhcp_server
*server
) {
153 log_dhcp_server(server
, "UNREF");
155 sd_dhcp_server_stop(server
);
157 sd_event_unref(server
->event
);
159 free(server
->timezone
);
161 for (sd_dhcp_lease_server_type_t i
= 0; i
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
; i
++)
162 free(server
->servers
[i
].addr
);
164 hashmap_free(server
->leases_by_client_id
);
165 hashmap_free(server
->static_leases_by_client_id
);
167 ordered_set_free(server
->extra_options
);
168 ordered_set_free(server
->vendor_options
);
170 free(server
->agent_circuit_id
);
171 free(server
->agent_remote_id
);
173 free(server
->bound_leases
);
175 free(server
->ifname
);
176 return mfree(server
);
179 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server
, sd_dhcp_server
, dhcp_server_free
);
181 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
182 _cleanup_(sd_dhcp_server_unrefp
) sd_dhcp_server
*server
= NULL
;
184 assert_return(ret
, -EINVAL
);
185 assert_return(ifindex
> 0, -EINVAL
);
187 server
= new(sd_dhcp_server
, 1);
191 *server
= (sd_dhcp_server
) {
196 .address
= htobe32(INADDR_ANY
),
197 .netmask
= htobe32(INADDR_ANY
),
199 .bind_to_interface
= true,
200 .default_lease_time
= DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC
, USEC_PER_SEC
),
201 .max_lease_time
= DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC
, USEC_PER_SEC
),
204 server
->leases_by_client_id
= hashmap_new(&dhcp_lease_hash_ops
);
205 if (!server
->leases_by_client_id
)
207 server
->static_leases_by_client_id
= hashmap_new(&dhcp_lease_hash_ops
);
208 if (!server
->static_leases_by_client_id
)
211 *ret
= TAKE_PTR(server
);
216 int sd_dhcp_server_set_ifname(sd_dhcp_server
*server
, const char *ifname
) {
217 assert_return(server
, -EINVAL
);
218 assert_return(ifname
, -EINVAL
);
220 if (!ifname_valid_full(ifname
, IFNAME_VALID_ALTERNATIVE
))
223 return free_and_strdup(&server
->ifname
, ifname
);
226 const char *sd_dhcp_server_get_ifname(sd_dhcp_server
*server
) {
230 return get_ifname(server
->ifindex
, &server
->ifname
);
233 int sd_dhcp_server_attach_event(sd_dhcp_server
*server
, sd_event
*event
, int64_t priority
) {
236 assert_return(server
, -EINVAL
);
237 assert_return(!server
->event
, -EBUSY
);
240 server
->event
= sd_event_ref(event
);
242 r
= sd_event_default(&server
->event
);
247 server
->event_priority
= priority
;
252 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
253 assert_return(server
, -EINVAL
);
255 server
->event
= sd_event_unref(server
->event
);
260 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
261 assert_return(server
, NULL
);
263 return server
->event
;
266 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
270 server
->receive_message
= sd_event_source_unref(server
->receive_message
);
271 server
->receive_broadcast
= sd_event_source_unref(server
->receive_broadcast
);
273 server
->fd_raw
= safe_close(server
->fd_raw
);
274 server
->fd
= safe_close(server
->fd
);
275 server
->fd_broadcast
= safe_close(server
->fd_broadcast
);
277 log_dhcp_server(server
, "STOPPED");
282 static int dhcp_server_send_unicast_raw(sd_dhcp_server
*server
,
283 DHCPPacket
*packet
, size_t len
) {
284 union sockaddr_union link
= {
285 .ll
.sll_family
= AF_PACKET
,
286 .ll
.sll_protocol
= htobe16(ETH_P_IP
),
287 .ll
.sll_ifindex
= server
->ifindex
,
288 .ll
.sll_halen
= ETH_ALEN
,
292 assert(server
->ifindex
> 0);
293 assert(server
->address
);
295 assert(len
> sizeof(DHCPPacket
));
297 memcpy(&link
.ll
.sll_addr
, &packet
->dhcp
.chaddr
, ETH_ALEN
);
299 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
301 DHCP_PORT_CLIENT
, len
, -1);
303 return dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
306 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
307 uint16_t destination_port
,
308 DHCPMessage
*message
, size_t len
) {
309 union sockaddr_union dest
= {
310 .in
.sin_family
= AF_INET
,
311 .in
.sin_port
= htobe16(destination_port
),
312 .in
.sin_addr
.s_addr
= destination
,
318 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo
))) control
= {};
319 struct msghdr msg
= {
321 .msg_namelen
= sizeof(dest
.in
),
325 struct cmsghdr
*cmsg
;
326 struct in_pktinfo
*pktinfo
;
329 assert(server
->fd
>= 0);
331 assert(len
> sizeof(DHCPMessage
));
333 if (server
->bind_to_interface
) {
334 msg
.msg_control
= &control
;
335 msg
.msg_controllen
= sizeof(control
);
337 cmsg
= CMSG_FIRSTHDR(&msg
);
340 cmsg
->cmsg_level
= IPPROTO_IP
;
341 cmsg
->cmsg_type
= IP_PKTINFO
;
342 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
344 /* we attach source interface and address info to the message
345 rather than binding the socket. This will be mostly useful
346 when we gain support for arbitrary number of server addresses
348 pktinfo
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
351 pktinfo
->ipi_ifindex
= server
->ifindex
;
352 pktinfo
->ipi_spec_dst
.s_addr
= server
->address
;
355 if (sendmsg(server
->fd
, &msg
, 0) < 0)
361 static bool requested_broadcast(DHCPMessage
*message
) {
363 return message
->flags
& htobe16(0x8000);
366 static int dhcp_server_send(sd_dhcp_server
*server
, be32_t destination
, uint16_t destination_port
,
367 DHCPPacket
*packet
, size_t optoffset
, bool l2_broadcast
) {
368 if (destination
!= INADDR_ANY
)
369 return dhcp_server_send_udp(server
, destination
,
370 destination_port
, &packet
->dhcp
,
371 sizeof(DHCPMessage
) + optoffset
);
372 else if (l2_broadcast
)
373 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
374 destination_port
, &packet
->dhcp
,
375 sizeof(DHCPMessage
) + optoffset
);
377 /* we cannot send UDP packet to specific MAC address when the
378 address is not yet configured, so must fall back to raw
380 return dhcp_server_send_unicast_raw(server
, packet
,
381 sizeof(DHCPPacket
) + optoffset
);
384 int dhcp_server_send_packet(sd_dhcp_server
*server
,
385 DHCPRequest
*req
, DHCPPacket
*packet
,
386 int type
, size_t optoffset
) {
387 be32_t destination
= INADDR_ANY
;
388 uint16_t destination_port
= DHCP_PORT_CLIENT
;
393 assert(req
->max_optlen
);
394 assert(req
->message
);
395 assert(optoffset
<= req
->max_optlen
);
398 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
399 SD_DHCP_OPTION_SERVER_IDENTIFIER
,
400 4, &server
->address
);
404 if (req
->agent_info_option
) {
405 size_t opt_full_length
= *(req
->agent_info_option
+ 1) + 2;
406 /* there must be space left for SD_DHCP_OPTION_END */
407 if (optoffset
+ opt_full_length
< req
->max_optlen
) {
408 memcpy(packet
->dhcp
.options
+ optoffset
, req
->agent_info_option
, opt_full_length
);
409 optoffset
+= opt_full_length
;
413 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
414 SD_DHCP_OPTION_END
, 0, NULL
);
418 /* RFC 2131 Section 4.1
420 If the ’giaddr’ field in a DHCP message from a client is non-zero,
421 the server sends any return messages to the ’DHCP server’ port on the
422 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
423 field is zero and the ’ciaddr’ field is nonzero, then the server
424 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
425 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
426 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
427 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
428 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
429 messages to the client’s hardware address and ’yiaddr’ address. In
430 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
431 messages to 0xffffffff.
435 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
436 different subnet. The server MUST set the broadcast bit in the
437 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
438 client, because the client may not have a correct network address
439 or subnet mask, and the client may not be answering ARP requests.
441 if (req
->message
->giaddr
) {
442 destination
= req
->message
->giaddr
;
443 destination_port
= DHCP_PORT_SERVER
;
444 if (type
== DHCP_NAK
)
445 packet
->dhcp
.flags
= htobe16(0x8000);
446 } else if (req
->message
->ciaddr
&& type
!= DHCP_NAK
)
447 destination
= req
->message
->ciaddr
;
449 bool l2_broadcast
= requested_broadcast(req
->message
) || type
== DHCP_NAK
;
450 return dhcp_server_send(server
, destination
, destination_port
, packet
, optoffset
, l2_broadcast
);
453 static int server_message_init(sd_dhcp_server
*server
, DHCPPacket
**ret
,
454 uint8_t type
, size_t *_optoffset
,
456 _cleanup_free_ DHCPPacket
*packet
= NULL
;
457 size_t optoffset
= 0;
463 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
, DHCP_NAK
));
465 packet
= malloc0(sizeof(DHCPPacket
) + req
->max_optlen
);
469 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
,
470 be32toh(req
->message
->xid
), type
, ARPHRD_ETHER
,
471 req
->max_optlen
, &optoffset
);
475 packet
->dhcp
.flags
= req
->message
->flags
;
476 packet
->dhcp
.giaddr
= req
->message
->giaddr
;
477 memcpy(&packet
->dhcp
.chaddr
, &req
->message
->chaddr
, ETH_ALEN
);
479 *_optoffset
= optoffset
;
480 *ret
= TAKE_PTR(packet
);
485 static int server_send_offer_or_ack(
486 sd_dhcp_server
*server
,
491 _cleanup_free_ DHCPPacket
*packet
= NULL
;
499 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
));
501 r
= server_message_init(server
, &packet
, type
, &offset
, req
);
505 packet
->dhcp
.yiaddr
= address
;
507 lease_time
= htobe32(req
->lifetime
);
508 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
509 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
514 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
515 SD_DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
519 if (server
->emit_router
) {
520 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
521 SD_DHCP_OPTION_ROUTER
, 4, &server
->address
);
526 if (type
== DHCP_ACK
) {
527 static const uint8_t option_map
[_SD_DHCP_LEASE_SERVER_TYPE_MAX
] = {
528 [SD_DHCP_LEASE_DNS
] = SD_DHCP_OPTION_DOMAIN_NAME_SERVER
,
529 [SD_DHCP_LEASE_NTP
] = SD_DHCP_OPTION_NTP_SERVER
,
530 [SD_DHCP_LEASE_SIP
] = SD_DHCP_OPTION_SIP_SERVER
,
531 [SD_DHCP_LEASE_POP3
] = SD_DHCP_OPTION_POP3_SERVER
,
532 [SD_DHCP_LEASE_SMTP
] = SD_DHCP_OPTION_SMTP_SERVER
,
533 [SD_DHCP_LEASE_LPR
] = SD_DHCP_OPTION_LPR_SERVER
,
536 for (sd_dhcp_lease_server_type_t k
= 0; k
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
; k
++) {
537 if (server
->servers
[k
].size
<= 0)
540 r
= dhcp_option_append(
541 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
543 sizeof(struct in_addr
) * server
->servers
[k
].size
,
544 server
->servers
[k
].addr
);
550 if (server
->timezone
) {
551 r
= dhcp_option_append(
552 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
553 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
,
554 strlen(server
->timezone
), server
->timezone
);
560 ORDERED_SET_FOREACH(j
, server
->extra_options
) {
561 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
562 j
->option
, j
->length
, j
->data
);
567 if (!ordered_set_isempty(server
->vendor_options
)) {
568 r
= dhcp_option_append(
569 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
570 SD_DHCP_OPTION_VENDOR_SPECIFIC
,
571 ordered_set_size(server
->vendor_options
), server
->vendor_options
);
576 r
= dhcp_server_send_packet(server
, req
, packet
, type
, offset
);
583 static int server_send_nak(sd_dhcp_server
*server
, DHCPRequest
*req
) {
584 _cleanup_free_ DHCPPacket
*packet
= NULL
;
588 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
592 return dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
595 static int server_send_forcerenew(sd_dhcp_server
*server
, be32_t address
,
596 be32_t gateway
, const uint8_t chaddr
[]) {
597 _cleanup_free_ DHCPPacket
*packet
= NULL
;
598 size_t optoffset
= 0;
602 assert(address
!= INADDR_ANY
);
605 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
609 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
610 DHCP_FORCERENEW
, ARPHRD_ETHER
,
611 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
615 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
616 &optoffset
, 0, SD_DHCP_OPTION_END
, 0, NULL
);
620 memcpy(&packet
->dhcp
.chaddr
, chaddr
, ETH_ALEN
);
622 r
= dhcp_server_send_udp(server
, address
, DHCP_PORT_CLIENT
,
624 sizeof(DHCPMessage
) + optoffset
);
631 static int parse_request(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
632 DHCPRequest
*req
= userdata
;
637 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
639 req
->lifetime
= unaligned_read_be32(option
);
642 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
:
644 memcpy(&req
->requested_ip
, option
, sizeof(be32_t
));
647 case SD_DHCP_OPTION_SERVER_IDENTIFIER
:
649 memcpy(&req
->server_id
, option
, sizeof(be32_t
));
652 case SD_DHCP_OPTION_CLIENT_IDENTIFIER
:
656 data
= memdup(option
, len
);
660 free(req
->client_id
.data
);
661 req
->client_id
.data
= data
;
662 req
->client_id
.length
= len
;
666 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
668 if (len
== 2 && unaligned_read_be16(option
) >= sizeof(DHCPPacket
))
669 req
->max_optlen
= unaligned_read_be16(option
) - sizeof(DHCPPacket
);
672 case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION
:
673 req
->agent_info_option
= (uint8_t*)option
- 2;
681 static DHCPRequest
* dhcp_request_free(DHCPRequest
*req
) {
685 free(req
->client_id
.data
);
689 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
691 static int ensure_sane_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPMessage
*message
) {
695 req
->message
= message
;
697 /* set client id based on MAC address if client did not send an explicit
699 if (!req
->client_id
.data
) {
702 data
= malloc0(ETH_ALEN
+ 1);
706 ((uint8_t*) data
)[0] = 0x01;
707 memcpy((uint8_t*) data
+ 1, &message
->chaddr
, ETH_ALEN
);
709 req
->client_id
.length
= ETH_ALEN
+ 1;
710 req
->client_id
.data
= data
;
713 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
714 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
716 if (req
->lifetime
<= 0)
717 req
->lifetime
= MAX(1ULL, server
->default_lease_time
);
719 if (server
->max_lease_time
> 0 && req
->lifetime
> server
->max_lease_time
)
720 req
->lifetime
= server
->max_lease_time
;
725 static int get_pool_offset(sd_dhcp_server
*server
, be32_t requested_ip
) {
728 if (!server
->pool_size
)
731 if (be32toh(requested_ip
) < (be32toh(server
->subnet
) | server
->pool_offset
) ||
732 be32toh(requested_ip
) >= (be32toh(server
->subnet
) | (server
->pool_offset
+ server
->pool_size
)))
735 return be32toh(requested_ip
& ~server
->netmask
) - server
->pool_offset
;
738 static int append_agent_information_option(sd_dhcp_server
*server
, DHCPMessage
*message
, size_t opt_length
, size_t size
) {
745 r
= dhcp_option_find_option(message
->options
, opt_length
, SD_DHCP_OPTION_END
, &offset
);
749 r
= dhcp_option_append(message
, size
, &offset
, 0, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION
, 0, server
);
753 r
= dhcp_option_append(message
, size
, &offset
, 0, SD_DHCP_OPTION_END
, 0, NULL
);
759 static int dhcp_server_relay_message(sd_dhcp_server
*server
, DHCPMessage
*message
, size_t opt_length
, size_t buflen
) {
760 _cleanup_free_ DHCPPacket
*packet
= NULL
;
765 assert(sd_dhcp_server_is_in_relay_mode(server
));
767 if (message
->op
== BOOTREQUEST
) {
768 log_dhcp_server(server
, "(relay agent) BOOTREQUEST (0x%x)", be32toh(message
->xid
));
769 if (message
->hops
>= 16)
773 /* https://tools.ietf.org/html/rfc1542#section-4.1.1 */
774 if (message
->giaddr
== 0)
775 message
->giaddr
= server
->address
;
777 if (server
->agent_circuit_id
|| server
->agent_remote_id
) {
778 r
= append_agent_information_option(server
, message
, opt_length
, buflen
- sizeof(DHCPMessage
));
780 return log_dhcp_server_errno(server
, r
, "could not append relay option: %m");
784 return dhcp_server_send_udp(server
, server
->relay_target
.s_addr
, DHCP_PORT_SERVER
, message
, sizeof(DHCPMessage
) + opt_length
);
785 } else if (message
->op
== BOOTREPLY
) {
786 log_dhcp_server(server
, "(relay agent) BOOTREPLY (0x%x)", be32toh(message
->xid
));
787 if (message
->giaddr
!= server
->address
)
788 return log_dhcp_server_errno(server
, SYNTHETIC_ERRNO(EBADMSG
),
789 "(relay agent) BOOTREPLY giaddr mismatch, discarding");
791 int message_type
= dhcp_option_parse(message
, sizeof(DHCPMessage
) + opt_length
, NULL
, NULL
, NULL
);
792 if (message_type
< 0)
795 packet
= malloc0(sizeof(DHCPPacket
) + opt_length
);
798 memcpy(&packet
->dhcp
, message
, sizeof(DHCPMessage
) + opt_length
);
800 r
= dhcp_option_remove_option(packet
->dhcp
.options
, opt_length
, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION
);
804 bool l2_broadcast
= requested_broadcast(message
) || message_type
== DHCP_NAK
;
805 const be32_t destination
= message_type
== DHCP_NAK
? INADDR_ANY
: message
->ciaddr
;
806 return dhcp_server_send(server
, destination
, DHCP_PORT_CLIENT
, packet
, opt_length
, l2_broadcast
);
811 static int prepare_new_lease(
812 DHCPLease
**ret_lease
,
814 const DHCPClientId
*client_id
,
815 const uint8_t chaddr
[static ETH_ALEN
],
819 _cleanup_(dhcp_lease_freep
) DHCPLease
*lease
= NULL
;
821 lease
= new(DHCPLease
, 1);
825 *lease
= (DHCPLease
) {
827 .client_id
.length
= client_id
->length
,
829 .expiration
= expiration
,
831 lease
->client_id
.data
= memdup(client_id
->data
, client_id
->length
);
832 if (!lease
->client_id
.data
)
835 memcpy(&lease
->chaddr
, chaddr
, ETH_ALEN
);
837 *ret_lease
= TAKE_PTR(lease
);
842 static bool static_leases_have_address(sd_dhcp_server
*server
, be32_t address
) {
847 HASHMAP_FOREACH(s
, server
->static_leases_by_client_id
)
848 if (s
->address
== address
)
854 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
856 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
, size_t length
) {
857 _cleanup_(dhcp_request_freep
) DHCPRequest
*req
= NULL
;
858 _cleanup_free_
char *error_message
= NULL
;
859 DHCPLease
*existing_lease
, *static_lease
;
865 if (message
->op
!= BOOTREQUEST
||
866 message
->htype
!= ARPHRD_ETHER
||
867 message
->hlen
!= ETHER_ADDR_LEN
)
870 req
= new0(DHCPRequest
, 1);
874 type
= dhcp_option_parse(message
, length
, parse_request
, req
, &error_message
);
878 r
= ensure_sane_request(server
, req
, message
);
880 /* this only fails on critical errors */
883 existing_lease
= hashmap_get(server
->leases_by_client_id
, &req
->client_id
);
884 static_lease
= hashmap_get(server
->static_leases_by_client_id
, &req
->client_id
);
888 case DHCP_DISCOVER
: {
889 be32_t address
= INADDR_ANY
;
892 log_dhcp_server(server
, "DISCOVER (0x%x)", be32toh(req
->message
->xid
));
894 if (!server
->pool_size
)
895 /* no pool allocated */
898 /* for now pick a random free address from the pool */
900 address
= static_lease
->address
;
901 else if (existing_lease
)
902 address
= existing_lease
->address
;
904 struct siphash state
;
908 /* even with no persistence of leases, we try to offer the same client
909 the same IP address. we do this by using the hash of the client id
910 as the offset into the pool of leases when finding the next free one */
912 siphash24_init(&state
, HASH_KEY
.bytes
);
913 client_id_hash_func(&req
->client_id
, &state
);
914 hash
= htole64(siphash24_finalize(&state
));
915 next_offer
= hash
% server
->pool_size
;
917 for (i
= 0; i
< server
->pool_size
; i
++) {
918 if (!server
->bound_leases
[next_offer
]) {
919 be32_t tmp
= server
->subnet
| htobe32(server
->pool_offset
+ next_offer
);
920 if (!static_leases_have_address(server
, tmp
)) {
926 next_offer
= (next_offer
+ 1) % server
->pool_size
;
930 if (address
== INADDR_ANY
)
931 /* no free addresses left */
934 r
= server_send_offer_or_ack(server
, req
, address
, DHCP_OFFER
);
936 /* this only fails on critical errors */
937 return log_dhcp_server_errno(server
, r
, "Could not send offer: %m");
939 log_dhcp_server(server
, "OFFER (0x%x)", be32toh(req
->message
->xid
));
943 log_dhcp_server(server
, "DECLINE (0x%x): %s", be32toh(req
->message
->xid
), strna(error_message
));
945 /* TODO: make sure we don't offer this address again */
951 bool init_reboot
= false;
954 /* see RFC 2131, section 4.3.2 */
956 if (req
->server_id
) {
957 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
958 be32toh(req
->message
->xid
));
961 if (req
->server_id
!= server
->address
)
962 /* client did not pick us */
965 if (req
->message
->ciaddr
)
966 /* this MUST be zero */
969 if (!req
->requested_ip
)
970 /* this must be filled in with the yiaddr
971 from the chosen OFFER */
974 address
= req
->requested_ip
;
975 } else if (req
->requested_ip
) {
976 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
977 be32toh(req
->message
->xid
));
980 if (req
->message
->ciaddr
)
981 /* this MUST be zero */
984 /* TODO: check more carefully if IP is correct */
985 address
= req
->requested_ip
;
988 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
989 be32toh(req
->message
->xid
));
991 /* REBINDING / RENEWING */
992 if (!req
->message
->ciaddr
)
993 /* this MUST be filled in with clients IP address */
996 address
= req
->message
->ciaddr
;
999 pool_offset
= get_pool_offset(server
, address
);
1001 /* verify that the requested address is from the pool, and either
1002 owned by the current client or free */
1003 if (pool_offset
>= 0 && static_lease
) {
1004 _cleanup_(dhcp_lease_freep
) DHCPLease
*lease
= NULL
, *old_lease
= NULL
;
1005 usec_t time_now
, expiration
;
1007 r
= sd_event_now(server
->event
, clock_boottime_or_monotonic(), &time_now
);
1011 expiration
= usec_add(req
->lifetime
* USEC_PER_SEC
, time_now
);
1013 r
= prepare_new_lease(&lease
, static_lease
->address
, &req
->client_id
,
1014 req
->message
->chaddr
, req
->message
->giaddr
, expiration
);
1018 r
= server_send_offer_or_ack(server
, req
, address
, DHCP_ACK
);
1020 /* this only fails on critical errors */
1021 return log_dhcp_server_errno(server
, r
, "Could not send ack: %m");
1023 log_dhcp_server(server
, "ACK (0x%x)", be32toh(req
->message
->xid
));
1025 server
->bound_leases
[pool_offset
] = lease
;
1027 old_lease
= hashmap_remove(server
->leases_by_client_id
, &lease
->client_id
);
1028 r
= hashmap_put(server
->leases_by_client_id
, &lease
->client_id
, lease
);
1030 return log_dhcp_server_errno(server
, r
, "Could not save lease: %m");
1033 if (server
->callback
)
1034 server
->callback(server
, SD_DHCP_SERVER_EVENT_LEASE_CHANGED
, server
->callback_userdata
);
1038 } else if (pool_offset
>= 0 && server
->bound_leases
[pool_offset
] == existing_lease
) {
1039 _cleanup_(dhcp_lease_freep
) DHCPLease
*new_lease
= NULL
;
1040 usec_t time_now
, expiration
;
1043 r
= sd_event_now(server
->event
, clock_boottime_or_monotonic(), &time_now
);
1047 expiration
= usec_add(req
->lifetime
* USEC_PER_SEC
, time_now
);
1049 if (!existing_lease
) {
1050 r
= prepare_new_lease(&new_lease
, address
, &req
->client_id
,
1051 req
->message
->chaddr
, req
->message
->giaddr
, expiration
);
1057 existing_lease
->expiration
= expiration
;
1058 lease
= existing_lease
;
1061 r
= server_send_offer_or_ack(server
, req
, address
, DHCP_ACK
);
1063 /* this only fails on critical errors */
1064 return log_dhcp_server_errno(server
, r
, "Could not send ack: %m");
1066 log_dhcp_server(server
, "ACK (0x%x)", be32toh(req
->message
->xid
));
1068 server
->bound_leases
[pool_offset
] = lease
;
1069 r
= hashmap_put(server
->leases_by_client_id
, &lease
->client_id
, lease
);
1071 return log_dhcp_server_errno(server
, r
, "Could not save lease: %m");
1072 TAKE_PTR(new_lease
);
1074 if (server
->callback
)
1075 server
->callback(server
, SD_DHCP_SERVER_EVENT_LEASE_CHANGED
, server
->callback_userdata
);
1079 } else if (init_reboot
) {
1080 r
= server_send_nak(server
, req
);
1082 /* this only fails on critical errors */
1083 return log_dhcp_server_errno(server
, r
, "Could not send nak: %m");
1085 log_dhcp_server(server
, "NAK (0x%x)", be32toh(req
->message
->xid
));
1092 case DHCP_RELEASE
: {
1095 log_dhcp_server(server
, "RELEASE (0x%x)",
1096 be32toh(req
->message
->xid
));
1098 if (!existing_lease
)
1101 if (existing_lease
->address
!= req
->message
->ciaddr
)
1104 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
1105 if (pool_offset
< 0)
1108 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
1109 server
->bound_leases
[pool_offset
] = NULL
;
1110 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
1111 dhcp_lease_free(existing_lease
);
1113 if (server
->callback
)
1114 server
->callback(server
, SD_DHCP_SERVER_EVENT_LEASE_CHANGED
, server
->callback_userdata
);
1123 static size_t relay_agent_information_length(const char* agent_circuit_id
, const char* agent_remote_id
) {
1125 if (agent_circuit_id
)
1126 sum
+= 2 + strlen(agent_circuit_id
);
1127 if (agent_remote_id
)
1128 sum
+= 2 + strlen(agent_remote_id
);
1132 static int server_receive_message(sd_event_source
*s
, int fd
,
1133 uint32_t revents
, void *userdata
) {
1134 _cleanup_free_ DHCPMessage
*message
= NULL
;
1135 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo
))) control
;
1136 sd_dhcp_server
*server
= userdata
;
1137 struct iovec iov
= {};
1138 struct msghdr msg
= {
1141 .msg_control
= &control
,
1142 .msg_controllen
= sizeof(control
),
1144 struct cmsghdr
*cmsg
;
1145 ssize_t datagram_size
, len
;
1150 datagram_size
= next_datagram_size_fd(fd
);
1151 if (datagram_size
< 0)
1152 return datagram_size
;
1154 size_t buflen
= datagram_size
;
1155 if (sd_dhcp_server_is_in_relay_mode(server
))
1156 /* Preallocate the additional size for DHCP Relay Agent Information Option if needed */
1157 buflen
+= relay_agent_information_length(server
->agent_circuit_id
, server
->agent_remote_id
) + 2;
1159 message
= malloc(buflen
);
1163 iov
= IOVEC_MAKE(message
, datagram_size
);
1165 len
= recvmsg_safe(fd
, &msg
, 0);
1166 if (IN_SET(len
, -EAGAIN
, -EINTR
))
1170 if ((size_t) len
< sizeof(DHCPMessage
))
1173 CMSG_FOREACH(cmsg
, &msg
) {
1174 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
1175 cmsg
->cmsg_type
== IP_PKTINFO
&&
1176 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
1177 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
1179 /* TODO figure out if this can be done as a filter on
1180 * the socket, like for IPv6 */
1181 if (server
->ifindex
!= info
->ipi_ifindex
)
1188 if (sd_dhcp_server_is_in_relay_mode(server
)) {
1189 r
= dhcp_server_relay_message(server
, message
, len
- sizeof(DHCPMessage
), buflen
);
1191 log_dhcp_server_errno(server
, r
, "Couldn't relay message: %m");
1193 r
= dhcp_server_handle_message(server
, message
, (size_t) len
);
1195 log_dhcp_server_errno(server
, r
, "Couldn't process incoming message: %m");
1200 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
1203 assert_return(server
, -EINVAL
);
1204 assert_return(server
->event
, -EINVAL
);
1206 if (sd_dhcp_server_is_running(server
))
1209 assert_return(!server
->receive_message
, -EBUSY
);
1210 assert_return(server
->fd_raw
< 0, -EBUSY
);
1211 assert_return(server
->fd
< 0, -EBUSY
);
1212 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
1214 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0);
1221 if (server
->bind_to_interface
)
1222 r
= dhcp_network_bind_udp_socket(server
->ifindex
, INADDR_ANY
, DHCP_PORT_SERVER
, -1);
1224 r
= dhcp_network_bind_udp_socket(0, server
->address
, DHCP_PORT_SERVER
, -1);
1229 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
1230 server
->fd
, EPOLLIN
,
1231 server_receive_message
, server
);
1235 r
= sd_event_source_set_priority(server
->receive_message
,
1236 server
->event_priority
);
1240 if (!server
->bind_to_interface
) {
1241 r
= dhcp_network_bind_udp_socket(server
->ifindex
, INADDR_BROADCAST
, DHCP_PORT_SERVER
, -1);
1245 server
->fd_broadcast
= r
;
1247 r
= sd_event_add_io(server
->event
, &server
->receive_broadcast
,
1248 server
->fd_broadcast
, EPOLLIN
,
1249 server_receive_message
, server
);
1253 r
= sd_event_source_set_priority(server
->receive_broadcast
,
1254 server
->event_priority
);
1259 log_dhcp_server(server
, "STARTED");
1264 sd_dhcp_server_stop(server
);
1268 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1271 assert_return(server
, -EINVAL
);
1272 assert(server
->bound_leases
);
1274 for (uint32_t i
= 0; i
< server
->pool_size
; i
++) {
1275 DHCPLease
*lease
= server
->bound_leases
[i
];
1277 if (!lease
|| lease
== &server
->invalid_lease
)
1280 r
= server_send_forcerenew(server
, lease
->address
,
1286 log_dhcp_server(server
, "FORCERENEW");
1292 int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server
*server
, int enabled
) {
1293 assert_return(server
, -EINVAL
);
1294 assert_return(!sd_dhcp_server_is_running(server
), -EBUSY
);
1296 if (!!enabled
== server
->bind_to_interface
)
1299 server
->bind_to_interface
= enabled
;
1304 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *tz
) {
1307 assert_return(server
, -EINVAL
);
1308 assert_return(timezone_is_valid(tz
, LOG_DEBUG
), -EINVAL
);
1310 if (streq_ptr(tz
, server
->timezone
))
1313 r
= free_and_strdup(&server
->timezone
, tz
);
1320 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1321 assert_return(server
, -EINVAL
);
1323 if (t
== server
->max_lease_time
)
1326 server
->max_lease_time
= t
;
1330 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1331 assert_return(server
, -EINVAL
);
1333 if (t
== server
->default_lease_time
)
1336 server
->default_lease_time
= t
;
1340 int sd_dhcp_server_set_servers(
1341 sd_dhcp_server
*server
,
1342 sd_dhcp_lease_server_type_t what
,
1343 const struct in_addr addresses
[],
1344 size_t n_addresses
) {
1346 struct in_addr
*c
= NULL
;
1348 assert_return(server
, -EINVAL
);
1349 assert_return(addresses
|| n_addresses
== 0, -EINVAL
);
1350 assert_return(what
>= 0, -EINVAL
);
1351 assert_return(what
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
, -EINVAL
);
1353 if (server
->servers
[what
].size
== n_addresses
&&
1354 memcmp(server
->servers
[what
].addr
, addresses
, sizeof(struct in_addr
) * n_addresses
) == 0)
1357 if (n_addresses
> 0) {
1358 c
= newdup(struct in_addr
, addresses
, n_addresses
);
1363 free(server
->servers
[what
].addr
);
1364 server
->servers
[what
].addr
= c
;
1365 server
->servers
[what
].size
= n_addresses
;
1369 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], size_t n
) {
1370 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_DNS
, dns
, n
);
1372 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], size_t n
) {
1373 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_NTP
, ntp
, n
);
1375 int sd_dhcp_server_set_sip(sd_dhcp_server
*server
, const struct in_addr sip
[], size_t n
) {
1376 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_SIP
, sip
, n
);
1378 int sd_dhcp_server_set_pop3(sd_dhcp_server
*server
, const struct in_addr pop3
[], size_t n
) {
1379 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_POP3
, pop3
, n
);
1381 int sd_dhcp_server_set_smtp(sd_dhcp_server
*server
, const struct in_addr smtp
[], size_t n
) {
1382 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_SMTP
, smtp
, n
);
1384 int sd_dhcp_server_set_lpr(sd_dhcp_server
*server
, const struct in_addr lpr
[], size_t n
) {
1385 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_LPR
, lpr
, n
);
1388 int sd_dhcp_server_set_emit_router(sd_dhcp_server
*server
, int enabled
) {
1389 assert_return(server
, -EINVAL
);
1391 if (enabled
== server
->emit_router
)
1394 server
->emit_router
= enabled
;
1399 int sd_dhcp_server_add_option(sd_dhcp_server
*server
, sd_dhcp_option
*v
) {
1402 assert_return(server
, -EINVAL
);
1403 assert_return(v
, -EINVAL
);
1405 r
= ordered_set_ensure_put(&server
->extra_options
, &dhcp_option_hash_ops
, v
);
1409 sd_dhcp_option_ref(v
);
1413 int sd_dhcp_server_add_vendor_option(sd_dhcp_server
*server
, sd_dhcp_option
*v
) {
1416 assert_return(server
, -EINVAL
);
1417 assert_return(v
, -EINVAL
);
1419 r
= ordered_set_ensure_put(&server
->vendor_options
, &dhcp_option_hash_ops
, v
);
1423 sd_dhcp_option_ref(v
);
1428 int sd_dhcp_server_set_callback(sd_dhcp_server
*server
, sd_dhcp_server_callback_t cb
, void *userdata
) {
1429 assert_return(server
, -EINVAL
);
1431 server
->callback
= cb
;
1432 server
->callback_userdata
= userdata
;
1437 int sd_dhcp_server_set_relay_target(sd_dhcp_server
*server
, const struct in_addr
*address
) {
1438 assert_return(server
, -EINVAL
);
1439 assert_return(!sd_dhcp_server_is_running(server
), -EBUSY
);
1441 if (memcmp(address
, &server
->relay_target
, sizeof(struct in_addr
)) == 0)
1444 server
->relay_target
= *address
;
1448 int sd_dhcp_server_set_relay_agent_information(
1449 sd_dhcp_server
*server
,
1450 const char *agent_circuit_id
,
1451 const char *agent_remote_id
) {
1452 _cleanup_free_
char *circuit_id_dup
= NULL
, *remote_id_dup
= NULL
;
1454 assert_return(server
, -EINVAL
);
1456 if (relay_agent_information_length(agent_circuit_id
, agent_remote_id
) > UINT8_MAX
)
1459 if (agent_circuit_id
) {
1460 circuit_id_dup
= strdup(agent_circuit_id
);
1461 if (!circuit_id_dup
)
1465 if (agent_remote_id
) {
1466 remote_id_dup
= strdup(agent_remote_id
);
1471 free_and_replace(server
->agent_circuit_id
, circuit_id_dup
);
1472 free_and_replace(server
->agent_remote_id
, remote_id_dup
);
1476 int sd_dhcp_server_set_static_lease(
1477 sd_dhcp_server
*server
,
1478 const struct in_addr
*address
,
1480 size_t client_id_size
) {
1482 _cleanup_(dhcp_lease_freep
) DHCPLease
*lease
= NULL
, *old
= NULL
;
1486 assert_return(server
, -EINVAL
);
1487 assert_return(client_id
, -EINVAL
);
1488 assert_return(client_id_size
== ETH_ALEN
+ 1, -EINVAL
);
1489 assert_return(!sd_dhcp_server_is_running(server
), -EBUSY
);
1491 /* Static lease with an empty or omitted address is a valid entry,
1492 * the server removes any static lease with the specified mac address. */
1493 if (!address
|| address
->s_addr
== 0) {
1494 _cleanup_free_
void *data
= NULL
;
1496 data
= memdup(client_id
, client_id_size
);
1500 c
= (DHCPClientId
) {
1501 .length
= client_id_size
,
1505 old
= hashmap_remove(server
->static_leases_by_client_id
, &c
);
1509 if (static_leases_have_address(server
, address
->s_addr
))
1512 lease
= new(DHCPLease
, 1);
1516 *lease
= (DHCPLease
) {
1517 .address
= address
->s_addr
,
1518 .client_id
.length
= client_id_size
,
1522 lease
->client_id
.data
= memdup(client_id
, client_id_size
);
1523 if (!lease
->client_id
.data
)
1526 r
= hashmap_ensure_put(&server
->static_leases_by_client_id
, &dhcp_lease_hash_ops
, &lease
->client_id
, lease
);