aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp
diff options
context:
space:
mode:
authorMartin Lewis <martin.lewis.x84@gmail.com>2020-06-23 15:25:08 -0500
committerDenys Vlasenko <vda.linux@googlemail.com>2020-06-29 14:57:02 +0200
commitacdc8eed89399a9fa5e7478ee40b928c65e3ab4e (patch)
tree406e5c338b8d22c895cb16bdee9151202efe0ead /networking/udhcp
parentfc2ce04a38ebfb03f9aeff205979786839cd5a7c (diff)
downloadbusybox-w32-acdc8eed89399a9fa5e7478ee40b928c65e3ab4e.tar.gz
busybox-w32-acdc8eed89399a9fa5e7478ee40b928c65e3ab4e.tar.bz2
busybox-w32-acdc8eed89399a9fa5e7478ee40b928c65e3ab4e.zip
udhcp: add option scanner
Added an option scanner to udhcp to enable iteration over packet options. Signed-off-by: Martin Lewis <martin.lewis.x84@gmail.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/udhcp')
-rw-r--r--networking/udhcp/common.c96
-rw-r--r--networking/udhcp/common.h8
2 files changed, 62 insertions, 42 deletions
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 16bf69707..20d843bab 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -15,7 +15,7 @@ const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
15}; 15};
16 16
17#if ENABLE_UDHCPC || ENABLE_UDHCPD 17#if ENABLE_UDHCPC || ENABLE_UDHCPD
18/* Supported options are easily added here. 18/* Supported options are easily added here, they need to be sorted.
19 * See RFC2132 for more options. 19 * See RFC2132 for more options.
20 * OPTION_REQ: these options are requested by udhcpc (unless -o). 20 * OPTION_REQ: these options are requested by udhcpc (unless -o).
21 */ 21 */
@@ -222,79 +222,91 @@ unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings
222 } 222 }
223} 223}
224 224
225/* Get an option with bounds checking (warning, result is not aligned) */ 225/* Initialize state to be used between subsequent udhcp_scan_options calls */
226uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) 226void FAST_FUNC init_scan_state(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state)
227{
228 scan_state->overload = 0;
229 scan_state->rem = sizeof(packet->options);
230 scan_state->optionptr = packet->options;
231}
232
233/* Iterate over packet's options, each call returning the next option.
234 * scan_state needs to be initialized with init_scan_state beforehand.
235 * Warning, result is not aligned. */
236uint8_t* FAST_FUNC udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state)
227{ 237{
228 uint8_t *optionptr;
229 int len; 238 int len;
230 int rem;
231 int overload = 0;
232 enum { 239 enum {
233 FILE_FIELD101 = FILE_FIELD * 0x101, 240 FILE_FIELD101 = FILE_FIELD * 0x101,
234 SNAME_FIELD101 = SNAME_FIELD * 0x101, 241 SNAME_FIELD101 = SNAME_FIELD * 0x101,
235 }; 242 };
236 243
237 /* option bytes: [code][len][data1][data2]..[dataLEN] */ 244 /* option bytes: [code][len][data1][data2]..[dataLEN] */
238 optionptr = packet->options;
239 rem = sizeof(packet->options);
240 while (1) { 245 while (1) {
241 if (rem <= 0) { 246 if (scan_state->rem <= 0) {
242 complain: 247 complain:
243 bb_simple_error_msg("bad packet, malformed option field"); 248 bb_simple_error_msg("bad packet, malformed option field");
244 return NULL; 249 return NULL;
245 } 250 }
246 251
247 /* DHCP_PADDING and DHCP_END have no [len] byte */ 252 /* DHCP_PADDING and DHCP_END have no [len] byte */
248 if (optionptr[OPT_CODE] == DHCP_PADDING) { 253 if (scan_state->optionptr[OPT_CODE] == DHCP_PADDING) {
249 rem--; 254 scan_state->rem--;
250 optionptr++; 255 scan_state->optionptr++;
251 continue; 256 continue;
252 } 257 }
253 if (optionptr[OPT_CODE] == DHCP_END) { 258 if (scan_state->optionptr[OPT_CODE] == DHCP_END) {
254 if ((overload & FILE_FIELD101) == FILE_FIELD) { 259 if ((scan_state->overload & FILE_FIELD101) == FILE_FIELD) {
255 /* can use packet->file, and didn't look at it yet */ 260 /* can use packet->file, and didn't look at it yet */
256 overload |= FILE_FIELD101; /* "we looked at it" */ 261 scan_state->overload |= FILE_FIELD101; /* "we looked at it" */
257 optionptr = packet->file; 262 scan_state->optionptr = packet->file;
258 rem = sizeof(packet->file); 263 scan_state->rem = sizeof(packet->file);
259 continue; 264 continue;
260 } 265 }
261 if ((overload & SNAME_FIELD101) == SNAME_FIELD) { 266 if ((scan_state->overload & SNAME_FIELD101) == SNAME_FIELD) {
262 /* can use packet->sname, and didn't look at it yet */ 267 /* can use packet->sname, and didn't look at it yet */
263 overload |= SNAME_FIELD101; /* "we looked at it" */ 268 scan_state->overload |= SNAME_FIELD101; /* "we looked at it" */
264 optionptr = packet->sname; 269 scan_state->optionptr = packet->sname;
265 rem = sizeof(packet->sname); 270 scan_state->rem = sizeof(packet->sname);
266 continue; 271 continue;
267 } 272 }
268 break; 273 break;
269 } 274 }
270 275
271 if (rem <= OPT_LEN) 276 if (scan_state->rem <= OPT_LEN)
272 goto complain; /* complain and return NULL */ 277 goto complain; /* complain and return NULL */
273 len = 2 + optionptr[OPT_LEN]; 278 len = 2 + scan_state->optionptr[OPT_LEN];
274 rem -= len; 279 scan_state->rem -= len;
275 if (rem < 0) 280 /* So far no valid option with length 0 known. */
281 if (scan_state->rem < 0 || scan_state->optionptr[OPT_LEN] == 0)
276 goto complain; /* complain and return NULL */ 282 goto complain; /* complain and return NULL */
277 283
278 if (optionptr[OPT_CODE] == code) { 284 if (scan_state->optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
279 if (optionptr[OPT_LEN] == 0) { 285 if (len >= 3)
280 /* So far no valid option with length 0 known. 286 scan_state->overload |= scan_state->optionptr[OPT_DATA];
281 * Having this check means that searching 287 } else {
282 * for DHCP_MESSAGE_TYPE need not worry 288 uint8_t *return_ptr = scan_state->optionptr;
283 * that returned pointer might be unsafe 289 scan_state->optionptr += len;
284 * to dereference. 290 return return_ptr;
285 */
286 goto complain; /* complain and return NULL */
287 }
288 log_option("option found", optionptr);
289 return optionptr + OPT_DATA;
290 } 291 }
292 scan_state->optionptr += len;
293 }
291 294
292 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { 295 return NULL;
293 if (len >= 3) 296}
294 overload |= optionptr[OPT_DATA]; 297
295 /* fall through */ 298/* Get an option with bounds checking (warning, result is not aligned) */
299uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
300{
301 uint8_t *optptr;
302 struct dhcp_scan_state scan_state;
303
304 init_scan_state(packet, &scan_state);
305 while ((optptr = udhcp_scan_options(packet, &scan_state)) != NULL) {
306 if (optptr[OPT_CODE] == code) {
307 log_option("option found", optptr);
308 return optptr + OPT_DATA;
296 } 309 }
297 optionptr += len;
298 } 310 }
299 311
300 /* log3 because udhcpc uses it a lot - very noisy */ 312 /* log3 because udhcpc uses it a lot - very noisy */
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 6214db06a..81c1dcbdc 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -107,6 +107,12 @@ enum {
107 OPTION_LIST = 0x20, 107 OPTION_LIST = 0x20,
108}; 108};
109 109
110struct dhcp_scan_state {
111 int overload;
112 int rem;
113 uint8_t *optionptr;
114};
115
110/* DHCP option codes (partial list). See RFC 2132 and 116/* DHCP option codes (partial list). See RFC 2132 and
111 * http://www.iana.org/assignments/bootp-dhcp-parameters/ 117 * http://www.iana.org/assignments/bootp-dhcp-parameters/
112 * Commented out options are handled by common option machinery, 118 * Commented out options are handled by common option machinery,
@@ -206,6 +212,8 @@ extern const uint8_t dhcp_option_lengths[] ALIGN1;
206 212
207unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings); 213unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings);
208 214
215void init_scan_state(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state) FAST_FUNC;
216uint8_t *udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state) FAST_FUNC;
209uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC; 217uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC;
210/* Same as above + ensures that option length is 4 bytes 218/* Same as above + ensures that option length is 4 bytes
211 * (returns NULL if size is different) 219 * (returns NULL if size is different)