Branch data Line data Source code
1 : : // $Id:$
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include <sys/types.h>
6 : : #include <sys/socket.h>
7 : : #include <netinet/in.h>
8 : : #include <arpa/nameser.h>
9 : : #include <arpa/inet.h>
10 : : #include <resolv.h>
11 : :
12 : : #include "NetVar.h"
13 : : #include "DNS.h"
14 : : #include "Val.h"
15 : : #include "TCP.h"
16 : : #include "Anon.h"
17 : : #include "DNS_Rewriter.h"
18 : :
19 : : DNS_Rewriter::DNS_Rewriter(Analyzer* analyzer, int arg_MTU,
20 : 0 : PacketDumper* dumper)
21 : 0 : : UDP_Rewriter(analyzer, arg_MTU, dumper)
22 : : {
23 : 0 : pkt_size = 0;
24 : 0 : current_pkt_id = 0;
25 : :
26 : 0 : pkt = new u_char[DNS_PKT_SIZE + DNS_HDR_SIZE];
27 : 0 : }
28 : :
29 : 0 : void DNS_Rewriter::DnsCopyHeader(Val* msg)
30 : : {
31 : : // New header - reset packet size.
32 : 0 : pkt_size = 0;
33 : :
34 : : // Move msg->AsRecordVal() to a RecordVal* to optimize.
35 : 0 : const RecordVal* msg_rec = msg->AsRecordVal();
36 : 0 : int id = msg_rec->Lookup(0)->AsCount();
37 : 0 : int opcode = msg_rec->Lookup(1)->AsCount();
38 : 0 : int rcode = msg_rec->Lookup(2)->AsCount();
39 : 0 : int QR = msg_rec->Lookup(3)->AsBool();
40 : 0 : int AA = msg_rec->Lookup(4)->AsBool();
41 : 0 : int TC = msg_rec->Lookup(5)->AsBool();
42 : 0 : int RD = msg_rec->Lookup(6)->AsBool();
43 : 0 : int RA = msg_rec->Lookup(7)->AsBool();
44 : 0 : int Z = msg_rec->Lookup(8)->AsCount();
45 : 0 : int qdcount = msg_rec->Lookup(9)->AsCount();
46 : 0 : int ancount = msg_rec->Lookup(10)->AsCount();
47 : 0 : int nscount = msg_rec->Lookup(11)->AsCount();
48 : 0 : int arcount = msg_rec->Lookup(12)->AsCount();
49 : :
50 : 0 : current_pkt_id = id;
51 : :
52 : : // Set the DNS flags.
53 : : uint16 flags = (QR << 15) | (AA << 10) | (TC << 9) |
54 : 0 : (RD << 8) | (RA << 7) | (Z << 4);
55 : :
56 : 0 : flags |= rcode | (opcode << 11);
57 : :
58 : 0 : (void) WriteShortVal(id);
59 : 0 : (void) WriteShortVal(flags);
60 : 0 : (void) WriteShortVal(qdcount);
61 : 0 : (void) WriteShortVal(ancount);
62 : 0 : (void) WriteShortVal(nscount);
63 : 0 : (void) WriteShortVal(arcount);
64 : :
65 : : // We've finished the header.
66 : 0 : pkt_size = DNS_HDR_SIZE;
67 : :
68 : : // Assign all the pointers for dn_comp().
69 : 0 : dpp = dn_ptrs;
70 : 0 : *dpp++ = pkt;
71 : 0 : *dpp++ = 0;
72 : :
73 : 0 : last_dn_ptr = dn_ptrs + sizeof dn_ptrs / sizeof dn_ptrs[0];
74 : 0 : }
75 : :
76 : 0 : int DNS_Rewriter::DnsCopyQuery(Val* val)
77 : : {
78 : 0 : const RecordVal* val_rec = val->AsRecordVal();
79 : :
80 : : // int type = val_rec->Lookup(0)->AsCount();
81 : :
82 : 0 : const BroString* query = val_rec->Lookup(1)->AsString();
83 : 0 : int atype = val_rec->Lookup(2)->AsCount();
84 : 0 : int aclass = val_rec->Lookup(3)->AsCount();
85 : :
86 : 0 : return DnsCopyQuery(query, atype, aclass);
87 : : }
88 : :
89 : : // Copy the question part of the query into memory.
90 : : // Return the number of bytes that the query string compressed to.
91 : : int DNS_Rewriter::DnsCopyQuery(const BroString* query, uint32 qtype,
92 : 0 : uint32 qclass)
93 : : {
94 : 0 : int len = query->Len();
95 : 0 : int psize = pkt_size;
96 : :
97 : : // Encode the query string.
98 : 0 : const char* dname = (char*) query->Bytes();
99 : : len = dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
100 : 0 : dn_ptrs, last_dn_ptr);
101 : :
102 : : // Can't encode in less than 2 bytes, or about to overwrite.
103 [ # # # # ]: 0 : if ( len < 1 || pkt_size + len + 4 > DNS_PKT_SIZE )
104 : : {
105 : 0 : warn("dn_comp couldn't encode name into packet");
106 : 0 : return 0;
107 : : }
108 : :
109 : 0 : pkt_size += len;
110 : :
111 : : // Set type.
112 [ # # ]: 0 : if ( ! WriteShortVal(qtype) )
113 : : {
114 : 0 : pkt_size = psize;
115 : 0 : return 0;
116 : : }
117 : :
118 : : // Set class.
119 [ # # ]: 0 : if ( ! WriteShortVal(qclass) )
120 : : {
121 : 0 : pkt_size = psize;
122 : 0 : return 0;
123 : : }
124 : :
125 : 0 : return len;
126 : : }
127 : :
128 : :
129 : : // PTR, NS and CNAME are all the same.
130 : 0 : void DNS_Rewriter::DnsCopyPTR(Val* ans, const BroString* name)
131 : : {
132 : 0 : DnsCopyCNAME(ans, name);
133 : 0 : }
134 : :
135 : : // Copy an NS RR into the packet.
136 : 0 : void DNS_Rewriter::DnsCopyNS( Val* ans, const BroString* name)
137 : : {
138 : 0 : DnsCopyCNAME(ans, name);
139 : 0 : }
140 : :
141 : : // Copy an A RR into the packet.
142 : 0 : void DNS_Rewriter::DnsCopyA(Val* ans, uint32 addr)
143 : : {
144 : 0 : int psize = pkt_size;
145 : :
146 : : // Put query part into packet.
147 : 0 : int len = DnsCopyQuery(ans);
148 : :
149 [ # # ]: 0 : if ( ! len )
150 : 0 : return;
151 : :
152 : 0 : double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
153 [ # # ]: 0 : if ( ! WriteDoubleAsInt(TTL) )
154 : : {
155 : 0 : pkt_size = psize;
156 : 0 : return;
157 : : }
158 : :
159 : : // Now we put in how long the resource data is (A rec is always 4).
160 [ # # ]: 0 : if ( ! WriteShortVal(4) )
161 : : {
162 : 0 : pkt_size = psize;
163 : 0 : return;
164 : : }
165 : :
166 : : // Stick in the address (already in network byte order).
167 [ # # ]: 0 : if ( ! WriteVal(uint32(ntohl(addr))) )
168 : : {
169 : 0 : pkt_size = psize;
170 : 0 : return;
171 : : }
172 : : }
173 : :
174 : : // Copy an AAAA RR into the packet.
175 : 0 : void DNS_Rewriter::DnsCopyAAAA(Val* ans, addr_type addr, const BroString* addrstr)
176 : : {
177 : 0 : int psize = pkt_size;
178 : :
179 : :
180 : : // Put query part into packet.
181 : 0 : int len = DnsCopyQuery(ans);
182 [ # # # # ]: 0 : if ( ! len || pkt_size + 6 > DNS_PKT_SIZE )
183 : 0 : return;
184 : :
185 : 0 : double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
186 [ # # ]: 0 : if ( ! WriteDoubleAsInt(TTL))
187 : : {
188 : 0 : pkt_size = psize;
189 : 0 : return;
190 : : }
191 : :
192 : : // Now we put in how long the resource data is (AAAA rec is always 16).
193 [ # # ]: 0 : if ( ! WriteShortVal(16) )
194 : : {
195 : 0 : pkt_size = psize;
196 : 0 : return;
197 : : }
198 : : #ifdef BROv6
199 : : if ( ! WriteVal(addr) )
200 : : {
201 : : pkt_size = psize;
202 : : return;
203 : : }
204 : : #else
205 : : uint32 addr_copy[4];
206 : 0 : char* addr_tmp = addrstr->Render(BroString::ESC_NONE);
207 : 0 : inet_pton(AF_INET6, addr_tmp, addr_copy);
208 : :
209 [ # # ]: 0 : if ( ! WriteVal(addr_copy) )
210 : : {
211 : 0 : pkt_size = psize;
212 : 0 : return;
213 : : }
214 : :
215 : 0 : delete addr_tmp;
216 : : #endif
217 : :
218 : : }
219 : :
220 : : // Copy a CNAME RR into the packet.
221 : 0 : void DNS_Rewriter::DnsCopyCNAME(Val* ans, const BroString* name)
222 : : {
223 : 0 : int psize = pkt_size;
224 : :
225 : : // Put query part into packet.
226 : 0 : int len = DnsCopyQuery(ans);
227 [ # # # # ]: 0 : if ( ! len || pkt_size + 6 > DNS_PKT_SIZE )
228 : 0 : return;
229 : :
230 : 0 : double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
231 [ # # ]: 0 : if ( ! WriteDoubleAsInt(TTL))
232 : : {
233 : 0 : pkt_size = psize;
234 : 0 : return;
235 : : }
236 : :
237 : : // Resource length (domain name length in packet).
238 : : // Have to skip till it's encoded, remember this spot.
239 : 0 : u_char* resource_len = pkt + pkt_size;
240 : 0 : pkt_size += 2;
241 : :
242 : : // Encode the domain name.
243 : 0 : const char* dname = (char*) name->CheckString();
244 : : len = dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
245 : 0 : dn_ptrs, last_dn_ptr);
246 : :
247 [ # # ]: 0 : if ( len < 1 )
248 : : {
249 : 0 : pkt_size = psize;
250 : 0 : return;
251 : : }
252 : :
253 : 0 : pkt_size += len;
254 : :
255 : : // Now we put in how long the name was to encode.
256 : 0 : uint16 net_rdlen = htons(short(len));
257 : 0 : memcpy(resource_len, &net_rdlen, sizeof(uint16));
258 : : }
259 : :
260 : : // Copy a CNAME RR into the packet.
261 : 0 : void DNS_Rewriter::DnsCopyTXT(Val* ans, const BroString* name)
262 : : {
263 : 0 : int psize = pkt_size;
264 : :
265 : : // Put query part into packet.
266 : 0 : int len = DnsCopyQuery(ans);
267 [ # # # # ]: 0 : if ( ! len || pkt_size + 6 > DNS_PKT_SIZE )
268 : 0 : return;
269 : :
270 : 0 : double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
271 [ # # ]: 0 : if ( ! WriteDoubleAsInt(TTL))
272 : : {
273 : 0 : pkt_size = psize;
274 : 0 : return;
275 : : }
276 : :
277 [ # # ]: 0 : if ( ! WriteShortVal(name->Len()+1))
278 : : {
279 : 0 : pkt_size = psize;
280 : 0 : return;
281 : : }
282 : :
283 [ # # ]: 0 : if ( ! WriteVal(uint8(name->Len())))
284 : : {
285 : 0 : pkt_size = psize;
286 : 0 : return;
287 : : }
288 : :
289 [ # # ]: 0 : if ( ! WriteVal(name))
290 : : {
291 : 0 : pkt_size = psize;
292 : 0 : return;
293 : : }
294 : :
295 : : }
296 : :
297 : : // Copy an MX RR into the packet.
298 : 0 : void DNS_Rewriter::DnsCopyMX(Val* ans, const BroString* name, uint32 preference)
299 : : {
300 : 0 : int psize = pkt_size;
301 : :
302 : : // Put query part into packet.
303 : 0 : int len = DnsCopyQuery(ans);
304 : :
305 [ # # # # ]: 0 : if ( ! len || pkt_size + len + 6 > DNS_PKT_SIZE )
306 : : {
307 : 0 : warn("DnsCopyMX: packet too large");
308 : 0 : return;
309 : : }
310 : :
311 : 0 : double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
312 [ # # ]: 0 : if ( ! WriteDoubleAsInt(TTL) )
313 : : {
314 : 0 : pkt_size = psize;
315 : 0 : warn("DnsCopyMX: packet too large");
316 : 0 : return;
317 : : }
318 : :
319 : : // Resource length (domain name length in packet).
320 : : // Have to skip till it's, remember this spot.
321 : 0 : u_char* resource_len = pkt + pkt_size;
322 : 0 : pkt_size += 2;
323 : :
324 [ # # ]: 0 : if ( ! WriteShortVal(preference))
325 : : {
326 : 0 : pkt_size = psize;
327 : 0 : warn("DnsCopyMX: packet too large");
328 : 0 : return;
329 : : }
330 : :
331 : : // Encode the domain name.
332 : 0 : const char* dname = (char*) name->CheckString();
333 : : len += dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
334 : 0 : dn_ptrs, last_dn_ptr);
335 : :
336 [ # # ]: 0 : if ( len < 1 )
337 : : {
338 : 0 : pkt_size = psize;
339 : 0 : warn("DnsCopyMX: packet too large");
340 : 0 : return;
341 : : }
342 : :
343 : 0 : pkt_size += len;
344 : :
345 : : // 2 bytes for the preference size above.
346 : 0 : len += 2;
347 : :
348 : : // Now we put in how long the name was to encode.
349 : 0 : uint16 net_rdlen = htons(short(len));
350 : 0 : memcpy(resource_len, &net_rdlen, sizeof(uint16));
351 : : }
352 : :
353 : : // Copy an SOA RR into the packet.
354 : 0 : void DNS_Rewriter::DnsCopySOA(Val* ans, Val* soa)
355 : : {
356 : : u_char* resource_len;
357 : 0 : int resource_offset = 0;
358 : 0 : int psize = pkt_size;
359 : :
360 : 0 : const RecordVal* soa_rec = soa->AsRecordVal();
361 : :
362 : 0 : const BroString* mname = soa_rec->Lookup(0)->AsString();
363 : 0 : const BroString* rname = soa_rec->Lookup(1)->AsString();
364 : 0 : uint32 serial = soa_rec->Lookup(2)->AsCount();
365 : 0 : double refresh = soa_rec->Lookup(3)->AsInterval();
366 : 0 : double retry = soa_rec->Lookup(4)->AsInterval();
367 : 0 : double expire = soa_rec->Lookup(5)->AsInterval();
368 : 0 : double minimum = soa_rec->Lookup(6)->AsInterval();
369 : :
370 : : // Put query part into packet.
371 : 0 : int len = DnsCopyQuery(ans);
372 : :
373 [ # # # # ]: 0 : if ( ! len || len + 6 > DNS_PKT_SIZE )
374 : 0 : return;
375 : :
376 : 0 : double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
377 [ # # ]: 0 : if ( ! WriteDoubleAsInt(TTL) )
378 : : {
379 : 0 : pkt_size = psize;
380 : 0 : return;
381 : : }
382 : :
383 : : // Resource length: have to skip till it's encoded.
384 : : // Remember this spot and offset.
385 : 0 : resource_len = pkt + pkt_size;
386 : 0 : pkt_size += 2;
387 : :
388 : : // Start counting from here (after rdlength).
389 : 0 : resource_offset = pkt_size;
390 : :
391 : : // Encode the domain name.
392 : 0 : const char* dname = (char*) mname->CheckString();
393 : : len = dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
394 : 0 : dn_ptrs, last_dn_ptr);
395 : :
396 [ # # ]: 0 : if ( len < 1 )
397 : : {
398 : 0 : pkt_size = psize;
399 : 0 : return;
400 : : }
401 : :
402 : 0 : pkt_size += len;
403 : :
404 : : // Encode the domain name.
405 : 0 : dname = (char*) rname->CheckString();
406 : : len = dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
407 : 0 : dn_ptrs, last_dn_ptr);
408 [ # # ]: 0 : if ( len < 1 )
409 : : {
410 : 0 : pkt_size = psize;
411 : 0 : return;
412 : : }
413 : :
414 : 0 : pkt_size += len;
415 : :
416 [ # # ][ # # ]: 0 : if ( ! WriteVal(serial) || ! WriteDoubleAsInt(refresh) ||
[ # # ][ # # ]
[ # # ][ # # ]
417 : : ! WriteDoubleAsInt(retry) || ! WriteDoubleAsInt(expire) ||
418 : : ! WriteDoubleAsInt(minimum) )
419 : : {
420 : 0 : pkt_size = psize;
421 : 0 : return;
422 : : }
423 : :
424 : : // Now we put in how long this packet was.
425 : 0 : uint16 net_rdlen = htons(short(pkt_size - resource_offset));
426 : 0 : memcpy(resource_len, &net_rdlen, sizeof(uint16));
427 : : }
428 : :
429 : 0 : void DNS_Rewriter::DnsCopyEDNSaddl(Val* ans)
430 : : {
431 : 0 : const RecordVal* ans_rec = ans->AsRecordVal();
432 : :
433 : 0 : int ans_type = ans_rec->Lookup(0)->AsCount();
434 : : // BroString* query_name = ans_rec->Lookup(1)->AsString();
435 : 0 : int atype = ans_rec->Lookup(2)->AsCount();
436 : 0 : int aclass = ans_rec->Lookup(3)->AsCount();
437 : 0 : int return_error = ans_rec->Lookup(4)->AsCount();
438 : 0 : int version = ans_rec->Lookup(5)->AsCount();
439 : 0 : int z = ans_rec->Lookup(6)->AsCount();
440 : 0 : double ttl = ans_rec->Lookup(7)->AsInterval();
441 : 0 : int is_query = ans_rec->Lookup(8)->AsCount();
442 : :
443 : 0 : int rcode = return_error;
444 : 0 : int ecode = 0;
445 : :
446 : 0 : int psize = pkt_size;
447 : :
448 [ # # ]: 0 : if ( return_error > 0xff )
449 : : {
450 : 0 : rcode &= 0xff;
451 : 0 : ecode = return_error >> 8;
452 : : }
453 : :
454 : : // Stick the version onto the ecode.
455 : 0 : ecode = (ecode << 8) | version;
456 : :
457 : : // Write fixed part of OPT RR
458 : : // Name '0'.
459 : 0 : memset(pkt + pkt_size, 0, 1);
460 : 0 : ++pkt_size;
461 : :
462 : : // Type (either 29 or 41).
463 [ # # ]: 0 : if ( ! WriteShortVal(atype) )
464 : : {
465 : 0 : pkt_size = psize;
466 : 0 : return;
467 : : }
468 : :
469 : : // UDP playload size
470 [ # # ]: 0 : if ( ! WriteShortVal(aclass) )
471 : : {
472 : 0 : pkt_size = psize;
473 : 0 : return;
474 : : }
475 : :
476 : : // Extended rcode + version.
477 [ # # ]: 0 : if ( ! WriteShortVal(ecode) )
478 : : {
479 : 0 : pkt_size = psize;
480 : 0 : return;
481 : : }
482 : :
483 : : // Z field.
484 [ # # ]: 0 : if ( ! WriteShortVal(z) )
485 : : {
486 : 0 : pkt_size = psize;
487 : 0 : return;
488 : : }
489 : :
490 : : // Data length (XXX:for now its zero!).
491 [ # # ]: 0 : if ( ! WriteShortVal(0) )
492 : : {
493 : 0 : pkt_size = psize;
494 : 0 : return;
495 : : }
496 : :
497 : : // Don't write data (XXX:we don't have it!).
498 : : }
499 : :
500 : : // Does this packet match the current packet being worked on?
501 : 0 : int DNS_Rewriter::DnsPktMatch(Val* msg)
502 : : {
503 : 0 : return msg->AsRecordVal()->Lookup(0)->AsInt() == current_pkt_id;
504 : : }
505 : :
506 : : // Supports copying of TXT values.
507 : 0 : int DNS_Rewriter::WriteVal(const BroString* val)
508 : : {
509 : 0 : int n = val->Len();
510 : :
511 [ # # ]: 0 : if ( pkt_size + n > DNS_PKT_SIZE )
512 : : {
513 : 0 : warn("WriteVal: couldn't write data into packet");
514 : 0 : return 0;
515 : : }
516 : :
517 : 0 : char* new_val = val->Render(BroString::ESC_NONE);
518 : 0 : memcpy(pkt + pkt_size, new_val, n);
519 : 0 : pkt_size += n;
520 : :
521 [ # # ]: 0 : delete[] new_val;
522 : :
523 : 0 : return n;
524 : : }
525 : :
526 : 0 : int DNS_Rewriter::WriteVal(const uint32* val)
527 : : {
528 [ # # ]: 0 : if ( pkt_size + 16 > DNS_PKT_SIZE )
529 : : {
530 : 0 : warn("WriteVal: couldn't write data into packet");
531 : 0 : return 0;
532 : : }
533 : :
534 : 0 : memcpy(pkt + pkt_size, &val[0], sizeof(uint32)); pkt_size += 4;
535 : 0 : memcpy(pkt + pkt_size, &val[1], sizeof(uint32)); pkt_size += 4;
536 : 0 : memcpy(pkt + pkt_size, &val[2], sizeof(uint32)); pkt_size += 4;
537 : 0 : memcpy(pkt + pkt_size, &val[3], sizeof(uint32)); pkt_size += 4;
538 : :
539 : 0 : return sizeof(uint32) * 4;
540 : : }
541 : :
542 : : // Write a 32 bit value given in host order to the packet.
543 : 0 : int DNS_Rewriter::WriteVal(uint32 val)
544 : : {
545 [ # # ]: 0 : if ( pkt_size + 4 > DNS_PKT_SIZE )
546 : : {
547 : 0 : warn("WriteVal: couldn't write data into packet");
548 : 0 : return 0;
549 : : }
550 : :
551 : 0 : uint32 net_val = htonl(val);
552 : 0 : memcpy(pkt + pkt_size, &net_val, sizeof(uint32));
553 : 0 : pkt_size += 4;
554 : :
555 : 0 : return sizeof(uint32);
556 : : }
557 : :
558 : : // Write a 16 bit value given in host order to the packet.
559 : 0 : int DNS_Rewriter::WriteVal(uint16 val)
560 : : {
561 [ # # ]: 0 : if ( pkt_size + 2 > DNS_PKT_SIZE )
562 : : {
563 : 0 : warn("WriteShortVal: couldn't write data into packet");
564 : 0 : return 0;
565 : : }
566 : :
567 : 0 : uint16 net_val = htons(val);
568 : 0 : memcpy(pkt + pkt_size, &net_val, sizeof(uint16));
569 : 0 : pkt_size += 2;
570 : :
571 : 0 : return sizeof(uint16);
572 : : }
573 : :
574 : : // Write a 8 bit value given in host order to the packet.
575 : 0 : int DNS_Rewriter::WriteVal(uint8 val)
576 : : {
577 [ # # ]: 0 : if ( pkt_size + 1 > DNS_PKT_SIZE )
578 : : {
579 : 0 : warn("WriteVal: couldn't write data into packet");
580 : 0 : return 0;
581 : : }
582 : :
583 : 0 : memcpy(pkt + pkt_size, &val, sizeof(uint8));
584 : 0 : pkt_size += sizeof(uint8);
585 : :
586 : 0 : return sizeof(uint8);
587 [ + - ][ + - ]: 6 : }
|