blob: 7e7ba0411fe10108fa12209a8304c9f905b29595 [file] [log] [blame]
Simon Kelleyc8e8f5c2021-01-24 21:59:37 +00001/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
Simon Kelley1d030162015-12-21 14:17:06 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16
17#include "dnsmasq.h"
Kyle Swenson545712c2021-11-17 12:25:04 -070018/* CRADLEPOINT */
19#include "opendns.h"
20/* CRADLEPOINT */
Simon Kelley1d030162015-12-21 14:17:06 +000021
Tarun Kunduf37019e2022-08-08 07:45:13 -070022unsigned char *process_ar(unsigned char *ansp, int arcount, struct dns_header *header, size_t plen);
23static void insert_appid_catid_to_ipset(unsigned char *ansp, size_t plen);
24static void add_appid_catid_to_ipset(struct ipsets **ipset, char *domain, char *set);
25static struct ipsets *search_domain_in_ipset(struct ipsets *ipset, char *domain);
26static struct ipsets *add_domain_to_ipset(struct ipsets *ipset, char *domain);
27static void add_set_to_ipset(struct ipsets *ipset, char *set);
28
Simon Kelley5bb88f02015-12-21 16:23:47 +000029unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign, int *is_last)
Simon Kelley1d030162015-12-21 14:17:06 +000030{
31 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
32 also return length of pseudoheader in *len and pointer to the UDP size in *p
33 Finally, check to see if a packet is signed. If it is we cannot change a single bit before
Simon Kelley5bb88f02015-12-21 16:23:47 +000034 forwarding. We look for TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
Simon Kelley1d030162015-12-21 14:17:06 +000035
36 int i, arcount = ntohs(header->arcount);
37 unsigned char *ansp = (unsigned char *)(header+1);
38 unsigned short rdlen, type, class;
39 unsigned char *ret = NULL;
40
41 if (is_sign)
42 {
43 *is_sign = 0;
44
45 if (OPCODE(header) == QUERY)
46 {
47 for (i = ntohs(header->qdcount); i != 0; i--)
48 {
49 if (!(ansp = skip_name(ansp, header, plen, 4)))
50 return NULL;
51
52 GETSHORT(type, ansp);
53 GETSHORT(class, ansp);
54
55 if (class == C_IN && type == T_TKEY)
56 *is_sign = 1;
57 }
58 }
59 }
60 else
61 {
62 if (!(ansp = skip_questions(header, plen)))
63 return NULL;
64 }
65
66 if (arcount == 0)
67 return NULL;
68
69 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
70 return NULL;
71
72 for (i = 0; i < arcount; i++)
73 {
74 unsigned char *save, *start = ansp;
75 if (!(ansp = skip_name(ansp, header, plen, 10)))
76 return NULL;
77
78 GETSHORT(type, ansp);
79 save = ansp;
80 GETSHORT(class, ansp);
81 ansp += 4; /* TTL */
82 GETSHORT(rdlen, ansp);
83 if (!ADD_RDLEN(header, ansp, plen, rdlen))
84 return NULL;
85 if (type == T_OPT)
86 {
87 if (len)
88 *len = ansp - start;
Simon Kelley5bb88f02015-12-21 16:23:47 +000089
Simon Kelley1d030162015-12-21 14:17:06 +000090 if (p)
91 *p = save;
Simon Kelley5bb88f02015-12-21 16:23:47 +000092
93 if (is_last)
94 *is_last = (i == arcount-1);
95
Simon Kelley1d030162015-12-21 14:17:06 +000096 ret = start;
97 }
98 else if (is_sign &&
99 i == arcount - 1 &&
100 class == C_ANY &&
101 type == T_TSIG)
102 *is_sign = 1;
103 }
104
105 return ret;
106}
Simon Kelley1d030162015-12-21 14:17:06 +0000107
Simon Kelley87985852016-04-25 15:33:30 +0100108
109/* replace == 2 ->delete existing option only. */
Simon Kelley1d030162015-12-21 14:17:06 +0000110size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000111 unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
Simon Kelley1d030162015-12-21 14:17:06 +0000112{
Simon Kelley5bb88f02015-12-21 16:23:47 +0000113 unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
114 int rdlen = 0, is_sign, is_last;
115 unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
Simon Kelley1d030162015-12-21 14:17:06 +0000116
Simon Kelley5bb88f02015-12-21 16:23:47 +0000117 p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
118
119 if (is_sign)
120 return plen;
121
122 if (p)
Simon Kelley1d030162015-12-21 14:17:06 +0000123 {
Simon Kelley5bb88f02015-12-21 16:23:47 +0000124 /* Existing header */
Simon Kelley1d030162015-12-21 14:17:06 +0000125 int i;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000126 unsigned short code, len;
127
128 p = udp_len;
129 GETSHORT(udp_sz, p);
130 GETSHORT(rcode, p);
Simon Kelley1d030162015-12-21 14:17:06 +0000131 GETSHORT(flags, p);
Simon Kelley5bb88f02015-12-21 16:23:47 +0000132
Simon Kelley1d030162015-12-21 14:17:06 +0000133 if (set_do)
134 {
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000135 p -= 2;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000136 flags |= 0x8000;
137 PUTSHORT(flags, p);
Simon Kelley1d030162015-12-21 14:17:06 +0000138 }
139
140 lenp = p;
141 GETSHORT(rdlen, p);
142 if (!CHECK_LEN(header, p, plen, rdlen))
143 return plen; /* bad packet */
144 datap = p;
145
146 /* no option to add */
147 if (optno == 0)
148 return plen;
149
150 /* check if option already there */
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000151 for (i = 0; i + 4 < rdlen;)
Simon Kelley1d030162015-12-21 14:17:06 +0000152 {
153 GETSHORT(code, p);
154 GETSHORT(len, p);
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000155
156 /* malformed option, delete the whole OPT RR and start again. */
Simon Kelley897c1132017-09-25 20:11:58 +0100157 if (i + 4 + len > rdlen)
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000158 {
159 rdlen = 0;
Simon Kelleyaa300f72016-03-01 15:19:13 +0000160 is_last = 0;
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000161 break;
162 }
163
Simon Kelley1d030162015-12-21 14:17:06 +0000164 if (code == optno)
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000165 {
Simon Kelley87985852016-04-25 15:33:30 +0100166 if (replace == 0)
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000167 return plen;
168
169 /* delete option if we're to replace it. */
170 p -= 4;
171 rdlen -= len + 4;
Simon Kelley6a0b00f2017-09-25 20:19:55 +0100172 memmove(p, p+len+4, rdlen - i);
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000173 PUTSHORT(rdlen, lenp);
174 lenp -= 2;
175 }
176 else
177 {
178 p += len;
179 i += len + 4;
180 }
Simon Kelley1d030162015-12-21 14:17:06 +0000181 }
Simon Kelley5bb88f02015-12-21 16:23:47 +0000182
183 /* If we're going to extend the RR, it has to be the last RR in the packet */
184 if (!is_last)
185 {
186 /* First, take a copy of the options. */
187 if (rdlen != 0 && (buff = whine_malloc(rdlen)))
188 memcpy(buff, datap, rdlen);
189
190 /* now, delete OPT RR */
191 plen = rrfilter(header, plen, 0);
192
193 /* Now, force addition of a new one */
194 p = NULL;
195 }
Simon Kelley1d030162015-12-21 14:17:06 +0000196 }
197
Simon Kelley5bb88f02015-12-21 16:23:47 +0000198 if (!p)
199 {
200 /* We are (re)adding the pseudoheader */
201 if (!(p = skip_questions(header, plen)) ||
202 !(p = skip_section(p,
203 ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
204 header, plen)))
Simon Kelley51eadb62017-09-25 20:16:50 +0100205 {
206 free(buff);
Simon Kelley5bb88f02015-12-21 16:23:47 +0000207 return plen;
Simon Kelley51eadb62017-09-25 20:16:50 +0100208 }
Simon Kelley897c1132017-09-25 20:11:58 +0100209 if (p + 11 > limit)
Simon Kelley51eadb62017-09-25 20:16:50 +0100210 {
211 free(buff);
212 return plen; /* Too big */
213 }
Simon Kelley5bb88f02015-12-21 16:23:47 +0000214 *p++ = 0; /* empty name */
215 PUTSHORT(T_OPT, p);
216 PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
217 PUTSHORT(rcode, p); /* extended RCODE and version */
218 PUTSHORT(flags, p); /* DO flag */
219 lenp = p;
220 PUTSHORT(rdlen, p); /* RDLEN */
221 datap = p;
222 /* Copy back any options */
223 if (buff)
224 {
Simon Kelley897c1132017-09-25 20:11:58 +0100225 if (p + rdlen > limit)
226 {
227 free(buff);
228 return plen; /* Too big */
229 }
Simon Kelley5bb88f02015-12-21 16:23:47 +0000230 memcpy(p, buff, rdlen);
231 free(buff);
232 p += rdlen;
233 }
Simon Kelleya3303e12017-09-07 20:45:00 +0100234
235 /* Only bump arcount if RR is going to fit */
236 if (((ssize_t)optlen) <= (limit - (p + 4)))
237 header->arcount = htons(ntohs(header->arcount) + 1);
Simon Kelley5bb88f02015-12-21 16:23:47 +0000238 }
239
240 if (((ssize_t)optlen) > (limit - (p + 4)))
241 return plen; /* Too big */
242
243 /* Add new option */
Simon Kelley87985852016-04-25 15:33:30 +0100244 if (optno != 0 && replace != 2)
Simon Kelley1d030162015-12-21 14:17:06 +0000245 {
Simon Kelley897c1132017-09-25 20:11:58 +0100246 if (p + 4 > limit)
247 return plen; /* Too big */
Simon Kelley1d030162015-12-21 14:17:06 +0000248 PUTSHORT(optno, p);
249 PUTSHORT(optlen, p);
Simon Kelley897c1132017-09-25 20:11:58 +0100250 if (p + optlen > limit)
251 return plen; /* Too big */
Simon Kelley1d030162015-12-21 14:17:06 +0000252 memcpy(p, opt, optlen);
253 p += optlen;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000254 PUTSHORT(p - datap, lenp);
Simon Kelley1d030162015-12-21 14:17:06 +0000255 }
Simon Kelley1d030162015-12-21 14:17:06 +0000256 return p - (unsigned char *)header;
Simon Kelley1d030162015-12-21 14:17:06 +0000257}
258
Simon Kelley33702ab2015-12-28 23:17:15 +0000259size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
Simon Kelleyefef4972015-12-21 17:30:44 +0000260{
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000261 return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0);
Simon Kelleyefef4972015-12-21 17:30:44 +0000262}
263
Simon Kelley33702ab2015-12-28 23:17:15 +0000264static unsigned char char64(unsigned char c)
265{
266 return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
267}
268
269static void encoder(unsigned char *in, char *out)
270{
271 out[0] = char64(in[0]>>2);
272 out[1] = char64((in[0]<<4) | (in[1]>>4));
273 out[2] = char64((in[1]<<2) | (in[2]>>6));
274 out[3] = char64(in[2]);
275}
276
Simon Kelley25e63f12020-11-25 21:17:52 +0000277static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
278 union mysockaddr *l3, time_t now, int *cacheablep)
Simon Kelley33702ab2015-12-28 23:17:15 +0000279{
Simon Kelley87985852016-04-25 15:33:30 +0100280 int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
Simon Kelley33702ab2015-12-28 23:17:15 +0000281 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelley9e4cf472016-02-17 20:26:32 +0000282 char encode[18]; /* handle 6 byte MACs */
Simon Kelley33702ab2015-12-28 23:17:15 +0000283
284 if ((maclen = find_mac(l3, mac, 1, now)) == 6)
285 {
Simon Kelley87985852016-04-25 15:33:30 +0100286 replace = 1;
Simon Kelley25e63f12020-11-25 21:17:52 +0000287 *cacheablep = 0;
Simon Kelley87985852016-04-25 15:33:30 +0100288
Simon Kelley9e4cf472016-02-17 20:26:32 +0000289 if (option_bool(OPT_MAC_HEX))
290 print_mac(encode, mac, maclen);
291 else
292 {
293 encoder(mac, encode);
294 encoder(mac+3, encode+4);
295 encode[8] = 0;
296 }
Simon Kelley33702ab2015-12-28 23:17:15 +0000297 }
298
Simon Kelley87985852016-04-25 15:33:30 +0100299 return add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
Simon Kelley33702ab2015-12-28 23:17:15 +0000300}
301
302
Simon Kelley25e63f12020-11-25 21:17:52 +0000303static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
304 union mysockaddr *l3, time_t now, int *cacheablep)
Simon Kelley1d030162015-12-21 14:17:06 +0000305{
Simon Kelley11867dc2015-12-23 16:15:58 +0000306 int maclen;
307 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelley1d030162015-12-21 14:17:06 +0000308
Simon Kelley33702ab2015-12-28 23:17:15 +0000309 if ((maclen = find_mac(l3, mac, 1, now)) != 0)
Simon Kelley25e63f12020-11-25 21:17:52 +0000310 {
311 *cacheablep = 0;
312 plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
313 }
314
Simon Kelley11867dc2015-12-23 16:15:58 +0000315 return plen;
Simon Kelley1d030162015-12-21 14:17:06 +0000316}
317
318struct subnet_opt {
319 u16 family;
Simon Kelleyee875042018-10-23 22:10:17 +0100320 u8 source_netmask, scope_netmask;
Simon Kelley1d030162015-12-21 14:17:06 +0000321 u8 addr[IN6ADDRSZ];
Simon Kelley1d030162015-12-21 14:17:06 +0000322};
323
324static void *get_addrp(union mysockaddr *addr, const short family)
325{
Simon Kelley1d030162015-12-21 14:17:06 +0000326 if (family == AF_INET6)
327 return &addr->in6.sin6_addr;
Simon Kelley1d030162015-12-21 14:17:06 +0000328
329 return &addr->in.sin_addr;
330}
331
Simon Kelley25e63f12020-11-25 21:17:52 +0000332static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
Simon Kelley1d030162015-12-21 14:17:06 +0000333{
334 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
335
336 int len;
Simon Kelley0fbd9802017-05-21 22:24:43 +0100337 void *addrp = NULL;
Simon Kelley1d030162015-12-21 14:17:06 +0000338 int sa_family = source->sa.sa_family;
Simon Kelley25e63f12020-11-25 21:17:52 +0000339 int cacheable = 0;
340
Simon Kelley22fe2fd2016-02-28 17:07:10 +0000341 opt->source_netmask = 0;
342 opt->scope_netmask = 0;
Simon Kelley25e63f12020-11-25 21:17:52 +0000343
Simon Kelley22fe2fd2016-02-28 17:07:10 +0000344 if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
Simon Kelley1d030162015-12-21 14:17:06 +0000345 {
346 opt->source_netmask = daemon->add_subnet6->mask;
347 if (daemon->add_subnet6->addr_used)
348 {
349 sa_family = daemon->add_subnet6->addr.sa.sa_family;
350 addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
Simon Kelley25e63f12020-11-25 21:17:52 +0000351 cacheable = 1;
Simon Kelley1d030162015-12-21 14:17:06 +0000352 }
353 else
354 addrp = &source->in6.sin6_addr;
355 }
Simon Kelley22fe2fd2016-02-28 17:07:10 +0000356
357 if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
Simon Kelley1d030162015-12-21 14:17:06 +0000358 {
359 opt->source_netmask = daemon->add_subnet4->mask;
360 if (daemon->add_subnet4->addr_used)
361 {
362 sa_family = daemon->add_subnet4->addr.sa.sa_family;
363 addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
Simon Kelley25e63f12020-11-25 21:17:52 +0000364 cacheable = 1; /* Address is constant */
Simon Kelley1d030162015-12-21 14:17:06 +0000365 }
Simon Kelley22fe2fd2016-02-28 17:07:10 +0000366 else
367 addrp = &source->in.sin_addr;
Simon Kelley1d030162015-12-21 14:17:06 +0000368 }
369
Simon Kelley22fe2fd2016-02-28 17:07:10 +0000370 opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
Simon Kelley22fe2fd2016-02-28 17:07:10 +0000371
Simon Kelley0fbd9802017-05-21 22:24:43 +0100372 if (addrp && opt->source_netmask != 0)
Simon Kelley1d030162015-12-21 14:17:06 +0000373 {
Simon Kelley1d030162015-12-21 14:17:06 +0000374 len = ((opt->source_netmask - 1) >> 3) + 1;
375 memcpy(opt->addr, addrp, len);
376 if (opt->source_netmask & 7)
377 opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
378 }
Simon Kelley25e63f12020-11-25 21:17:52 +0000379 else
380 {
381 cacheable = 1; /* No address ever supplied. */
382 len = 0;
383 }
384
385 if (cacheablep)
386 *cacheablep = cacheable;
Simon Kelley22fe2fd2016-02-28 17:07:10 +0000387
Simon Kelley1d030162015-12-21 14:17:06 +0000388 return len + 4;
389}
390
Simon Kelley25e63f12020-11-25 21:17:52 +0000391static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
Simon Kelley1d030162015-12-21 14:17:06 +0000392{
393 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
394
395 int len;
396 struct subnet_opt opt;
397
Simon Kelley25e63f12020-11-25 21:17:52 +0000398 len = calc_subnet_opt(&opt, source, cacheable);
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000399 return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
Simon Kelley1d030162015-12-21 14:17:06 +0000400}
401
Simon Kelley1d030162015-12-21 14:17:06 +0000402int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
403{
404 /* Section 9.2, Check that subnet option in reply matches. */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000405
406 int len, calc_len;
Simon Kelley1d030162015-12-21 14:17:06 +0000407 struct subnet_opt opt;
408 unsigned char *p;
409 int code, i, rdlen;
410
Simon Kelley25e63f12020-11-25 21:17:52 +0000411 calc_len = calc_subnet_opt(&opt, peer, NULL);
Simon Kelley1d030162015-12-21 14:17:06 +0000412
Simon Kelley25e63f12020-11-25 21:17:52 +0000413 if (!(p = skip_name(pseudoheader, header, plen, 10)))
414 return 1;
415
416 p += 8; /* skip UDP length and RCODE */
417
418 GETSHORT(rdlen, p);
419 if (!CHECK_LEN(header, p, plen, rdlen))
420 return 1; /* bad packet */
421
422 /* check if option there */
Simon Kelley1d030162015-12-21 14:17:06 +0000423 for (i = 0; i + 4 < rdlen; i += len + 4)
424 {
425 GETSHORT(code, p);
426 GETSHORT(len, p);
427 if (code == EDNS0_OPTION_CLIENT_SUBNET)
428 {
429 /* make sure this doesn't mismatch. */
430 opt.scope_netmask = p[3];
431 if (len != calc_len || memcmp(p, &opt, len) != 0)
432 return 0;
433 }
434 p += len;
435 }
436
437 return 1;
438}
Simon Kelley33702ab2015-12-28 23:17:15 +0000439
Simon Kelley25e63f12020-11-25 21:17:52 +0000440/* Set *check_subnet if we add a client subnet option, which needs to checked
441 in the reply. Set *cacheable to zero if we add an option which the answer
442 may depend on. */
Simon Kelley33702ab2015-12-28 23:17:15 +0000443size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
Simon Kelley25e63f12020-11-25 21:17:52 +0000444 union mysockaddr *source, time_t now, int *check_subnet, int *cacheable)
Simon Kelley33702ab2015-12-28 23:17:15 +0000445{
Kyle Swenson545712c2021-11-17 12:25:04 -0700446/* CRADLEPOINT */
447 unsigned char *edns_options = daemon->edns_options;
448 size_t edns_options_len = daemon->edns_options_len;
449 int i, len, code;
450/* CRADLEPOINT */
451
Simon Kelley33702ab2015-12-28 23:17:15 +0000452 *check_subnet = 0;
Simon Kelley25e63f12020-11-25 21:17:52 +0000453 *cacheable = 1;
454
Simon Kelley33702ab2015-12-28 23:17:15 +0000455 if (option_bool(OPT_ADD_MAC))
Simon Kelley25e63f12020-11-25 21:17:52 +0000456 plen = add_mac(header, plen, limit, source, now, cacheable);
Simon Kelley33702ab2015-12-28 23:17:15 +0000457
Simon Kelley9e4cf472016-02-17 20:26:32 +0000458 if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
Simon Kelley25e63f12020-11-25 21:17:52 +0000459 plen = add_dns_client(header, plen, limit, source, now, cacheable);
460
Simon Kelley1e505122016-01-25 21:29:23 +0000461 if (daemon->dns_client_id)
462 plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000463 (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
Simon Kelley33702ab2015-12-28 23:17:15 +0000464
465 if (option_bool(OPT_CLIENT_SUBNET))
466 {
Simon Kelley25e63f12020-11-25 21:17:52 +0000467 plen = add_source_addr(header, plen, limit, source, cacheable);
Simon Kelley33702ab2015-12-28 23:17:15 +0000468 *check_subnet = 1;
469 }
Kyle Swenson545712c2021-11-17 12:25:04 -0700470
471/* CRADLEPOINT */
472 if (daemon->ssid_device_id_map.map) {
473 opendns_pop_tag_from_query((unsigned char *) header, &plen,
474 &edns_options, &edns_options_len);
475 }
476
477 if (edns_options) {
478 for (i = edns_options_len; i > 0; i -= len + 4)
479 {
480 GETSHORT(code, edns_options);
481 GETSHORT(len, edns_options);
482 plen = add_pseudoheader(header, plen, limit, PACKETSZ, code,
483 (unsigned char *)edns_options, len, 0, 1);
484 edns_options += len;
485
486 /* my_syslog(LOG_DEBUG, _("EDNS options added")); */
487 }
488 }
489/* CRADLEPOINT */
490
Simon Kelley33702ab2015-12-28 23:17:15 +0000491 return plen;
492}
Tarun Kunduf37019e2022-08-08 07:45:13 -0700493
494int process_appid_catid(struct dns_header *dns_buffer, size_t dns_buffer_length)
495{
496 struct dns_header *header = dns_buffer;
497 unsigned char *ansp;
498
499 /* Skip DNS header and all questions records
500 if packet is malformed, return as-is. */
501 if (!(ansp = skip_questions(dns_buffer, dns_buffer_length)))
502 return dns_buffer_length;
503
504 /* Skip all answers records and auth records
505 if packet is malformed, return as-is. */
506 if (!(ansp = skip_section(ansp, ntohs(dns_buffer->ancount) + ntohs(dns_buffer->nscount),
507 dns_buffer, dns_buffer_length)))
508 return dns_buffer_length;
509
510 /* Now processing Additional records */
511 if (!(ansp = process_ar(ansp, ntohs(header->arcount), dns_buffer, dns_buffer_length)))
512 return dns_buffer_length;
tarun.kundu519669e2023-01-04 09:21:28 -0800513 return dns_buffer_length;
Tarun Kunduf37019e2022-08-08 07:45:13 -0700514}
515
516unsigned char *process_ar(unsigned char *ansp, int arcount, struct dns_header *header, size_t plen)
517{
518 unsigned short rdlen, type, index, opcode, opdlen, oplen;
519
520 for (index = 0; index < arcount; index++)
521 {
522 if (!(ansp = skip_name(ansp, header, plen, 10)))
523 return NULL;
524 GETSHORT(type, ansp);
525 ansp += 6; /* To skip type, UDP payload size, extended RCODE and flags. Ref: RFC6891 */
526 GETSHORT(rdlen, ansp);
527 if (type == T_OPT)
528 {
529 while (rdlen > 0)
530 {
531 GETSHORT(opcode, ansp);
532 GETSHORT(opdlen, ansp);
533 /* 2 byte option code + 2 byte option length + option data */
534 oplen = 2 + 2 + opdlen;
535 if (opcode == EDNS0_OPTION_APPID)
536 {
537 insert_appid_catid_to_ipset(ansp, opdlen);
538 memmove(ansp, ansp + oplen, plen - oplen);
Tarun Kundu54166152022-09-08 15:09:52 -0700539 header->arcount = htons(arcount-1);
Tarun Kunduf37019e2022-08-08 07:45:13 -0700540 }
541 else
542 {
543 ansp += oplen;
544 }
545 rdlen -= oplen;
546 }
547 }
548 else
549 {
550 ansp += rdlen - 8;
551 }
552 }
553 return ansp;
554}
555
556static void insert_appid_catid_to_ipset(unsigned char *ansp, size_t plen)
557{
558 unsigned char *end = ansp + plen;
559 char *set_ipv4, *set_ipv6;
560 ansp++;
561 while (ansp < end)
562 {
563 int entry_len = strnlen((char *)ansp, plen) + 1;
564 if (ansp + entry_len > end)
565 {
566 // Malformed data
567 return;
568 }
569
570 if ((set_ipv4 = whine_malloc(5 + entry_len)))
571 {
572 memcpy(set_ipv4, "ip4-", 4);
573 strncpy(set_ipv4 + 4, (char *)ansp, entry_len);
574 add_appid_catid_to_ipset(&daemon->ipsets, daemon->namebuff, set_ipv4);
575 free(set_ipv4);
576 }
577
578 if ((set_ipv6 = whine_malloc(5 + entry_len)))
579 {
580 memcpy(set_ipv6, "ip6-", 4);
581 strncpy(set_ipv6 + 4, (char *)ansp, entry_len);
582 add_appid_catid_to_ipset(&daemon->ipsets, daemon->namebuff, set_ipv6);
583 free(set_ipv6);
584 }
585
586 ansp += entry_len;
587 }
588}
589
590static void add_appid_catid_to_ipset(struct ipsets **ipset, char *domain, char *set)
591{
592 struct ipsets *ipsetptr;
593 if (!(*ipset))
594 {
595 if ((*ipset = whine_malloc(sizeof(struct ipsets))))
596 {
597 memset(*ipset, 0, sizeof(struct ipsets));
598 ipsetptr = *ipset;
599 if ((ipsetptr->domain = whine_malloc(strlen(domain) + 1)))
600 {
601 strcpy(ipsetptr->domain, domain);
602 }
603 }
604 }
605
606 ipsetptr = search_domain_in_ipset(*ipset, domain);
607
608 if (!(ipsetptr))
609 ipsetptr = add_domain_to_ipset(*ipset, domain);
610 if (ipsetptr)
611 add_set_to_ipset(ipsetptr, set);
612}
613
614static struct ipsets *search_domain_in_ipset(struct ipsets *ipset, char *domain)
615{
616 while (ipset)
617 {
618 if (strcmp(ipset->domain, domain) == 0)
619 {
620 return ipset;
621 }
622 ipset = ipset->next;
623 }
624 return NULL;
625}
626
627static struct ipsets *add_domain_to_ipset(struct ipsets *ipset, char *domain)
628{
629 while (ipset)
630 {
631 if (ipset->next == NULL)
632 break;
633 ipset = ipset->next;
634 }
635
636 if ((ipset->next = whine_malloc(sizeof(struct ipsets))))
637 {
638 memset(ipset->next, 0, sizeof(struct ipsets));
639 if ((ipset->next->domain = whine_malloc(strlen(domain) + 1)))
640 {
641 strcpy(ipset->next->domain, domain);
642 return ipset->next;
643 }
644 }
645 return NULL;
646}
647
648static void add_set_to_ipset(struct ipsets *ipset, char *set)
649{
650 int count = 0;
651 if (!(ipset->sets))
652 {
653 if ((ipset->sets = realloc(ipset->sets, 2 * sizeof(char *))) == NULL)
654 {
655 my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int)(2 * sizeof(char *)));
656 return;
657 }
658 if ((ipset->sets[0] = whine_malloc(strlen(set) + 1)))
659 {
660 strcpy(ipset->sets[0], set);
661 ipset->sets[1] = NULL;
662 return;
663 }
664 }
665
666 while (ipset->sets[count])
667 {
668 if (strcmp(ipset->sets[count], set) == 0)
669 return;
670 else
671 count++;
672 }
673 if ((ipset->sets = realloc(ipset->sets, sizeof(char *) * (count + 2))) == NULL)
674 {
675 my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int)((count + 2) * sizeof(char *)));
676 return;
677 }
678 if ((ipset->sets[count] = whine_malloc(strlen(set) + 1)))
679 {
680 strcpy(ipset->sets[count], set);
681 ipset->sets[count + 1] = NULL;
682 }
683 return;
684}