1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2013 Intel Corporation. All rights reserved.
8 #include "sd-dhcp-server.h"
10 #include "alloc-util.h"
11 #include "dhcp-internal.h"
12 #include "dhcp-server-internal.h"
14 #include "in-addr-util.h"
17 #include "siphash24.h"
18 #include "string-util.h"
19 #include "unaligned.h"
21 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
22 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
24 static DHCPLease
*dhcp_lease_free(DHCPLease
*lease
) {
28 free(lease
->client_id
.data
);
32 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
33 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
34 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
35 * accidentally hand it out */
36 int sd_dhcp_server_configure_pool(sd_dhcp_server
*server
, struct in_addr
*address
, unsigned char prefixlen
, uint32_t offset
, uint32_t size
) {
37 struct in_addr netmask_addr
;
39 uint32_t server_off
, broadcast_off
, size_max
;
41 assert_return(server
, -EINVAL
);
42 assert_return(address
, -EINVAL
);
43 assert_return(address
->s_addr
!= INADDR_ANY
, -EINVAL
);
44 assert_return(prefixlen
<= 32, -ERANGE
);
46 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr
, prefixlen
));
47 netmask
= netmask_addr
.s_addr
;
49 server_off
= be32toh(address
->s_addr
& ~netmask
);
50 broadcast_off
= be32toh(~netmask
);
52 /* the server address cannot be the subnet address */
53 assert_return(server_off
!= 0, -ERANGE
);
55 /* nor the broadcast address */
56 assert_return(server_off
!= broadcast_off
, -ERANGE
);
58 /* 0 offset means we should set a default, we skip the first (subnet) address
59 and take the next one */
63 size_max
= (broadcast_off
+ 1) /* the number of addresses in the subnet */
64 - offset
/* exclude the addresses before the offset */
65 - 1; /* exclude the last (broadcast) address */
67 /* The pool must contain at least one address */
68 assert_return(size_max
>= 1, -ERANGE
);
71 assert_return(size
<= size_max
, -ERANGE
);
75 if (server
->address
!= address
->s_addr
|| server
->netmask
!= netmask
|| server
->pool_size
!= size
|| server
->pool_offset
!= offset
) {
77 free(server
->bound_leases
);
78 server
->bound_leases
= new0(DHCPLease
*, size
);
79 if (!server
->bound_leases
)
82 server
->pool_offset
= offset
;
83 server
->pool_size
= size
;
85 server
->address
= address
->s_addr
;
86 server
->netmask
= netmask
;
87 server
->subnet
= address
->s_addr
& netmask
;
89 if (server_off
>= offset
&& server_off
- offset
< size
)
90 server
->bound_leases
[server_off
- offset
] = &server
->invalid_lease
;
92 /* Drop any leases associated with the old address range */
93 hashmap_clear(server
->leases_by_client_id
);
99 int sd_dhcp_server_is_running(sd_dhcp_server
*server
) {
100 assert_return(server
, false);
102 return !!server
->receive_message
;
105 void client_id_hash_func(const DHCPClientId
*id
, struct siphash
*state
) {
110 siphash24_compress(&id
->length
, sizeof(id
->length
), state
);
111 siphash24_compress(id
->data
, id
->length
, state
);
114 int client_id_compare_func(const DHCPClientId
*a
, const DHCPClientId
*b
) {
117 assert(!a
->length
|| a
->data
);
118 assert(!b
->length
|| b
->data
);
120 r
= CMP(a
->length
, b
->length
);
124 return memcmp(a
->data
, b
->data
, a
->length
);
127 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(dhcp_lease_hash_ops
, DHCPClientId
, client_id_hash_func
, client_id_compare_func
,
128 DHCPLease
, dhcp_lease_free
);
130 static sd_dhcp_server
*dhcp_server_free(sd_dhcp_server
*server
) {
133 log_dhcp_server(server
, "UNREF");
135 sd_dhcp_server_stop(server
);
137 sd_event_unref(server
->event
);
139 free(server
->timezone
);
143 hashmap_free(server
->leases_by_client_id
);
145 free(server
->bound_leases
);
146 return mfree(server
);
149 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server
, sd_dhcp_server
, dhcp_server_free
);
151 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
152 _cleanup_(sd_dhcp_server_unrefp
) sd_dhcp_server
*server
= NULL
;
154 assert_return(ret
, -EINVAL
);
155 assert_return(ifindex
> 0, -EINVAL
);
157 server
= new0(sd_dhcp_server
, 1);
164 server
->address
= htobe32(INADDR_ANY
);
165 server
->netmask
= htobe32(INADDR_ANY
);
166 server
->ifindex
= ifindex
;
168 server
->leases_by_client_id
= hashmap_new(&dhcp_lease_hash_ops
);
169 if (!server
->leases_by_client_id
)
172 server
->default_lease_time
= DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC
, USEC_PER_SEC
);
173 server
->max_lease_time
= DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC
, USEC_PER_SEC
);
175 *ret
= TAKE_PTR(server
);
180 int sd_dhcp_server_attach_event(sd_dhcp_server
*server
, sd_event
*event
, int64_t priority
) {
183 assert_return(server
, -EINVAL
);
184 assert_return(!server
->event
, -EBUSY
);
187 server
->event
= sd_event_ref(event
);
189 r
= sd_event_default(&server
->event
);
194 server
->event_priority
= priority
;
199 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
200 assert_return(server
, -EINVAL
);
202 server
->event
= sd_event_unref(server
->event
);
207 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
208 assert_return(server
, NULL
);
210 return server
->event
;
213 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
214 assert_return(server
, -EINVAL
);
216 server
->receive_message
=
217 sd_event_source_unref(server
->receive_message
);
219 server
->fd_raw
= safe_close(server
->fd_raw
);
220 server
->fd
= safe_close(server
->fd
);
222 log_dhcp_server(server
, "STOPPED");
227 static int dhcp_server_send_unicast_raw(sd_dhcp_server
*server
,
228 DHCPPacket
*packet
, size_t len
) {
229 union sockaddr_union link
= {
230 .ll
.sll_family
= AF_PACKET
,
231 .ll
.sll_protocol
= htobe16(ETH_P_IP
),
232 .ll
.sll_ifindex
= server
->ifindex
,
233 .ll
.sll_halen
= ETH_ALEN
,
237 assert(server
->ifindex
> 0);
238 assert(server
->address
);
240 assert(len
> sizeof(DHCPPacket
));
242 memcpy(&link
.ll
.sll_addr
, &packet
->dhcp
.chaddr
, ETH_ALEN
);
244 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
246 DHCP_PORT_CLIENT
, len
);
248 return dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
251 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
252 uint16_t destination_port
,
253 DHCPMessage
*message
, size_t len
) {
254 union sockaddr_union dest
= {
255 .in
.sin_family
= AF_INET
,
256 .in
.sin_port
= htobe16(destination_port
),
257 .in
.sin_addr
.s_addr
= destination
,
263 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))] = {};
264 struct msghdr msg
= {
266 .msg_namelen
= sizeof(dest
.in
),
269 .msg_control
= cmsgbuf
,
270 .msg_controllen
= sizeof(cmsgbuf
),
272 struct cmsghdr
*cmsg
;
273 struct in_pktinfo
*pktinfo
;
276 assert(server
->fd
>= 0);
278 assert(len
> sizeof(DHCPMessage
));
280 cmsg
= CMSG_FIRSTHDR(&msg
);
283 cmsg
->cmsg_level
= IPPROTO_IP
;
284 cmsg
->cmsg_type
= IP_PKTINFO
;
285 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
287 /* we attach source interface and address info to the message
288 rather than binding the socket. This will be mostly useful
289 when we gain support for arbitrary number of server addresses
291 pktinfo
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
294 pktinfo
->ipi_ifindex
= server
->ifindex
;
295 pktinfo
->ipi_spec_dst
.s_addr
= server
->address
;
297 if (sendmsg(server
->fd
, &msg
, 0) < 0)
303 static bool requested_broadcast(DHCPRequest
*req
) {
306 return req
->message
->flags
& htobe16(0x8000);
309 int dhcp_server_send_packet(sd_dhcp_server
*server
,
310 DHCPRequest
*req
, DHCPPacket
*packet
,
311 int type
, size_t optoffset
) {
312 be32_t destination
= INADDR_ANY
;
313 uint16_t destination_port
= DHCP_PORT_CLIENT
;
318 assert(req
->max_optlen
);
319 assert(optoffset
<= req
->max_optlen
);
322 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
323 SD_DHCP_OPTION_SERVER_IDENTIFIER
,
324 4, &server
->address
);
328 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
329 SD_DHCP_OPTION_END
, 0, NULL
);
333 /* RFC 2131 Section 4.1
335 If the ’giaddr’ field in a DHCP message from a client is non-zero,
336 the server sends any return messages to the ’DHCP server’ port on the
337 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
338 field is zero and the ’ciaddr’ field is nonzero, then the server
339 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
340 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
341 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
342 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
343 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
344 messages to the client’s hardware address and ’yiaddr’ address. In
345 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
346 messages to 0xffffffff.
350 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
351 different subnet. The server MUST set the broadcast bit in the
352 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
353 client, because the client may not have a correct network address
354 or subnet mask, and the client may not be answering ARP requests.
356 if (req
->message
->giaddr
) {
357 destination
= req
->message
->giaddr
;
358 destination_port
= DHCP_PORT_SERVER
;
359 if (type
== DHCP_NAK
)
360 packet
->dhcp
.flags
= htobe16(0x8000);
361 } else if (req
->message
->ciaddr
&& type
!= DHCP_NAK
)
362 destination
= req
->message
->ciaddr
;
364 if (destination
!= INADDR_ANY
)
365 return dhcp_server_send_udp(server
, destination
,
366 destination_port
, &packet
->dhcp
,
367 sizeof(DHCPMessage
) + optoffset
);
368 else if (requested_broadcast(req
) || type
== DHCP_NAK
)
369 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
370 destination_port
, &packet
->dhcp
,
371 sizeof(DHCPMessage
) + optoffset
);
373 /* we cannot send UDP packet to specific MAC address when the
374 address is not yet configured, so must fall back to raw
376 return dhcp_server_send_unicast_raw(server
, packet
,
377 sizeof(DHCPPacket
) + optoffset
);
380 static int server_message_init(sd_dhcp_server
*server
, DHCPPacket
**ret
,
381 uint8_t type
, size_t *_optoffset
,
383 _cleanup_free_ DHCPPacket
*packet
= NULL
;
384 size_t optoffset
= 0;
390 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
, DHCP_NAK
));
392 packet
= malloc0(sizeof(DHCPPacket
) + req
->max_optlen
);
396 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
,
397 be32toh(req
->message
->xid
), type
, ARPHRD_ETHER
,
398 req
->max_optlen
, &optoffset
);
402 packet
->dhcp
.flags
= req
->message
->flags
;
403 packet
->dhcp
.giaddr
= req
->message
->giaddr
;
404 memcpy(&packet
->dhcp
.chaddr
, &req
->message
->chaddr
, ETH_ALEN
);
406 *_optoffset
= optoffset
;
407 *ret
= TAKE_PTR(packet
);
412 static int server_send_offer(sd_dhcp_server
*server
, DHCPRequest
*req
,
414 _cleanup_free_ DHCPPacket
*packet
= NULL
;
419 r
= server_message_init(server
, &packet
, DHCP_OFFER
, &offset
, req
);
423 packet
->dhcp
.yiaddr
= address
;
425 lease_time
= htobe32(req
->lifetime
);
426 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
427 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
432 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
433 SD_DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
437 if (server
->emit_router
) {
438 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
439 SD_DHCP_OPTION_ROUTER
, 4, &server
->address
);
444 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_OFFER
, offset
);
451 static int server_send_ack(sd_dhcp_server
*server
, DHCPRequest
*req
,
453 _cleanup_free_ DHCPPacket
*packet
= NULL
;
458 r
= server_message_init(server
, &packet
, DHCP_ACK
, &offset
, req
);
462 packet
->dhcp
.yiaddr
= address
;
464 lease_time
= htobe32(req
->lifetime
);
465 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
466 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
471 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
472 SD_DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
476 if (server
->emit_router
) {
477 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
478 SD_DHCP_OPTION_ROUTER
, 4, &server
->address
);
483 if (server
->n_dns
> 0) {
484 r
= dhcp_option_append(
485 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
486 SD_DHCP_OPTION_DOMAIN_NAME_SERVER
,
487 sizeof(struct in_addr
) * server
->n_dns
, server
->dns
);
492 if (server
->n_ntp
> 0) {
493 r
= dhcp_option_append(
494 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
495 SD_DHCP_OPTION_NTP_SERVER
,
496 sizeof(struct in_addr
) * server
->n_ntp
, server
->ntp
);
501 if (server
->timezone
) {
502 r
= dhcp_option_append(
503 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
504 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
,
505 strlen(server
->timezone
), server
->timezone
);
510 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_ACK
, offset
);
517 static int server_send_nak(sd_dhcp_server
*server
, DHCPRequest
*req
) {
518 _cleanup_free_ DHCPPacket
*packet
= NULL
;
522 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
526 return dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
529 static int server_send_forcerenew(sd_dhcp_server
*server
, be32_t address
,
530 be32_t gateway
, uint8_t chaddr
[]) {
531 _cleanup_free_ DHCPPacket
*packet
= NULL
;
532 size_t optoffset
= 0;
536 assert(address
!= INADDR_ANY
);
539 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
543 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
544 DHCP_FORCERENEW
, ARPHRD_ETHER
,
545 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
549 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
550 &optoffset
, 0, SD_DHCP_OPTION_END
, 0, NULL
);
554 memcpy(&packet
->dhcp
.chaddr
, chaddr
, ETH_ALEN
);
556 r
= dhcp_server_send_udp(server
, address
, DHCP_PORT_CLIENT
,
558 sizeof(DHCPMessage
) + optoffset
);
565 static int parse_request(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
566 DHCPRequest
*req
= userdata
;
571 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
573 req
->lifetime
= unaligned_read_be32(option
);
576 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
:
578 memcpy(&req
->requested_ip
, option
, sizeof(be32_t
));
581 case SD_DHCP_OPTION_SERVER_IDENTIFIER
:
583 memcpy(&req
->server_id
, option
, sizeof(be32_t
));
586 case SD_DHCP_OPTION_CLIENT_IDENTIFIER
:
590 data
= memdup(option
, len
);
594 free(req
->client_id
.data
);
595 req
->client_id
.data
= data
;
596 req
->client_id
.length
= len
;
600 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
602 if (len
== 2 && unaligned_read_be16(option
) >= sizeof(DHCPPacket
))
603 req
->max_optlen
= unaligned_read_be16(option
) - sizeof(DHCPPacket
);
611 static void dhcp_request_free(DHCPRequest
*req
) {
615 free(req
->client_id
.data
);
619 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
621 static int ensure_sane_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPMessage
*message
) {
625 req
->message
= message
;
627 /* set client id based on MAC address if client did not send an explicit
629 if (!req
->client_id
.data
) {
632 data
= malloc0(ETH_ALEN
+ 1);
636 ((uint8_t*) data
)[0] = 0x01;
637 memcpy((uint8_t*) data
+ 1, &message
->chaddr
, ETH_ALEN
);
639 req
->client_id
.length
= ETH_ALEN
+ 1;
640 req
->client_id
.data
= data
;
643 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
644 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
646 if (req
->lifetime
<= 0)
647 req
->lifetime
= MAX(1ULL, server
->default_lease_time
);
649 if (server
->max_lease_time
> 0 && req
->lifetime
> server
->max_lease_time
)
650 req
->lifetime
= server
->max_lease_time
;
655 static int get_pool_offset(sd_dhcp_server
*server
, be32_t requested_ip
) {
658 if (!server
->pool_size
)
661 if (be32toh(requested_ip
) < (be32toh(server
->subnet
) | server
->pool_offset
) ||
662 be32toh(requested_ip
) >= (be32toh(server
->subnet
) | (server
->pool_offset
+ server
->pool_size
)))
665 return be32toh(requested_ip
& ~server
->netmask
) - server
->pool_offset
;
668 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
670 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
,
672 _cleanup_(dhcp_request_freep
) DHCPRequest
*req
= NULL
;
673 _cleanup_free_
char *error_message
= NULL
;
674 DHCPLease
*existing_lease
;
680 if (message
->op
!= BOOTREQUEST
||
681 message
->htype
!= ARPHRD_ETHER
||
682 message
->hlen
!= ETHER_ADDR_LEN
)
685 req
= new0(DHCPRequest
, 1);
689 type
= dhcp_option_parse(message
, length
, parse_request
, req
, &error_message
);
693 r
= ensure_sane_request(server
, req
, message
);
695 /* this only fails on critical errors */
698 existing_lease
= hashmap_get(server
->leases_by_client_id
,
703 case DHCP_DISCOVER
: {
704 be32_t address
= INADDR_ANY
;
707 log_dhcp_server(server
, "DISCOVER (0x%x)",
708 be32toh(req
->message
->xid
));
710 if (!server
->pool_size
)
711 /* no pool allocated */
714 /* for now pick a random free address from the pool */
716 address
= existing_lease
->address
;
718 struct siphash state
;
722 /* even with no persistence of leases, we try to offer the same client
723 the same IP address. we do this by using the hash of the client id
724 as the offset into the pool of leases when finding the next free one */
726 siphash24_init(&state
, HASH_KEY
.bytes
);
727 client_id_hash_func(&req
->client_id
, &state
);
728 hash
= htole64(siphash24_finalize(&state
));
729 next_offer
= hash
% server
->pool_size
;
731 for (i
= 0; i
< server
->pool_size
; i
++) {
732 if (!server
->bound_leases
[next_offer
]) {
733 address
= server
->subnet
| htobe32(server
->pool_offset
+ next_offer
);
737 next_offer
= (next_offer
+ 1) % server
->pool_size
;
741 if (address
== INADDR_ANY
)
742 /* no free addresses left */
745 r
= server_send_offer(server
, req
, address
);
747 /* this only fails on critical errors */
748 return log_dhcp_server_errno(server
, r
, "Could not send offer: %m");
750 log_dhcp_server(server
, "OFFER (0x%x)", be32toh(req
->message
->xid
));
754 log_dhcp_server(server
, "DECLINE (0x%x): %s", be32toh(req
->message
->xid
), strna(error_message
));
756 /* TODO: make sure we don't offer this address again */
762 bool init_reboot
= false;
765 /* see RFC 2131, section 4.3.2 */
767 if (req
->server_id
) {
768 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
769 be32toh(req
->message
->xid
));
772 if (req
->server_id
!= server
->address
)
773 /* client did not pick us */
776 if (req
->message
->ciaddr
)
777 /* this MUST be zero */
780 if (!req
->requested_ip
)
781 /* this must be filled in with the yiaddr
782 from the chosen OFFER */
785 address
= req
->requested_ip
;
786 } else if (req
->requested_ip
) {
787 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
788 be32toh(req
->message
->xid
));
791 if (req
->message
->ciaddr
)
792 /* this MUST be zero */
795 /* TODO: check more carefully if IP is correct */
796 address
= req
->requested_ip
;
799 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
800 be32toh(req
->message
->xid
));
802 /* REBINDING / RENEWING */
803 if (!req
->message
->ciaddr
)
804 /* this MUST be filled in with clients IP address */
807 address
= req
->message
->ciaddr
;
810 pool_offset
= get_pool_offset(server
, address
);
812 /* verify that the requested address is from the pool, and either
813 owned by the current client or free */
814 if (pool_offset
>= 0 &&
815 server
->bound_leases
[pool_offset
] == existing_lease
) {
819 if (!existing_lease
) {
820 lease
= new0(DHCPLease
, 1);
823 lease
->address
= address
;
824 lease
->client_id
.data
= memdup(req
->client_id
.data
,
825 req
->client_id
.length
);
826 if (!lease
->client_id
.data
) {
830 lease
->client_id
.length
= req
->client_id
.length
;
831 memcpy(&lease
->chaddr
, &req
->message
->chaddr
,
833 lease
->gateway
= req
->message
->giaddr
;
835 lease
= existing_lease
;
837 r
= sd_event_now(server
->event
,
838 clock_boottime_or_monotonic(),
842 dhcp_lease_free(lease
);
846 lease
->expiration
= req
->lifetime
* USEC_PER_SEC
+ time_now
;
848 r
= server_send_ack(server
, req
, address
);
850 /* this only fails on critical errors */
851 log_dhcp_server_errno(server
, r
, "Could not send ack: %m");
854 dhcp_lease_free(lease
);
858 log_dhcp_server(server
, "ACK (0x%x)",
859 be32toh(req
->message
->xid
));
861 server
->bound_leases
[pool_offset
] = lease
;
862 hashmap_put(server
->leases_by_client_id
,
863 &lease
->client_id
, lease
);
868 } else if (init_reboot
) {
869 r
= server_send_nak(server
, req
);
871 /* this only fails on critical errors */
872 return log_dhcp_server_errno(server
, r
, "Could not send nak: %m");
874 log_dhcp_server(server
, "NAK (0x%x)", be32toh(req
->message
->xid
));
884 log_dhcp_server(server
, "RELEASE (0x%x)",
885 be32toh(req
->message
->xid
));
890 if (existing_lease
->address
!= req
->message
->ciaddr
)
893 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
897 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
898 server
->bound_leases
[pool_offset
] = NULL
;
899 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
900 dhcp_lease_free(existing_lease
);
909 static int server_receive_message(sd_event_source
*s
, int fd
,
910 uint32_t revents
, void *userdata
) {
911 _cleanup_free_ DHCPMessage
*message
= NULL
;
912 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))];
913 sd_dhcp_server
*server
= userdata
;
914 struct iovec iov
= {};
915 struct msghdr msg
= {
918 .msg_control
= cmsgbuf
,
919 .msg_controllen
= sizeof(cmsgbuf
),
921 struct cmsghdr
*cmsg
;
927 buflen
= next_datagram_size_fd(fd
);
931 message
= malloc(buflen
);
935 iov
= IOVEC_MAKE(message
, buflen
);
937 len
= recvmsg(fd
, &msg
, 0);
939 if (IN_SET(errno
, EAGAIN
, EINTR
))
944 if ((size_t)len
< sizeof(DHCPMessage
))
947 CMSG_FOREACH(cmsg
, &msg
) {
948 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
949 cmsg
->cmsg_type
== IP_PKTINFO
&&
950 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
951 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
953 /* TODO figure out if this can be done as a filter on
954 * the socket, like for IPv6 */
955 if (server
->ifindex
!= info
->ipi_ifindex
)
962 r
= dhcp_server_handle_message(server
, message
, (size_t) len
);
964 log_dhcp_server_errno(server
, r
, "Couldn't process incoming message: %m");
969 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
972 assert_return(server
, -EINVAL
);
973 assert_return(server
->event
, -EINVAL
);
974 assert_return(!server
->receive_message
, -EBUSY
);
975 assert_return(server
->fd_raw
< 0, -EBUSY
);
976 assert_return(server
->fd
< 0, -EBUSY
);
977 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
979 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0);
982 sd_dhcp_server_stop(server
);
987 r
= dhcp_network_bind_udp_socket(server
->ifindex
, INADDR_ANY
, DHCP_PORT_SERVER
);
989 sd_dhcp_server_stop(server
);
994 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
996 server_receive_message
, server
);
998 sd_dhcp_server_stop(server
);
1002 r
= sd_event_source_set_priority(server
->receive_message
,
1003 server
->event_priority
);
1005 sd_dhcp_server_stop(server
);
1009 log_dhcp_server(server
, "STARTED");
1014 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1018 assert_return(server
, -EINVAL
);
1019 assert(server
->bound_leases
);
1021 for (i
= 0; i
< server
->pool_size
; i
++) {
1022 DHCPLease
*lease
= server
->bound_leases
[i
];
1024 if (!lease
|| lease
== &server
->invalid_lease
)
1027 r
= server_send_forcerenew(server
, lease
->address
,
1033 log_dhcp_server(server
, "FORCERENEW");
1039 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *tz
) {
1042 assert_return(server
, -EINVAL
);
1043 assert_return(timezone_is_valid(tz
, LOG_DEBUG
), -EINVAL
);
1045 if (streq_ptr(tz
, server
->timezone
))
1048 r
= free_and_strdup(&server
->timezone
, tz
);
1055 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1056 assert_return(server
, -EINVAL
);
1058 if (t
== server
->max_lease_time
)
1061 server
->max_lease_time
= t
;
1065 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1066 assert_return(server
, -EINVAL
);
1068 if (t
== server
->default_lease_time
)
1071 server
->default_lease_time
= t
;
1075 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], unsigned n
) {
1076 assert_return(server
, -EINVAL
);
1077 assert_return(dns
|| n
<= 0, -EINVAL
);
1079 if (server
->n_dns
== n
&&
1080 memcmp(server
->dns
, dns
, sizeof(struct in_addr
) * n
) == 0)
1084 server
->dns
= mfree(server
->dns
);
1089 c
= newdup(struct in_addr
, dns
, n
);
1101 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], unsigned n
) {
1102 assert_return(server
, -EINVAL
);
1103 assert_return(ntp
|| n
<= 0, -EINVAL
);
1105 if (server
->n_ntp
== n
&&
1106 memcmp(server
->ntp
, ntp
, sizeof(struct in_addr
) * n
) == 0)
1110 server
->ntp
= mfree(server
->ntp
);
1115 c
= newdup(struct in_addr
, ntp
, n
);
1127 int sd_dhcp_server_set_emit_router(sd_dhcp_server
*server
, int enabled
) {
1128 assert_return(server
, -EINVAL
);
1130 if (enabled
== server
->emit_router
)
1133 server
->emit_router
= enabled
;