blob: a9a67f20b3aca8adb18a16cb8ee9fd736fe977b7 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include "resolv_cache.h"
Robert Greenwalt9363d912011-07-25 12:30:17 -070030#include <resolv.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080031#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34#include "pthread.h"
35
Mattias Falk3e0c5102011-01-31 12:42:26 +010036#include <errno.h>
37#include "arpa_nameser.h"
Robert Greenwalt9363d912011-07-25 12:30:17 -070038#include <net/if.h>
39#include <netdb.h>
40#include <linux/if.h>
41
42#include <arpa/inet.h>
43#include "resolv_private.h"
Mattias Falk3e0c5102011-01-31 12:42:26 +010044
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080045/* This code implements a small and *simple* DNS resolver cache.
46 *
Mattias Falk3e0c5102011-01-31 12:42:26 +010047 * It is only used to cache DNS answers for a time defined by the smallest TTL
48 * among the answer records in order to reduce DNS traffic. It is not supposed
49 * to be a full DNS cache, since we plan to implement that in the future in a
50 * dedicated process running on the system.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080051 *
52 * Note that its design is kept simple very intentionally, i.e.:
53 *
54 * - it takes raw DNS query packet data as input, and returns raw DNS
55 * answer packet data as output
56 *
57 * (this means that two similar queries that encode the DNS name
58 * differently will be treated distinctly).
59 *
Mattias Falk3e0c5102011-01-31 12:42:26 +010060 * the smallest TTL value among the answer records are used as the time
61 * to keep an answer in the cache.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080062 *
63 * this is bad, but we absolutely want to avoid parsing the answer packets
64 * (and should be solved by the later full DNS cache process).
65 *
66 * - the implementation is just a (query-data) => (answer-data) hash table
67 * with a trivial least-recently-used expiration policy.
68 *
69 * Doing this keeps the code simple and avoids to deal with a lot of things
70 * that a full DNS cache is expected to do.
71 *
72 * The API is also very simple:
73 *
74 * - the client calls _resolv_cache_get() to obtain a handle to the cache.
75 * this will initialize the cache on first usage. the result can be NULL
76 * if the cache is disabled.
77 *
78 * - the client calls _resolv_cache_lookup() before performing a query
79 *
80 * if the function returns RESOLV_CACHE_FOUND, a copy of the answer data
81 * has been copied into the client-provided answer buffer.
82 *
83 * if the function returns RESOLV_CACHE_NOTFOUND, the client should perform
84 * a request normally, *then* call _resolv_cache_add() to add the received
85 * answer to the cache.
86 *
87 * if the function returns RESOLV_CACHE_UNSUPPORTED, the client should
88 * perform a request normally, and *not* call _resolv_cache_add()
89 *
90 * note that RESOLV_CACHE_UNSUPPORTED is also returned if the answer buffer
91 * is too short to accomodate the cached result.
92 *
93 * - when network settings change, the cache must be flushed since the list
94 * of DNS servers probably changed. this is done by calling
95 * _resolv_cache_reset()
96 *
97 * the parameter to this function must be an ever-increasing generation
98 * number corresponding to the current network settings state.
99 *
100 * This is done because several threads could detect the same network
101 * settings change (but at different times) and will all end up calling the
102 * same function. Comparing with the last used generation number ensures
103 * that the cache is only flushed once per network change.
104 */
105
106/* the name of an environment variable that will be checked the first time
107 * this code is called if its value is "0", then the resolver cache is
108 * disabled.
109 */
110#define CONFIG_ENV "BIONIC_DNSCACHE"
111
112/* entries older than CONFIG_SECONDS seconds are always discarded.
113 */
114#define CONFIG_SECONDS (60*10) /* 10 minutes */
115
116/* maximum number of entries kept in the cache. This value has been
117 * determined by browsing through various sites and counting the number
118 * of corresponding requests. Keep in mind that our framework is currently
119 * performing two requests per name lookup (one for IPv4, the other for IPv6)
120 *
121 * www.google.com 4
122 * www.ysearch.com 6
123 * www.amazon.com 8
124 * www.nytimes.com 22
125 * www.espn.com 28
126 * www.msn.com 28
127 * www.lemonde.fr 35
128 *
129 * (determined in 2009-2-17 from Paris, France, results may vary depending
130 * on location)
131 *
132 * most high-level websites use lots of media/ad servers with different names
133 * but these are generally reused when browsing through the site.
134 *
135 * As such, a valud of 64 should be relatively conformtable at the moment.
136 */
137#define CONFIG_MAX_ENTRIES 64
138
139/****************************************************************************/
140/****************************************************************************/
141/***** *****/
142/***** *****/
143/***** *****/
144/****************************************************************************/
145/****************************************************************************/
146
147/* set to 1 to debug cache operations */
148#define DEBUG 0
149
150/* set to 1 to debug query data */
151#define DEBUG_DATA 0
152
Mattias Falk3e0c5102011-01-31 12:42:26 +0100153#undef XLOG
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800154#if DEBUG
155# include <logd.h>
156# define XLOG(...) \
157 __libc_android_log_print(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__)
158
159#include <stdio.h>
160#include <stdarg.h>
161
162/** BOUNDED BUFFER FORMATTING
163 **/
164
165/* technical note:
166 *
167 * the following debugging routines are used to append data to a bounded
168 * buffer they take two parameters that are:
169 *
170 * - p : a pointer to the current cursor position in the buffer
171 * this value is initially set to the buffer's address.
172 *
173 * - end : the address of the buffer's limit, i.e. of the first byte
174 * after the buffer. this address should never be touched.
175 *
176 * IMPORTANT: it is assumed that end > buffer_address, i.e.
177 * that the buffer is at least one byte.
178 *
179 * the _bprint_() functions return the new value of 'p' after the data
180 * has been appended, and also ensure the following:
181 *
182 * - the returned value will never be strictly greater than 'end'
183 *
184 * - a return value equal to 'end' means that truncation occured
185 * (in which case, end[-1] will be set to 0)
186 *
187 * - after returning from a _bprint_() function, the content of the buffer
188 * is always 0-terminated, even in the event of truncation.
189 *
190 * these conventions allow you to call _bprint_ functions multiple times and
191 * only check for truncation at the end of the sequence, as in:
192 *
193 * char buff[1000], *p = buff, *end = p + sizeof(buff);
194 *
195 * p = _bprint_c(p, end, '"');
196 * p = _bprint_s(p, end, my_string);
197 * p = _bprint_c(p, end, '"');
198 *
199 * if (p >= end) {
200 * // buffer was too small
201 * }
202 *
203 * printf( "%s", buff );
204 */
205
206/* add a char to a bounded buffer */
207static char*
208_bprint_c( char* p, char* end, int c )
209{
210 if (p < end) {
211 if (p+1 == end)
212 *p++ = 0;
213 else {
214 *p++ = (char) c;
215 *p = 0;
216 }
217 }
218 return p;
219}
220
221/* add a sequence of bytes to a bounded buffer */
222static char*
223_bprint_b( char* p, char* end, const char* buf, int len )
224{
225 int avail = end - p;
226
227 if (avail <= 0 || len <= 0)
228 return p;
229
230 if (avail > len)
231 avail = len;
232
233 memcpy( p, buf, avail );
234 p += avail;
235
236 if (p < end)
237 p[0] = 0;
238 else
239 end[-1] = 0;
240
241 return p;
242}
243
244/* add a string to a bounded buffer */
245static char*
246_bprint_s( char* p, char* end, const char* str )
247{
248 return _bprint_b(p, end, str, strlen(str));
249}
250
251/* add a formatted string to a bounded buffer */
252static char*
253_bprint( char* p, char* end, const char* format, ... )
254{
255 int avail, n;
256 va_list args;
257
258 avail = end - p;
259
260 if (avail <= 0)
261 return p;
262
263 va_start(args, format);
David 'Digit' Turnerd378c682010-03-08 15:13:04 -0800264 n = vsnprintf( p, avail, format, args);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800265 va_end(args);
266
267 /* certain C libraries return -1 in case of truncation */
268 if (n < 0 || n > avail)
269 n = avail;
270
271 p += n;
272 /* certain C libraries do not zero-terminate in case of truncation */
273 if (p == end)
274 p[-1] = 0;
275
276 return p;
277}
278
279/* add a hex value to a bounded buffer, up to 8 digits */
280static char*
281_bprint_hex( char* p, char* end, unsigned value, int numDigits )
282{
283 char text[sizeof(unsigned)*2];
284 int nn = 0;
285
286 while (numDigits-- > 0) {
287 text[nn++] = "0123456789abcdef"[(value >> (numDigits*4)) & 15];
288 }
289 return _bprint_b(p, end, text, nn);
290}
291
292/* add the hexadecimal dump of some memory area to a bounded buffer */
293static char*
294_bprint_hexdump( char* p, char* end, const uint8_t* data, int datalen )
295{
296 int lineSize = 16;
297
298 while (datalen > 0) {
299 int avail = datalen;
300 int nn;
301
302 if (avail > lineSize)
303 avail = lineSize;
304
305 for (nn = 0; nn < avail; nn++) {
306 if (nn > 0)
307 p = _bprint_c(p, end, ' ');
308 p = _bprint_hex(p, end, data[nn], 2);
309 }
310 for ( ; nn < lineSize; nn++ ) {
311 p = _bprint_s(p, end, " ");
312 }
313 p = _bprint_s(p, end, " ");
314
315 for (nn = 0; nn < avail; nn++) {
316 int c = data[nn];
317
318 if (c < 32 || c > 127)
319 c = '.';
320
321 p = _bprint_c(p, end, c);
322 }
323 p = _bprint_c(p, end, '\n');
324
325 data += avail;
326 datalen -= avail;
327 }
328 return p;
329}
330
331/* dump the content of a query of packet to the log */
332static void
333XLOG_BYTES( const void* base, int len )
334{
335 char buff[1024];
336 char* p = buff, *end = p + sizeof(buff);
337
338 p = _bprint_hexdump(p, end, base, len);
339 XLOG("%s",buff);
340}
341
342#else /* !DEBUG */
343# define XLOG(...) ((void)0)
344# define XLOG_BYTES(a,b) ((void)0)
345#endif
346
347static time_t
348_time_now( void )
349{
350 struct timeval tv;
351
352 gettimeofday( &tv, NULL );
353 return tv.tv_sec;
354}
355
356/* reminder: the general format of a DNS packet is the following:
357 *
358 * HEADER (12 bytes)
359 * QUESTION (variable)
360 * ANSWER (variable)
361 * AUTHORITY (variable)
362 * ADDITIONNAL (variable)
363 *
364 * the HEADER is made of:
365 *
366 * ID : 16 : 16-bit unique query identification field
367 *
368 * QR : 1 : set to 0 for queries, and 1 for responses
369 * Opcode : 4 : set to 0 for queries
370 * AA : 1 : set to 0 for queries
371 * TC : 1 : truncation flag, will be set to 0 in queries
372 * RD : 1 : recursion desired
373 *
374 * RA : 1 : recursion available (0 in queries)
375 * Z : 3 : three reserved zero bits
376 * RCODE : 4 : response code (always 0=NOERROR in queries)
377 *
378 * QDCount: 16 : question count
379 * ANCount: 16 : Answer count (0 in queries)
380 * NSCount: 16: Authority Record count (0 in queries)
381 * ARCount: 16: Additionnal Record count (0 in queries)
382 *
383 * the QUESTION is made of QDCount Question Record (QRs)
384 * the ANSWER is made of ANCount RRs
385 * the AUTHORITY is made of NSCount RRs
386 * the ADDITIONNAL is made of ARCount RRs
387 *
388 * Each Question Record (QR) is made of:
389 *
390 * QNAME : variable : Query DNS NAME
391 * TYPE : 16 : type of query (A=1, PTR=12, MX=15, AAAA=28, ALL=255)
392 * CLASS : 16 : class of query (IN=1)
393 *
394 * Each Resource Record (RR) is made of:
395 *
396 * NAME : variable : DNS NAME
397 * TYPE : 16 : type of query (A=1, PTR=12, MX=15, AAAA=28, ALL=255)
398 * CLASS : 16 : class of query (IN=1)
399 * TTL : 32 : seconds to cache this RR (0=none)
400 * RDLENGTH: 16 : size of RDDATA in bytes
401 * RDDATA : variable : RR data (depends on TYPE)
402 *
403 * Each QNAME contains a domain name encoded as a sequence of 'labels'
404 * terminated by a zero. Each label has the following format:
405 *
406 * LEN : 8 : lenght of label (MUST be < 64)
407 * NAME : 8*LEN : label length (must exclude dots)
408 *
409 * A value of 0 in the encoding is interpreted as the 'root' domain and
410 * terminates the encoding. So 'www.android.com' will be encoded as:
411 *
412 * <3>www<7>android<3>com<0>
413 *
414 * Where <n> represents the byte with value 'n'
415 *
416 * Each NAME reflects the QNAME of the question, but has a slightly more
417 * complex encoding in order to provide message compression. This is achieved
418 * by using a 2-byte pointer, with format:
419 *
420 * TYPE : 2 : 0b11 to indicate a pointer, 0b01 and 0b10 are reserved
421 * OFFSET : 14 : offset to another part of the DNS packet
422 *
423 * The offset is relative to the start of the DNS packet and must point
424 * A pointer terminates the encoding.
425 *
426 * The NAME can be encoded in one of the following formats:
427 *
428 * - a sequence of simple labels terminated by 0 (like QNAMEs)
429 * - a single pointer
430 * - a sequence of simple labels terminated by a pointer
431 *
432 * A pointer shall always point to either a pointer of a sequence of
433 * labels (which can themselves be terminated by either a 0 or a pointer)
434 *
435 * The expanded length of a given domain name should not exceed 255 bytes.
436 *
437 * NOTE: we don't parse the answer packets, so don't need to deal with NAME
438 * records, only QNAMEs.
439 */
440
441#define DNS_HEADER_SIZE 12
442
443#define DNS_TYPE_A "\00\01" /* big-endian decimal 1 */
444#define DNS_TYPE_PTR "\00\014" /* big-endian decimal 12 */
445#define DNS_TYPE_MX "\00\017" /* big-endian decimal 15 */
446#define DNS_TYPE_AAAA "\00\034" /* big-endian decimal 28 */
447#define DNS_TYPE_ALL "\00\0377" /* big-endian decimal 255 */
448
449#define DNS_CLASS_IN "\00\01" /* big-endian decimal 1 */
450
451typedef struct {
452 const uint8_t* base;
453 const uint8_t* end;
454 const uint8_t* cursor;
455} DnsPacket;
456
457static void
458_dnsPacket_init( DnsPacket* packet, const uint8_t* buff, int bufflen )
459{
460 packet->base = buff;
461 packet->end = buff + bufflen;
462 packet->cursor = buff;
463}
464
465static void
466_dnsPacket_rewind( DnsPacket* packet )
467{
468 packet->cursor = packet->base;
469}
470
471static void
472_dnsPacket_skip( DnsPacket* packet, int count )
473{
474 const uint8_t* p = packet->cursor + count;
475
476 if (p > packet->end)
477 p = packet->end;
478
479 packet->cursor = p;
480}
481
482static int
483_dnsPacket_readInt16( DnsPacket* packet )
484{
485 const uint8_t* p = packet->cursor;
486
487 if (p+2 > packet->end)
488 return -1;
489
490 packet->cursor = p+2;
491 return (p[0]<< 8) | p[1];
492}
493
494/** QUERY CHECKING
495 **/
496
497/* check bytes in a dns packet. returns 1 on success, 0 on failure.
498 * the cursor is only advanced in the case of success
499 */
500static int
501_dnsPacket_checkBytes( DnsPacket* packet, int numBytes, const void* bytes )
502{
503 const uint8_t* p = packet->cursor;
504
505 if (p + numBytes > packet->end)
506 return 0;
507
508 if (memcmp(p, bytes, numBytes) != 0)
509 return 0;
510
511 packet->cursor = p + numBytes;
512 return 1;
513}
514
515/* parse and skip a given QNAME stored in a query packet,
516 * from the current cursor position. returns 1 on success,
517 * or 0 for malformed data.
518 */
519static int
520_dnsPacket_checkQName( DnsPacket* packet )
521{
522 const uint8_t* p = packet->cursor;
523 const uint8_t* end = packet->end;
524
525 for (;;) {
526 int c;
527
528 if (p >= end)
529 break;
530
531 c = *p++;
532
533 if (c == 0) {
534 packet->cursor = p;
535 return 1;
536 }
537
538 /* we don't expect label compression in QNAMEs */
539 if (c >= 64)
540 break;
541
542 p += c;
543 /* we rely on the bound check at the start
544 * of the loop here */
545 }
546 /* malformed data */
547 XLOG("malformed QNAME");
548 return 0;
549}
550
551/* parse and skip a given QR stored in a packet.
552 * returns 1 on success, and 0 on failure
553 */
554static int
555_dnsPacket_checkQR( DnsPacket* packet )
556{
557 int len;
558
559 if (!_dnsPacket_checkQName(packet))
560 return 0;
561
562 /* TYPE must be one of the things we support */
563 if (!_dnsPacket_checkBytes(packet, 2, DNS_TYPE_A) &&
564 !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_PTR) &&
565 !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_MX) &&
566 !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_AAAA) &&
567 !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_ALL))
568 {
569 XLOG("unsupported TYPE");
570 return 0;
571 }
572 /* CLASS must be IN */
573 if (!_dnsPacket_checkBytes(packet, 2, DNS_CLASS_IN)) {
574 XLOG("unsupported CLASS");
575 return 0;
576 }
577
578 return 1;
579}
580
581/* check the header of a DNS Query packet, return 1 if it is one
582 * type of query we can cache, or 0 otherwise
583 */
584static int
585_dnsPacket_checkQuery( DnsPacket* packet )
586{
587 const uint8_t* p = packet->base;
588 int qdCount, anCount, dnCount, arCount;
589
590 if (p + DNS_HEADER_SIZE > packet->end) {
591 XLOG("query packet too small");
592 return 0;
593 }
594
595 /* QR must be set to 0, opcode must be 0 and AA must be 0 */
596 /* RA, Z, and RCODE must be 0 */
597 if ((p[2] & 0xFC) != 0 || p[3] != 0) {
598 XLOG("query packet flags unsupported");
599 return 0;
600 }
601
602 /* Note that we ignore the TC and RD bits here for the
603 * following reasons:
604 *
605 * - there is no point for a query packet sent to a server
606 * to have the TC bit set, but the implementation might
607 * set the bit in the query buffer for its own needs
608 * between a _resolv_cache_lookup and a
609 * _resolv_cache_add. We should not freak out if this
610 * is the case.
611 *
612 * - we consider that the result from a RD=0 or a RD=1
613 * query might be different, hence that the RD bit
614 * should be used to differentiate cached result.
615 *
616 * this implies that RD is checked when hashing or
617 * comparing query packets, but not TC
618 */
619
620 /* ANCOUNT, DNCOUNT and ARCOUNT must be 0 */
621 qdCount = (p[4] << 8) | p[5];
622 anCount = (p[6] << 8) | p[7];
623 dnCount = (p[8] << 8) | p[9];
624 arCount = (p[10]<< 8) | p[11];
625
626 if (anCount != 0 || dnCount != 0 || arCount != 0) {
627 XLOG("query packet contains non-query records");
628 return 0;
629 }
630
631 if (qdCount == 0) {
632 XLOG("query packet doesn't contain query record");
633 return 0;
634 }
635
636 /* Check QDCOUNT QRs */
637 packet->cursor = p + DNS_HEADER_SIZE;
638
639 for (;qdCount > 0; qdCount--)
640 if (!_dnsPacket_checkQR(packet))
641 return 0;
642
643 return 1;
644}
645
646/** QUERY DEBUGGING
647 **/
648#if DEBUG
649static char*
650_dnsPacket_bprintQName(DnsPacket* packet, char* bp, char* bend)
651{
652 const uint8_t* p = packet->cursor;
653 const uint8_t* end = packet->end;
654 int first = 1;
655
656 for (;;) {
657 int c;
658
659 if (p >= end)
660 break;
661
662 c = *p++;
663
664 if (c == 0) {
665 packet->cursor = p;
666 return bp;
667 }
668
669 /* we don't expect label compression in QNAMEs */
670 if (c >= 64)
671 break;
672
673 if (first)
674 first = 0;
675 else
676 bp = _bprint_c(bp, bend, '.');
677
678 bp = _bprint_b(bp, bend, (const char*)p, c);
679
680 p += c;
681 /* we rely on the bound check at the start
682 * of the loop here */
683 }
684 /* malformed data */
685 bp = _bprint_s(bp, bend, "<MALFORMED>");
686 return bp;
687}
688
689static char*
690_dnsPacket_bprintQR(DnsPacket* packet, char* p, char* end)
691{
692#define QQ(x) { DNS_TYPE_##x, #x }
693 static const struct {
694 const char* typeBytes;
695 const char* typeString;
696 } qTypes[] =
697 {
698 QQ(A), QQ(PTR), QQ(MX), QQ(AAAA), QQ(ALL),
699 { NULL, NULL }
700 };
701 int nn;
702 const char* typeString = NULL;
703
704 /* dump QNAME */
705 p = _dnsPacket_bprintQName(packet, p, end);
706
707 /* dump TYPE */
708 p = _bprint_s(p, end, " (");
709
710 for (nn = 0; qTypes[nn].typeBytes != NULL; nn++) {
711 if (_dnsPacket_checkBytes(packet, 2, qTypes[nn].typeBytes)) {
712 typeString = qTypes[nn].typeString;
713 break;
714 }
715 }
716
717 if (typeString != NULL)
718 p = _bprint_s(p, end, typeString);
719 else {
720 int typeCode = _dnsPacket_readInt16(packet);
721 p = _bprint(p, end, "UNKNOWN-%d", typeCode);
722 }
723
724 p = _bprint_c(p, end, ')');
725
726 /* skip CLASS */
727 _dnsPacket_skip(packet, 2);
728 return p;
729}
730
731/* this function assumes the packet has already been checked */
732static char*
733_dnsPacket_bprintQuery( DnsPacket* packet, char* p, char* end )
734{
735 int qdCount;
736
737 if (packet->base[2] & 0x1) {
738 p = _bprint_s(p, end, "RECURSIVE ");
739 }
740
741 _dnsPacket_skip(packet, 4);
742 qdCount = _dnsPacket_readInt16(packet);
743 _dnsPacket_skip(packet, 6);
744
745 for ( ; qdCount > 0; qdCount-- ) {
746 p = _dnsPacket_bprintQR(packet, p, end);
747 }
748 return p;
749}
750#endif
751
752
753/** QUERY HASHING SUPPORT
754 **
755 ** THE FOLLOWING CODE ASSUMES THAT THE INPUT PACKET HAS ALREADY
756 ** BEEN SUCCESFULLY CHECKED.
757 **/
758
759/* use 32-bit FNV hash function */
760#define FNV_MULT 16777619U
761#define FNV_BASIS 2166136261U
762
763static unsigned
764_dnsPacket_hashBytes( DnsPacket* packet, int numBytes, unsigned hash )
765{
766 const uint8_t* p = packet->cursor;
767 const uint8_t* end = packet->end;
768
769 while (numBytes > 0 && p < end) {
770 hash = hash*FNV_MULT ^ *p++;
771 }
772 packet->cursor = p;
773 return hash;
774}
775
776
777static unsigned
778_dnsPacket_hashQName( DnsPacket* packet, unsigned hash )
779{
780 const uint8_t* p = packet->cursor;
781 const uint8_t* end = packet->end;
782
783 for (;;) {
784 int c;
785
786 if (p >= end) { /* should not happen */
787 XLOG("%s: INTERNAL_ERROR: read-overflow !!\n", __FUNCTION__);
788 break;
789 }
790
791 c = *p++;
792
793 if (c == 0)
794 break;
795
796 if (c >= 64) {
797 XLOG("%s: INTERNAL_ERROR: malformed domain !!\n", __FUNCTION__);
798 break;
799 }
800 if (p + c >= end) {
801 XLOG("%s: INTERNAL_ERROR: simple label read-overflow !!\n",
802 __FUNCTION__);
803 break;
804 }
805 while (c > 0) {
806 hash = hash*FNV_MULT ^ *p++;
807 c -= 1;
808 }
809 }
810 packet->cursor = p;
811 return hash;
812}
813
814static unsigned
815_dnsPacket_hashQR( DnsPacket* packet, unsigned hash )
816{
817 int len;
818
819 hash = _dnsPacket_hashQName(packet, hash);
820 hash = _dnsPacket_hashBytes(packet, 4, hash); /* TYPE and CLASS */
821 return hash;
822}
823
824static unsigned
825_dnsPacket_hashQuery( DnsPacket* packet )
826{
827 unsigned hash = FNV_BASIS;
828 int count;
829 _dnsPacket_rewind(packet);
830
831 /* we ignore the TC bit for reasons explained in
832 * _dnsPacket_checkQuery().
833 *
834 * however we hash the RD bit to differentiate
835 * between answers for recursive and non-recursive
836 * queries.
837 */
838 hash = hash*FNV_MULT ^ (packet->base[2] & 1);
839
840 /* assume: other flags are 0 */
841 _dnsPacket_skip(packet, 4);
842
843 /* read QDCOUNT */
844 count = _dnsPacket_readInt16(packet);
845
846 /* assume: ANcount, NScount, ARcount are 0 */
847 _dnsPacket_skip(packet, 6);
848
849 /* hash QDCOUNT QRs */
850 for ( ; count > 0; count-- )
851 hash = _dnsPacket_hashQR(packet, hash);
852
853 return hash;
854}
855
856
857/** QUERY COMPARISON
858 **
859 ** THE FOLLOWING CODE ASSUMES THAT THE INPUT PACKETS HAVE ALREADY
860 ** BEEN SUCCESFULLY CHECKED.
861 **/
862
863static int
864_dnsPacket_isEqualDomainName( DnsPacket* pack1, DnsPacket* pack2 )
865{
866 const uint8_t* p1 = pack1->cursor;
867 const uint8_t* end1 = pack1->end;
868 const uint8_t* p2 = pack2->cursor;
869 const uint8_t* end2 = pack2->end;
870
871 for (;;) {
872 int c1, c2;
873
874 if (p1 >= end1 || p2 >= end2) {
875 XLOG("%s: INTERNAL_ERROR: read-overflow !!\n", __FUNCTION__);
876 break;
877 }
878 c1 = *p1++;
879 c2 = *p2++;
880 if (c1 != c2)
881 break;
882
883 if (c1 == 0) {
884 pack1->cursor = p1;
885 pack2->cursor = p2;
886 return 1;
887 }
888 if (c1 >= 64) {
889 XLOG("%s: INTERNAL_ERROR: malformed domain !!\n", __FUNCTION__);
890 break;
891 }
892 if ((p1+c1 > end1) || (p2+c1 > end2)) {
893 XLOG("%s: INTERNAL_ERROR: simple label read-overflow !!\n",
894 __FUNCTION__);
895 break;
896 }
897 if (memcmp(p1, p2, c1) != 0)
898 break;
899 p1 += c1;
900 p2 += c1;
901 /* we rely on the bound checks at the start of the loop */
902 }
903 /* not the same, or one is malformed */
904 XLOG("different DN");
905 return 0;
906}
907
908static int
909_dnsPacket_isEqualBytes( DnsPacket* pack1, DnsPacket* pack2, int numBytes )
910{
911 const uint8_t* p1 = pack1->cursor;
912 const uint8_t* p2 = pack2->cursor;
913
914 if ( p1 + numBytes > pack1->end || p2 + numBytes > pack2->end )
915 return 0;
916
917 if ( memcmp(p1, p2, numBytes) != 0 )
918 return 0;
919
920 pack1->cursor += numBytes;
921 pack2->cursor += numBytes;
922 return 1;
923}
924
925static int
926_dnsPacket_isEqualQR( DnsPacket* pack1, DnsPacket* pack2 )
927{
928 /* compare domain name encoding + TYPE + CLASS */
929 if ( !_dnsPacket_isEqualDomainName(pack1, pack2) ||
930 !_dnsPacket_isEqualBytes(pack1, pack2, 2+2) )
931 return 0;
932
933 return 1;
934}
935
936static int
937_dnsPacket_isEqualQuery( DnsPacket* pack1, DnsPacket* pack2 )
938{
939 int count1, count2;
940
941 /* compare the headers, ignore most fields */
942 _dnsPacket_rewind(pack1);
943 _dnsPacket_rewind(pack2);
944
945 /* compare RD, ignore TC, see comment in _dnsPacket_checkQuery */
946 if ((pack1->base[2] & 1) != (pack2->base[2] & 1)) {
947 XLOG("different RD");
948 return 0;
949 }
950
951 /* assume: other flags are all 0 */
952 _dnsPacket_skip(pack1, 4);
953 _dnsPacket_skip(pack2, 4);
954
955 /* compare QDCOUNT */
956 count1 = _dnsPacket_readInt16(pack1);
957 count2 = _dnsPacket_readInt16(pack2);
958 if (count1 != count2 || count1 < 0) {
959 XLOG("different QDCOUNT");
960 return 0;
961 }
962
963 /* assume: ANcount, NScount and ARcount are all 0 */
964 _dnsPacket_skip(pack1, 6);
965 _dnsPacket_skip(pack2, 6);
966
967 /* compare the QDCOUNT QRs */
968 for ( ; count1 > 0; count1-- ) {
969 if (!_dnsPacket_isEqualQR(pack1, pack2)) {
970 XLOG("different QR");
971 return 0;
972 }
973 }
974 return 1;
975}
976
977/****************************************************************************/
978/****************************************************************************/
979/***** *****/
980/***** *****/
981/***** *****/
982/****************************************************************************/
983/****************************************************************************/
984
985/* cache entry. for simplicity, 'hash' and 'hlink' are inlined in this
986 * structure though they are conceptually part of the hash table.
987 *
988 * similarly, mru_next and mru_prev are part of the global MRU list
989 */
990typedef struct Entry {
991 unsigned int hash; /* hash value */
992 struct Entry* hlink; /* next in collision chain */
993 struct Entry* mru_prev;
994 struct Entry* mru_next;
995
996 const uint8_t* query;
997 int querylen;
998 const uint8_t* answer;
999 int answerlen;
Mattias Falk3e0c5102011-01-31 12:42:26 +01001000 time_t expires; /* time_t when the entry isn't valid any more */
1001 int id; /* for debugging purpose */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001002} Entry;
1003
Mattias Falk3e0c5102011-01-31 12:42:26 +01001004/**
1005 * Parse the answer records and find the smallest
1006 * TTL among the answer records.
1007 *
1008 * The returned TTL is the number of seconds to
1009 * keep the answer in the cache.
1010 *
1011 * In case of parse error zero (0) is returned which
1012 * indicates that the answer shall not be cached.
1013 */
1014static u_long
1015answer_getTTL(const void* answer, int answerlen)
1016{
1017 ns_msg handle;
1018 int ancount, n;
1019 u_long result, ttl;
1020 ns_rr rr;
1021
1022 result = 0;
1023 if (ns_initparse(answer, answerlen, &handle) >= 0) {
1024 // get number of answer records
1025 ancount = ns_msg_count(handle, ns_s_an);
1026 for (n = 0; n < ancount; n++) {
1027 if (ns_parserr(&handle, ns_s_an, n, &rr) == 0) {
1028 ttl = ns_rr_ttl(rr);
1029 if (n == 0 || ttl < result) {
1030 result = ttl;
1031 }
1032 } else {
1033 XLOG("ns_parserr failed ancount no = %d. errno = %s\n", n, strerror(errno));
1034 }
1035 }
1036 } else {
1037 XLOG("ns_parserr failed. %s\n", strerror(errno));
1038 }
1039
1040 XLOG("TTL = %d\n", result);
1041
1042 return result;
1043}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001044
1045static void
1046entry_free( Entry* e )
1047{
1048 /* everything is allocated in a single memory block */
1049 if (e) {
1050 free(e);
1051 }
1052}
1053
1054static __inline__ void
1055entry_mru_remove( Entry* e )
1056{
1057 e->mru_prev->mru_next = e->mru_next;
1058 e->mru_next->mru_prev = e->mru_prev;
1059}
1060
1061static __inline__ void
1062entry_mru_add( Entry* e, Entry* list )
1063{
1064 Entry* first = list->mru_next;
1065
1066 e->mru_next = first;
1067 e->mru_prev = list;
1068
1069 list->mru_next = e;
1070 first->mru_prev = e;
1071}
1072
1073/* compute the hash of a given entry, this is a hash of most
1074 * data in the query (key) */
1075static unsigned
1076entry_hash( const Entry* e )
1077{
1078 DnsPacket pack[1];
1079
1080 _dnsPacket_init(pack, e->query, e->querylen);
1081 return _dnsPacket_hashQuery(pack);
1082}
1083
1084/* initialize an Entry as a search key, this also checks the input query packet
1085 * returns 1 on success, or 0 in case of unsupported/malformed data */
1086static int
1087entry_init_key( Entry* e, const void* query, int querylen )
1088{
1089 DnsPacket pack[1];
1090
1091 memset(e, 0, sizeof(*e));
1092
1093 e->query = query;
1094 e->querylen = querylen;
1095 e->hash = entry_hash(e);
1096
1097 _dnsPacket_init(pack, query, querylen);
1098
1099 return _dnsPacket_checkQuery(pack);
1100}
1101
1102/* allocate a new entry as a cache node */
1103static Entry*
1104entry_alloc( const Entry* init, const void* answer, int answerlen )
1105{
1106 Entry* e;
1107 int size;
1108
1109 size = sizeof(*e) + init->querylen + answerlen;
1110 e = calloc(size, 1);
1111 if (e == NULL)
1112 return e;
1113
1114 e->hash = init->hash;
1115 e->query = (const uint8_t*)(e+1);
1116 e->querylen = init->querylen;
1117
1118 memcpy( (char*)e->query, init->query, e->querylen );
1119
1120 e->answer = e->query + e->querylen;
1121 e->answerlen = answerlen;
1122
1123 memcpy( (char*)e->answer, answer, e->answerlen );
1124
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001125 return e;
1126}
1127
1128static int
1129entry_equals( const Entry* e1, const Entry* e2 )
1130{
1131 DnsPacket pack1[1], pack2[1];
1132
1133 if (e1->querylen != e2->querylen) {
1134 return 0;
1135 }
1136 _dnsPacket_init(pack1, e1->query, e1->querylen);
1137 _dnsPacket_init(pack2, e2->query, e2->querylen);
1138
1139 return _dnsPacket_isEqualQuery(pack1, pack2);
1140}
1141
1142/****************************************************************************/
1143/****************************************************************************/
1144/***** *****/
1145/***** *****/
1146/***** *****/
1147/****************************************************************************/
1148/****************************************************************************/
1149
1150/* We use a simple hash table with external collision lists
1151 * for simplicity, the hash-table fields 'hash' and 'hlink' are
1152 * inlined in the Entry structure.
1153 */
1154#define MAX_HASH_ENTRIES (2*CONFIG_MAX_ENTRIES)
1155
1156typedef struct resolv_cache {
1157 int num_entries;
1158 Entry mru_list;
1159 pthread_mutex_t lock;
1160 unsigned generation;
1161 int last_id;
1162 Entry* entries[ MAX_HASH_ENTRIES ];
1163} Cache;
1164
Robert Greenwalt9363d912011-07-25 12:30:17 -07001165typedef struct resolv_cache_info {
1166 char ifname[IF_NAMESIZE + 1];
1167 struct in_addr ifaddr;
1168 Cache* cache;
1169 struct resolv_cache_info* next;
1170 char* nameservers[MAXNS +1];
1171 struct addrinfo* nsaddrinfo[MAXNS + 1];
1172} CacheInfo;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001173
1174#define HTABLE_VALID(x) ((x) != NULL && (x) != HTABLE_DELETED)
1175
1176static void
1177_cache_flush_locked( Cache* cache )
1178{
1179 int nn;
1180 time_t now = _time_now();
1181
1182 for (nn = 0; nn < MAX_HASH_ENTRIES; nn++)
1183 {
1184 Entry** pnode = &cache->entries[nn];
1185
1186 while (*pnode != NULL) {
1187 Entry* node = *pnode;
1188 *pnode = node->hlink;
1189 entry_free(node);
1190 }
1191 }
1192
1193 cache->mru_list.mru_next = cache->mru_list.mru_prev = &cache->mru_list;
1194 cache->num_entries = 0;
1195 cache->last_id = 0;
1196
1197 XLOG("*************************\n"
1198 "*** DNS CACHE FLUSHED ***\n"
1199 "*************************");
1200}
1201
Jim Huang7cc56662010-10-15 02:02:57 +08001202static struct resolv_cache*
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001203_resolv_cache_create( void )
1204{
1205 struct resolv_cache* cache;
1206
1207 cache = calloc(sizeof(*cache), 1);
1208 if (cache) {
1209 cache->generation = ~0U;
1210 pthread_mutex_init( &cache->lock, NULL );
1211 cache->mru_list.mru_prev = cache->mru_list.mru_next = &cache->mru_list;
1212 XLOG("%s: cache created\n", __FUNCTION__);
1213 }
1214 return cache;
1215}
1216
1217
1218#if DEBUG
1219static void
1220_dump_query( const uint8_t* query, int querylen )
1221{
1222 char temp[256], *p=temp, *end=p+sizeof(temp);
1223 DnsPacket pack[1];
1224
1225 _dnsPacket_init(pack, query, querylen);
1226 p = _dnsPacket_bprintQuery(pack, p, end);
1227 XLOG("QUERY: %s", temp);
1228}
1229
1230static void
1231_cache_dump_mru( Cache* cache )
1232{
1233 char temp[512], *p=temp, *end=p+sizeof(temp);
1234 Entry* e;
1235
1236 p = _bprint(temp, end, "MRU LIST (%2d): ", cache->num_entries);
1237 for (e = cache->mru_list.mru_next; e != &cache->mru_list; e = e->mru_next)
1238 p = _bprint(p, end, " %d", e->id);
1239
1240 XLOG("%s", temp);
1241}
Mattias Falk3e0c5102011-01-31 12:42:26 +01001242
1243static void
1244_dump_answer(const void* answer, int answerlen)
1245{
1246 res_state statep;
1247 FILE* fp;
1248 char* buf;
1249 int fileLen;
1250
1251 fp = fopen("/data/reslog.txt", "w+");
1252 if (fp != NULL) {
1253 statep = __res_get_state();
1254
1255 res_pquery(statep, answer, answerlen, fp);
1256
1257 //Get file length
1258 fseek(fp, 0, SEEK_END);
1259 fileLen=ftell(fp);
1260 fseek(fp, 0, SEEK_SET);
1261 buf = (char *)malloc(fileLen+1);
1262 if (buf != NULL) {
1263 //Read file contents into buffer
1264 fread(buf, fileLen, 1, fp);
1265 XLOG("%s\n", buf);
1266 free(buf);
1267 }
1268 fclose(fp);
1269 remove("/data/reslog.txt");
1270 }
1271 else {
1272 XLOG("_dump_answer: can't open file\n");
1273 }
1274}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001275#endif
1276
1277#if DEBUG
1278# define XLOG_QUERY(q,len) _dump_query((q), (len))
Mattias Falk3e0c5102011-01-31 12:42:26 +01001279# define XLOG_ANSWER(a, len) _dump_answer((a), (len))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001280#else
1281# define XLOG_QUERY(q,len) ((void)0)
Mattias Falk3e0c5102011-01-31 12:42:26 +01001282# define XLOG_ANSWER(a,len) ((void)0)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001283#endif
1284
1285/* This function tries to find a key within the hash table
1286 * In case of success, it will return a *pointer* to the hashed key.
1287 * In case of failure, it will return a *pointer* to NULL
1288 *
1289 * So, the caller must check '*result' to check for success/failure.
1290 *
1291 * The main idea is that the result can later be used directly in
1292 * calls to _resolv_cache_add or _resolv_cache_remove as the 'lookup'
1293 * parameter. This makes the code simpler and avoids re-searching
1294 * for the key position in the htable.
1295 *
1296 * The result of a lookup_p is only valid until you alter the hash
1297 * table.
1298 */
1299static Entry**
1300_cache_lookup_p( Cache* cache,
1301 Entry* key )
1302{
1303 int index = key->hash % MAX_HASH_ENTRIES;
1304 Entry** pnode = &cache->entries[ key->hash % MAX_HASH_ENTRIES ];
1305
1306 while (*pnode != NULL) {
1307 Entry* node = *pnode;
1308
1309 if (node == NULL)
1310 break;
1311
1312 if (node->hash == key->hash && entry_equals(node, key))
1313 break;
1314
1315 pnode = &node->hlink;
1316 }
1317 return pnode;
1318}
1319
1320/* Add a new entry to the hash table. 'lookup' must be the
1321 * result of an immediate previous failed _lookup_p() call
1322 * (i.e. with *lookup == NULL), and 'e' is the pointer to the
1323 * newly created entry
1324 */
1325static void
1326_cache_add_p( Cache* cache,
1327 Entry** lookup,
1328 Entry* e )
1329{
1330 *lookup = e;
1331 e->id = ++cache->last_id;
1332 entry_mru_add(e, &cache->mru_list);
1333 cache->num_entries += 1;
1334
1335 XLOG("%s: entry %d added (count=%d)", __FUNCTION__,
1336 e->id, cache->num_entries);
1337}
1338
1339/* Remove an existing entry from the hash table,
1340 * 'lookup' must be the result of an immediate previous
1341 * and succesful _lookup_p() call.
1342 */
1343static void
1344_cache_remove_p( Cache* cache,
1345 Entry** lookup )
1346{
1347 Entry* e = *lookup;
1348
1349 XLOG("%s: entry %d removed (count=%d)", __FUNCTION__,
1350 e->id, cache->num_entries-1);
1351
1352 entry_mru_remove(e);
1353 *lookup = e->hlink;
1354 entry_free(e);
1355 cache->num_entries -= 1;
1356}
1357
1358/* Remove the oldest entry from the hash table.
1359 */
1360static void
1361_cache_remove_oldest( Cache* cache )
1362{
1363 Entry* oldest = cache->mru_list.mru_prev;
1364 Entry** lookup = _cache_lookup_p(cache, oldest);
1365
1366 if (*lookup == NULL) { /* should not happen */
1367 XLOG("%s: OLDEST NOT IN HTABLE ?", __FUNCTION__);
1368 return;
1369 }
1370 _cache_remove_p(cache, lookup);
1371}
1372
1373
1374ResolvCacheStatus
1375_resolv_cache_lookup( struct resolv_cache* cache,
1376 const void* query,
1377 int querylen,
1378 void* answer,
1379 int answersize,
1380 int *answerlen )
1381{
1382 DnsPacket pack[1];
1383 Entry key[1];
1384 int index;
1385 Entry** lookup;
1386 Entry* e;
1387 time_t now;
1388
1389 ResolvCacheStatus result = RESOLV_CACHE_NOTFOUND;
1390
1391 XLOG("%s: lookup", __FUNCTION__);
1392 XLOG_QUERY(query, querylen);
1393
1394 /* we don't cache malformed queries */
1395 if (!entry_init_key(key, query, querylen)) {
1396 XLOG("%s: unsupported query", __FUNCTION__);
1397 return RESOLV_CACHE_UNSUPPORTED;
1398 }
1399 /* lookup cache */
1400 pthread_mutex_lock( &cache->lock );
1401
1402 /* see the description of _lookup_p to understand this.
1403 * the function always return a non-NULL pointer.
1404 */
1405 lookup = _cache_lookup_p(cache, key);
1406 e = *lookup;
1407
1408 if (e == NULL) {
1409 XLOG( "NOT IN CACHE");
1410 goto Exit;
1411 }
1412
1413 now = _time_now();
1414
1415 /* remove stale entries here */
Mattias Falk3e0c5102011-01-31 12:42:26 +01001416 if (now >= e->expires) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001417 XLOG( " NOT IN CACHE (STALE ENTRY %p DISCARDED)", *lookup );
1418 _cache_remove_p(cache, lookup);
1419 goto Exit;
1420 }
1421
1422 *answerlen = e->answerlen;
1423 if (e->answerlen > answersize) {
1424 /* NOTE: we return UNSUPPORTED if the answer buffer is too short */
1425 result = RESOLV_CACHE_UNSUPPORTED;
1426 XLOG(" ANSWER TOO LONG");
1427 goto Exit;
1428 }
1429
1430 memcpy( answer, e->answer, e->answerlen );
1431
1432 /* bump up this entry to the top of the MRU list */
1433 if (e != cache->mru_list.mru_next) {
1434 entry_mru_remove( e );
1435 entry_mru_add( e, &cache->mru_list );
1436 }
1437
1438 XLOG( "FOUND IN CACHE entry=%p", e );
1439 result = RESOLV_CACHE_FOUND;
1440
1441Exit:
1442 pthread_mutex_unlock( &cache->lock );
1443 return result;
1444}
1445
1446
1447void
1448_resolv_cache_add( struct resolv_cache* cache,
1449 const void* query,
1450 int querylen,
1451 const void* answer,
1452 int answerlen )
1453{
1454 Entry key[1];
1455 Entry* e;
1456 Entry** lookup;
Mattias Falk3e0c5102011-01-31 12:42:26 +01001457 u_long ttl;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001458
1459 /* don't assume that the query has already been cached
1460 */
1461 if (!entry_init_key( key, query, querylen )) {
1462 XLOG( "%s: passed invalid query ?", __FUNCTION__);
1463 return;
1464 }
1465
1466 pthread_mutex_lock( &cache->lock );
1467
1468 XLOG( "%s: query:", __FUNCTION__ );
1469 XLOG_QUERY(query,querylen);
Mattias Falk3e0c5102011-01-31 12:42:26 +01001470 XLOG_ANSWER(answer, answerlen);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001471#if DEBUG_DATA
1472 XLOG( "answer:");
1473 XLOG_BYTES(answer,answerlen);
1474#endif
1475
1476 lookup = _cache_lookup_p(cache, key);
1477 e = *lookup;
1478
1479 if (e != NULL) { /* should not happen */
1480 XLOG("%s: ALREADY IN CACHE (%p) ? IGNORING ADD",
1481 __FUNCTION__, e);
1482 goto Exit;
1483 }
1484
1485 if (cache->num_entries >= CONFIG_MAX_ENTRIES) {
1486 _cache_remove_oldest(cache);
1487 /* need to lookup again */
1488 lookup = _cache_lookup_p(cache, key);
1489 e = *lookup;
1490 if (e != NULL) {
1491 XLOG("%s: ALREADY IN CACHE (%p) ? IGNORING ADD",
1492 __FUNCTION__, e);
1493 goto Exit;
1494 }
1495 }
1496
Mattias Falk3e0c5102011-01-31 12:42:26 +01001497 ttl = answer_getTTL(answer, answerlen);
1498 if (ttl > 0) {
1499 e = entry_alloc(key, answer, answerlen);
1500 if (e != NULL) {
1501 e->expires = ttl + _time_now();
1502 _cache_add_p(cache, lookup, e);
1503 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001504 }
1505#if DEBUG
1506 _cache_dump_mru(cache);
1507#endif
1508Exit:
1509 pthread_mutex_unlock( &cache->lock );
1510}
1511
1512/****************************************************************************/
1513/****************************************************************************/
1514/***** *****/
1515/***** *****/
1516/***** *****/
1517/****************************************************************************/
1518/****************************************************************************/
1519
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001520static pthread_once_t _res_cache_once;
1521
Robert Greenwalt9363d912011-07-25 12:30:17 -07001522// Head of the list of caches. Protected by _res_cache_list_lock.
1523static struct resolv_cache_info _res_cache_list;
1524
1525// name of the current default inteface
1526static char _res_default_ifname[IF_NAMESIZE + 1];
1527
1528// lock protecting everything in the _resolve_cache_info structs (next ptr, etc)
1529static pthread_mutex_t _res_cache_list_lock;
1530
1531
1532/* lookup the default interface name */
1533static char *_get_default_iface_locked();
1534/* insert resolv_cache_info into the list of resolv_cache_infos */
1535static void _insert_cache_info_locked(struct resolv_cache_info* cache_info);
1536/* creates a resolv_cache_info */
1537static struct resolv_cache_info* _create_cache_info( void );
1538/* gets cache associated with an interface name, or NULL if none exists */
1539static struct resolv_cache* _find_named_cache_locked(const char* ifname);
1540/* gets a resolv_cache_info associated with an interface name, or NULL if not found */
1541static struct resolv_cache_info* _find_cache_info_locked(const char* ifname);
1542/* free dns name server list of a resolv_cache_info structure */
1543static void _free_nameservers(struct resolv_cache_info* cache_info);
1544/* look up the named cache, and creates one if needed */
1545static struct resolv_cache* _get_res_cache_for_iface_locked(const char* ifname);
1546/* empty the named cache */
1547static void _flush_cache_for_iface_locked(const char* ifname);
1548/* empty the nameservers set for the named cache */
1549static void _free_nameservers_locked(struct resolv_cache_info* cache_info);
1550/* lookup the namserver for the name interface */
1551static int _get_nameserver_locked(const char* ifname, int n, char* addr, int addrLen);
1552/* lookup the addr of the nameserver for the named interface */
1553static struct addrinfo* _get_nameserver_addr_locked(const char* ifname, int n);
1554/* lookup the inteface's address */
1555static struct in_addr* _get_addr_locked(const char * ifname);
1556
1557
1558
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001559static void
Robert Greenwalt9363d912011-07-25 12:30:17 -07001560_res_cache_init(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001561{
1562 const char* env = getenv(CONFIG_ENV);
1563
1564 if (env && atoi(env) == 0) {
1565 /* the cache is disabled */
1566 return;
1567 }
1568
Robert Greenwalt9363d912011-07-25 12:30:17 -07001569 memset(&_res_default_ifname, 0, sizeof(_res_default_ifname));
1570 memset(&_res_cache_list, 0, sizeof(_res_cache_list));
1571 pthread_mutex_init(&_res_cache_list_lock, NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001572}
1573
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001574struct resolv_cache*
Robert Greenwalt9363d912011-07-25 12:30:17 -07001575__get_res_cache(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001576{
Robert Greenwalt9363d912011-07-25 12:30:17 -07001577 struct resolv_cache *cache;
1578
1579 pthread_once(&_res_cache_once, _res_cache_init);
1580
1581 pthread_mutex_lock(&_res_cache_list_lock);
1582
1583 char* ifname = _get_default_iface_locked();
1584
1585 // if default interface not set then use the first cache
1586 // associated with an interface as the default one.
1587 if (ifname[0] == '\0') {
1588 struct resolv_cache_info* cache_info = _res_cache_list.next;
1589 while (cache_info) {
1590 if (cache_info->ifname[0] != '\0') {
1591 ifname = cache_info->ifname;
1592 break;
1593 }
1594
1595 cache_info = cache_info->next;
1596 }
1597 }
1598 cache = _get_res_cache_for_iface_locked(ifname);
1599
1600 pthread_mutex_unlock(&_res_cache_list_lock);
1601 XLOG("_get_res_cache. default_ifname = %s\n", ifname);
1602 return cache;
1603}
1604
1605static struct resolv_cache*
1606_get_res_cache_for_iface_locked(const char* ifname)
1607{
1608 if (ifname == NULL)
1609 return NULL;
1610
1611 struct resolv_cache* cache = _find_named_cache_locked(ifname);
1612 if (!cache) {
1613 struct resolv_cache_info* cache_info = _create_cache_info();
1614 if (cache_info) {
1615 cache = _resolv_cache_create();
1616 if (cache) {
1617 int len = sizeof(cache_info->ifname);
1618 cache_info->cache = cache;
1619 strncpy(cache_info->ifname, ifname, len - 1);
1620 cache_info->ifname[len - 1] = '\0';
1621
1622 _insert_cache_info_locked(cache_info);
1623 } else {
1624 free(cache_info);
1625 }
1626 }
1627 }
1628 return cache;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001629}
1630
1631void
Robert Greenwalt9363d912011-07-25 12:30:17 -07001632_resolv_cache_reset(unsigned generation)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001633{
1634 XLOG("%s: generation=%d", __FUNCTION__, generation);
1635
Robert Greenwalt9363d912011-07-25 12:30:17 -07001636 pthread_once(&_res_cache_once, _res_cache_init);
1637 pthread_mutex_lock(&_res_cache_list_lock);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001638
Robert Greenwalt9363d912011-07-25 12:30:17 -07001639 char* ifname = _get_default_iface_locked();
1640 // if default interface not set then use the first cache
1641 // associated with an interface as the default one.
1642 // Note: Copied the code from __get_res_cache since this
1643 // method will be deleted/obsolete when cache per interface
1644 // implemented all over
1645 if (ifname[0] == '\0') {
1646 struct resolv_cache_info* cache_info = _res_cache_list.next;
1647 while (cache_info) {
1648 if (cache_info->ifname[0] != '\0') {
1649 ifname = cache_info->ifname;
1650 break;
1651 }
1652
1653 cache_info = cache_info->next;
1654 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001655 }
Robert Greenwalt9363d912011-07-25 12:30:17 -07001656 struct resolv_cache* cache = _get_res_cache_for_iface_locked(ifname);
1657
1658 if (cache != NULL) {
1659 pthread_mutex_lock( &cache->lock );
1660 if (cache->generation != generation) {
1661 _cache_flush_locked(cache);
1662 cache->generation = generation;
1663 }
1664 pthread_mutex_unlock( &cache->lock );
1665 }
1666
1667 pthread_mutex_unlock(&_res_cache_list_lock);
1668}
1669
1670void
1671_resolv_flush_cache_for_default_iface(void)
1672{
1673 char* ifname;
1674
1675 pthread_once(&_res_cache_once, _res_cache_init);
1676 pthread_mutex_lock(&_res_cache_list_lock);
1677
1678 ifname = _get_default_iface_locked();
1679 _flush_cache_for_iface_locked(ifname);
1680
1681 pthread_mutex_unlock(&_res_cache_list_lock);
1682}
1683
1684void
1685_resolv_flush_cache_for_iface(const char* ifname)
1686{
1687 pthread_once(&_res_cache_once, _res_cache_init);
1688 pthread_mutex_lock(&_res_cache_list_lock);
1689
1690 _flush_cache_for_iface_locked(ifname);
1691
1692 pthread_mutex_unlock(&_res_cache_list_lock);
1693}
1694
1695static void
1696_flush_cache_for_iface_locked(const char* ifname)
1697{
1698 struct resolv_cache* cache = _find_named_cache_locked(ifname);
1699 if (cache) {
1700 pthread_mutex_lock(&cache->lock);
1701 _cache_flush_locked(cache);
1702 pthread_mutex_unlock(&cache->lock);
1703 }
1704}
1705
1706static struct resolv_cache_info*
1707_create_cache_info(void)
1708{
1709 struct resolv_cache_info* cache_info;
1710
1711 cache_info = calloc(sizeof(*cache_info), 1);
1712 return cache_info;
1713}
1714
1715static void
1716_insert_cache_info_locked(struct resolv_cache_info* cache_info)
1717{
1718 struct resolv_cache_info* last;
1719
1720 for (last = &_res_cache_list; last->next; last = last->next);
1721
1722 last->next = cache_info;
1723
1724}
1725
1726static struct resolv_cache*
1727_find_named_cache_locked(const char* ifname) {
1728
1729 struct resolv_cache_info* info = _find_cache_info_locked(ifname);
1730
1731 if (info != NULL) return info->cache;
1732
1733 return NULL;
1734}
1735
1736static struct resolv_cache_info*
1737_find_cache_info_locked(const char* ifname)
1738{
1739 if (ifname == NULL)
1740 return NULL;
1741
1742 struct resolv_cache_info* cache_info = _res_cache_list.next;
1743
1744 while (cache_info) {
1745 if (strcmp(cache_info->ifname, ifname) == 0) {
1746 break;
1747 }
1748
1749 cache_info = cache_info->next;
1750 }
1751 return cache_info;
1752}
1753
1754static char*
1755_get_default_iface_locked(void)
1756{
1757 char* iface = _res_default_ifname;
1758
1759 return iface;
1760}
1761
1762void
1763_resolv_set_default_iface(const char* ifname)
1764{
1765 XLOG("_resolv_set_default_if ifname %s\n",ifname);
1766
1767 pthread_once(&_res_cache_once, _res_cache_init);
1768 pthread_mutex_lock(&_res_cache_list_lock);
1769
1770 int size = sizeof(_res_default_ifname);
1771 memset(_res_default_ifname, 0, size);
1772 strncpy(_res_default_ifname, ifname, size - 1);
1773 _res_default_ifname[size - 1] = '\0';
1774
1775 pthread_mutex_unlock(&_res_cache_list_lock);
1776}
1777
1778void
1779_resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numservers)
1780{
1781 int i, rt, index;
1782 struct addrinfo hints;
1783 char sbuf[NI_MAXSERV];
1784
1785 pthread_once(&_res_cache_once, _res_cache_init);
1786
1787 pthread_mutex_lock(&_res_cache_list_lock);
1788 // creates the cache if not created
1789 _get_res_cache_for_iface_locked(ifname);
1790
1791 struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
1792
1793 if (cache_info != NULL) {
1794 // free current before adding new
1795 _free_nameservers_locked(cache_info);
1796
1797 memset(&hints, 0, sizeof(hints));
1798 hints.ai_family = PF_UNSPEC;
1799 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
1800 hints.ai_flags = AI_NUMERICHOST;
1801 sprintf(sbuf, "%u", NAMESERVER_PORT);
1802
1803 index = 0;
1804 for (i = 0; i < numservers && i < MAXNS; i++) {
1805 rt = getaddrinfo(servers[i], sbuf, &hints, &cache_info->nsaddrinfo[index]);
1806 if (rt == 0) {
1807 cache_info->nameservers[index] = strdup(servers[i]);
1808 index++;
1809 } else {
1810 cache_info->nsaddrinfo[index] = NULL;
1811 }
1812 }
1813 }
1814 pthread_mutex_unlock(&_res_cache_list_lock);
1815}
1816
1817static void
1818_free_nameservers_locked(struct resolv_cache_info* cache_info)
1819{
1820 int i;
1821 for (i = 0; i <= MAXNS; i++) {
1822 free(cache_info->nameservers[i]);
1823 cache_info->nameservers[i] = NULL;
1824 if (cache_info->nsaddrinfo[i] != NULL) {
1825 freeaddrinfo(cache_info->nsaddrinfo[i]);
1826 cache_info->nsaddrinfo[i] = NULL;
1827 }
1828 }
1829}
1830
1831int
1832_resolv_cache_get_nameserver(int n, char* addr, int addrLen)
1833{
1834 char *ifname;
1835 int result = 0;
1836
1837 pthread_once(&_res_cache_once, _res_cache_init);
1838 pthread_mutex_lock(&_res_cache_list_lock);
1839
1840 ifname = _get_default_iface_locked();
1841 result = _get_nameserver_locked(ifname, n, addr, addrLen);
1842
1843 pthread_mutex_unlock(&_res_cache_list_lock);
1844 return result;
1845}
1846
1847static int
1848_get_nameserver_locked(const char* ifname, int n, char* addr, int addrLen)
1849{
1850 int len = 0;
1851 char* ns;
1852 struct resolv_cache_info* cache_info;
1853
1854 if (n < 1 || n > MAXNS || !addr)
1855 return 0;
1856
1857 cache_info = _find_cache_info_locked(ifname);
1858 if (cache_info) {
1859 ns = cache_info->nameservers[n - 1];
1860 if (ns) {
1861 len = strlen(ns);
1862 if (len < addrLen) {
1863 strncpy(addr, ns, len);
1864 addr[len] = '\0';
1865 } else {
1866 len = 0;
1867 }
1868 }
1869 }
1870
1871 return len;
1872}
1873
1874struct addrinfo*
1875_cache_get_nameserver_addr(int n)
1876{
1877 struct addrinfo *result;
1878 char* ifname;
1879
1880 pthread_once(&_res_cache_once, _res_cache_init);
1881 pthread_mutex_lock(&_res_cache_list_lock);
1882
1883 ifname = _get_default_iface_locked();
1884
1885 result = _get_nameserver_addr_locked(ifname, n);
1886 pthread_mutex_unlock(&_res_cache_list_lock);
1887 return result;
1888}
1889
1890static struct addrinfo*
1891_get_nameserver_addr_locked(const char* ifname, int n)
1892{
1893 struct addrinfo* ai = NULL;
1894 struct resolv_cache_info* cache_info;
1895
1896 if (n < 1 || n > MAXNS)
1897 return NULL;
1898
1899 cache_info = _find_cache_info_locked(ifname);
1900 if (cache_info) {
1901 ai = cache_info->nsaddrinfo[n - 1];
1902 }
1903 return ai;
1904}
1905
1906void
1907_resolv_set_addr_of_iface(const char* ifname, struct in_addr* addr)
1908{
1909 pthread_once(&_res_cache_once, _res_cache_init);
1910 pthread_mutex_lock(&_res_cache_list_lock);
1911 struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
1912 if (cache_info) {
1913 memcpy(&cache_info->ifaddr, addr, sizeof(*addr));
1914
1915 if (DEBUG) {
1916 char* addr_s = inet_ntoa(cache_info->ifaddr);
1917 XLOG("address of interface %s is %s\n", ifname, addr_s);
1918 }
1919 }
1920 pthread_mutex_unlock(&_res_cache_list_lock);
1921}
1922
1923struct in_addr*
1924_resolv_get_addr_of_default_iface(void)
1925{
1926 struct in_addr* ai = NULL;
1927 char* ifname;
1928
1929 pthread_once(&_res_cache_once, _res_cache_init);
1930 pthread_mutex_lock(&_res_cache_list_lock);
1931 ifname = _get_default_iface_locked();
1932 ai = _get_addr_locked(ifname);
1933 pthread_mutex_unlock(&_res_cache_list_lock);
1934
1935 return ai;
1936}
1937
1938struct in_addr*
1939_resolv_get_addr_of_iface(const char* ifname)
1940{
1941 struct in_addr* ai = NULL;
1942
1943 pthread_once(&_res_cache_once, _res_cache_init);
1944 pthread_mutex_lock(&_res_cache_list_lock);
1945 ai =_get_addr_locked(ifname);
1946 pthread_mutex_unlock(&_res_cache_list_lock);
1947 return ai;
1948}
1949
1950static struct in_addr*
1951_get_addr_locked(const char * ifname)
1952{
1953 struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
1954 if (cache_info) {
1955 return &cache_info->ifaddr;
1956 }
1957 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001958}