Annotation of embedaddon/coova-chilli/src/dns.c, revision 1.1.1.1
1.1 misho 1: /*
2: * DNS library functions
3: * Copyright (c) 2006-2008 David Bird <david@coova.com>
4: *
5: * The contents of this file may be used under the terms of the GNU
6: * General Public License Version 2, provided that the above copyright
7: * notice and this permission notice is included in all copies or
8: * substantial portions of the software.
9: *
10: */
11:
12: #include "dns.h"
13: #include "garden.h"
14: #include "syserr.h"
15: #include "dhcp.h"
16: #include "options.h"
17:
18: #define antidnstunnel options.dnsparanoia
19:
20: extern struct dhcp_t *dhcp;
21:
22: char *
23: dns_fullname(char *data, size_t dlen, uint8_t *res, uint8_t *opkt, size_t olen, int lvl) {
24: char *d = data;
25: unsigned short l;
26:
27: if (lvl >= 15)
28: return 0;
29:
30: while ((l = *res++) != 0) {
31: if ((l & 0xC0) == 0xC0) {
32: unsigned short offset = ((l & ~0xC0) << 8) + *res;
33: if (offset > olen) {
34: log_dbg("bad value");
35: return 0;
36: }
37: /*log_dbg("skip[%d]\n",offset);*/
38: dns_fullname(d, dlen, opkt + (size_t)offset, opkt, olen, lvl+1);
39: break;
40: }
41:
42: if (l >= dlen) {
43: log_dbg("bad value");
44: return 0;
45: }
46:
47: /*log_dbg("part[%.*s]\n",l,res);*/
48:
49: memcpy(d, res, l);
50: d += l; dlen -= l;
51: res += l;
52:
53: *d = '.';
54: d += 1; dlen -= 1;
55: }
56:
57: if (!lvl && data[strlen((char*)data)-1]=='.')
58: data[strlen((char*)data)-1]=0;
59:
60: return data;
61: }
62:
63: int dns_getname(uint8_t **pktp, size_t *left, char *name, size_t namesz, size_t *nameln) {
64: size_t namelen = *nameln;
65: uint8_t *p_pkt = *pktp;
66: size_t len = *left;
67: uint8_t l;
68:
69: namelen = 0;
70: while (len-- && (l = name[namelen++] = *p_pkt++) != 0) {
71: if ((l & 0xC0) == 0xC0) {
72: if (namelen >= namesz) {
73: log_err(0, "name too long in DNS packet");
74: break;
75: }
76: name[namelen++] = *p_pkt++;
77: len--;
78: break;
79: }
80: }
81:
82: *pktp = p_pkt;
83: *nameln = namelen;
84: *left = len;
85:
86: if (!len) {
87: log_err(0, "failed to parse DNS packet");
88: return -1;
89: }
90:
91: return 0;
92: }
93:
94: static void
95: add_A_to_garden(uint8_t *p) {
96: struct in_addr reqaddr;
97: pass_through pt;
98: memcpy(&reqaddr.s_addr, p, 4);
99: memset(&pt, 0, sizeof(pass_through));
100: pt.mask.s_addr = 0xffffffff;
101: pt.host = reqaddr;
102: if (pass_through_add(dhcp->pass_throughs,
103: MAX_PASS_THROUGHS,
104: &dhcp->num_pass_throughs,
105: &pt))
106: ;
107: }
108:
109: int
110: dns_copy_res(int q,
111: uint8_t **pktp, size_t *left,
112: uint8_t *opkt, size_t olen,
113: char *question, size_t qsize) {
114:
115: #define return_error \
116: { log_dbg("%s:%d: failed parsing DNS packet",__FILE__,__LINE__); return -1; }
117:
118: uint8_t *p_pkt = *pktp;
119: size_t len = *left;
120:
121: uint8_t name[PKT_IP_PLEN];
122: size_t namelen = 0;
123:
124: uint16_t type;
125: uint16_t class;
126: uint32_t ttl;
127: uint16_t rdlen;
128:
129: uint32_t ul;
130: uint16_t us;
131:
132: if (dns_getname(&p_pkt, &len, (char *)name, sizeof(name), &namelen))
133: return_error;
134:
135: if (antidnstunnel && namelen > 128) {
136: log_warn(0,"dropping dns for anti-dnstunnel (namelen: %d)",namelen);
137: return -1;
138: }
139:
140: if (len < 4)
141: return_error;
142:
143: memcpy(&us, p_pkt, sizeof(us));
144: type = ntohs(us);
145: p_pkt += 2;
146: len -= 2;
147:
148: memcpy(&us, p_pkt, sizeof(us));
149: class = ntohs(us);
150: p_pkt += 2;
151: len -= 2;
152:
153: log_dbg("It was a dns record type: %d class: %d", type, class);
154:
155:
156: /* if dnsparanoia, checks here */
157:
158: if (antidnstunnel) {
159: switch (type) {
160: case 1:/* A */
161: log_dbg("A record");
162: break;
163: case 5:/* CNAME */
164: log_dbg("CNAME record");
165: break;
166: default:
167: if (options.debug) switch(type) {
168: case 6: log_dbg("SOA record"); break;
169: case 12: log_dbg("PTR record"); break;
170: case 15: log_dbg("MX record"); break;
171: case 16: log_dbg("TXT record"); break;
172: default: log_dbg("Record type %d", type); break;
173: }
174: log_warn(0, "dropping dns for anti-dnstunnel (type %d: length %d)", type, rdlen);
175: return -1;
176: }
177: }
178:
179: if (q) {
180: dns_fullname(question, qsize, *pktp, opkt, olen, 0);
181:
182: log_dbg("Q: %s", question);
183:
184: *pktp = p_pkt;
185: *left = len;
186:
187: return 0;
188: }
189:
190: if (len < 6)
191: return_error;
192:
193: memcpy(&ul, p_pkt, sizeof(ul));
194: ttl = ntohl(ul);
195: p_pkt += 4;
196: len -= 4;
197:
198: memcpy(&us, p_pkt, sizeof(us));
199: rdlen = ntohs(us);
200: p_pkt += 2;
201: len -= 2;
202:
203: /*log_dbg("-> w ttl: %d rdlength: %d/%d", ttl, rdlen, len);*/
204:
205: if (len < rdlen)
206: return_error;
207:
208: /*
209: * dns records
210: */
211:
212: switch (type) {
213:
214: case 1:/* A */
215: log_dbg("A record");
216: if (options.uamdomains) {
217: int id;
218: for (id=0; options.uamdomains[id]; id++) {
219:
220: log_dbg("checking %s [%s]", options.uamdomains[id], question);
221:
222: if (strlen(question) >= strlen(options.uamdomains[id]) &&
223: !strcmp(options.uamdomains[id],
224: question + (strlen(question) - strlen(options.uamdomains[id])))) {
225: size_t offset;
226: for (offset=0; offset < rdlen; offset += 4) {
227: add_A_to_garden(p_pkt+offset);
228: }
229:
230: break;
231: }
232: }
233: }
234: break;
235:
236: case 5:/* CNAME */
237: {
238: char cname[256];
239: memset(cname,0,sizeof(cname));
240: dns_fullname(cname, sizeof(cname)-1, p_pkt, opkt, olen, 0);
241: log_dbg("CNAME record %s", cname);
242: }
243: break;
244:
245: default:
246:
247: if (options.debug) switch(type) {
248: case 6: log_dbg("SOA record"); break;
249: case 12: log_dbg("PTR record"); break;
250: case 15: log_dbg("MX record"); break;
251: case 16: log_dbg("TXT record"); break;
252: default: log_dbg("Record type %d", type); break;
253: }
254:
255: if (antidnstunnel) {
256: log_warn(0, "dropping dns for anti-dnstunnel (type %d: length %d)", type, rdlen);
257: return -1;
258: }
259:
260: break;
261: }
262:
263: p_pkt += rdlen;
264: len -= rdlen;
265:
266: *pktp = p_pkt;
267: *left = len;
268:
269: return 0;
270: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>