• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #define _GNU_SOURCE		/* For strnlen() */
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 // #include <arpa/inet.h>
6 #include <netinet/in.h>
7 
8 // #include "dhcp.h"
9 #include <dhcp.h>
10 
11 /*
12  * Unpack DHCP options from a field.  Assumes opt is pre-initalized
13  * (to all zero in the common case.)
14  */
dhcp_unpack_field(const void * field,size_t len,struct dhcp_option opt[256])15 int dhcp_unpack_field(const void *field, size_t len,
16 		      struct dhcp_option opt[256])
17 {
18 	const uint8_t *p = field;
19 	int err = 0;
20 
21 	while (len > 1) {
22 		uint8_t op;
23 		size_t xlen;
24 
25 		op = *p++; len--;
26 		if (op == 0)
27 			continue;
28 		else if (op == 255)
29 			break;
30 
31 		xlen = *p++; len--;
32 		if (xlen > len)
33 			break;
34 		if (opt[op].len < 0)
35 			opt[op].len = 0;
36 		if (xlen) {
37 			opt[op].data = realloc(opt[op].data,
38 					       opt[op].len + xlen + 1);
39 			if (!opt[op].data) {
40 				err = ENOMEM;
41 				continue;
42 			}
43 			memcpy((char *)opt[op].data + opt[op].len, p, xlen);
44 			opt[op].len += xlen;
45 			/* Null-terminate as a courtesy to users */
46 			*((char *)opt[op].data + opt[op].len) = 0;
47 			p += xlen;
48 			len -= xlen;
49 		}
50 	}
51 
52 	return err;
53 }
54 
55 /*
56  * Unpack a DHCP packet, with overload support.  Do not use this
57  * to unpack an encapsulated option set.
58  */
dhcp_unpack_packet(const void * packet,size_t len,struct dhcp_option opt[256])59 int dhcp_unpack_packet(const void *packet, size_t len,
60 		       struct dhcp_option opt[256])
61 {
62 	const struct dhcp_packet *pkt = packet;
63 	int err;
64 	uint8_t overload;
65 	int i;
66 
67 	if (len < 240 || pkt->magic != htonl(DHCP_VENDOR_MAGIC))
68 		return EINVAL;	/* Bogus packet */
69 
70 	for (i = 0; i < 256; i++) {
71 		opt[i].len = -1; /* Option not present */
72 		opt[i].data = NULL;
73 	}
74 
75 	err = dhcp_unpack_field(pkt->options, len-240, opt);
76 
77 	overload = 0;
78 	if (opt[52].len == 1) {
79 		overload = *(uint8_t *)opt[52].data;
80 		free(opt[52].data);
81 		opt[52].len = -1;
82 		opt[52].data = NULL;
83 	}
84 
85 	if (overload & 1) {
86 		err |= dhcp_unpack_field(pkt->file, 128, opt);
87 	} else {
88 		opt[67].len  = strnlen((const char *)pkt->file, 128);
89 		if (opt[67].len) {
90 			opt[67].data = malloc(opt[67].len + 1);
91 			if (opt[67].data) {
92 				memcpy(opt[67].data, pkt->file, opt[67].len);
93 				*((char *)opt[67].data + opt[67].len) = 0;
94 			} else {
95 				err |= ENOMEM;
96 			}
97 		}
98 	}
99 
100 	if (overload & 2) {
101 		err |= dhcp_unpack_field(pkt->sname, 64, opt);
102 	} else {
103 		opt[66].len  = strnlen((const char *)pkt->sname, 64);
104 		if (opt[66].len) {
105 			opt[66].data = malloc(opt[66].len + 1);
106 			if (opt[66].data) {
107 				memcpy(opt[66].data, pkt->file, opt[66].len);
108 				*((char *)opt[66].data + opt[66].len) = 0;
109 			} else {
110 				err |= ENOMEM;
111 			}
112 		}
113 	}
114 
115 	return err;
116 }
117