blob: 248173a84c1f8acff288c00c806bb153abf45a08 [file] [log] [blame]
Greg Hartman76d05dc2016-11-23 15:51:27 -08001#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 */
15int 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 */
59int 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}