7 |
* |
* |
8 |
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
9 |
*/ |
*/ |
10 |
|
#include "common.h" |
11 |
|
#include "dhcpd.h" |
12 |
|
#include "dhcpc.h" |
13 |
|
#include "options.h" |
14 |
|
|
15 |
#include <features.h> |
//#include <features.h> |
16 |
#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION |
#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION |
17 |
#include <netpacket/packet.h> |
#include <netpacket/packet.h> |
18 |
#include <net/ethernet.h> |
#include <net/ethernet.h> |
22 |
#include <linux/if_ether.h> |
#include <linux/if_ether.h> |
23 |
#endif |
#endif |
24 |
|
|
|
#include "common.h" |
|
|
#include "dhcpd.h" |
|
|
#include "dhcpc.h" |
|
|
#include "options.h" |
|
|
|
|
25 |
|
|
26 |
/* Create a random xid */ |
/* Create a random xid */ |
27 |
uint32_t FAST_FUNC random_xid(void) |
uint32_t FAST_FUNC random_xid(void) |
36 |
} |
} |
37 |
|
|
38 |
|
|
39 |
/* initialize a packet with the proper defaults */ |
/* Initialize the packet with the proper defaults */ |
40 |
static void init_packet(struct dhcpMessage *packet, char type) |
static void init_packet(struct dhcp_packet *packet, char type) |
41 |
{ |
{ |
42 |
udhcp_init_header(packet, type); |
udhcp_init_header(packet, type); |
43 |
memcpy(packet->chaddr, client_config.arp, 6); |
memcpy(packet->chaddr, client_config.client_mac, 6); |
44 |
if (client_config.clientid) |
if (client_config.clientid) |
45 |
add_option_string(packet->options, client_config.clientid); |
add_option_string(packet->options, client_config.clientid); |
46 |
if (client_config.hostname) |
if (client_config.hostname) |
55 |
/* Add a parameter request list for stubborn DHCP servers. Pull the data |
/* Add a parameter request list for stubborn DHCP servers. Pull the data |
56 |
* from the struct in options.c. Don't do bounds checking here because it |
* from the struct in options.c. Don't do bounds checking here because it |
57 |
* goes towards the head of the packet. */ |
* goes towards the head of the packet. */ |
58 |
static void add_param_req_option(struct dhcpMessage *packet) |
static void add_param_req_option(struct dhcp_packet *packet) |
59 |
{ |
{ |
60 |
uint8_t c; |
uint8_t c; |
61 |
int end = end_option(packet->options); |
int end = end_option(packet->options); |
95 |
* client reverts to using the IP broadcast address. |
* client reverts to using the IP broadcast address. |
96 |
*/ |
*/ |
97 |
|
|
98 |
static int raw_bcast_from_client_config_ifindex(struct dhcpMessage *packet) |
static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet) |
99 |
{ |
{ |
100 |
return udhcp_send_raw_packet(packet, |
return udhcp_send_raw_packet(packet, |
101 |
/*src*/ INADDR_ANY, CLIENT_PORT, |
/*src*/ INADDR_ANY, CLIENT_PORT, |
108 |
/* Broadcast a DHCP decline message */ |
/* Broadcast a DHCP decline message */ |
109 |
int FAST_FUNC send_decline(uint32_t xid, uint32_t server, uint32_t requested) |
int FAST_FUNC send_decline(uint32_t xid, uint32_t server, uint32_t requested) |
110 |
{ |
{ |
111 |
struct dhcpMessage packet; |
struct dhcp_packet packet; |
112 |
|
|
113 |
init_packet(&packet, DHCPDECLINE); |
init_packet(&packet, DHCPDECLINE); |
114 |
packet.xid = xid; |
packet.xid = xid; |
121 |
} |
} |
122 |
#endif |
#endif |
123 |
|
|
124 |
|
|
125 |
/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ |
/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ |
126 |
int FAST_FUNC send_discover(uint32_t xid, uint32_t requested) |
int FAST_FUNC send_discover(uint32_t xid, uint32_t requested) |
127 |
{ |
{ |
128 |
struct dhcpMessage packet; |
struct dhcp_packet packet; |
129 |
|
|
130 |
init_packet(&packet, DHCPDISCOVER); |
init_packet(&packet, DHCPDISCOVER); |
131 |
packet.xid = xid; |
packet.xid = xid; |
143 |
} |
} |
144 |
|
|
145 |
|
|
146 |
/* Broadcasts a DHCP request message */ |
/* Broadcast a DHCP request message */ |
147 |
/* RFC 2131 3.1 paragraph 3: |
/* RFC 2131 3.1 paragraph 3: |
148 |
* "The client _broadcasts_ a DHCPREQUEST message..." |
* "The client _broadcasts_ a DHCPREQUEST message..." |
149 |
*/ |
*/ |
150 |
int FAST_FUNC send_select(uint32_t xid, uint32_t server, uint32_t requested) |
int FAST_FUNC send_select(uint32_t xid, uint32_t server, uint32_t requested) |
151 |
{ |
{ |
152 |
struct dhcpMessage packet; |
struct dhcp_packet packet; |
153 |
struct in_addr addr; |
struct in_addr addr; |
154 |
|
|
155 |
init_packet(&packet, DHCPREQUEST); |
init_packet(&packet, DHCPREQUEST); |
165 |
} |
} |
166 |
|
|
167 |
|
|
168 |
/* Unicasts or broadcasts a DHCP renew message */ |
/* Unicast or broadcast a DHCP renew message */ |
169 |
int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) |
int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) |
170 |
{ |
{ |
171 |
struct dhcpMessage packet; |
struct dhcp_packet packet; |
172 |
|
|
173 |
init_packet(&packet, DHCPREQUEST); |
init_packet(&packet, DHCPREQUEST); |
174 |
packet.xid = xid; |
packet.xid = xid; |
185 |
} |
} |
186 |
|
|
187 |
|
|
188 |
/* Unicasts a DHCP release message */ |
/* Unicast a DHCP release message */ |
189 |
int FAST_FUNC send_release(uint32_t server, uint32_t ciaddr) |
int FAST_FUNC send_release(uint32_t server, uint32_t ciaddr) |
190 |
{ |
{ |
191 |
struct dhcpMessage packet; |
struct dhcp_packet packet; |
192 |
|
|
193 |
init_packet(&packet, DHCPRELEASE); |
init_packet(&packet, DHCPRELEASE); |
194 |
packet.xid = random_xid(); |
packet.xid = random_xid(); |
202 |
|
|
203 |
|
|
204 |
/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ |
/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ |
205 |
int FAST_FUNC udhcp_recv_raw_packet(struct dhcpMessage *payload, int fd) |
int FAST_FUNC udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) |
206 |
{ |
{ |
207 |
int bytes; |
int bytes; |
208 |
struct udp_dhcp_packet packet; |
struct ip_udp_dhcp_packet packet; |
209 |
uint16_t check; |
uint16_t check; |
210 |
|
|
211 |
memset(&packet, 0, sizeof(packet)); |
memset(&packet, 0, sizeof(packet)); |
212 |
bytes = safe_read(fd, &packet, sizeof(packet)); |
bytes = safe_read(fd, &packet, sizeof(packet)); |
213 |
if (bytes < 0) { |
if (bytes < 0) { |
214 |
DEBUG("Cannot read on raw listening socket - ignoring"); |
log1("Packet read error, ignoring"); |
215 |
/* NB: possible down interface, etc. Caller should pause. */ |
/* NB: possible down interface, etc. Caller should pause. */ |
216 |
return bytes; /* returns -1 */ |
return bytes; /* returns -1 */ |
217 |
} |
} |
218 |
|
|
219 |
if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) { |
if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) { |
220 |
DEBUG("Packet is too short, ignoring"); |
log1("Packet is too short, ignoring"); |
221 |
return -2; |
return -2; |
222 |
} |
} |
223 |
|
|
224 |
if (bytes < ntohs(packet.ip.tot_len)) { |
if (bytes < ntohs(packet.ip.tot_len)) { |
225 |
/* packet is bigger than sizeof(packet), we did partial read */ |
/* packet is bigger than sizeof(packet), we did partial read */ |
226 |
DEBUG("Oversized packet, ignoring"); |
log1("Oversized packet, ignoring"); |
227 |
return -2; |
return -2; |
228 |
} |
} |
229 |
|
|
237 |
/* || bytes > (int) sizeof(packet) - can't happen */ |
/* || bytes > (int) sizeof(packet) - can't happen */ |
238 |
|| ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip)) |
|| ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip)) |
239 |
) { |
) { |
240 |
DEBUG("Unrelated/bogus packet"); |
log1("Unrelated/bogus packet, ignoring"); |
241 |
return -2; |
return -2; |
242 |
} |
} |
243 |
|
|
245 |
check = packet.ip.check; |
check = packet.ip.check; |
246 |
packet.ip.check = 0; |
packet.ip.check = 0; |
247 |
if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) { |
if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) { |
248 |
DEBUG("Bad IP header checksum, ignoring"); |
log1("Bad IP header checksum, ignoring"); |
249 |
return -2; |
return -2; |
250 |
} |
} |
251 |
|
|
256 |
check = packet.udp.check; |
check = packet.udp.check; |
257 |
packet.udp.check = 0; |
packet.udp.check = 0; |
258 |
if (check && check != udhcp_checksum(&packet, bytes)) { |
if (check && check != udhcp_checksum(&packet, bytes)) { |
259 |
bb_error_msg("packet with bad UDP checksum received, ignoring"); |
log1("Packet with bad UDP checksum received, ignoring"); |
260 |
return -2; |
return -2; |
261 |
} |
} |
262 |
|
|
263 |
memcpy(payload, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp))); |
memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp))); |
264 |
|
|
265 |
if (payload->cookie != htonl(DHCP_MAGIC)) { |
if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) { |
266 |
bb_error_msg("received bogus message (bad magic), ignoring"); |
bb_info_msg("Packet with bad magic, ignoring"); |
267 |
return -2; |
return -2; |
268 |
} |
} |
269 |
DEBUG("Got valid DHCP packet"); |
log1("Got valid DHCP packet"); |
270 |
|
udhcp_dump_packet(dhcp_pkt); |
271 |
return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); |
return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); |
272 |
} |
} |