diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-03-21 06:15:28 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-03-21 06:15:28 +0100 |
| commit | c7dc79e71ddbc1498736a2bbf65a3da179557f83 (patch) | |
| tree | ab470e39f11f432b2099d3ebbe779d224bc1efba | |
| parent | 2e7aa928360eb9b1c90fa2356734cee794b66516 (diff) | |
| download | busybox-w32-c7dc79e71ddbc1498736a2bbf65a3da179557f83.tar.gz busybox-w32-c7dc79e71ddbc1498736a2bbf65a3da179557f83.tar.bz2 busybox-w32-c7dc79e71ddbc1498736a2bbf65a3da179557f83.zip | |
udhcpd: untangle incredibly messy handling of DHCPREQUEST
Also fixes attacks possible via DHCPDECLINE / DHCPRELEASE
function old new delta
udhcpd_main 1846 1949 +103
send_renew 105 142 +37
send_NAK 61 - -61
send_ACK 180 - -180
------------------------------------------------------------------------------
(add/remove: 0/2 grow/shrink: 2/0 up/down: 140/-241) Total: -101 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | networking/udhcp/clientpacket.c | 52 | ||||
| -rw-r--r-- | networking/udhcp/common.h | 75 | ||||
| -rw-r--r-- | networking/udhcp/dhcpc.h | 1 | ||||
| -rw-r--r-- | networking/udhcp/dhcpd.c | 264 | ||||
| -rw-r--r-- | networking/udhcp/files.c | 14 | ||||
| -rw-r--r-- | networking/udhcp/options.c | 2 | ||||
| -rw-r--r-- | networking/udhcp/options.h | 30 | ||||
| -rw-r--r-- | networking/udhcp/packet.c | 11 | ||||
| -rw-r--r-- | networking/udhcp/script.c | 2 |
9 files changed, 267 insertions, 184 deletions
diff --git a/networking/udhcp/clientpacket.c b/networking/udhcp/clientpacket.c index a255d6e84..a0be42885 100644 --- a/networking/udhcp/clientpacket.c +++ b/networking/udhcp/clientpacket.c | |||
| @@ -109,24 +109,6 @@ static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet) | |||
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | 111 | ||
| 112 | #if ENABLE_FEATURE_UDHCPC_ARPING | ||
| 113 | /* Broadcast a DHCP decline message */ | ||
| 114 | int FAST_FUNC send_decline(uint32_t xid, uint32_t server, uint32_t requested) | ||
| 115 | { | ||
| 116 | struct dhcp_packet packet; | ||
| 117 | |||
| 118 | init_packet(&packet, DHCPDECLINE); | ||
| 119 | packet.xid = xid; | ||
| 120 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); | ||
| 121 | add_simple_option(packet.options, DHCP_SERVER_ID, server); | ||
| 122 | |||
| 123 | bb_info_msg("Sending decline..."); | ||
| 124 | |||
| 125 | return raw_bcast_from_client_config_ifindex(&packet); | ||
| 126 | } | ||
| 127 | #endif | ||
| 128 | |||
| 129 | |||
| 130 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ | 112 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ |
| 131 | int FAST_FUNC send_discover(uint32_t xid, uint32_t requested) | 113 | int FAST_FUNC send_discover(uint32_t xid, uint32_t requested) |
| 132 | { | 114 | { |
| @@ -136,11 +118,9 @@ int FAST_FUNC send_discover(uint32_t xid, uint32_t requested) | |||
| 136 | packet.xid = xid; | 118 | packet.xid = xid; |
| 137 | if (requested) | 119 | if (requested) |
| 138 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); | 120 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); |
| 139 | |||
| 140 | /* Explicitly saying that we want RFC-compliant packets helps | 121 | /* Explicitly saying that we want RFC-compliant packets helps |
| 141 | * some buggy DHCP servers to NOT send bigger packets */ | 122 | * some buggy DHCP servers to NOT send bigger packets */ |
| 142 | add_simple_option(packet.options, DHCP_MAX_SIZE, htons(576)); | 123 | add_simple_option(packet.options, DHCP_MAX_SIZE, htons(576)); |
| 143 | |||
| 144 | add_param_req_option(&packet); | 124 | add_param_req_option(&packet); |
| 145 | 125 | ||
| 146 | bb_info_msg("Sending discover..."); | 126 | bb_info_msg("Sending discover..."); |
| @@ -159,7 +139,6 @@ int FAST_FUNC send_select(uint32_t xid, uint32_t server, uint32_t requested) | |||
| 159 | 139 | ||
| 160 | init_packet(&packet, DHCPREQUEST); | 140 | init_packet(&packet, DHCPREQUEST); |
| 161 | packet.xid = xid; | 141 | packet.xid = xid; |
| 162 | |||
| 163 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); | 142 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); |
| 164 | add_simple_option(packet.options, DHCP_SERVER_ID, server); | 143 | add_simple_option(packet.options, DHCP_SERVER_ID, server); |
| 165 | add_param_req_option(&packet); | 144 | add_param_req_option(&packet); |
| @@ -177,17 +156,46 @@ int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | |||
| 177 | 156 | ||
| 178 | init_packet(&packet, DHCPREQUEST); | 157 | init_packet(&packet, DHCPREQUEST); |
| 179 | packet.xid = xid; | 158 | packet.xid = xid; |
| 159 | /* RFC 2131: | ||
| 160 | * "3.2 Client-server interaction - reusing a previously | ||
| 161 | * allocated network address"... | ||
| 162 | * The client broadcasts a DHCPREQUEST message on its local subnet. | ||
| 163 | * The message includes the client's network address in the | ||
| 164 | * REQUESTED_IP option. As the client has not received its | ||
| 165 | * network address, it MUST NOT fill in the 'ciaddr' field." | ||
| 166 | * | ||
| 167 | * FIXME: we seem to not follow this, we do set ciaddr. | ||
| 168 | */ | ||
| 180 | packet.ciaddr = ciaddr; | 169 | packet.ciaddr = ciaddr; |
| 181 | 170 | add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr); | |
| 171 | if (server) | ||
| 172 | add_simple_option(packet.options, DHCP_SERVER_ID, server); | ||
| 182 | add_param_req_option(&packet); | 173 | add_param_req_option(&packet); |
| 174 | |||
| 183 | bb_info_msg("Sending renew..."); | 175 | bb_info_msg("Sending renew..."); |
| 184 | if (server) | 176 | if (server) |
| 185 | return udhcp_send_kernel_packet(&packet, | 177 | return udhcp_send_kernel_packet(&packet, |
| 186 | ciaddr, CLIENT_PORT, | 178 | ciaddr, CLIENT_PORT, |
| 187 | server, SERVER_PORT); | 179 | server, SERVER_PORT); |
| 180 | return raw_bcast_from_client_config_ifindex(&packet); | ||
| 181 | } | ||
| 182 | |||
| 183 | |||
| 184 | #if ENABLE_FEATURE_UDHCPC_ARPING | ||
| 185 | /* Broadcast a DHCP decline message */ | ||
| 186 | int FAST_FUNC send_decline(uint32_t xid, uint32_t server, uint32_t requested) | ||
| 187 | { | ||
| 188 | struct dhcp_packet packet; | ||
| 189 | |||
| 190 | init_packet(&packet, DHCPDECLINE); | ||
| 191 | packet.xid = xid; | ||
| 192 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); | ||
| 193 | add_simple_option(packet.options, DHCP_SERVER_ID, server); | ||
| 188 | 194 | ||
| 195 | bb_info_msg("Sending decline..."); | ||
| 189 | return raw_bcast_from_client_config_ifindex(&packet); | 196 | return raw_bcast_from_client_config_ifindex(&packet); |
| 190 | } | 197 | } |
| 198 | #endif | ||
| 191 | 199 | ||
| 192 | 200 | ||
| 193 | /* Unicast a DHCP release message */ | 201 | /* Unicast a DHCP release message */ |
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index d7c874e5b..cf3e0cd39 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
| @@ -21,11 +21,17 @@ extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */ | |||
| 21 | 21 | ||
| 22 | /*** packet.h ***/ | 22 | /*** packet.h ***/ |
| 23 | 23 | ||
| 24 | #define DHCP_OPTIONS_BUFSIZE 308 | 24 | /* DHCP protocol. See RFC 2131 */ |
| 25 | #define DHCP_MAGIC 0x63825363 | ||
| 26 | |||
| 27 | #define DHCP_OPTIONS_BUFSIZE 308 | ||
| 28 | |||
| 29 | #define BOOTREQUEST 1 | ||
| 30 | #define BOOTREPLY 2 | ||
| 25 | 31 | ||
| 26 | //TODO: rename ciaddr/yiaddr/chaddr | 32 | //TODO: rename ciaddr/yiaddr/chaddr |
| 27 | struct dhcp_packet { | 33 | struct dhcp_packet { |
| 28 | uint8_t op; /* 1 = BOOTREQUEST, 2 = BOOTREPLY */ | 34 | uint8_t op; /* BOOTREQUEST or BOOTREPLY */ |
| 29 | uint8_t htype; /* hardware address type. 1 = 10mb ethernet */ | 35 | uint8_t htype; /* hardware address type. 1 = 10mb ethernet */ |
| 30 | uint8_t hlen; /* hardware address length */ | 36 | uint8_t hlen; /* hardware address length */ |
| 31 | uint8_t hops; /* used by relay agents only */ | 37 | uint8_t hops; /* used by relay agents only */ |
| @@ -61,6 +67,71 @@ struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { | |||
| 61 | [(sizeof(struct ip_udp_dhcp_packet) != 576 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS) ? -1 : 1]; | 67 | [(sizeof(struct ip_udp_dhcp_packet) != 576 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS) ? -1 : 1]; |
| 62 | }; | 68 | }; |
| 63 | 69 | ||
| 70 | // RFC 2131 Table 5: Fields and options used by DHCP clients | ||
| 71 | // | ||
| 72 | // Field DHCPDISCOVER DHCPREQUEST DHCPDECLINE, | ||
| 73 | // DHCPINFORM DHCPRELEASE | ||
| 74 | // ----- ------------ ----------- ----------- | ||
| 75 | // 'op' BOOTREQUEST BOOTREQUEST BOOTREQUEST | ||
| 76 | // 'hops' 0 0 0 | ||
| 77 | // 'xid' selected by client 'xid' from server selected by | ||
| 78 | // DHCPOFFER message client | ||
| 79 | // 'secs' 0 or seconds since 0 or seconds since 0 | ||
| 80 | // DHCP process started DHCP process started | ||
| 81 | // 'flags' Set 'BROADCAST' Set 'BROADCAST' 0 | ||
| 82 | // flag if client flag if client | ||
| 83 | // requires broadcast requires broadcast | ||
| 84 | // reply reply | ||
| 85 | // 'ciaddr' 0 (DHCPDISCOVER) 0 or client's 0 (DHCPDECLINE) | ||
| 86 | // client's network address client's network | ||
| 87 | // network address (BOUND/RENEW/REBIND) address | ||
| 88 | // (DHCPINFORM) (DHCPRELEASE) | ||
| 89 | // 'yiaddr' 0 0 0 | ||
| 90 | // 'siaddr' 0 0 0 | ||
| 91 | // 'giaddr' 0 0 0 | ||
| 92 | // 'chaddr' client's hardware client's hardware client's hardware | ||
| 93 | // address address address | ||
| 94 | // 'sname' options, if options, if (unused) | ||
| 95 | // indicated in indicated in | ||
| 96 | // 'sname/file' 'sname/file' | ||
| 97 | // option; otherwise option; otherwise | ||
| 98 | // unused unused | ||
| 99 | // 'file' options, if options, if (unused) | ||
| 100 | // indicated in indicated in | ||
| 101 | // 'sname/file' 'sname/file' | ||
| 102 | // option; otherwise option; otherwise | ||
| 103 | // unused unused | ||
| 104 | // 'options' options options (unused) | ||
| 105 | // | ||
| 106 | // Option DHCPDISCOVER DHCPREQUEST DHCPDECLINE, | ||
| 107 | // DHCPINFORM DHCPRELEASE | ||
| 108 | // ------ ------------ ----------- ----------- | ||
| 109 | // Requested IP address MAY MUST (in MUST | ||
| 110 | // (DISCOVER) SELECTING or (DHCPDECLINE), | ||
| 111 | // MUST NOT INIT-REBOOT) MUST NOT | ||
| 112 | // (INFORM) MUST NOT (in (DHCPRELEASE) | ||
| 113 | // BOUND or | ||
| 114 | // RENEWING) | ||
| 115 | // IP address lease time MAY MAY MUST NOT | ||
| 116 | // (DISCOVER) | ||
| 117 | // MUST NOT | ||
| 118 | // (INFORM) | ||
| 119 | // Use 'file'/'sname' fields MAY MAY MAY | ||
| 120 | // Client identifier MAY MAY MAY | ||
| 121 | // Vendor class identifier MAY MAY MUST NOT | ||
| 122 | // Server identifier MUST NOT MUST (after MUST | ||
| 123 | // SELECTING) | ||
| 124 | // MUST NOT (after | ||
| 125 | // INIT-REBOOT, | ||
| 126 | // BOUND, RENEWING | ||
| 127 | // or REBINDING) | ||
| 128 | // Parameter request list MAY MAY MUST NOT | ||
| 129 | // Maximum message size MAY MAY MUST NOT | ||
| 130 | // Message SHOULD NOT SHOULD NOT SHOULD | ||
| 131 | // Site-specific MAY MAY MUST NOT | ||
| 132 | // All others MAY MAY MUST NOT | ||
| 133 | |||
| 134 | |||
| 64 | uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; | 135 | uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; |
| 65 | 136 | ||
| 66 | void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; | 137 | void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; |
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index dfab2368c..c9827b6e7 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h | |||
| @@ -40,7 +40,6 @@ int send_select(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC; | |||
| 40 | int send_decline(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC; | 40 | int send_decline(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC; |
| 41 | #endif | 41 | #endif |
| 42 | int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC; | 42 | int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC; |
| 43 | int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC; | ||
| 44 | int send_release(uint32_t server, uint32_t ciaddr) FAST_FUNC; | 43 | int send_release(uint32_t server, uint32_t ciaddr) FAST_FUNC; |
| 45 | 44 | ||
| 46 | int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) FAST_FUNC; | 45 | int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) FAST_FUNC; |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index f594bad66..a529e1b58 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
| @@ -28,18 +28,8 @@ | |||
| 28 | #include "options.h" | 28 | #include "options.h" |
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | /* send a packet to gateway_nip using the kernel ip stack */ | 31 | /* Send a packet to a specific mac address and ip address by creating our own ip packet */ |
| 32 | static int send_packet_to_relay(struct dhcp_packet *dhcp_pkt) | 32 | static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast) |
| 33 | { | ||
| 34 | log1("Forwarding packet to relay"); | ||
| 35 | |||
| 36 | return udhcp_send_kernel_packet(dhcp_pkt, | ||
| 37 | server_config.server_nip, SERVER_PORT, | ||
| 38 | dhcp_pkt->gateway_nip, SERVER_PORT); | ||
| 39 | } | ||
| 40 | |||
| 41 | /* send a packet to a specific mac address and ip address by creating our own ip packet */ | ||
| 42 | static int send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast) | ||
| 43 | { | 33 | { |
| 44 | const uint8_t *chaddr; | 34 | const uint8_t *chaddr; |
| 45 | uint32_t ciaddr; | 35 | uint32_t ciaddr; |
| @@ -69,25 +59,36 @@ static int send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadca | |||
| 69 | chaddr = dhcp_pkt->chaddr; | 59 | chaddr = dhcp_pkt->chaddr; |
| 70 | } | 60 | } |
| 71 | 61 | ||
| 72 | return udhcp_send_raw_packet(dhcp_pkt, | 62 | udhcp_send_raw_packet(dhcp_pkt, |
| 73 | /*src*/ server_config.server_nip, SERVER_PORT, | 63 | /*src*/ server_config.server_nip, SERVER_PORT, |
| 74 | /*dst*/ ciaddr, CLIENT_PORT, chaddr, | 64 | /*dst*/ ciaddr, CLIENT_PORT, chaddr, |
| 75 | server_config.ifindex); | 65 | server_config.ifindex); |
| 76 | } | 66 | } |
| 77 | 67 | ||
| 78 | /* Send the dhcp packet. | 68 | /* Send a packet to gateway_nip using the kernel ip stack */ |
| 79 | * If force broadcast is set, the packet will be broadcast. | 69 | static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt) |
| 80 | */ | 70 | { |
| 81 | static int send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) | 71 | log1("Forwarding packet to relay"); |
| 72 | |||
| 73 | udhcp_send_kernel_packet(dhcp_pkt, | ||
| 74 | server_config.server_nip, SERVER_PORT, | ||
| 75 | dhcp_pkt->gateway_nip, SERVER_PORT); | ||
| 76 | } | ||
| 77 | |||
| 78 | static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) | ||
| 82 | { | 79 | { |
| 83 | if (dhcp_pkt->gateway_nip) | 80 | if (dhcp_pkt->gateway_nip) |
| 84 | return send_packet_to_relay(dhcp_pkt); | 81 | send_packet_to_relay(dhcp_pkt); |
| 85 | return send_packet_to_client(dhcp_pkt, force_broadcast); | 82 | else |
| 83 | send_packet_to_client(dhcp_pkt, force_broadcast); | ||
| 86 | } | 84 | } |
| 87 | 85 | ||
| 88 | static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type) | 86 | static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type) |
| 89 | { | 87 | { |
| 88 | /* Sets op, htype, hlen, cookie fields | ||
| 89 | * and adds DHCP_MESSAGE_TYPE option */ | ||
| 90 | udhcp_init_header(packet, type); | 90 | udhcp_init_header(packet, type); |
| 91 | |||
| 91 | packet->xid = oldpacket->xid; | 92 | packet->xid = oldpacket->xid; |
| 92 | memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr)); | 93 | memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr)); |
| 93 | packet->flags = oldpacket->flags; | 94 | packet->flags = oldpacket->flags; |
| @@ -132,26 +133,32 @@ static uint32_t select_lease_time(struct dhcp_packet *packet) | |||
| 132 | return lease_time_sec; | 133 | return lease_time_sec; |
| 133 | } | 134 | } |
| 134 | 135 | ||
| 135 | /* send a DHCP OFFER to a DHCP DISCOVER */ | 136 | /* We got a DHCP DISCOVER. Send an OFFER. */ |
| 136 | static int send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) | 137 | static void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) |
| 137 | { | 138 | { |
| 138 | struct dhcp_packet packet; | 139 | struct dhcp_packet packet; |
| 139 | uint32_t lease_time_sec = server_config.max_lease_sec; | 140 | uint32_t lease_time_sec; |
| 140 | const char *p_host_name; | ||
| 141 | struct in_addr addr; | 141 | struct in_addr addr; |
| 142 | 142 | ||
| 143 | init_packet(&packet, oldpacket, DHCPOFFER); | 143 | init_packet(&packet, oldpacket, DHCPOFFER); |
| 144 | 144 | ||
| 145 | /* ADDME: if static, short circuit */ | 145 | /* If it is a static lease, use its IP */ |
| 146 | packet.yiaddr = static_lease_nip; | ||
| 147 | /* Else: */ | ||
| 146 | if (!static_lease_nip) { | 148 | if (!static_lease_nip) { |
| 149 | /* We have no static lease for client's chaddr */ | ||
| 147 | uint32_t req_nip; | 150 | uint32_t req_nip; |
| 148 | uint8_t *req_ip_opt; | 151 | uint8_t *req_ip_opt; |
| 152 | const char *p_host_name; | ||
| 149 | 153 | ||
| 150 | /* The client is in our lease/offered table */ | ||
| 151 | if (lease) { | 154 | if (lease) { |
| 155 | /* We have a dynamic lease for client's chaddr. | ||
| 156 | * Reuse its IP (even if lease is expired). | ||
| 157 | * Note that we ignore requested IP in this case. | ||
| 158 | */ | ||
| 152 | packet.yiaddr = lease->lease_nip; | 159 | packet.yiaddr = lease->lease_nip; |
| 153 | } | 160 | } |
| 154 | /* Or the client has requested an IP */ | 161 | /* Or: if client has requested an IP */ |
| 155 | else if ((req_ip_opt = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL | 162 | else if ((req_ip_opt = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL |
| 156 | /* (read IP) */ | 163 | /* (read IP) */ |
| 157 | && (move_from_unaligned32(req_nip, req_ip_opt), 1) | 164 | && (move_from_unaligned32(req_nip, req_ip_opt), 1) |
| @@ -165,50 +172,49 @@ static int send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, | |||
| 165 | ) { | 172 | ) { |
| 166 | packet.yiaddr = req_nip; | 173 | packet.yiaddr = req_nip; |
| 167 | } | 174 | } |
| 168 | /* Otherwise, find a free IP */ | ||
| 169 | else { | 175 | else { |
| 176 | /* Otherwise, find a free IP */ | ||
| 170 | packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr); | 177 | packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr); |
| 171 | } | 178 | } |
| 172 | 179 | ||
| 173 | if (!packet.yiaddr) { | 180 | if (!packet.yiaddr) { |
| 174 | bb_error_msg("no IP addresses to give - OFFER abandoned"); | 181 | bb_error_msg("no free IP addresses. OFFER abandoned"); |
| 175 | return -1; | 182 | return; |
| 176 | } | 183 | } |
| 184 | /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */ | ||
| 177 | p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); | 185 | p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); |
| 178 | if (add_lease(packet.chaddr, packet.yiaddr, | 186 | lease = add_lease(packet.chaddr, packet.yiaddr, |
| 179 | server_config.offer_time, | 187 | server_config.offer_time, |
| 180 | p_host_name, | 188 | p_host_name, |
| 181 | p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0 | 189 | p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0 |
| 182 | ) == 0 | 190 | ); |
| 183 | ) { | 191 | if (!lease) { |
| 184 | bb_error_msg("lease pool is full - OFFER abandoned"); | 192 | bb_error_msg("no free IP addresses. OFFER abandoned"); |
| 185 | return -1; | 193 | return; |
| 186 | } | 194 | } |
| 187 | lease_time_sec = select_lease_time(oldpacket); | ||
| 188 | } else { | ||
| 189 | /* It is a static lease... use it */ | ||
| 190 | packet.yiaddr = static_lease_nip; | ||
| 191 | } | 195 | } |
| 192 | 196 | ||
| 197 | lease_time_sec = select_lease_time(oldpacket); | ||
| 193 | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); | 198 | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); |
| 194 | add_server_options(&packet); | 199 | add_server_options(&packet); |
| 195 | 200 | ||
| 196 | addr.s_addr = packet.yiaddr; | 201 | addr.s_addr = packet.yiaddr; |
| 197 | bb_info_msg("Sending OFFER of %s", inet_ntoa(addr)); | 202 | bb_info_msg("Sending OFFER of %s", inet_ntoa(addr)); |
| 198 | return send_packet(&packet, /*force_bcast:*/ 0); | 203 | /* send_packet emits error message itself if it detects failure */ |
| 204 | send_packet(&packet, /*force_bcast:*/ 0); | ||
| 199 | } | 205 | } |
| 200 | 206 | ||
| 201 | static int send_NAK(struct dhcp_packet *oldpacket) | 207 | static void send_NAK(struct dhcp_packet *oldpacket) |
| 202 | { | 208 | { |
| 203 | struct dhcp_packet packet; | 209 | struct dhcp_packet packet; |
| 204 | 210 | ||
| 205 | init_packet(&packet, oldpacket, DHCPNAK); | 211 | init_packet(&packet, oldpacket, DHCPNAK); |
| 206 | 212 | ||
| 207 | log1("Sending NAK"); | 213 | log1("Sending NAK"); |
| 208 | return send_packet(&packet, /*force_bcast:*/ 1); | 214 | send_packet(&packet, /*force_bcast:*/ 1); |
| 209 | } | 215 | } |
| 210 | 216 | ||
| 211 | static int send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) | 217 | static void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) |
| 212 | { | 218 | { |
| 213 | struct dhcp_packet packet; | 219 | struct dhcp_packet packet; |
| 214 | uint32_t lease_time_sec; | 220 | uint32_t lease_time_sec; |
| @@ -219,15 +225,13 @@ static int send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) | |||
| 219 | packet.yiaddr = yiaddr; | 225 | packet.yiaddr = yiaddr; |
| 220 | 226 | ||
| 221 | lease_time_sec = select_lease_time(oldpacket); | 227 | lease_time_sec = select_lease_time(oldpacket); |
| 222 | |||
| 223 | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); | 228 | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); |
| 229 | |||
| 224 | add_server_options(&packet); | 230 | add_server_options(&packet); |
| 225 | 231 | ||
| 226 | addr.s_addr = packet.yiaddr; | 232 | addr.s_addr = yiaddr; |
| 227 | bb_info_msg("Sending ACK to %s", inet_ntoa(addr)); | 233 | bb_info_msg("Sending ACK to %s", inet_ntoa(addr)); |
| 228 | 234 | send_packet(&packet, /*force_bcast:*/ 0); | |
| 229 | if (send_packet(&packet, /*force_bcast:*/ 0) < 0) | ||
| 230 | return -1; | ||
| 231 | 235 | ||
| 232 | p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); | 236 | p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); |
| 233 | add_lease(packet.chaddr, packet.yiaddr, | 237 | add_lease(packet.chaddr, packet.yiaddr, |
| @@ -239,18 +243,21 @@ static int send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) | |||
| 239 | /* rewrite the file with leases at every new acceptance */ | 243 | /* rewrite the file with leases at every new acceptance */ |
| 240 | write_leases(); | 244 | write_leases(); |
| 241 | } | 245 | } |
| 242 | |||
| 243 | return 0; | ||
| 244 | } | 246 | } |
| 245 | 247 | ||
| 246 | static int send_inform(struct dhcp_packet *oldpacket) | 248 | static void send_inform(struct dhcp_packet *oldpacket) |
| 247 | { | 249 | { |
| 248 | struct dhcp_packet packet; | 250 | struct dhcp_packet packet; |
| 249 | 251 | ||
| 252 | /* "The server responds to a DHCPINFORM message by sending a DHCPACK | ||
| 253 | * message directly to the address given in the 'ciaddr' field | ||
| 254 | * of the DHCPINFORM message. The server MUST NOT send a lease | ||
| 255 | * expiration time to the client and SHOULD NOT fill in 'yiaddr'." | ||
| 256 | */ | ||
| 250 | init_packet(&packet, oldpacket, DHCPACK); | 257 | init_packet(&packet, oldpacket, DHCPACK); |
| 251 | add_server_options(&packet); | 258 | add_server_options(&packet); |
| 252 | 259 | ||
| 253 | return send_packet(&packet, /*force_bcast:*/ 0); | 260 | send_packet(&packet, /*force_bcast:*/ 0); |
| 254 | } | 261 | } |
| 255 | 262 | ||
| 256 | 263 | ||
| @@ -352,6 +359,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
| 352 | while (1) { /* loop until universe collapses */ | 359 | while (1) { /* loop until universe collapses */ |
| 353 | int bytes; | 360 | int bytes; |
| 354 | struct timeval tv; | 361 | struct timeval tv; |
| 362 | uint8_t *server_id_opt; | ||
| 363 | uint8_t *requested_opt; | ||
| 364 | uint32_t requested_nip = requested_nip; /* for compiler */ | ||
| 355 | 365 | ||
| 356 | if (server_socket < 0) { | 366 | if (server_socket < 0) { |
| 357 | server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, | 367 | server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, |
| @@ -404,124 +414,126 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
| 404 | } | 414 | } |
| 405 | continue; | 415 | continue; |
| 406 | } | 416 | } |
| 407 | |||
| 408 | if (packet.hlen != 6) { | 417 | if (packet.hlen != 6) { |
| 409 | bb_error_msg("MAC length != 6, ignoring packet"); | 418 | bb_error_msg("MAC length != 6, ignoring packet"); |
| 410 | continue; | 419 | continue; |
| 411 | } | 420 | } |
| 412 | 421 | if (packet.op != BOOTREQUEST) { | |
| 422 | bb_error_msg("not a REQUEST, ignoring packet"); | ||
| 423 | continue; | ||
| 424 | } | ||
| 413 | state = get_option(&packet, DHCP_MESSAGE_TYPE); | 425 | state = get_option(&packet, DHCP_MESSAGE_TYPE); |
| 414 | if (state == NULL) { | 426 | if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) { |
| 415 | bb_error_msg("no message type option, ignoring packet"); | 427 | bb_error_msg("no or bad message type option, ignoring packet"); |
| 416 | continue; | 428 | continue; |
| 417 | } | 429 | } |
| 418 | 430 | ||
| 419 | /* Look for a static lease */ | 431 | /* Look for a static/dynamic lease */ |
| 420 | static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); | 432 | static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); |
| 421 | if (static_lease_nip) { | 433 | if (static_lease_nip) { |
| 422 | bb_info_msg("Found static lease: %x", static_lease_nip); | 434 | bb_info_msg("Found static lease: %x", static_lease_nip); |
| 423 | |||
| 424 | memcpy(&fake_lease.lease_mac, &packet.chaddr, 6); | 435 | memcpy(&fake_lease.lease_mac, &packet.chaddr, 6); |
| 425 | fake_lease.lease_nip = static_lease_nip; | 436 | fake_lease.lease_nip = static_lease_nip; |
| 426 | fake_lease.expires = 0; | 437 | fake_lease.expires = 0; |
| 427 | |||
| 428 | lease = &fake_lease; | 438 | lease = &fake_lease; |
| 429 | } else { | 439 | } else { |
| 430 | lease = find_lease_by_mac(packet.chaddr); | 440 | lease = find_lease_by_mac(packet.chaddr); |
| 431 | } | 441 | } |
| 432 | 442 | ||
| 443 | /* Get REQUESTED_IP and SERVER_ID if present */ | ||
| 444 | server_id_opt = get_option(&packet, DHCP_SERVER_ID); | ||
| 445 | if (server_id_opt) { | ||
| 446 | uint32_t server_id_net; | ||
| 447 | move_from_unaligned32(server_id_net, server_id_opt); | ||
| 448 | if (server_id_net != server_config.server_nip) { | ||
| 449 | /* client talks to somebody else */ | ||
| 450 | log1("server ID doesn't match, ignoring"); | ||
| 451 | continue; | ||
| 452 | } | ||
| 453 | } | ||
| 454 | requested_opt = get_option(&packet, DHCP_REQUESTED_IP); | ||
| 455 | if (requested_opt) { | ||
| 456 | move_from_unaligned32(requested_nip, requested_opt); | ||
| 457 | } | ||
| 458 | |||
| 433 | switch (state[0]) { | 459 | switch (state[0]) { |
| 460 | |||
| 434 | case DHCPDISCOVER: | 461 | case DHCPDISCOVER: |
| 435 | log1("Received DISCOVER"); | 462 | log1("Received DISCOVER"); |
| 436 | 463 | ||
| 437 | if (send_offer(&packet, static_lease_nip, lease) < 0) { | 464 | send_offer(&packet, static_lease_nip, lease); |
| 438 | bb_error_msg("send OFFER failed"); | ||
| 439 | } | ||
| 440 | break; | 465 | break; |
| 441 | case DHCPREQUEST: { | ||
| 442 | uint8_t *server_id_opt, *requested_opt; | ||
| 443 | uint32_t server_id_net = server_id_net; /* for compiler */ | ||
| 444 | uint32_t requested_nip = requested_nip; /* for compiler */ | ||
| 445 | 466 | ||
| 467 | case DHCPREQUEST: | ||
| 446 | log1("Received REQUEST"); | 468 | log1("Received REQUEST"); |
| 447 | 469 | ||
| 448 | requested_opt = get_option(&packet, DHCP_REQUESTED_IP); | 470 | /* RFC 2131: "The REQUESTED_IP option MUST be set |
| 449 | server_id_opt = get_option(&packet, DHCP_SERVER_ID); | 471 | * to the value of 'yiaddr' in the DHCPOFFER message |
| 450 | if (requested_opt) | 472 | * from the server." */ |
| 451 | move_from_unaligned32(requested_nip, requested_opt); | 473 | if (!requested_opt) { |
| 452 | if (server_id_opt) | 474 | log1("no requested IP, ignoring"); |
| 453 | move_from_unaligned32(server_id_net, server_id_opt); | 475 | break; |
| 454 | 476 | } | |
| 455 | if (lease) { | 477 | if (lease && requested_nip == lease->lease_nip) { |
| 456 | if (server_id_opt) { | 478 | /* client requests IP which matches the lease. |
| 457 | /* SELECTING State */ | 479 | * ACK it, and bump lease expiration time. */ |
| 458 | if (server_id_net == server_config.server_nip | 480 | send_ACK(&packet, lease->lease_nip); |
| 459 | && requested_opt | 481 | break; |
| 460 | && requested_nip == lease->lease_nip | 482 | } |
| 461 | ) { | 483 | if (server_id_opt) { |
| 462 | send_ACK(&packet, lease->lease_nip); | 484 | /* client was talking specifically to us. |
| 463 | } | 485 | * "No, we don't have this IP for you". */ |
| 464 | } else if (requested_opt) { | 486 | send_NAK(&packet); |
| 465 | /* INIT-REBOOT State */ | ||
| 466 | if (lease->lease_nip == requested_nip) | ||
| 467 | send_ACK(&packet, lease->lease_nip); | ||
| 468 | else | ||
| 469 | send_NAK(&packet); | ||
| 470 | } else if (lease->lease_nip == packet.ciaddr) { | ||
| 471 | /* RENEWING or REBINDING State */ | ||
| 472 | send_ACK(&packet, lease->lease_nip); | ||
| 473 | } else { /* don't know what to do!!!! */ | ||
| 474 | send_NAK(&packet); | ||
| 475 | } | ||
| 476 | |||
| 477 | /* what to do if we have no record of the client */ | ||
| 478 | } else if (server_id_opt) { | ||
| 479 | /* SELECTING State */ | ||
| 480 | |||
| 481 | } else if (requested_opt) { | ||
| 482 | /* INIT-REBOOT State */ | ||
| 483 | lease = find_lease_by_nip(requested_nip); | ||
| 484 | if (lease) { | ||
| 485 | if (is_expired_lease(lease)) { | ||
| 486 | /* probably best if we drop this lease */ | ||
| 487 | memset(lease->lease_mac, 0, sizeof(lease->lease_mac)); | ||
| 488 | } else { | ||
| 489 | /* make some contention for this address */ | ||
| 490 | send_NAK(&packet); | ||
| 491 | } | ||
| 492 | } else { | ||
| 493 | uint32_t r = ntohl(requested_nip); | ||
| 494 | if (r < server_config.start_ip | ||
| 495 | || r > server_config.end_ip | ||
| 496 | ) { | ||
| 497 | send_NAK(&packet); | ||
| 498 | } | ||
| 499 | /* else remain silent */ | ||
| 500 | } | ||
| 501 | |||
| 502 | } else { | ||
| 503 | /* RENEWING or REBINDING State */ | ||
| 504 | } | 487 | } |
| 505 | break; | 488 | break; |
| 506 | } | 489 | |
| 507 | case DHCPDECLINE: | 490 | case DHCPDECLINE: |
| 491 | /* RFC 2131: | ||
| 492 | * "If the server receives a DHCPDECLINE message, | ||
| 493 | * the client has discovered through some other means | ||
| 494 | * that the suggested network address is already | ||
| 495 | * in use. The server MUST mark the network address | ||
| 496 | * as not available and SHOULD notify the local | ||
| 497 | * sysadmin of a possible configuration problem." | ||
| 498 | * | ||
| 499 | * SERVER_ID must be present, | ||
| 500 | * REQUESTED_IP must be present, | ||
| 501 | * chaddr must be filled in, | ||
| 502 | * ciaddr must be 0 (we do not check this) | ||
| 503 | */ | ||
| 508 | log1("Received DECLINE"); | 504 | log1("Received DECLINE"); |
| 509 | if (lease) { | 505 | if (server_id_opt |
| 506 | && requested_opt | ||
| 507 | && lease /* chaddr matches this lease */ | ||
| 508 | && requested_nip == lease->lease_nip | ||
| 509 | ) { | ||
| 510 | memset(lease->lease_mac, 0, sizeof(lease->lease_mac)); | 510 | memset(lease->lease_mac, 0, sizeof(lease->lease_mac)); |
| 511 | lease->expires = time(NULL) + server_config.decline_time; | 511 | lease->expires = time(NULL) + server_config.decline_time; |
| 512 | } | 512 | } |
| 513 | break; | 513 | break; |
| 514 | |||
| 514 | case DHCPRELEASE: | 515 | case DHCPRELEASE: |
| 516 | /* "Upon receipt of a DHCPRELEASE message, the server | ||
| 517 | * marks the network address as not allocated." | ||
| 518 | * | ||
| 519 | * SERVER_ID must be present, | ||
| 520 | * REQUESTED_IP must not be present (we do not check this), | ||
| 521 | * chaddr must be filled in, | ||
| 522 | * ciaddr must be filled in | ||
| 523 | */ | ||
| 515 | log1("Received RELEASE"); | 524 | log1("Received RELEASE"); |
| 516 | if (lease) | 525 | if (server_id_opt |
| 526 | && lease /* chaddr matches this lease */ | ||
| 527 | && packet.ciaddr == lease->lease_nip | ||
| 528 | ) { | ||
| 517 | lease->expires = time(NULL); | 529 | lease->expires = time(NULL); |
| 530 | } | ||
| 518 | break; | 531 | break; |
| 532 | |||
| 519 | case DHCPINFORM: | 533 | case DHCPINFORM: |
| 520 | log1("Received INFORM"); | 534 | log1("Received INFORM"); |
| 521 | send_inform(&packet); | 535 | send_inform(&packet); |
| 522 | break; | 536 | break; |
| 523 | default: | ||
| 524 | bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]); | ||
| 525 | } | 537 | } |
| 526 | } | 538 | } |
| 527 | ret0: | 539 | ret0: |
diff --git a/networking/udhcp/files.c b/networking/udhcp/files.c index 40cfe9fd2..62f4a388f 100644 --- a/networking/udhcp/files.c +++ b/networking/udhcp/files.c | |||
| @@ -99,7 +99,7 @@ static void attach_option(struct option_set **opt_list, | |||
| 99 | log2("Attaching option %02x to list", option->code); | 99 | log2("Attaching option %02x to list", option->code); |
| 100 | 100 | ||
| 101 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 101 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
| 102 | if ((option->flags & TYPE_MASK) == OPTION_STR1035) | 102 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035) |
| 103 | /* reuse buffer and length for RFC1035-formatted string */ | 103 | /* reuse buffer and length for RFC1035-formatted string */ |
| 104 | buffer = (char *)dname_enc(NULL, 0, buffer, &length); | 104 | buffer = (char *)dname_enc(NULL, 0, buffer, &length); |
| 105 | #endif | 105 | #endif |
| @@ -118,7 +118,7 @@ static void attach_option(struct option_set **opt_list, | |||
| 118 | new->next = *curr; | 118 | new->next = *curr; |
| 119 | *curr = new; | 119 | *curr = new; |
| 120 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 120 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
| 121 | if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) | 121 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035 && buffer != NULL) |
| 122 | free(buffer); | 122 | free(buffer); |
| 123 | #endif | 123 | #endif |
| 124 | return; | 124 | return; |
| @@ -128,7 +128,7 @@ static void attach_option(struct option_set **opt_list, | |||
| 128 | log1("Attaching option %02x to existing member of list", option->code); | 128 | log1("Attaching option %02x to existing member of list", option->code); |
| 129 | if (option->flags & OPTION_LIST) { | 129 | if (option->flags & OPTION_LIST) { |
| 130 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 130 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
| 131 | if ((option->flags & TYPE_MASK) == OPTION_STR1035) | 131 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035) |
| 132 | /* reuse buffer and length for RFC1035-formatted string */ | 132 | /* reuse buffer and length for RFC1035-formatted string */ |
| 133 | buffer = (char *)dname_enc(existing->data + 2, | 133 | buffer = (char *)dname_enc(existing->data + 2, |
| 134 | existing->data[OPT_LEN], buffer, &length); | 134 | existing->data[OPT_LEN], buffer, &length); |
| @@ -136,7 +136,7 @@ static void attach_option(struct option_set **opt_list, | |||
| 136 | if (existing->data[OPT_LEN] + length <= 255) { | 136 | if (existing->data[OPT_LEN] + length <= 255) { |
| 137 | existing->data = xrealloc(existing->data, | 137 | existing->data = xrealloc(existing->data, |
| 138 | existing->data[OPT_LEN] + length + 3); | 138 | existing->data[OPT_LEN] + length + 3); |
| 139 | if ((option->flags & TYPE_MASK) == OPTION_STRING) { | 139 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STRING) { |
| 140 | /* ' ' can bring us to 256 - bad */ | 140 | /* ' ' can bring us to 256 - bad */ |
| 141 | if (existing->data[OPT_LEN] + length >= 255) | 141 | if (existing->data[OPT_LEN] + length >= 255) |
| 142 | return; | 142 | return; |
| @@ -148,7 +148,7 @@ static void attach_option(struct option_set **opt_list, | |||
| 148 | existing->data[OPT_LEN] += length; | 148 | existing->data[OPT_LEN] += length; |
| 149 | } /* else, ignore the data, we could put this in a second option in the future */ | 149 | } /* else, ignore the data, we could put this in a second option in the future */ |
| 150 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 150 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
| 151 | if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) | 151 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035 && buffer != NULL) |
| 152 | free(buffer); | 152 | free(buffer); |
| 153 | #endif | 153 | #endif |
| 154 | } /* else, ignore the new data */ | 154 | } /* else, ignore the new data */ |
| @@ -182,10 +182,10 @@ static int FAST_FUNC read_opt(const char *const_line, void *arg) | |||
| 182 | do { | 182 | do { |
| 183 | val = strtok(NULL, ", \t"); | 183 | val = strtok(NULL, ", \t"); |
| 184 | if (!val) break; | 184 | if (!val) break; |
| 185 | length = dhcp_option_lengths[option->flags & TYPE_MASK]; | 185 | length = dhcp_option_lengths[option->flags & OPTION_TYPE_MASK]; |
| 186 | retval = 0; | 186 | retval = 0; |
| 187 | opt = buffer; /* new meaning for variable opt */ | 187 | opt = buffer; /* new meaning for variable opt */ |
| 188 | switch (option->flags & TYPE_MASK) { | 188 | switch (option->flags & OPTION_TYPE_MASK) { |
| 189 | case OPTION_IP: | 189 | case OPTION_IP: |
| 190 | retval = read_nip(val, buffer); | 190 | retval = read_nip(val, buffer); |
| 191 | break; | 191 | break; |
diff --git a/networking/udhcp/options.c b/networking/udhcp/options.c index 5bef985bc..29a264047 100644 --- a/networking/udhcp/options.c +++ b/networking/udhcp/options.c | |||
| @@ -252,7 +252,7 @@ void FAST_FUNC add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data | |||
| 252 | uint8_t option[6], len; | 252 | uint8_t option[6], len; |
| 253 | 253 | ||
| 254 | option[OPT_CODE] = code; | 254 | option[OPT_CODE] = code; |
| 255 | len = dhcp_option_lengths[dh->flags & TYPE_MASK]; | 255 | len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK]; |
| 256 | option[OPT_LEN] = len; | 256 | option[OPT_LEN] = len; |
| 257 | if (BB_BIG_ENDIAN) | 257 | if (BB_BIG_ENDIAN) |
| 258 | data <<= 8 * (4 - len); | 258 | data <<= 8 * (4 - len); |
diff --git a/networking/udhcp/options.h b/networking/udhcp/options.h index 05090f12e..3ca4dc42d 100644 --- a/networking/udhcp/options.h +++ b/networking/udhcp/options.h | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | 5 | ||
| 6 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | 6 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
| 7 | 7 | ||
| 8 | #define TYPE_MASK 0x0F | ||
| 9 | 8 | ||
| 10 | enum { | 9 | enum { |
| 11 | OPTION_IP = 1, | 10 | OPTION_IP = 1, |
| @@ -21,19 +20,13 @@ enum { | |||
| 21 | OPTION_U32, | 20 | OPTION_U32, |
| 22 | OPTION_S32, | 21 | OPTION_S32, |
| 23 | OPTION_STATIC_ROUTES, | 22 | OPTION_STATIC_ROUTES, |
| 24 | }; | ||
| 25 | |||
| 26 | /* Client requests this option by default */ | ||
| 27 | #define OPTION_REQ 0x10 | ||
| 28 | /* There can be a list of 1 or more of these */ | ||
| 29 | #define OPTION_LIST 0x20 | ||
| 30 | 23 | ||
| 31 | /*****************************************************************/ | 24 | OPTION_TYPE_MASK = 0x0f, |
| 32 | /* Do not modify below here unless you know what you are doing!! */ | 25 | /* Client requests this option by default */ |
| 33 | /*****************************************************************/ | 26 | OPTION_REQ = 0x10, |
| 34 | 27 | /* There can be a list of 1 or more of these */ | |
| 35 | /* DHCP protocol. See RFC 2131 */ | 28 | OPTION_LIST = 0x20, |
| 36 | #define DHCP_MAGIC 0x63825363 | 29 | }; |
| 37 | 30 | ||
| 38 | /* DHCP option codes (partial list). See RFC 2132 and | 31 | /* DHCP option codes (partial list). See RFC 2132 and |
| 39 | * http://www.iana.org/assignments/bootp-dhcp-parameters/ | 32 | * http://www.iana.org/assignments/bootp-dhcp-parameters/ |
| @@ -81,7 +74,6 @@ enum { | |||
| 81 | //#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ | 74 | //#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ |
| 82 | #define DHCP_END 0xff | 75 | #define DHCP_END 0xff |
| 83 | 76 | ||
| 84 | |||
| 85 | /* Offsets in option byte sequence */ | 77 | /* Offsets in option byte sequence */ |
| 86 | #define OPT_CODE 0 | 78 | #define OPT_CODE 0 |
| 87 | #define OPT_LEN 1 | 79 | #define OPT_LEN 1 |
| @@ -91,12 +83,7 @@ enum { | |||
| 91 | #define FILE_FIELD 1 | 83 | #define FILE_FIELD 1 |
| 92 | #define SNAME_FIELD 2 | 84 | #define SNAME_FIELD 2 |
| 93 | 85 | ||
| 94 | #define BOOTREQUEST 1 | 86 | /* DHCP_MESSAGE_TYPE values */ |
| 95 | #define BOOTREPLY 2 | ||
| 96 | |||
| 97 | #define ETH_10MB 1 | ||
| 98 | #define ETH_10MB_LEN 6 | ||
| 99 | |||
| 100 | #define DHCPDISCOVER 1 /* client -> server */ | 87 | #define DHCPDISCOVER 1 /* client -> server */ |
| 101 | #define DHCPOFFER 2 /* client <- server */ | 88 | #define DHCPOFFER 2 /* client <- server */ |
| 102 | #define DHCPREQUEST 3 /* client -> server */ | 89 | #define DHCPREQUEST 3 /* client -> server */ |
| @@ -105,6 +92,9 @@ enum { | |||
| 105 | #define DHCPNAK 6 /* client <- server */ | 92 | #define DHCPNAK 6 /* client <- server */ |
| 106 | #define DHCPRELEASE 7 /* client -> server */ | 93 | #define DHCPRELEASE 7 /* client -> server */ |
| 107 | #define DHCPINFORM 8 /* client -> server */ | 94 | #define DHCPINFORM 8 /* client -> server */ |
| 95 | #define DHCP_MINTYPE DHCPDISCOVER | ||
| 96 | #define DHCP_MAXTYPE DHCPINFORM | ||
| 97 | |||
| 108 | 98 | ||
| 109 | struct dhcp_option { | 99 | struct dhcp_option { |
| 110 | uint8_t flags; | 100 | uint8_t flags; |
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 90410cbc0..84d83098c 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) | 22 | void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) |
| 23 | { | 23 | { |
| 24 | memset(packet, 0, sizeof(struct dhcp_packet)); | 24 | memset(packet, 0, sizeof(*packet)); |
| 25 | packet->op = BOOTREQUEST; /* if client to a server */ | 25 | packet->op = BOOTREQUEST; /* if client to a server */ |
| 26 | switch (type) { | 26 | switch (type) { |
| 27 | case DHCPOFFER: | 27 | case DHCPOFFER: |
| @@ -29,10 +29,11 @@ void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) | |||
| 29 | case DHCPNAK: | 29 | case DHCPNAK: |
| 30 | packet->op = BOOTREPLY; /* if server to client */ | 30 | packet->op = BOOTREPLY; /* if server to client */ |
| 31 | } | 31 | } |
| 32 | packet->htype = ETH_10MB; | 32 | packet->htype = 1; /* ethernet */ |
| 33 | packet->hlen = ETH_10MB_LEN; | 33 | packet->hlen = 6; |
| 34 | packet->cookie = htonl(DHCP_MAGIC); | 34 | packet->cookie = htonl(DHCP_MAGIC); |
| 35 | packet->options[0] = DHCP_END; | 35 | if (DHCP_END != 0) |
| 36 | packet->options[0] = DHCP_END; | ||
| 36 | add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); | 37 | add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); |
| 37 | } | 38 | } |
| 38 | 39 | ||
| @@ -228,6 +229,7 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, | |||
| 228 | msg = "sendto"; | 229 | msg = "sendto"; |
| 229 | ret_close: | 230 | ret_close: |
| 230 | close(fd); | 231 | close(fd); |
| 232 | /* FIXME: and if result >= 0 but != IP_UPD_DHCP_SIZE? */ | ||
| 231 | if (result < 0) { | 233 | if (result < 0) { |
| 232 | ret_msg: | 234 | ret_msg: |
| 233 | bb_perror_msg(msg, "PACKET"); | 235 | bb_perror_msg(msg, "PACKET"); |
| @@ -280,6 +282,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, | |||
| 280 | msg = "write"; | 282 | msg = "write"; |
| 281 | ret_close: | 283 | ret_close: |
| 282 | close(fd); | 284 | close(fd); |
| 285 | /* FIXME: and if result >= 0 but != DHCP_SIZE? */ | ||
| 283 | if (result < 0) { | 286 | if (result < 0) { |
| 284 | ret_msg: | 287 | ret_msg: |
| 285 | bb_perror_msg(msg, "UDP"); | 288 | bb_perror_msg(msg, "UDP"); |
diff --git a/networking/udhcp/script.c b/networking/udhcp/script.c index b4413fa16..400fd2b9b 100644 --- a/networking/udhcp/script.c +++ b/networking/udhcp/script.c | |||
| @@ -64,7 +64,7 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
| 64 | 64 | ||
| 65 | /* option points to OPT_DATA, need to go back and get OPT_LEN */ | 65 | /* option points to OPT_DATA, need to go back and get OPT_LEN */ |
| 66 | len = option[OPT_LEN - OPT_DATA]; | 66 | len = option[OPT_LEN - OPT_DATA]; |
| 67 | type = type_p->flags & TYPE_MASK; | 67 | type = type_p->flags & OPTION_TYPE_MASK; |
| 68 | optlen = dhcp_option_lengths[type]; | 68 | optlen = dhcp_option_lengths[type]; |
| 69 | upper_length = len_of_option_as_string[type] * (len / optlen); | 69 | upper_length = len_of_option_as_string[type] * (len / optlen); |
| 70 | 70 | ||
