This patch makes udhcpd respond correctly to queries from BOOTP clients.

It contains the following changes:

The end field, or DHCP_END option, is required in DHCP requests but 
optional in BOOTP requests. Only complain about missing end fields if 
there are DHCP options in the packet. However, we still send an end 
field in all replies, because some BOOTP clients expect one in replies 
even if they didn't send one in the request.

Requests without a DHCP_MESSAGE_TYPE are recognized as BOOTP requests 
and handled appropriately, instead of being discarded. We still require 
an RFC 1048 options field, but we allow it to be empty.

Since a BOOTP client will keep using the assigned IP forever, we only 
send a BOOTP reply if a static lease exists for that client.

BOOTP replies shouldn't contain DHCP_* options, so we omit them if there 
was no DHCP_MESSAGE_TYPE in the request. Options other than DHCP_* 
options are still sent.

The options field of a BOOTP reply must be exactly 64 bytes. If we 
construct a reply with more than 64 bytes of options, we give up and log 
an error instead of sending it. udhcp_send_raw_packet already pads the 
options field to 64 bytes if it is too short.

This implementation has been tested against an HP PA-RISC client.


--- networking/udhcp/common.c.orig      2023-05-22 18:41:39.000000000 -0700
+++ networking/udhcp/common.c   2023-05-21 19:18:15.000000000 -0700
@@ -234,6 +234,7 @@
 void FAST_FUNC init_scan_state(struct dhcp_packet *packet, struct 
dhcp_scan_state *scan_state)
 {
        scan_state->overload = 0;
+       scan_state->is_dhcp = 0;
        scan_state->rem = sizeof(packet->options);
        scan_state->optionptr = packet->options;
 }
@@ -251,12 +252,17 @@
 
        /* option bytes: [code][len][data1][data2]..[dataLEN] */
        while (1) {
+               if (scan_state->rem == 0 && !scan_state->is_dhcp)
+                       break; /* BOOTP packet without end field */
                if (scan_state->rem <= 0) {
  complain:
                        bb_simple_error_msg("bad packet, malformed option 
field");
                        return NULL;
                }
 
+               if (scan_state->optionptr[OPT_CODE] >= DHCP_REQUESTED_IP && 
scan_state->optionptr[OPT_CODE] <= DHCP_CLIENT_ID)
+                       scan_state->is_dhcp = 1;
+
                /* DHCP_PADDING and DHCP_END have no [len] byte */
                if (scan_state->optionptr[OPT_CODE] == DHCP_PADDING) {
                        scan_state->rem--;
--- networking/udhcp/common.h.orig      2023-01-03 06:17:01.000000000 -0800
+++ networking/udhcp/common.h   2023-05-21 19:01:24.000000000 -0700
@@ -123,6 +123,7 @@
 
 struct dhcp_scan_state {
        int overload;
+       int is_dhcp;
        int rem;
        uint8_t *optionptr;
 };
--- networking/udhcp/packet.c.orig      2023-01-03 06:17:01.000000000 -0800
+++ networking/udhcp/packet.c   2023-05-23 00:22:45.000000000 -0700
@@ -18,6 +18,7 @@
        memset(packet, 0, sizeof(*packet));
        packet->op = BOOTREQUEST; /* if client to a server */
        switch (type) {
+       case 0:
        case DHCPOFFER:
        case DHCPACK:
        case DHCPNAK:
@@ -28,7 +29,8 @@
        packet->cookie = htonl(DHCP_MAGIC);
        if (DHCP_END != 0)
                packet->options[0] = DHCP_END;
-       udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type);
+       if (type)
+               udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type);
 }
 #endif
 
--- networking/udhcp/dhcpd.c.orig       2023-01-03 06:17:01.000000000 -0800
+++ networking/udhcp/dhcpd.c    2023-05-28 17:08:51.000000000 -0700
@@ -649,7 +649,8 @@
        packet->flags = oldpacket->flags;
        packet->gateway_nip = oldpacket->gateway_nip;
        packet->ciaddr = oldpacket->ciaddr;
-       udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_data.server_nip);
+       if(type)
+               udhcp_add_simple_option(packet, DHCP_SERVER_ID, 
server_data.server_nip);
 }
 
 /* Fill options field, siaddr_nip, and sname and boot_file fields.
@@ -733,8 +734,11 @@
 {
        struct dhcp_packet packet;
        uint32_t lease_time_sec;
+       char message_type = DHCPOFFER;
 
-       init_packet(&packet, oldpacket, DHCPOFFER);
+       if (!udhcp_get_option(oldpacket, DHCP_MESSAGE_TYPE))
+               message_type = 0;
+       init_packet(&packet, oldpacket, message_type);
 
        /* If it is a static lease, use its IP */
        packet.yiaddr = static_lease_nip;
@@ -785,8 +789,13 @@
        }
 
        lease_time_sec = select_lease_time(oldpacket);
-       udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, 
htonl(lease_time_sec));
+       if (udhcp_get_option(oldpacket, DHCP_MESSAGE_TYPE))
+               udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, 
htonl(lease_time_sec));
        add_server_options(&packet);
+       if (!udhcp_get_option(oldpacket, DHCP_MESSAGE_TYPE) && 
udhcp_end_option(packet.options) > 63) {
+               bb_simple_error_msg("BOOTP BOOTREPLY would be too large, not 
sending");
+               return;
+       }
 
        /* send_packet emits error message itself if it detects failure */
        send_packet_verbose(&packet, "sending OFFER to %s");
@@ -1050,8 +1059,8 @@
                        continue;
                }
                msg_type = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
-               if (!msg_type || msg_type[0] < DHCP_MINTYPE || msg_type[0] > 
DHCP_MAXTYPE) {
-                       bb_info_msg("no or bad message type option%s", ", 
ignoring packet");
+               if (msg_type && (msg_type[0] < DHCP_MINTYPE || msg_type[0] > 
DHCP_MAXTYPE)) {
+                       bb_info_msg("bad message type option%s", ", ignoring 
packet");
                        continue;
                }
 
@@ -1086,6 +1095,17 @@
                        move_from_unaligned32(requested_nip, requested_ip_opt);
                }
 
+               /* Handle BOOTP clients */
+               if (!msg_type) {
+                       log1("received %s", "BOOTP BOOTREQUEST");
+                       if (!static_lease_nip) {
+                               log1("no static lease for BOOTP client%s", ", 
ignoring packet");
+                               continue;
+                       }
+                       send_offer(&packet, static_lease_nip, lease, 
requested_nip, arpping_ms);
+                       continue;
+               }
+
                switch (msg_type[0]) {
 
                case DHCPDISCOVER:

_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to