blob: a2bc7ca440bc8c4bdddbdf4393a785fa97d06538 [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"
Mattias Falk23d3e6b2011-04-04 16:12:35 +020030#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"
Mattias Falk3a4910c2011-02-14 12:41:11 +010038#include <sys/system_properties.h>
Mattias Falk23d3e6b2011-04-04 16:12:35 +020039#include <net/if.h>
40#include <netdb.h>
41#include <linux/if.h>
42
43#include <arpa/inet.h>
44#include "resolv_private.h"
David 'Digit' Turner208898e2012-01-13 14:24:08 +010045#include "resolv_iface.h"
Mattias Falk3e0c5102011-01-31 12:42:26 +010046
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080047/* This code implements a small and *simple* DNS resolver cache.
48 *
Mattias Falk3e0c5102011-01-31 12:42:26 +010049 * It is only used to cache DNS answers for a time defined by the smallest TTL
50 * among the answer records in order to reduce DNS traffic. It is not supposed
51 * to be a full DNS cache, since we plan to implement that in the future in a
52 * dedicated process running on the system.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080053 *
54 * Note that its design is kept simple very intentionally, i.e.:
55 *
56 * - it takes raw DNS query packet data as input, and returns raw DNS
57 * answer packet data as output
58 *
59 * (this means that two similar queries that encode the DNS name
60 * differently will be treated distinctly).
61 *
Mattias Falk3e0c5102011-01-31 12:42:26 +010062 * the smallest TTL value among the answer records are used as the time
63 * to keep an answer in the cache.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080064 *
65 * this is bad, but we absolutely want to avoid parsing the answer packets
66 * (and should be solved by the later full DNS cache process).
67 *
68 * - the implementation is just a (query-data) => (answer-data) hash table
69 * with a trivial least-recently-used expiration policy.
70 *
71 * Doing this keeps the code simple and avoids to deal with a lot of things
72 * that a full DNS cache is expected to do.
73 *
74 * The API is also very simple:
75 *
76 * - the client calls _resolv_cache_get() to obtain a handle to the cache.
77 * this will initialize the cache on first usage. the result can be NULL
78 * if the cache is disabled.
79 *
80 * - the client calls _resolv_cache_lookup() before performing a query
81 *
82 * if the function returns RESOLV_CACHE_FOUND, a copy of the answer data
83 * has been copied into the client-provided answer buffer.
84 *
85 * if the function returns RESOLV_CACHE_NOTFOUND, the client should perform
86 * a request normally, *then* call _resolv_cache_add() to add the received
87 * answer to the cache.
88 *
89 * if the function returns RESOLV_CACHE_UNSUPPORTED, the client should
90 * perform a request normally, and *not* call _resolv_cache_add()
91 *
92 * note that RESOLV_CACHE_UNSUPPORTED is also returned if the answer buffer
93 * is too short to accomodate the cached result.
94 *
95 * - when network settings change, the cache must be flushed since the list
96 * of DNS servers probably changed. this is done by calling
97 * _resolv_cache_reset()
98 *
99 * the parameter to this function must be an ever-increasing generation
100 * number corresponding to the current network settings state.
101 *
102 * This is done because several threads could detect the same network
103 * settings change (but at different times) and will all end up calling the
104 * same function. Comparing with the last used generation number ensures
105 * that the cache is only flushed once per network change.
106 */
107
108/* the name of an environment variable that will be checked the first time
109 * this code is called if its value is "0", then the resolver cache is
110 * disabled.
111 */
112#define CONFIG_ENV "BIONIC_DNSCACHE"
113
114/* entries older than CONFIG_SECONDS seconds are always discarded.
115 */
116#define CONFIG_SECONDS (60*10) /* 10 minutes */
117
Mattias Falk3a4910c2011-02-14 12:41:11 +0100118/* default number of entries kept in the cache. This value has been
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800119 * determined by browsing through various sites and counting the number
120 * of corresponding requests. Keep in mind that our framework is currently
121 * performing two requests per name lookup (one for IPv4, the other for IPv6)
122 *
123 * www.google.com 4
124 * www.ysearch.com 6
125 * www.amazon.com 8
126 * www.nytimes.com 22
127 * www.espn.com 28
128 * www.msn.com 28
129 * www.lemonde.fr 35
130 *
131 * (determined in 2009-2-17 from Paris, France, results may vary depending
132 * on location)
133 *
134 * most high-level websites use lots of media/ad servers with different names
135 * but these are generally reused when browsing through the site.
136 *
Mattias Falk3a4910c2011-02-14 12:41:11 +0100137 * As such, a value of 64 should be relatively comfortable at the moment.
138 *
139 * The system property ro.net.dns_cache_size can be used to override the default
140 * value with a custom value
Robert Greenwalt52764f52012-01-25 15:16:03 -0800141 *
142 *
143 * ******************************************
144 * * NOTE - this has changed.
145 * * 1) we've added IPv6 support so each dns query results in 2 responses
146 * * 2) we've made this a system-wide cache, so the cost is less (it's not
147 * * duplicated in each process) and the need is greater (more processes
148 * * making different requests).
149 * * Upping by 2x for IPv6
150 * * Upping by another 5x for the centralized nature
151 * *****************************************
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800152 */
Robert Greenwalt52764f52012-01-25 15:16:03 -0800153#define CONFIG_MAX_ENTRIES 64 * 2 * 5
Mattias Falk3a4910c2011-02-14 12:41:11 +0100154/* name of the system property that can be used to set the cache size */
155#define DNS_CACHE_SIZE_PROP_NAME "ro.net.dns_cache_size"
156
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800157/****************************************************************************/
158/****************************************************************************/
159/***** *****/
160/***** *****/
161/***** *****/
162/****************************************************************************/
163/****************************************************************************/
164
165/* set to 1 to debug cache operations */
166#define DEBUG 0
167
168/* set to 1 to debug query data */
169#define DEBUG_DATA 0
170
Mattias Falk3e0c5102011-01-31 12:42:26 +0100171#undef XLOG
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800172#if DEBUG
Elliott Hughes8f2a5a02013-03-15 15:30:25 -0700173# include "libc_logging.h"
174# define XLOG(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800175
176#include <stdio.h>
177#include <stdarg.h>
178
179/** BOUNDED BUFFER FORMATTING
180 **/
181
182/* technical note:
183 *
184 * the following debugging routines are used to append data to a bounded
185 * buffer they take two parameters that are:
186 *
187 * - p : a pointer to the current cursor position in the buffer
188 * this value is initially set to the buffer's address.
189 *
190 * - end : the address of the buffer's limit, i.e. of the first byte
191 * after the buffer. this address should never be touched.
192 *
193 * IMPORTANT: it is assumed that end > buffer_address, i.e.
194 * that the buffer is at least one byte.
195 *
196 * the _bprint_() functions return the new value of 'p' after the data
197 * has been appended, and also ensure the following:
198 *
199 * - the returned value will never be strictly greater than 'end'
200 *
201 * - a return value equal to 'end' means that truncation occured
202 * (in which case, end[-1] will be set to 0)
203 *
204 * - after returning from a _bprint_() function, the content of the buffer
205 * is always 0-terminated, even in the event of truncation.
206 *
207 * these conventions allow you to call _bprint_ functions multiple times and
208 * only check for truncation at the end of the sequence, as in:
209 *
210 * char buff[1000], *p = buff, *end = p + sizeof(buff);
211 *
212 * p = _bprint_c(p, end, '"');
213 * p = _bprint_s(p, end, my_string);
214 * p = _bprint_c(p, end, '"');
215 *
216 * if (p >= end) {
217 * // buffer was too small
218 * }
219 *
220 * printf( "%s", buff );
221 */
222
223/* add a char to a bounded buffer */
224static char*
225_bprint_c( char* p, char* end, int c )
226{
227 if (p < end) {
228 if (p+1 == end)
229 *p++ = 0;
230 else {
231 *p++ = (char) c;
232 *p = 0;
233 }
234 }
235 return p;
236}
237
238/* add a sequence of bytes to a bounded buffer */
239static char*
240_bprint_b( char* p, char* end, const char* buf, int len )
241{
242 int avail = end - p;
243
244 if (avail <= 0 || len <= 0)
245 return p;
246
247 if (avail > len)
248 avail = len;
249
250 memcpy( p, buf, avail );
251 p += avail;
252
253 if (p < end)
254 p[0] = 0;
255 else
256 end[-1] = 0;
257
258 return p;
259}
260
261/* add a string to a bounded buffer */
262static char*
263_bprint_s( char* p, char* end, const char* str )
264{
265 return _bprint_b(p, end, str, strlen(str));
266}
267
268/* add a formatted string to a bounded buffer */
269static char*
270_bprint( char* p, char* end, const char* format, ... )
271{
272 int avail, n;
273 va_list args;
274
275 avail = end - p;
276
277 if (avail <= 0)
278 return p;
279
280 va_start(args, format);
David 'Digit' Turnerd378c682010-03-08 15:13:04 -0800281 n = vsnprintf( p, avail, format, args);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800282 va_end(args);
283
284 /* certain C libraries return -1 in case of truncation */
285 if (n < 0 || n > avail)
286 n = avail;
287
288 p += n;
289 /* certain C libraries do not zero-terminate in case of truncation */
290 if (p == end)
291 p[-1] = 0;
292
293 return p;
294}
295
296/* add a hex value to a bounded buffer, up to 8 digits */
297static char*
298_bprint_hex( char* p, char* end, unsigned value, int numDigits )
299{
300 char text[sizeof(unsigned)*2];
301 int nn = 0;
302
303 while (numDigits-- > 0) {
304 text[nn++] = "0123456789abcdef"[(value >> (numDigits*4)) & 15];
305 }
306 return _bprint_b(p, end, text, nn);
307}
308
309/* add the hexadecimal dump of some memory area to a bounded buffer */
310static char*
311_bprint_hexdump( char* p, char* end, const uint8_t* data, int datalen )
312{
313 int lineSize = 16;
314
315 while (datalen > 0) {
316 int avail = datalen;
317 int nn;
318
319 if (avail > lineSize)
320 avail = lineSize;
321
322 for (nn = 0; nn < avail; nn++) {
323 if (nn > 0)
324 p = _bprint_c(p, end, ' ');
325 p = _bprint_hex(p, end, data[nn], 2);
326 }
327 for ( ; nn < lineSize; nn++ ) {
328 p = _bprint_s(p, end, " ");
329 }
330 p = _bprint_s(p, end, " ");
331
332 for (nn = 0; nn < avail; nn++) {
333 int c = data[nn];
334
335 if (c < 32 || c > 127)
336 c = '.';
337
338 p = _bprint_c(p, end, c);
339 }
340 p = _bprint_c(p, end, '\n');
341
342 data += avail;
343 datalen -= avail;
344 }
345 return p;
346}
347
348/* dump the content of a query of packet to the log */
349static void
350XLOG_BYTES( const void* base, int len )
351{
352 char buff[1024];
353 char* p = buff, *end = p + sizeof(buff);
354
355 p = _bprint_hexdump(p, end, base, len);
356 XLOG("%s",buff);
357}
358
359#else /* !DEBUG */
360# define XLOG(...) ((void)0)
361# define XLOG_BYTES(a,b) ((void)0)
362#endif
363
364static time_t
365_time_now( void )
366{
367 struct timeval tv;
368
369 gettimeofday( &tv, NULL );
370 return tv.tv_sec;
371}
372
373/* reminder: the general format of a DNS packet is the following:
374 *
375 * HEADER (12 bytes)
376 * QUESTION (variable)
377 * ANSWER (variable)
378 * AUTHORITY (variable)
379 * ADDITIONNAL (variable)
380 *
381 * the HEADER is made of:
382 *
383 * ID : 16 : 16-bit unique query identification field
384 *
385 * QR : 1 : set to 0 for queries, and 1 for responses
386 * Opcode : 4 : set to 0 for queries
387 * AA : 1 : set to 0 for queries
388 * TC : 1 : truncation flag, will be set to 0 in queries
389 * RD : 1 : recursion desired
390 *
391 * RA : 1 : recursion available (0 in queries)
392 * Z : 3 : three reserved zero bits
393 * RCODE : 4 : response code (always 0=NOERROR in queries)
394 *
395 * QDCount: 16 : question count
396 * ANCount: 16 : Answer count (0 in queries)
397 * NSCount: 16: Authority Record count (0 in queries)
398 * ARCount: 16: Additionnal Record count (0 in queries)
399 *
400 * the QUESTION is made of QDCount Question Record (QRs)
401 * the ANSWER is made of ANCount RRs
402 * the AUTHORITY is made of NSCount RRs
403 * the ADDITIONNAL is made of ARCount RRs
404 *
405 * Each Question Record (QR) is made of:
406 *
407 * QNAME : variable : Query DNS NAME
408 * TYPE : 16 : type of query (A=1, PTR=12, MX=15, AAAA=28, ALL=255)
409 * CLASS : 16 : class of query (IN=1)
410 *
411 * Each Resource Record (RR) is made of:
412 *
413 * NAME : variable : DNS NAME
414 * TYPE : 16 : type of query (A=1, PTR=12, MX=15, AAAA=28, ALL=255)
415 * CLASS : 16 : class of query (IN=1)
416 * TTL : 32 : seconds to cache this RR (0=none)
417 * RDLENGTH: 16 : size of RDDATA in bytes
418 * RDDATA : variable : RR data (depends on TYPE)
419 *
420 * Each QNAME contains a domain name encoded as a sequence of 'labels'
421 * terminated by a zero. Each label has the following format:
422 *
423 * LEN : 8 : lenght of label (MUST be < 64)
424 * NAME : 8*LEN : label length (must exclude dots)
425 *
426 * A value of 0 in the encoding is interpreted as the 'root' domain and
427 * terminates the encoding. So 'www.android.com' will be encoded as:
428 *
429 * <3>www<7>android<3>com<0>
430 *
431 * Where <n> represents the byte with value 'n'
432 *
433 * Each NAME reflects the QNAME of the question, but has a slightly more
434 * complex encoding in order to provide message compression. This is achieved
435 * by using a 2-byte pointer, with format:
436 *
437 * TYPE : 2 : 0b11 to indicate a pointer, 0b01 and 0b10 are reserved
438 * OFFSET : 14 : offset to another part of the DNS packet
439 *
440 * The offset is relative to the start of the DNS packet and must point
441 * A pointer terminates the encoding.
442 *
443 * The NAME can be encoded in one of the following formats:
444 *
445 * - a sequence of simple labels terminated by 0 (like QNAMEs)
446 * - a single pointer
447 * - a sequence of simple labels terminated by a pointer
448 *
449 * A pointer shall always point to either a pointer of a sequence of
450 * labels (which can themselves be terminated by either a 0 or a pointer)
451 *
452 * The expanded length of a given domain name should not exceed 255 bytes.
453 *
454 * NOTE: we don't parse the answer packets, so don't need to deal with NAME
455 * records, only QNAMEs.
456 */
457
458#define DNS_HEADER_SIZE 12
459
460#define DNS_TYPE_A "\00\01" /* big-endian decimal 1 */
461#define DNS_TYPE_PTR "\00\014" /* big-endian decimal 12 */
462#define DNS_TYPE_MX "\00\017" /* big-endian decimal 15 */
463#define DNS_TYPE_AAAA "\00\034" /* big-endian decimal 28 */
464#define DNS_TYPE_ALL "\00\0377" /* big-endian decimal 255 */
465
466#define DNS_CLASS_IN "\00\01" /* big-endian decimal 1 */
467
468typedef struct {
469 const uint8_t* base;
470 const uint8_t* end;
471 const uint8_t* cursor;
472} DnsPacket;
473
474static void
475_dnsPacket_init( DnsPacket* packet, const uint8_t* buff, int bufflen )
476{
477 packet->base = buff;
478 packet->end = buff + bufflen;
479 packet->cursor = buff;
480}
481
482static void
483_dnsPacket_rewind( DnsPacket* packet )
484{
485 packet->cursor = packet->base;
486}
487
488static void
489_dnsPacket_skip( DnsPacket* packet, int count )
490{
491 const uint8_t* p = packet->cursor + count;
492
493 if (p > packet->end)
494 p = packet->end;
495
496 packet->cursor = p;
497}
498
499static int
500_dnsPacket_readInt16( DnsPacket* packet )
501{
502 const uint8_t* p = packet->cursor;
503
504 if (p+2 > packet->end)
505 return -1;
506
507 packet->cursor = p+2;
508 return (p[0]<< 8) | p[1];
509}
510
511/** QUERY CHECKING
512 **/
513
514/* check bytes in a dns packet. returns 1 on success, 0 on failure.
515 * the cursor is only advanced in the case of success
516 */
517static int
518_dnsPacket_checkBytes( DnsPacket* packet, int numBytes, const void* bytes )
519{
520 const uint8_t* p = packet->cursor;
521
522 if (p + numBytes > packet->end)
523 return 0;
524
525 if (memcmp(p, bytes, numBytes) != 0)
526 return 0;
527
528 packet->cursor = p + numBytes;
529 return 1;
530}
531
532/* parse and skip a given QNAME stored in a query packet,
533 * from the current cursor position. returns 1 on success,
534 * or 0 for malformed data.
535 */
536static int
537_dnsPacket_checkQName( DnsPacket* packet )
538{
539 const uint8_t* p = packet->cursor;
540 const uint8_t* end = packet->end;
541
542 for (;;) {
543 int c;
544
545 if (p >= end)
546 break;
547
548 c = *p++;
549
550 if (c == 0) {
551 packet->cursor = p;
552 return 1;
553 }
554
555 /* we don't expect label compression in QNAMEs */
556 if (c >= 64)
557 break;
558
559 p += c;
560 /* we rely on the bound check at the start
561 * of the loop here */
562 }
563 /* malformed data */
564 XLOG("malformed QNAME");
565 return 0;
566}
567
568/* parse and skip a given QR stored in a packet.
569 * returns 1 on success, and 0 on failure
570 */
571static int
572_dnsPacket_checkQR( DnsPacket* packet )
573{
574 int len;
575
576 if (!_dnsPacket_checkQName(packet))
577 return 0;
578
579 /* TYPE must be one of the things we support */
580 if (!_dnsPacket_checkBytes(packet, 2, DNS_TYPE_A) &&
581 !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_PTR) &&
582 !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_MX) &&
583 !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_AAAA) &&
584 !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_ALL))
585 {
586 XLOG("unsupported TYPE");
587 return 0;
588 }
589 /* CLASS must be IN */
590 if (!_dnsPacket_checkBytes(packet, 2, DNS_CLASS_IN)) {
591 XLOG("unsupported CLASS");
592 return 0;
593 }
594
595 return 1;
596}
597
598/* check the header of a DNS Query packet, return 1 if it is one
599 * type of query we can cache, or 0 otherwise
600 */
601static int
602_dnsPacket_checkQuery( DnsPacket* packet )
603{
604 const uint8_t* p = packet->base;
605 int qdCount, anCount, dnCount, arCount;
606
607 if (p + DNS_HEADER_SIZE > packet->end) {
608 XLOG("query packet too small");
609 return 0;
610 }
611
612 /* QR must be set to 0, opcode must be 0 and AA must be 0 */
613 /* RA, Z, and RCODE must be 0 */
614 if ((p[2] & 0xFC) != 0 || p[3] != 0) {
615 XLOG("query packet flags unsupported");
616 return 0;
617 }
618
619 /* Note that we ignore the TC and RD bits here for the
620 * following reasons:
621 *
622 * - there is no point for a query packet sent to a server
623 * to have the TC bit set, but the implementation might
624 * set the bit in the query buffer for its own needs
625 * between a _resolv_cache_lookup and a
626 * _resolv_cache_add. We should not freak out if this
627 * is the case.
628 *
629 * - we consider that the result from a RD=0 or a RD=1
630 * query might be different, hence that the RD bit
631 * should be used to differentiate cached result.
632 *
633 * this implies that RD is checked when hashing or
634 * comparing query packets, but not TC
635 */
636
637 /* ANCOUNT, DNCOUNT and ARCOUNT must be 0 */
638 qdCount = (p[4] << 8) | p[5];
639 anCount = (p[6] << 8) | p[7];
640 dnCount = (p[8] << 8) | p[9];
641 arCount = (p[10]<< 8) | p[11];
642
643 if (anCount != 0 || dnCount != 0 || arCount != 0) {
644 XLOG("query packet contains non-query records");
645 return 0;
646 }
647
648 if (qdCount == 0) {
649 XLOG("query packet doesn't contain query record");
650 return 0;
651 }
652
653 /* Check QDCOUNT QRs */
654 packet->cursor = p + DNS_HEADER_SIZE;
655
656 for (;qdCount > 0; qdCount--)
657 if (!_dnsPacket_checkQR(packet))
658 return 0;
659
660 return 1;
661}
662
663/** QUERY DEBUGGING
664 **/
665#if DEBUG
666static char*
667_dnsPacket_bprintQName(DnsPacket* packet, char* bp, char* bend)
668{
669 const uint8_t* p = packet->cursor;
670 const uint8_t* end = packet->end;
671 int first = 1;
672
673 for (;;) {
674 int c;
675
676 if (p >= end)
677 break;
678
679 c = *p++;
680
681 if (c == 0) {
682 packet->cursor = p;
683 return bp;
684 }
685
686 /* we don't expect label compression in QNAMEs */
687 if (c >= 64)
688 break;
689
690 if (first)
691 first = 0;
692 else
693 bp = _bprint_c(bp, bend, '.');
694
695 bp = _bprint_b(bp, bend, (const char*)p, c);
696
697 p += c;
698 /* we rely on the bound check at the start
699 * of the loop here */
700 }
701 /* malformed data */
702 bp = _bprint_s(bp, bend, "<MALFORMED>");
703 return bp;
704}
705
706static char*
707_dnsPacket_bprintQR(DnsPacket* packet, char* p, char* end)
708{
709#define QQ(x) { DNS_TYPE_##x, #x }
Elliott Hughes8f2a5a02013-03-15 15:30:25 -0700710 static const struct {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800711 const char* typeBytes;
Elliott Hughes8f2a5a02013-03-15 15:30:25 -0700712 const char* typeString;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800713 } qTypes[] =
714 {
715 QQ(A), QQ(PTR), QQ(MX), QQ(AAAA), QQ(ALL),
716 { NULL, NULL }
717 };
718 int nn;
719 const char* typeString = NULL;
720
721 /* dump QNAME */
722 p = _dnsPacket_bprintQName(packet, p, end);
723
724 /* dump TYPE */
725 p = _bprint_s(p, end, " (");
726
727 for (nn = 0; qTypes[nn].typeBytes != NULL; nn++) {
728 if (_dnsPacket_checkBytes(packet, 2, qTypes[nn].typeBytes)) {
729 typeString = qTypes[nn].typeString;
730 break;
731 }
732 }
733
734 if (typeString != NULL)
735 p = _bprint_s(p, end, typeString);
736 else {
737 int typeCode = _dnsPacket_readInt16(packet);
738 p = _bprint(p, end, "UNKNOWN-%d", typeCode);
739 }
740
741 p = _bprint_c(p, end, ')');
742
743 /* skip CLASS */
744 _dnsPacket_skip(packet, 2);
745 return p;
746}
747
748/* this function assumes the packet has already been checked */
749static char*
750_dnsPacket_bprintQuery( DnsPacket* packet, char* p, char* end )
751{
752 int qdCount;
753
754 if (packet->base[2] & 0x1) {
755 p = _bprint_s(p, end, "RECURSIVE ");
756 }
757
758 _dnsPacket_skip(packet, 4);
759 qdCount = _dnsPacket_readInt16(packet);
760 _dnsPacket_skip(packet, 6);
761
762 for ( ; qdCount > 0; qdCount-- ) {
763 p = _dnsPacket_bprintQR(packet, p, end);
764 }
765 return p;
766}
767#endif
768
769
770/** QUERY HASHING SUPPORT
771 **
772 ** THE FOLLOWING CODE ASSUMES THAT THE INPUT PACKET HAS ALREADY
773 ** BEEN SUCCESFULLY CHECKED.
774 **/
775
776/* use 32-bit FNV hash function */
777#define FNV_MULT 16777619U
778#define FNV_BASIS 2166136261U
779
780static unsigned
781_dnsPacket_hashBytes( DnsPacket* packet, int numBytes, unsigned hash )
782{
783 const uint8_t* p = packet->cursor;
784 const uint8_t* end = packet->end;
785
786 while (numBytes > 0 && p < end) {
787 hash = hash*FNV_MULT ^ *p++;
788 }
789 packet->cursor = p;
790 return hash;
791}
792
793
794static unsigned
795_dnsPacket_hashQName( DnsPacket* packet, unsigned hash )
796{
797 const uint8_t* p = packet->cursor;
798 const uint8_t* end = packet->end;
799
800 for (;;) {
801 int c;
802
803 if (p >= end) { /* should not happen */
804 XLOG("%s: INTERNAL_ERROR: read-overflow !!\n", __FUNCTION__);
805 break;
806 }
807
808 c = *p++;
809
810 if (c == 0)
811 break;
812
813 if (c >= 64) {
814 XLOG("%s: INTERNAL_ERROR: malformed domain !!\n", __FUNCTION__);
815 break;
816 }
817 if (p + c >= end) {
818 XLOG("%s: INTERNAL_ERROR: simple label read-overflow !!\n",
819 __FUNCTION__);
820 break;
821 }
822 while (c > 0) {
823 hash = hash*FNV_MULT ^ *p++;
824 c -= 1;
825 }
826 }
827 packet->cursor = p;
828 return hash;
829}
830
831static unsigned
832_dnsPacket_hashQR( DnsPacket* packet, unsigned hash )
833{
834 int len;
835
836 hash = _dnsPacket_hashQName(packet, hash);
837 hash = _dnsPacket_hashBytes(packet, 4, hash); /* TYPE and CLASS */
838 return hash;
839}
840
841static unsigned
842_dnsPacket_hashQuery( DnsPacket* packet )
843{
844 unsigned hash = FNV_BASIS;
845 int count;
846 _dnsPacket_rewind(packet);
847
848 /* we ignore the TC bit for reasons explained in
849 * _dnsPacket_checkQuery().
850 *
851 * however we hash the RD bit to differentiate
852 * between answers for recursive and non-recursive
853 * queries.
854 */
855 hash = hash*FNV_MULT ^ (packet->base[2] & 1);
856
857 /* assume: other flags are 0 */
858 _dnsPacket_skip(packet, 4);
859
860 /* read QDCOUNT */
861 count = _dnsPacket_readInt16(packet);
862
863 /* assume: ANcount, NScount, ARcount are 0 */
864 _dnsPacket_skip(packet, 6);
865
866 /* hash QDCOUNT QRs */
867 for ( ; count > 0; count-- )
868 hash = _dnsPacket_hashQR(packet, hash);
869
870 return hash;
871}
872
873
874/** QUERY COMPARISON
875 **
876 ** THE FOLLOWING CODE ASSUMES THAT THE INPUT PACKETS HAVE ALREADY
877 ** BEEN SUCCESFULLY CHECKED.
878 **/
879
880static int
881_dnsPacket_isEqualDomainName( DnsPacket* pack1, DnsPacket* pack2 )
882{
883 const uint8_t* p1 = pack1->cursor;
884 const uint8_t* end1 = pack1->end;
885 const uint8_t* p2 = pack2->cursor;
886 const uint8_t* end2 = pack2->end;
887
888 for (;;) {
889 int c1, c2;
890
891 if (p1 >= end1 || p2 >= end2) {
892 XLOG("%s: INTERNAL_ERROR: read-overflow !!\n", __FUNCTION__);
893 break;
894 }
895 c1 = *p1++;
896 c2 = *p2++;
897 if (c1 != c2)
898 break;
899
900 if (c1 == 0) {
901 pack1->cursor = p1;
902 pack2->cursor = p2;
903 return 1;
904 }
905 if (c1 >= 64) {
906 XLOG("%s: INTERNAL_ERROR: malformed domain !!\n", __FUNCTION__);
907 break;
908 }
909 if ((p1+c1 > end1) || (p2+c1 > end2)) {
910 XLOG("%s: INTERNAL_ERROR: simple label read-overflow !!\n",
911 __FUNCTION__);
912 break;
913 }
914 if (memcmp(p1, p2, c1) != 0)
915 break;
916 p1 += c1;
917 p2 += c1;
918 /* we rely on the bound checks at the start of the loop */
919 }
920 /* not the same, or one is malformed */
921 XLOG("different DN");
922 return 0;
923}
924
925static int
926_dnsPacket_isEqualBytes( DnsPacket* pack1, DnsPacket* pack2, int numBytes )
927{
928 const uint8_t* p1 = pack1->cursor;
929 const uint8_t* p2 = pack2->cursor;
930
931 if ( p1 + numBytes > pack1->end || p2 + numBytes > pack2->end )
932 return 0;
933
934 if ( memcmp(p1, p2, numBytes) != 0 )
935 return 0;
936
937 pack1->cursor += numBytes;
938 pack2->cursor += numBytes;
939 return 1;
940}
941
942static int
943_dnsPacket_isEqualQR( DnsPacket* pack1, DnsPacket* pack2 )
944{
945 /* compare domain name encoding + TYPE + CLASS */
946 if ( !_dnsPacket_isEqualDomainName(pack1, pack2) ||
947 !_dnsPacket_isEqualBytes(pack1, pack2, 2+2) )
948 return 0;
949
950 return 1;
951}
952
953static int
954_dnsPacket_isEqualQuery( DnsPacket* pack1, DnsPacket* pack2 )
955{
956 int count1, count2;
957
958 /* compare the headers, ignore most fields */
959 _dnsPacket_rewind(pack1);
960 _dnsPacket_rewind(pack2);
961
962 /* compare RD, ignore TC, see comment in _dnsPacket_checkQuery */
963 if ((pack1->base[2] & 1) != (pack2->base[2] & 1)) {
964 XLOG("different RD");
965 return 0;
966 }
967
968 /* assume: other flags are all 0 */
969 _dnsPacket_skip(pack1, 4);
970 _dnsPacket_skip(pack2, 4);
971
972 /* compare QDCOUNT */
973 count1 = _dnsPacket_readInt16(pack1);
974 count2 = _dnsPacket_readInt16(pack2);
975 if (count1 != count2 || count1 < 0) {
976 XLOG("different QDCOUNT");
977 return 0;
978 }
979
980 /* assume: ANcount, NScount and ARcount are all 0 */
981 _dnsPacket_skip(pack1, 6);
982 _dnsPacket_skip(pack2, 6);
983
984 /* compare the QDCOUNT QRs */
985 for ( ; count1 > 0; count1-- ) {
986 if (!_dnsPacket_isEqualQR(pack1, pack2)) {
987 XLOG("different QR");
988 return 0;
989 }
990 }
991 return 1;
992}
993
994/****************************************************************************/
995/****************************************************************************/
996/***** *****/
997/***** *****/
998/***** *****/
999/****************************************************************************/
1000/****************************************************************************/
1001
1002/* cache entry. for simplicity, 'hash' and 'hlink' are inlined in this
1003 * structure though they are conceptually part of the hash table.
1004 *
1005 * similarly, mru_next and mru_prev are part of the global MRU list
1006 */
1007typedef struct Entry {
1008 unsigned int hash; /* hash value */
1009 struct Entry* hlink; /* next in collision chain */
1010 struct Entry* mru_prev;
1011 struct Entry* mru_next;
1012
1013 const uint8_t* query;
1014 int querylen;
1015 const uint8_t* answer;
1016 int answerlen;
Mattias Falk3e0c5102011-01-31 12:42:26 +01001017 time_t expires; /* time_t when the entry isn't valid any more */
1018 int id; /* for debugging purpose */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001019} Entry;
1020
Mattias Falk3e0c5102011-01-31 12:42:26 +01001021/**
1022 * Parse the answer records and find the smallest
1023 * TTL among the answer records.
1024 *
1025 * The returned TTL is the number of seconds to
1026 * keep the answer in the cache.
1027 *
1028 * In case of parse error zero (0) is returned which
1029 * indicates that the answer shall not be cached.
1030 */
1031static u_long
1032answer_getTTL(const void* answer, int answerlen)
1033{
1034 ns_msg handle;
1035 int ancount, n;
1036 u_long result, ttl;
1037 ns_rr rr;
1038
1039 result = 0;
1040 if (ns_initparse(answer, answerlen, &handle) >= 0) {
1041 // get number of answer records
1042 ancount = ns_msg_count(handle, ns_s_an);
1043 for (n = 0; n < ancount; n++) {
1044 if (ns_parserr(&handle, ns_s_an, n, &rr) == 0) {
1045 ttl = ns_rr_ttl(rr);
1046 if (n == 0 || ttl < result) {
1047 result = ttl;
1048 }
1049 } else {
1050 XLOG("ns_parserr failed ancount no = %d. errno = %s\n", n, strerror(errno));
1051 }
1052 }
1053 } else {
1054 XLOG("ns_parserr failed. %s\n", strerror(errno));
1055 }
1056
1057 XLOG("TTL = %d\n", result);
1058
1059 return result;
1060}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001061
1062static void
1063entry_free( Entry* e )
1064{
1065 /* everything is allocated in a single memory block */
1066 if (e) {
1067 free(e);
1068 }
1069}
1070
1071static __inline__ void
1072entry_mru_remove( Entry* e )
1073{
1074 e->mru_prev->mru_next = e->mru_next;
1075 e->mru_next->mru_prev = e->mru_prev;
1076}
1077
1078static __inline__ void
1079entry_mru_add( Entry* e, Entry* list )
1080{
1081 Entry* first = list->mru_next;
1082
1083 e->mru_next = first;
1084 e->mru_prev = list;
1085
1086 list->mru_next = e;
1087 first->mru_prev = e;
1088}
1089
1090/* compute the hash of a given entry, this is a hash of most
1091 * data in the query (key) */
1092static unsigned
1093entry_hash( const Entry* e )
1094{
1095 DnsPacket pack[1];
1096
1097 _dnsPacket_init(pack, e->query, e->querylen);
1098 return _dnsPacket_hashQuery(pack);
1099}
1100
1101/* initialize an Entry as a search key, this also checks the input query packet
1102 * returns 1 on success, or 0 in case of unsupported/malformed data */
1103static int
1104entry_init_key( Entry* e, const void* query, int querylen )
1105{
1106 DnsPacket pack[1];
1107
1108 memset(e, 0, sizeof(*e));
1109
1110 e->query = query;
1111 e->querylen = querylen;
1112 e->hash = entry_hash(e);
1113
1114 _dnsPacket_init(pack, query, querylen);
1115
1116 return _dnsPacket_checkQuery(pack);
1117}
1118
1119/* allocate a new entry as a cache node */
1120static Entry*
1121entry_alloc( const Entry* init, const void* answer, int answerlen )
1122{
1123 Entry* e;
1124 int size;
1125
1126 size = sizeof(*e) + init->querylen + answerlen;
1127 e = calloc(size, 1);
1128 if (e == NULL)
1129 return e;
1130
1131 e->hash = init->hash;
1132 e->query = (const uint8_t*)(e+1);
1133 e->querylen = init->querylen;
1134
1135 memcpy( (char*)e->query, init->query, e->querylen );
1136
1137 e->answer = e->query + e->querylen;
1138 e->answerlen = answerlen;
1139
1140 memcpy( (char*)e->answer, answer, e->answerlen );
1141
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001142 return e;
1143}
1144
1145static int
1146entry_equals( const Entry* e1, const Entry* e2 )
1147{
1148 DnsPacket pack1[1], pack2[1];
1149
1150 if (e1->querylen != e2->querylen) {
1151 return 0;
1152 }
1153 _dnsPacket_init(pack1, e1->query, e1->querylen);
1154 _dnsPacket_init(pack2, e2->query, e2->querylen);
1155
1156 return _dnsPacket_isEqualQuery(pack1, pack2);
1157}
1158
1159/****************************************************************************/
1160/****************************************************************************/
1161/***** *****/
1162/***** *****/
1163/***** *****/
1164/****************************************************************************/
1165/****************************************************************************/
1166
1167/* We use a simple hash table with external collision lists
1168 * for simplicity, the hash-table fields 'hash' and 'hlink' are
1169 * inlined in the Entry structure.
1170 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001171
Mattias Falka59cfcf2011-09-06 15:15:06 +02001172/* Maximum time for a thread to wait for an pending request */
1173#define PENDING_REQUEST_TIMEOUT 20;
1174
1175typedef struct pending_req_info {
1176 unsigned int hash;
1177 pthread_cond_t cond;
1178 struct pending_req_info* next;
1179} PendingReqInfo;
1180
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001181typedef struct resolv_cache {
Mattias Falk3a4910c2011-02-14 12:41:11 +01001182 int max_entries;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001183 int num_entries;
1184 Entry mru_list;
1185 pthread_mutex_t lock;
1186 unsigned generation;
1187 int last_id;
Mattias Falk3a4910c2011-02-14 12:41:11 +01001188 Entry* entries;
Mattias Falka59cfcf2011-09-06 15:15:06 +02001189 PendingReqInfo pending_requests;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001190} Cache;
1191
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001192typedef struct resolv_cache_info {
1193 char ifname[IF_NAMESIZE + 1];
1194 struct in_addr ifaddr;
1195 Cache* cache;
1196 struct resolv_cache_info* next;
1197 char* nameservers[MAXNS +1];
1198 struct addrinfo* nsaddrinfo[MAXNS + 1];
1199} CacheInfo;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001200
1201#define HTABLE_VALID(x) ((x) != NULL && (x) != HTABLE_DELETED)
1202
1203static void
Mattias Falka59cfcf2011-09-06 15:15:06 +02001204_cache_flush_pending_requests_locked( struct resolv_cache* cache )
1205{
1206 struct pending_req_info *ri, *tmp;
1207 if (cache) {
1208 ri = cache->pending_requests.next;
1209
1210 while (ri) {
1211 tmp = ri;
1212 ri = ri->next;
1213 pthread_cond_broadcast(&tmp->cond);
1214
1215 pthread_cond_destroy(&tmp->cond);
1216 free(tmp);
1217 }
1218
1219 cache->pending_requests.next = NULL;
1220 }
1221}
1222
1223/* return 0 if no pending request is found matching the key
1224 * if a matching request is found the calling thread will wait
1225 * and return 1 when released */
1226static int
1227_cache_check_pending_request_locked( struct resolv_cache* cache, Entry* key )
1228{
1229 struct pending_req_info *ri, *prev;
1230 int exist = 0;
1231
1232 if (cache && key) {
1233 ri = cache->pending_requests.next;
1234 prev = &cache->pending_requests;
1235 while (ri) {
1236 if (ri->hash == key->hash) {
1237 exist = 1;
1238 break;
1239 }
1240 prev = ri;
1241 ri = ri->next;
1242 }
1243
1244 if (!exist) {
1245 ri = calloc(1, sizeof(struct pending_req_info));
1246 if (ri) {
1247 ri->hash = key->hash;
1248 pthread_cond_init(&ri->cond, NULL);
1249 prev->next = ri;
1250 }
1251 } else {
1252 struct timespec ts = {0,0};
1253 ts.tv_sec = _time_now() + PENDING_REQUEST_TIMEOUT;
1254 int rv = pthread_cond_timedwait(&ri->cond, &cache->lock, &ts);
1255 }
1256 }
1257
1258 return exist;
1259}
1260
1261/* notify any waiting thread that waiting on a request
1262 * matching the key has been added to the cache */
1263static void
1264_cache_notify_waiting_tid_locked( struct resolv_cache* cache, Entry* key )
1265{
1266 struct pending_req_info *ri, *prev;
1267
1268 if (cache && key) {
1269 ri = cache->pending_requests.next;
1270 prev = &cache->pending_requests;
1271 while (ri) {
1272 if (ri->hash == key->hash) {
1273 pthread_cond_broadcast(&ri->cond);
1274 break;
1275 }
1276 prev = ri;
1277 ri = ri->next;
1278 }
1279
1280 // remove item from list and destroy
1281 if (ri) {
1282 prev->next = ri->next;
1283 pthread_cond_destroy(&ri->cond);
1284 free(ri);
1285 }
1286 }
1287}
1288
1289/* notify the cache that the query failed */
1290void
1291_resolv_cache_query_failed( struct resolv_cache* cache,
1292 const void* query,
1293 int querylen)
1294{
1295 Entry key[1];
1296
1297 if (cache && entry_init_key(key, query, querylen)) {
1298 pthread_mutex_lock(&cache->lock);
1299 _cache_notify_waiting_tid_locked(cache, key);
1300 pthread_mutex_unlock(&cache->lock);
1301 }
1302}
1303
1304static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001305_cache_flush_locked( Cache* cache )
1306{
1307 int nn;
1308 time_t now = _time_now();
1309
Mattias Falk3a4910c2011-02-14 12:41:11 +01001310 for (nn = 0; nn < cache->max_entries; nn++)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001311 {
Mattias Falk3a4910c2011-02-14 12:41:11 +01001312 Entry** pnode = (Entry**) &cache->entries[nn];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001313
1314 while (*pnode != NULL) {
1315 Entry* node = *pnode;
1316 *pnode = node->hlink;
1317 entry_free(node);
1318 }
1319 }
1320
Mattias Falka59cfcf2011-09-06 15:15:06 +02001321 // flush pending request
1322 _cache_flush_pending_requests_locked(cache);
1323
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001324 cache->mru_list.mru_next = cache->mru_list.mru_prev = &cache->mru_list;
1325 cache->num_entries = 0;
1326 cache->last_id = 0;
1327
1328 XLOG("*************************\n"
1329 "*** DNS CACHE FLUSHED ***\n"
1330 "*************************");
1331}
1332
Mattias Falk3a4910c2011-02-14 12:41:11 +01001333/* Return max number of entries allowed in the cache,
1334 * i.e. cache size. The cache size is either defined
1335 * by system property ro.net.dns_cache_size or by
1336 * CONFIG_MAX_ENTRIES if system property not set
1337 * or set to invalid value. */
1338static int
1339_res_cache_get_max_entries( void )
1340{
1341 int result = -1;
1342 char cache_size[PROP_VALUE_MAX];
1343
Robert Greenwalt52764f52012-01-25 15:16:03 -08001344 const char* cache_mode = getenv("ANDROID_DNS_MODE");
1345
1346 if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
1347 // Don't use the cache in local mode. This is used by the
1348 // proxy itself.
1349 // TODO - change this to 0 when all dns stuff uses proxy (5918973)
1350 XLOG("setup cache for non-cache process. size=1");
1351 return 1;
1352 }
1353
Mattias Falk3a4910c2011-02-14 12:41:11 +01001354 if (__system_property_get(DNS_CACHE_SIZE_PROP_NAME, cache_size) > 0) {
1355 result = atoi(cache_size);
1356 }
1357
1358 // ro.net.dns_cache_size not set or set to negative value
1359 if (result <= 0) {
1360 result = CONFIG_MAX_ENTRIES;
1361 }
1362
1363 XLOG("cache size: %d", result);
1364 return result;
1365}
1366
Jim Huang7cc56662010-10-15 02:02:57 +08001367static struct resolv_cache*
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001368_resolv_cache_create( void )
1369{
1370 struct resolv_cache* cache;
1371
1372 cache = calloc(sizeof(*cache), 1);
1373 if (cache) {
Mattias Falk3a4910c2011-02-14 12:41:11 +01001374 cache->max_entries = _res_cache_get_max_entries();
1375 cache->entries = calloc(sizeof(*cache->entries), cache->max_entries);
1376 if (cache->entries) {
1377 cache->generation = ~0U;
1378 pthread_mutex_init( &cache->lock, NULL );
1379 cache->mru_list.mru_prev = cache->mru_list.mru_next = &cache->mru_list;
1380 XLOG("%s: cache created\n", __FUNCTION__);
1381 } else {
1382 free(cache);
1383 cache = NULL;
1384 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001385 }
1386 return cache;
1387}
1388
1389
1390#if DEBUG
1391static void
1392_dump_query( const uint8_t* query, int querylen )
1393{
1394 char temp[256], *p=temp, *end=p+sizeof(temp);
1395 DnsPacket pack[1];
1396
1397 _dnsPacket_init(pack, query, querylen);
1398 p = _dnsPacket_bprintQuery(pack, p, end);
1399 XLOG("QUERY: %s", temp);
1400}
1401
1402static void
1403_cache_dump_mru( Cache* cache )
1404{
1405 char temp[512], *p=temp, *end=p+sizeof(temp);
1406 Entry* e;
1407
1408 p = _bprint(temp, end, "MRU LIST (%2d): ", cache->num_entries);
1409 for (e = cache->mru_list.mru_next; e != &cache->mru_list; e = e->mru_next)
1410 p = _bprint(p, end, " %d", e->id);
1411
1412 XLOG("%s", temp);
1413}
Mattias Falk3e0c5102011-01-31 12:42:26 +01001414
1415static void
1416_dump_answer(const void* answer, int answerlen)
1417{
1418 res_state statep;
1419 FILE* fp;
1420 char* buf;
1421 int fileLen;
1422
1423 fp = fopen("/data/reslog.txt", "w+");
1424 if (fp != NULL) {
1425 statep = __res_get_state();
1426
1427 res_pquery(statep, answer, answerlen, fp);
1428
1429 //Get file length
1430 fseek(fp, 0, SEEK_END);
1431 fileLen=ftell(fp);
1432 fseek(fp, 0, SEEK_SET);
1433 buf = (char *)malloc(fileLen+1);
1434 if (buf != NULL) {
1435 //Read file contents into buffer
1436 fread(buf, fileLen, 1, fp);
1437 XLOG("%s\n", buf);
1438 free(buf);
1439 }
1440 fclose(fp);
1441 remove("/data/reslog.txt");
1442 }
1443 else {
1444 XLOG("_dump_answer: can't open file\n");
1445 }
1446}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001447#endif
1448
1449#if DEBUG
1450# define XLOG_QUERY(q,len) _dump_query((q), (len))
Mattias Falk3e0c5102011-01-31 12:42:26 +01001451# define XLOG_ANSWER(a, len) _dump_answer((a), (len))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001452#else
1453# define XLOG_QUERY(q,len) ((void)0)
Mattias Falk3e0c5102011-01-31 12:42:26 +01001454# define XLOG_ANSWER(a,len) ((void)0)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001455#endif
1456
1457/* This function tries to find a key within the hash table
1458 * In case of success, it will return a *pointer* to the hashed key.
1459 * In case of failure, it will return a *pointer* to NULL
1460 *
1461 * So, the caller must check '*result' to check for success/failure.
1462 *
1463 * The main idea is that the result can later be used directly in
1464 * calls to _resolv_cache_add or _resolv_cache_remove as the 'lookup'
1465 * parameter. This makes the code simpler and avoids re-searching
1466 * for the key position in the htable.
1467 *
1468 * The result of a lookup_p is only valid until you alter the hash
1469 * table.
1470 */
1471static Entry**
1472_cache_lookup_p( Cache* cache,
1473 Entry* key )
1474{
Mattias Falk3a4910c2011-02-14 12:41:11 +01001475 int index = key->hash % cache->max_entries;
1476 Entry** pnode = (Entry**) &cache->entries[ index ];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001477
1478 while (*pnode != NULL) {
1479 Entry* node = *pnode;
1480
1481 if (node == NULL)
1482 break;
1483
1484 if (node->hash == key->hash && entry_equals(node, key))
1485 break;
1486
1487 pnode = &node->hlink;
1488 }
Elliott Hughes8f2a5a02013-03-15 15:30:25 -07001489 return pnode;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001490}
1491
1492/* Add a new entry to the hash table. 'lookup' must be the
1493 * result of an immediate previous failed _lookup_p() call
1494 * (i.e. with *lookup == NULL), and 'e' is the pointer to the
1495 * newly created entry
1496 */
1497static void
1498_cache_add_p( Cache* cache,
1499 Entry** lookup,
1500 Entry* e )
1501{
1502 *lookup = e;
1503 e->id = ++cache->last_id;
1504 entry_mru_add(e, &cache->mru_list);
1505 cache->num_entries += 1;
1506
1507 XLOG("%s: entry %d added (count=%d)", __FUNCTION__,
1508 e->id, cache->num_entries);
1509}
1510
1511/* Remove an existing entry from the hash table,
1512 * 'lookup' must be the result of an immediate previous
1513 * and succesful _lookup_p() call.
1514 */
1515static void
1516_cache_remove_p( Cache* cache,
1517 Entry** lookup )
1518{
1519 Entry* e = *lookup;
1520
1521 XLOG("%s: entry %d removed (count=%d)", __FUNCTION__,
1522 e->id, cache->num_entries-1);
1523
1524 entry_mru_remove(e);
1525 *lookup = e->hlink;
1526 entry_free(e);
1527 cache->num_entries -= 1;
1528}
1529
1530/* Remove the oldest entry from the hash table.
1531 */
1532static void
1533_cache_remove_oldest( Cache* cache )
1534{
1535 Entry* oldest = cache->mru_list.mru_prev;
1536 Entry** lookup = _cache_lookup_p(cache, oldest);
1537
1538 if (*lookup == NULL) { /* should not happen */
1539 XLOG("%s: OLDEST NOT IN HTABLE ?", __FUNCTION__);
1540 return;
1541 }
Robert Greenwalt7f84da62011-09-02 07:44:36 -07001542 if (DEBUG) {
1543 XLOG("Cache full - removing oldest");
1544 XLOG_QUERY(oldest->query, oldest->querylen);
1545 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001546 _cache_remove_p(cache, lookup);
1547}
1548
Anders Fredlunddd161822011-05-20 08:12:37 +02001549/* Remove all expired entries from the hash table.
1550 */
1551static void _cache_remove_expired(Cache* cache) {
1552 Entry* e;
1553 time_t now = _time_now();
1554
1555 for (e = cache->mru_list.mru_next; e != &cache->mru_list;) {
1556 // Entry is old, remove
1557 if (now >= e->expires) {
1558 Entry** lookup = _cache_lookup_p(cache, e);
1559 if (*lookup == NULL) { /* should not happen */
1560 XLOG("%s: ENTRY NOT IN HTABLE ?", __FUNCTION__);
1561 return;
1562 }
1563 e = e->mru_next;
1564 _cache_remove_p(cache, lookup);
1565 } else {
1566 e = e->mru_next;
1567 }
1568 }
1569}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001570
1571ResolvCacheStatus
1572_resolv_cache_lookup( struct resolv_cache* cache,
1573 const void* query,
1574 int querylen,
1575 void* answer,
1576 int answersize,
1577 int *answerlen )
1578{
1579 DnsPacket pack[1];
1580 Entry key[1];
1581 int index;
1582 Entry** lookup;
1583 Entry* e;
1584 time_t now;
1585
1586 ResolvCacheStatus result = RESOLV_CACHE_NOTFOUND;
1587
1588 XLOG("%s: lookup", __FUNCTION__);
1589 XLOG_QUERY(query, querylen);
1590
1591 /* we don't cache malformed queries */
1592 if (!entry_init_key(key, query, querylen)) {
1593 XLOG("%s: unsupported query", __FUNCTION__);
1594 return RESOLV_CACHE_UNSUPPORTED;
1595 }
1596 /* lookup cache */
1597 pthread_mutex_lock( &cache->lock );
1598
1599 /* see the description of _lookup_p to understand this.
1600 * the function always return a non-NULL pointer.
1601 */
1602 lookup = _cache_lookup_p(cache, key);
1603 e = *lookup;
1604
1605 if (e == NULL) {
1606 XLOG( "NOT IN CACHE");
Mattias Falka59cfcf2011-09-06 15:15:06 +02001607 // calling thread will wait if an outstanding request is found
1608 // that matching this query
1609 if (!_cache_check_pending_request_locked(cache, key)) {
1610 goto Exit;
1611 } else {
1612 lookup = _cache_lookup_p(cache, key);
1613 e = *lookup;
1614 if (e == NULL) {
1615 goto Exit;
1616 }
1617 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001618 }
1619
1620 now = _time_now();
1621
1622 /* remove stale entries here */
Mattias Falk3e0c5102011-01-31 12:42:26 +01001623 if (now >= e->expires) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001624 XLOG( " NOT IN CACHE (STALE ENTRY %p DISCARDED)", *lookup );
Robert Greenwalt7f84da62011-09-02 07:44:36 -07001625 XLOG_QUERY(e->query, e->querylen);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001626 _cache_remove_p(cache, lookup);
1627 goto Exit;
1628 }
1629
1630 *answerlen = e->answerlen;
1631 if (e->answerlen > answersize) {
1632 /* NOTE: we return UNSUPPORTED if the answer buffer is too short */
1633 result = RESOLV_CACHE_UNSUPPORTED;
1634 XLOG(" ANSWER TOO LONG");
1635 goto Exit;
1636 }
1637
1638 memcpy( answer, e->answer, e->answerlen );
1639
1640 /* bump up this entry to the top of the MRU list */
1641 if (e != cache->mru_list.mru_next) {
1642 entry_mru_remove( e );
1643 entry_mru_add( e, &cache->mru_list );
1644 }
1645
1646 XLOG( "FOUND IN CACHE entry=%p", e );
1647 result = RESOLV_CACHE_FOUND;
1648
1649Exit:
1650 pthread_mutex_unlock( &cache->lock );
1651 return result;
1652}
1653
1654
1655void
1656_resolv_cache_add( struct resolv_cache* cache,
1657 const void* query,
1658 int querylen,
1659 const void* answer,
1660 int answerlen )
1661{
1662 Entry key[1];
1663 Entry* e;
1664 Entry** lookup;
Mattias Falk3e0c5102011-01-31 12:42:26 +01001665 u_long ttl;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001666
1667 /* don't assume that the query has already been cached
1668 */
1669 if (!entry_init_key( key, query, querylen )) {
1670 XLOG( "%s: passed invalid query ?", __FUNCTION__);
1671 return;
1672 }
1673
1674 pthread_mutex_lock( &cache->lock );
1675
1676 XLOG( "%s: query:", __FUNCTION__ );
1677 XLOG_QUERY(query,querylen);
Mattias Falk3e0c5102011-01-31 12:42:26 +01001678 XLOG_ANSWER(answer, answerlen);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001679#if DEBUG_DATA
1680 XLOG( "answer:");
1681 XLOG_BYTES(answer,answerlen);
1682#endif
1683
1684 lookup = _cache_lookup_p(cache, key);
1685 e = *lookup;
1686
1687 if (e != NULL) { /* should not happen */
1688 XLOG("%s: ALREADY IN CACHE (%p) ? IGNORING ADD",
1689 __FUNCTION__, e);
1690 goto Exit;
1691 }
1692
Mattias Falk3a4910c2011-02-14 12:41:11 +01001693 if (cache->num_entries >= cache->max_entries) {
Anders Fredlunddd161822011-05-20 08:12:37 +02001694 _cache_remove_expired(cache);
1695 if (cache->num_entries >= cache->max_entries) {
1696 _cache_remove_oldest(cache);
1697 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001698 /* need to lookup again */
1699 lookup = _cache_lookup_p(cache, key);
1700 e = *lookup;
1701 if (e != NULL) {
1702 XLOG("%s: ALREADY IN CACHE (%p) ? IGNORING ADD",
1703 __FUNCTION__, e);
1704 goto Exit;
1705 }
1706 }
1707
Mattias Falk3e0c5102011-01-31 12:42:26 +01001708 ttl = answer_getTTL(answer, answerlen);
1709 if (ttl > 0) {
1710 e = entry_alloc(key, answer, answerlen);
1711 if (e != NULL) {
1712 e->expires = ttl + _time_now();
1713 _cache_add_p(cache, lookup, e);
1714 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001715 }
1716#if DEBUG
1717 _cache_dump_mru(cache);
1718#endif
1719Exit:
Mattias Falka59cfcf2011-09-06 15:15:06 +02001720 _cache_notify_waiting_tid_locked(cache, key);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001721 pthread_mutex_unlock( &cache->lock );
1722}
1723
1724/****************************************************************************/
1725/****************************************************************************/
1726/***** *****/
1727/***** *****/
1728/***** *****/
1729/****************************************************************************/
1730/****************************************************************************/
1731
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001732static pthread_once_t _res_cache_once;
1733
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001734// Head of the list of caches. Protected by _res_cache_list_lock.
1735static struct resolv_cache_info _res_cache_list;
1736
1737// name of the current default inteface
1738static char _res_default_ifname[IF_NAMESIZE + 1];
1739
1740// lock protecting everything in the _resolve_cache_info structs (next ptr, etc)
1741static pthread_mutex_t _res_cache_list_lock;
1742
1743
1744/* lookup the default interface name */
1745static char *_get_default_iface_locked();
1746/* insert resolv_cache_info into the list of resolv_cache_infos */
1747static void _insert_cache_info_locked(struct resolv_cache_info* cache_info);
1748/* creates a resolv_cache_info */
1749static struct resolv_cache_info* _create_cache_info( void );
1750/* gets cache associated with an interface name, or NULL if none exists */
1751static struct resolv_cache* _find_named_cache_locked(const char* ifname);
1752/* gets a resolv_cache_info associated with an interface name, or NULL if not found */
1753static struct resolv_cache_info* _find_cache_info_locked(const char* ifname);
1754/* free dns name server list of a resolv_cache_info structure */
1755static void _free_nameservers(struct resolv_cache_info* cache_info);
1756/* look up the named cache, and creates one if needed */
1757static struct resolv_cache* _get_res_cache_for_iface_locked(const char* ifname);
1758/* empty the named cache */
1759static void _flush_cache_for_iface_locked(const char* ifname);
1760/* empty the nameservers set for the named cache */
1761static void _free_nameservers_locked(struct resolv_cache_info* cache_info);
1762/* lookup the namserver for the name interface */
1763static int _get_nameserver_locked(const char* ifname, int n, char* addr, int addrLen);
1764/* lookup the addr of the nameserver for the named interface */
1765static struct addrinfo* _get_nameserver_addr_locked(const char* ifname, int n);
1766/* lookup the inteface's address */
1767static struct in_addr* _get_addr_locked(const char * ifname);
1768
1769
1770
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001771static void
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001772_res_cache_init(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001773{
1774 const char* env = getenv(CONFIG_ENV);
1775
1776 if (env && atoi(env) == 0) {
1777 /* the cache is disabled */
1778 return;
1779 }
1780
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001781 memset(&_res_default_ifname, 0, sizeof(_res_default_ifname));
1782 memset(&_res_cache_list, 0, sizeof(_res_cache_list));
1783 pthread_mutex_init(&_res_cache_list_lock, NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001784}
1785
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001786struct resolv_cache*
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001787__get_res_cache(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001788{
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001789 struct resolv_cache *cache;
1790
1791 pthread_once(&_res_cache_once, _res_cache_init);
1792
1793 pthread_mutex_lock(&_res_cache_list_lock);
1794
1795 char* ifname = _get_default_iface_locked();
1796
1797 // if default interface not set then use the first cache
1798 // associated with an interface as the default one.
1799 if (ifname[0] == '\0') {
1800 struct resolv_cache_info* cache_info = _res_cache_list.next;
1801 while (cache_info) {
1802 if (cache_info->ifname[0] != '\0') {
1803 ifname = cache_info->ifname;
Robert Greenwalt9363d912011-07-25 12:30:17 -07001804 break;
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001805 }
1806
1807 cache_info = cache_info->next;
1808 }
1809 }
1810 cache = _get_res_cache_for_iface_locked(ifname);
1811
1812 pthread_mutex_unlock(&_res_cache_list_lock);
1813 XLOG("_get_res_cache. default_ifname = %s\n", ifname);
1814 return cache;
1815}
1816
1817static struct resolv_cache*
1818_get_res_cache_for_iface_locked(const char* ifname)
1819{
1820 if (ifname == NULL)
1821 return NULL;
1822
1823 struct resolv_cache* cache = _find_named_cache_locked(ifname);
1824 if (!cache) {
1825 struct resolv_cache_info* cache_info = _create_cache_info();
1826 if (cache_info) {
1827 cache = _resolv_cache_create();
1828 if (cache) {
1829 int len = sizeof(cache_info->ifname);
1830 cache_info->cache = cache;
1831 strncpy(cache_info->ifname, ifname, len - 1);
1832 cache_info->ifname[len - 1] = '\0';
1833
1834 _insert_cache_info_locked(cache_info);
1835 } else {
1836 free(cache_info);
1837 }
1838 }
1839 }
1840 return cache;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001841}
1842
1843void
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001844_resolv_cache_reset(unsigned generation)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001845{
1846 XLOG("%s: generation=%d", __FUNCTION__, generation);
1847
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001848 pthread_once(&_res_cache_once, _res_cache_init);
1849 pthread_mutex_lock(&_res_cache_list_lock);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001850
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001851 char* ifname = _get_default_iface_locked();
1852 // if default interface not set then use the first cache
1853 // associated with an interface as the default one.
1854 // Note: Copied the code from __get_res_cache since this
1855 // method will be deleted/obsolete when cache per interface
1856 // implemented all over
1857 if (ifname[0] == '\0') {
1858 struct resolv_cache_info* cache_info = _res_cache_list.next;
1859 while (cache_info) {
1860 if (cache_info->ifname[0] != '\0') {
1861 ifname = cache_info->ifname;
Robert Greenwalt9363d912011-07-25 12:30:17 -07001862 break;
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001863 }
1864
1865 cache_info = cache_info->next;
1866 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001867 }
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001868 struct resolv_cache* cache = _get_res_cache_for_iface_locked(ifname);
1869
Robert Greenwalt9363d912011-07-25 12:30:17 -07001870 if (cache != NULL) {
1871 pthread_mutex_lock( &cache->lock );
1872 if (cache->generation != generation) {
1873 _cache_flush_locked(cache);
1874 cache->generation = generation;
1875 }
1876 pthread_mutex_unlock( &cache->lock );
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001877 }
1878
Mattias Falk23d3e6b2011-04-04 16:12:35 +02001879 pthread_mutex_unlock(&_res_cache_list_lock);
1880}
1881
1882void
1883_resolv_flush_cache_for_default_iface(void)
1884{
1885 char* ifname;
1886
1887 pthread_once(&_res_cache_once, _res_cache_init);
1888 pthread_mutex_lock(&_res_cache_list_lock);
1889
1890 ifname = _get_default_iface_locked();
1891 _flush_cache_for_iface_locked(ifname);
1892
1893 pthread_mutex_unlock(&_res_cache_list_lock);
1894}
1895
1896void
1897_resolv_flush_cache_for_iface(const char* ifname)
1898{
1899 pthread_once(&_res_cache_once, _res_cache_init);
1900 pthread_mutex_lock(&_res_cache_list_lock);
1901
1902 _flush_cache_for_iface_locked(ifname);
1903
1904 pthread_mutex_unlock(&_res_cache_list_lock);
1905}
1906
1907static void
1908_flush_cache_for_iface_locked(const char* ifname)
1909{
1910 struct resolv_cache* cache = _find_named_cache_locked(ifname);
1911 if (cache) {
1912 pthread_mutex_lock(&cache->lock);
1913 _cache_flush_locked(cache);
1914 pthread_mutex_unlock(&cache->lock);
1915 }
1916}
1917
1918static struct resolv_cache_info*
1919_create_cache_info(void)
1920{
1921 struct resolv_cache_info* cache_info;
1922
1923 cache_info = calloc(sizeof(*cache_info), 1);
1924 return cache_info;
1925}
1926
1927static void
1928_insert_cache_info_locked(struct resolv_cache_info* cache_info)
1929{
1930 struct resolv_cache_info* last;
1931
1932 for (last = &_res_cache_list; last->next; last = last->next);
1933
1934 last->next = cache_info;
1935
1936}
1937
1938static struct resolv_cache*
1939_find_named_cache_locked(const char* ifname) {
1940
1941 struct resolv_cache_info* info = _find_cache_info_locked(ifname);
1942
1943 if (info != NULL) return info->cache;
1944
1945 return NULL;
1946}
1947
1948static struct resolv_cache_info*
1949_find_cache_info_locked(const char* ifname)
1950{
1951 if (ifname == NULL)
1952 return NULL;
1953
1954 struct resolv_cache_info* cache_info = _res_cache_list.next;
1955
1956 while (cache_info) {
1957 if (strcmp(cache_info->ifname, ifname) == 0) {
1958 break;
1959 }
1960
1961 cache_info = cache_info->next;
1962 }
1963 return cache_info;
1964}
1965
1966static char*
1967_get_default_iface_locked(void)
1968{
1969 char* iface = _res_default_ifname;
1970
1971 return iface;
1972}
1973
1974void
1975_resolv_set_default_iface(const char* ifname)
1976{
1977 XLOG("_resolv_set_default_if ifname %s\n",ifname);
1978
1979 pthread_once(&_res_cache_once, _res_cache_init);
1980 pthread_mutex_lock(&_res_cache_list_lock);
1981
1982 int size = sizeof(_res_default_ifname);
1983 memset(_res_default_ifname, 0, size);
1984 strncpy(_res_default_ifname, ifname, size - 1);
1985 _res_default_ifname[size - 1] = '\0';
1986
1987 pthread_mutex_unlock(&_res_cache_list_lock);
1988}
1989
1990void
1991_resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numservers)
1992{
1993 int i, rt, index;
1994 struct addrinfo hints;
1995 char sbuf[NI_MAXSERV];
1996
1997 pthread_once(&_res_cache_once, _res_cache_init);
1998
1999 pthread_mutex_lock(&_res_cache_list_lock);
2000 // creates the cache if not created
2001 _get_res_cache_for_iface_locked(ifname);
2002
2003 struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
2004
2005 if (cache_info != NULL) {
2006 // free current before adding new
2007 _free_nameservers_locked(cache_info);
2008
2009 memset(&hints, 0, sizeof(hints));
2010 hints.ai_family = PF_UNSPEC;
2011 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
2012 hints.ai_flags = AI_NUMERICHOST;
2013 sprintf(sbuf, "%u", NAMESERVER_PORT);
2014
2015 index = 0;
2016 for (i = 0; i < numservers && i < MAXNS; i++) {
2017 rt = getaddrinfo(servers[i], sbuf, &hints, &cache_info->nsaddrinfo[index]);
2018 if (rt == 0) {
2019 cache_info->nameservers[index] = strdup(servers[i]);
2020 index++;
2021 } else {
2022 cache_info->nsaddrinfo[index] = NULL;
2023 }
2024 }
2025 }
2026 pthread_mutex_unlock(&_res_cache_list_lock);
2027}
2028
2029static void
2030_free_nameservers_locked(struct resolv_cache_info* cache_info)
2031{
2032 int i;
2033 for (i = 0; i <= MAXNS; i++) {
2034 free(cache_info->nameservers[i]);
2035 cache_info->nameservers[i] = NULL;
Robert Greenwalt9363d912011-07-25 12:30:17 -07002036 if (cache_info->nsaddrinfo[i] != NULL) {
2037 freeaddrinfo(cache_info->nsaddrinfo[i]);
2038 cache_info->nsaddrinfo[i] = NULL;
2039 }
Mattias Falk23d3e6b2011-04-04 16:12:35 +02002040 }
2041}
2042
2043int
2044_resolv_cache_get_nameserver(int n, char* addr, int addrLen)
2045{
2046 char *ifname;
2047 int result = 0;
2048
2049 pthread_once(&_res_cache_once, _res_cache_init);
2050 pthread_mutex_lock(&_res_cache_list_lock);
2051
2052 ifname = _get_default_iface_locked();
2053 result = _get_nameserver_locked(ifname, n, addr, addrLen);
2054
2055 pthread_mutex_unlock(&_res_cache_list_lock);
2056 return result;
2057}
2058
2059static int
2060_get_nameserver_locked(const char* ifname, int n, char* addr, int addrLen)
2061{
2062 int len = 0;
2063 char* ns;
2064 struct resolv_cache_info* cache_info;
2065
2066 if (n < 1 || n > MAXNS || !addr)
2067 return 0;
2068
2069 cache_info = _find_cache_info_locked(ifname);
2070 if (cache_info) {
2071 ns = cache_info->nameservers[n - 1];
2072 if (ns) {
2073 len = strlen(ns);
2074 if (len < addrLen) {
2075 strncpy(addr, ns, len);
2076 addr[len] = '\0';
2077 } else {
2078 len = 0;
2079 }
2080 }
2081 }
2082
2083 return len;
2084}
2085
2086struct addrinfo*
2087_cache_get_nameserver_addr(int n)
2088{
2089 struct addrinfo *result;
2090 char* ifname;
2091
2092 pthread_once(&_res_cache_once, _res_cache_init);
2093 pthread_mutex_lock(&_res_cache_list_lock);
2094
2095 ifname = _get_default_iface_locked();
2096
2097 result = _get_nameserver_addr_locked(ifname, n);
2098 pthread_mutex_unlock(&_res_cache_list_lock);
2099 return result;
2100}
2101
2102static struct addrinfo*
2103_get_nameserver_addr_locked(const char* ifname, int n)
2104{
2105 struct addrinfo* ai = NULL;
2106 struct resolv_cache_info* cache_info;
2107
2108 if (n < 1 || n > MAXNS)
2109 return NULL;
2110
2111 cache_info = _find_cache_info_locked(ifname);
2112 if (cache_info) {
2113 ai = cache_info->nsaddrinfo[n - 1];
2114 }
2115 return ai;
2116}
2117
2118void
2119_resolv_set_addr_of_iface(const char* ifname, struct in_addr* addr)
2120{
2121 pthread_once(&_res_cache_once, _res_cache_init);
2122 pthread_mutex_lock(&_res_cache_list_lock);
2123 struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
2124 if (cache_info) {
2125 memcpy(&cache_info->ifaddr, addr, sizeof(*addr));
2126
2127 if (DEBUG) {
2128 char* addr_s = inet_ntoa(cache_info->ifaddr);
2129 XLOG("address of interface %s is %s\n", ifname, addr_s);
2130 }
2131 }
2132 pthread_mutex_unlock(&_res_cache_list_lock);
2133}
2134
2135struct in_addr*
2136_resolv_get_addr_of_default_iface(void)
2137{
2138 struct in_addr* ai = NULL;
2139 char* ifname;
2140
2141 pthread_once(&_res_cache_once, _res_cache_init);
2142 pthread_mutex_lock(&_res_cache_list_lock);
2143 ifname = _get_default_iface_locked();
2144 ai = _get_addr_locked(ifname);
2145 pthread_mutex_unlock(&_res_cache_list_lock);
2146
2147 return ai;
2148}
2149
2150struct in_addr*
2151_resolv_get_addr_of_iface(const char* ifname)
2152{
2153 struct in_addr* ai = NULL;
2154
2155 pthread_once(&_res_cache_once, _res_cache_init);
2156 pthread_mutex_lock(&_res_cache_list_lock);
2157 ai =_get_addr_locked(ifname);
2158 pthread_mutex_unlock(&_res_cache_list_lock);
2159 return ai;
2160}
2161
2162static struct in_addr*
2163_get_addr_locked(const char * ifname)
2164{
2165 struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
2166 if (cache_info) {
2167 return &cache_info->ifaddr;
2168 }
2169 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002170}