blob: d0b43481d9687a3fedcc543211bdffcb5296ad80 [file] [log] [blame]
Kyle Swenson545712c2021-11-17 12:25:04 -07001
2#include "dnsmasq.h"
3#include "opendns.h"
4
5const unsigned char *
6opendns_ssid_to_device_id(size_t * const device_id_len_p,
7 const unsigned char * const ssid,
8 const size_t ssid_len)
9{
10 unsigned char *map = daemon->ssid_device_id_map.map;
11 unsigned char *map_tmp;
12 unsigned char *ssid_tmp;
13 unsigned char *device_id_tmp;
14 size_t ssid_tmp_len;
15 size_t device_id_len;
16
17 if (map == NULL || ssid == NULL) {
18 return NULL;
19 }
20 map_tmp = map;
21 while ((ssid_tmp_len = (size_t) *map_tmp) > 0U) {
22 ssid_tmp = ++map_tmp;
23 map_tmp += ssid_tmp_len;
24 device_id_len = (size_t) *map_tmp;
25 device_id_tmp = ++map_tmp;
26 if (ssid_tmp_len == ssid_len &&
27 memcmp(ssid_tmp, ssid, ssid_len) == 0) {
28 *device_id_len_p = device_id_len;
29 return device_id_tmp;
30 }
31 map_tmp += device_id_len;
32 }
33 return NULL;
34}
35
36static int
37opendns_parse_hex_char(unsigned char * const device_id,
38 size_t * const device_id_pos_p, int * const state_p,
39 unsigned char * const val_p, size_t device_id_len_max,
40 const int c)
41{
42 unsigned char c_val;
43
44 switch (*state_p) {
45 case 0:
46 case 1:
47 if (isspace(c) || (c == ':' && *state_p == 0)) {
48 break;
49 }
50 if (c == '#') {
51 *state_p = 2;
52 break;
53 }
54 if (!isxdigit(c)) {
55 return -1;
56 }
57 c_val = (c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10;
58 if (*state_p == 0) {
59 *val_p = c_val * 16U;
60 *state_p = 1;
61 } else {
62 *val_p |= c_val;
63 device_id[(*device_id_pos_p)++] = *val_p;
64 if (*device_id_pos_p >= device_id_len_max) {
65 return 0;
66 }
67 *state_p = 0;
68 }
69 break;
70 case 2:
71 if (c == '\n') {
72 *state_p = 0;
73 }
74 }
75 return 1;
76}
77
78size_t
79opendns_parse_hex(const char * const device_id_hex,
80 unsigned char * const device_id,
81 const size_t device_id_len_max)
82{
83 const char *p = device_id_hex;
84 size_t device_id_pos = (size_t) 0U;
85 int c;
86 int ret;
87 int state = 0;
88 unsigned char val = 0U;
89
90 if (device_id_hex == NULL) {
91 return (size_t) 0U;
92 }
93 while ((c = tolower((int) (unsigned char) *p)) != 0) {
94 ret = opendns_parse_hex_char(device_id, &device_id_pos,
95 &state, &val, device_id_len_max, c);
96 if (ret < 0) {
97 return (size_t) 0U;
98 }
99 if (ret == 0) {
100 break;
101 }
102 p++;
103 }
104 return device_id_pos;
105}
106
107char *
108opendns_parse_device_id_opt(char * const arg)
109{
110 struct ssid_device_id_map * const ssid_device_id_map =
111 &daemon->ssid_device_id_map;
112 unsigned char *device_id;
113 unsigned char *tmp_map;
114 char *device_id_hex;
115 char *sep;
116 char *ssid;
117 size_t device_id_hex_len;
118 size_t device_id_len;
119 size_t device_id_len_max;
120 size_t pos;
121 size_t ssid_len;
122 size_t tmp_map_size;
123
124 if ((sep = strrchr(arg, ',')) == NULL ||
125 *(device_id_hex = sep + 1) == 0) {
126 return _("missing device id");
127 }
128 *sep = 0;
129 if (*(ssid = arg) == 0) {
130 return _("missing SSID");
131 }
132 ssid_len = (size_t) (sep - ssid);
133 if (ssid_len > 255U) {
134 return _("SSID too long");
135 }
136 device_id_hex_len = strlen(device_id_hex);
137 device_id_len_max = (device_id_hex_len + 1U) / 2U;
138 device_id = safe_malloc(device_id_len_max);
139 if (device_id_len_max > 255U) {
140 free(device_id);
141 return _("device id too long");
142 }
143 device_id_len = opendns_parse_hex(device_id_hex, device_id,
144 device_id_len_max);
145 if (device_id_len <= 0U) {
146 free(device_id);
147 return _("unable to parse a hex device id");
148 }
149 if (device_id_len > device_id_len_max) {
150 free(device_id);
151 return _("parsed device id too long");
152 }
153 tmp_map_size = ssid_device_id_map->map_size + 1U +
154 ssid_len + 1U + device_id_len;
155 if (ssid_device_id_map->map == NULL) {
156 tmp_map_size++;
157 }
158 if ((tmp_map = realloc(ssid_device_id_map->map,
159 tmp_map_size)) == NULL) {
160 die(_("could not get memory"), NULL, EC_NOMEM);
161 }
162 if (ssid_device_id_map->map_size <= 0U) {
163 pos = 0U;
164 } else {
165 pos = ssid_device_id_map->map_size - 1U;
166 }
167 tmp_map[pos++] = (unsigned char) ssid_len;
168 memcpy(&tmp_map[pos], ssid, ssid_len);
169 pos += ssid_len;
170 tmp_map[pos++] = (unsigned char) device_id_len;
171 memcpy(&tmp_map[pos], device_id, device_id_len);
172 pos += device_id_len;
173 free(device_id);
174 tmp_map[pos] = 0U;
175 ssid_device_id_map->map = tmp_map;
176 ssid_device_id_map->map_size = tmp_map_size;
177
178 return NULL;
179}
180
181int
182opendns_pop_tag_from_query(unsigned char * const packet,
183 size_t * const packet_size_p,
184 unsigned char * * const edns_options,
185 size_t *edns_options_len_p)
186{
187 static unsigned char edns_options_tpl[2U + 2U + 7U + 255U] = {
188 0U, 4U, 0U, 0U, 'O', 'p', 'e', 'n', 'D', 'N', 'S'
189 };
190 const unsigned char *device_id;
191 const unsigned char *tag;
192 unsigned char *tmp;
193 size_t edns_options_len;
194 size_t device_id_len;
195 size_t packet_size = *packet_size_p;
196 size_t tag_len;
197
198 if (packet_size <= 0U) {
199 *edns_options = NULL;
200 *edns_options_len_p = 0U;
201 return -1;
202 }
203 tag_len = (size_t) packet[packet_size - 1U];
204 if (tag_len >= packet_size) {
205 *edns_options = NULL;
206 *edns_options_len_p = 0U;
207 return -1;
208 }
209 tag = &packet[packet_size - tag_len - 1U];
210 if ((device_id = opendns_ssid_to_device_id(&device_id_len,
211 tag, tag_len)) == NULL) {
212 return -1;
213 }
214 edns_options_len = 2U + 2U + sizeof "OpenDNS" - 1U + device_id_len;
215 if (edns_options_len > sizeof edns_options_tpl) {
216 return -1;
217 }
218 memcpy(edns_options_tpl + 2U + 2U + sizeof "OpenDNS" - 1U,
219 device_id, device_id_len);
220 if (packet_size <= 1U + device_id_len) {
221 return -1;
222 }
223 tmp = edns_options_tpl + 2U;
224 PUTSHORT(sizeof "OpenDNS" - 1U + device_id_len, tmp);
225 *edns_options = edns_options_tpl;
226 *edns_options_len_p = edns_options_len;
227 packet_size -= 1U + tag_len;
228 *packet_size_p = packet_size;
229
230 return 0;
231}