• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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"
30 
31 #include <resolv.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include "pthread.h"
38 
39 #include <errno.h>
40 #include <arpa/nameser.h>
41 #include <net/if.h>
42 #include <netdb.h>
43 #include <linux/if.h>
44 
45 #include <arpa/inet.h>
46 #include "resolv_private.h"
47 #include "resolv_netid.h"
48 #include "res_private.h"
49 
50 #include <async_safe/log.h>
51 
52 /* This code implements a small and *simple* DNS resolver cache.
53  *
54  * It is only used to cache DNS answers for a time defined by the smallest TTL
55  * among the answer records in order to reduce DNS traffic. It is not supposed
56  * to be a full DNS cache, since we plan to implement that in the future in a
57  * dedicated process running on the system.
58  *
59  * Note that its design is kept simple very intentionally, i.e.:
60  *
61  *  - it takes raw DNS query packet data as input, and returns raw DNS
62  *    answer packet data as output
63  *
64  *    (this means that two similar queries that encode the DNS name
65  *     differently will be treated distinctly).
66  *
67  *    the smallest TTL value among the answer records are used as the time
68  *    to keep an answer in the cache.
69  *
70  *    this is bad, but we absolutely want to avoid parsing the answer packets
71  *    (and should be solved by the later full DNS cache process).
72  *
73  *  - the implementation is just a (query-data) => (answer-data) hash table
74  *    with a trivial least-recently-used expiration policy.
75  *
76  * Doing this keeps the code simple and avoids to deal with a lot of things
77  * that a full DNS cache is expected to do.
78  *
79  * The API is also very simple:
80  *
81  *   - the client calls _resolv_cache_get() to obtain a handle to the cache.
82  *     this will initialize the cache on first usage. the result can be NULL
83  *     if the cache is disabled.
84  *
85  *   - the client calls _resolv_cache_lookup() before performing a query
86  *
87  *     if the function returns RESOLV_CACHE_FOUND, a copy of the answer data
88  *     has been copied into the client-provided answer buffer.
89  *
90  *     if the function returns RESOLV_CACHE_NOTFOUND, the client should perform
91  *     a request normally, *then* call _resolv_cache_add() to add the received
92  *     answer to the cache.
93  *
94  *     if the function returns RESOLV_CACHE_UNSUPPORTED, the client should
95  *     perform a request normally, and *not* call _resolv_cache_add()
96  *
97  *     note that RESOLV_CACHE_UNSUPPORTED is also returned if the answer buffer
98  *     is too short to accomodate the cached result.
99  */
100 
101 /* default number of entries kept in the cache. This value has been
102  * determined by browsing through various sites and counting the number
103  * of corresponding requests. Keep in mind that our framework is currently
104  * performing two requests per name lookup (one for IPv4, the other for IPv6)
105  *
106  *    www.google.com      4
107  *    www.ysearch.com     6
108  *    www.amazon.com      8
109  *    www.nytimes.com     22
110  *    www.espn.com        28
111  *    www.msn.com         28
112  *    www.lemonde.fr      35
113  *
114  * (determined in 2009-2-17 from Paris, France, results may vary depending
115  *  on location)
116  *
117  * most high-level websites use lots of media/ad servers with different names
118  * but these are generally reused when browsing through the site.
119  *
120  * As such, a value of 64 should be relatively comfortable at the moment.
121  *
122  * ******************************************
123  * * NOTE - this has changed.
124  * * 1) we've added IPv6 support so each dns query results in 2 responses
125  * * 2) we've made this a system-wide cache, so the cost is less (it's not
126  * *    duplicated in each process) and the need is greater (more processes
127  * *    making different requests).
128  * * Upping by 2x for IPv6
129  * * Upping by another 5x for the centralized nature
130  * *****************************************
131  */
132 #define  CONFIG_MAX_ENTRIES    64 * 2 * 5
133 
134 /****************************************************************************/
135 /****************************************************************************/
136 /*****                                                                  *****/
137 /*****                                                                  *****/
138 /*****                                                                  *****/
139 /****************************************************************************/
140 /****************************************************************************/
141 
142 /* set to 1 to debug cache operations */
143 #define  DEBUG       0
144 
145 /* set to 1 to debug query data */
146 #define  DEBUG_DATA  0
147 
148 #if DEBUG
149 #define __DEBUG__
150 #else
151 #define __DEBUG__ __attribute__((unused))
152 #endif
153 
154 #undef XLOG
155 
156 #define XLOG(...) ({ \
157     if (DEBUG) { \
158         async_safe_format_log(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__); \
159     } else { \
160         ((void)0); \
161     } \
162 })
163 
164 /** BOUNDED BUFFER FORMATTING
165  **/
166 
167 /* technical note:
168  *
169  *   the following debugging routines are used to append data to a bounded
170  *   buffer they take two parameters that are:
171  *
172  *   - p : a pointer to the current cursor position in the buffer
173  *         this value is initially set to the buffer's address.
174  *
175  *   - end : the address of the buffer's limit, i.e. of the first byte
176  *           after the buffer. this address should never be touched.
177  *
178  *           IMPORTANT: it is assumed that end > buffer_address, i.e.
179  *                      that the buffer is at least one byte.
180  *
181  *   the _bprint_() functions return the new value of 'p' after the data
182  *   has been appended, and also ensure the following:
183  *
184  *   - the returned value will never be strictly greater than 'end'
185  *
186  *   - a return value equal to 'end' means that truncation occured
187  *     (in which case, end[-1] will be set to 0)
188  *
189  *   - after returning from a _bprint_() function, the content of the buffer
190  *     is always 0-terminated, even in the event of truncation.
191  *
192  *  these conventions allow you to call _bprint_ functions multiple times and
193  *  only check for truncation at the end of the sequence, as in:
194  *
195  *     char  buff[1000], *p = buff, *end = p + sizeof(buff);
196  *
197  *     p = _bprint_c(p, end, '"');
198  *     p = _bprint_s(p, end, my_string);
199  *     p = _bprint_c(p, end, '"');
200  *
201  *     if (p >= end) {
202  *        // buffer was too small
203  *     }
204  *
205  *     printf( "%s", buff );
206  */
207 
208 /* add a char to a bounded buffer */
209 char*
_bprint_c(char * p,char * end,int c)210 _bprint_c( char*  p, char*  end, int  c )
211 {
212     if (p < end) {
213         if (p+1 == end)
214             *p++ = 0;
215         else {
216             *p++ = (char) c;
217             *p   = 0;
218         }
219     }
220     return p;
221 }
222 
223 /* add a sequence of bytes to a bounded buffer */
224 char*
_bprint_b(char * p,char * end,const char * buf,int len)225 _bprint_b( char*  p, char*  end, const char*  buf, int  len )
226 {
227     int  avail = end - p;
228 
229     if (avail <= 0 || len <= 0)
230         return p;
231 
232     if (avail > len)
233         avail = len;
234 
235     memcpy( p, buf, avail );
236     p += avail;
237 
238     if (p < end)
239         p[0] = 0;
240     else
241         end[-1] = 0;
242 
243     return p;
244 }
245 
246 /* add a string to a bounded buffer */
247 char*
_bprint_s(char * p,char * end,const char * str)248 _bprint_s( char*  p, char*  end, const char*  str )
249 {
250     return _bprint_b(p, end, str, strlen(str));
251 }
252 
253 /* add a formatted string to a bounded buffer */
254 char* _bprint( char*  p, char*  end, const char*  format, ... ) __DEBUG__;
_bprint(char * p,char * end,const char * format,...)255 char* _bprint( char*  p, char*  end, const char*  format, ... )
256 {
257     int      avail, n;
258     va_list  args;
259 
260     avail = end - p;
261 
262     if (avail <= 0)
263         return p;
264 
265     va_start(args, format);
266     n = vsnprintf( p, avail, format, args);
267     va_end(args);
268 
269     /* certain C libraries return -1 in case of truncation */
270     if (n < 0 || n > avail)
271         n = avail;
272 
273     p += n;
274     /* certain C libraries do not zero-terminate in case of truncation */
275     if (p == end)
276         p[-1] = 0;
277 
278     return p;
279 }
280 
281 /* add a hex value to a bounded buffer, up to 8 digits */
282 char*
_bprint_hex(char * p,char * end,unsigned value,int numDigits)283 _bprint_hex( char*  p, char*  end, unsigned  value, int  numDigits )
284 {
285     char   text[sizeof(unsigned)*2];
286     int    nn = 0;
287 
288     while (numDigits-- > 0) {
289         text[nn++] = "0123456789abcdef"[(value >> (numDigits*4)) & 15];
290     }
291     return _bprint_b(p, end, text, nn);
292 }
293 
294 /* add the hexadecimal dump of some memory area to a bounded buffer */
295 char*
_bprint_hexdump(char * p,char * end,const uint8_t * data,int datalen)296 _bprint_hexdump( char*  p, char*  end, const uint8_t*  data, int  datalen )
297 {
298     int   lineSize = 16;
299 
300     while (datalen > 0) {
301         int  avail = datalen;
302         int  nn;
303 
304         if (avail > lineSize)
305             avail = lineSize;
306 
307         for (nn = 0; nn < avail; nn++) {
308             if (nn > 0)
309                 p = _bprint_c(p, end, ' ');
310             p = _bprint_hex(p, end, data[nn], 2);
311         }
312         for ( ; nn < lineSize; nn++ ) {
313             p = _bprint_s(p, end, "   ");
314         }
315         p = _bprint_s(p, end, "  ");
316 
317         for (nn = 0; nn < avail; nn++) {
318             int  c = data[nn];
319 
320             if (c < 32 || c > 127)
321                 c = '.';
322 
323             p = _bprint_c(p, end, c);
324         }
325         p = _bprint_c(p, end, '\n');
326 
327         data    += avail;
328         datalen -= avail;
329     }
330     return p;
331 }
332 
333 /* dump the content of a query of packet to the log */
334 void XLOG_BYTES( const void*  base, int  len ) __DEBUG__;
XLOG_BYTES(const void * base,int len)335 void XLOG_BYTES( const void*  base, int  len )
336 {
337     if (DEBUG_DATA) {
338         char  buff[1024];
339         char*  p = buff, *end = p + sizeof(buff);
340 
341         p = _bprint_hexdump(p, end, base, len);
342         XLOG("%s",buff);
343     }
344 } __DEBUG__
345 
346 static time_t
_time_now(void)347 _time_now( void )
348 {
349     struct timeval  tv;
350 
351     gettimeofday( &tv, NULL );
352     return tv.tv_sec;
353 }
354 
355 /* reminder: the general format of a DNS packet is the following:
356  *
357  *    HEADER  (12 bytes)
358  *    QUESTION  (variable)
359  *    ANSWER (variable)
360  *    AUTHORITY (variable)
361  *    ADDITIONNAL (variable)
362  *
363  * the HEADER is made of:
364  *
365  *   ID     : 16 : 16-bit unique query identification field
366  *
367  *   QR     :  1 : set to 0 for queries, and 1 for responses
368  *   Opcode :  4 : set to 0 for queries
369  *   AA     :  1 : set to 0 for queries
370  *   TC     :  1 : truncation flag, will be set to 0 in queries
371  *   RD     :  1 : recursion desired
372  *
373  *   RA     :  1 : recursion available (0 in queries)
374  *   Z      :  3 : three reserved zero bits
375  *   RCODE  :  4 : response code (always 0=NOERROR in queries)
376  *
377  *   QDCount: 16 : question count
378  *   ANCount: 16 : Answer count (0 in queries)
379  *   NSCount: 16: Authority Record count (0 in queries)
380  *   ARCount: 16: Additionnal Record count (0 in queries)
381  *
382  * the QUESTION is made of QDCount Question Record (QRs)
383  * the ANSWER is made of ANCount RRs
384  * the AUTHORITY is made of NSCount RRs
385  * the ADDITIONNAL is made of ARCount RRs
386  *
387  * Each Question Record (QR) is made of:
388  *
389  *   QNAME   : variable : Query DNS NAME
390  *   TYPE    : 16       : type of query (A=1, PTR=12, MX=15, AAAA=28, ALL=255)
391  *   CLASS   : 16       : class of query (IN=1)
392  *
393  * Each Resource Record (RR) is made of:
394  *
395  *   NAME    : variable : DNS NAME
396  *   TYPE    : 16       : type of query (A=1, PTR=12, MX=15, AAAA=28, ALL=255)
397  *   CLASS   : 16       : class of query (IN=1)
398  *   TTL     : 32       : seconds to cache this RR (0=none)
399  *   RDLENGTH: 16       : size of RDDATA in bytes
400  *   RDDATA  : variable : RR data (depends on TYPE)
401  *
402  * Each QNAME contains a domain name encoded as a sequence of 'labels'
403  * terminated by a zero. Each label has the following format:
404  *
405  *    LEN  : 8     : lenght of label (MUST be < 64)
406  *    NAME : 8*LEN : label length (must exclude dots)
407  *
408  * A value of 0 in the encoding is interpreted as the 'root' domain and
409  * terminates the encoding. So 'www.android.com' will be encoded as:
410  *
411  *   <3>www<7>android<3>com<0>
412  *
413  * Where <n> represents the byte with value 'n'
414  *
415  * Each NAME reflects the QNAME of the question, but has a slightly more
416  * complex encoding in order to provide message compression. This is achieved
417  * by using a 2-byte pointer, with format:
418  *
419  *    TYPE   : 2  : 0b11 to indicate a pointer, 0b01 and 0b10 are reserved
420  *    OFFSET : 14 : offset to another part of the DNS packet
421  *
422  * The offset is relative to the start of the DNS packet and must point
423  * A pointer terminates the encoding.
424  *
425  * The NAME can be encoded in one of the following formats:
426  *
427  *   - a sequence of simple labels terminated by 0 (like QNAMEs)
428  *   - a single pointer
429  *   - a sequence of simple labels terminated by a pointer
430  *
431  * A pointer shall always point to either a pointer of a sequence of
432  * labels (which can themselves be terminated by either a 0 or a pointer)
433  *
434  * The expanded length of a given domain name should not exceed 255 bytes.
435  *
436  * NOTE: we don't parse the answer packets, so don't need to deal with NAME
437  *       records, only QNAMEs.
438  */
439 
440 #define  DNS_HEADER_SIZE  12
441 
442 #define  DNS_TYPE_A   "\00\01"   /* big-endian decimal 1 */
443 #define  DNS_TYPE_PTR "\00\014"  /* big-endian decimal 12 */
444 #define  DNS_TYPE_MX  "\00\017"  /* big-endian decimal 15 */
445 #define  DNS_TYPE_AAAA "\00\034" /* big-endian decimal 28 */
446 #define  DNS_TYPE_ALL "\00\0377" /* big-endian decimal 255 */
447 
448 #define  DNS_CLASS_IN "\00\01"   /* big-endian decimal 1 */
449 
450 typedef struct {
451     const uint8_t*  base;
452     const uint8_t*  end;
453     const uint8_t*  cursor;
454 } DnsPacket;
455 
456 static void
_dnsPacket_init(DnsPacket * packet,const uint8_t * buff,int bufflen)457 _dnsPacket_init( DnsPacket*  packet, const uint8_t*  buff, int  bufflen )
458 {
459     packet->base   = buff;
460     packet->end    = buff + bufflen;
461     packet->cursor = buff;
462 }
463 
464 static void
_dnsPacket_rewind(DnsPacket * packet)465 _dnsPacket_rewind( DnsPacket*  packet )
466 {
467     packet->cursor = packet->base;
468 }
469 
470 static void
_dnsPacket_skip(DnsPacket * packet,int count)471 _dnsPacket_skip( DnsPacket*  packet, int  count )
472 {
473     const uint8_t*  p = packet->cursor + count;
474 
475     if (p > packet->end)
476         p = packet->end;
477 
478     packet->cursor = p;
479 }
480 
481 static int
_dnsPacket_readInt16(DnsPacket * packet)482 _dnsPacket_readInt16( DnsPacket*  packet )
483 {
484     const uint8_t*  p = packet->cursor;
485 
486     if (p+2 > packet->end)
487         return -1;
488 
489     packet->cursor = p+2;
490     return (p[0]<< 8) | p[1];
491 }
492 
493 /** QUERY CHECKING
494  **/
495 
496 /* check bytes in a dns packet. returns 1 on success, 0 on failure.
497  * the cursor is only advanced in the case of success
498  */
499 static int
_dnsPacket_checkBytes(DnsPacket * packet,int numBytes,const void * bytes)500 _dnsPacket_checkBytes( DnsPacket*  packet, int  numBytes, const void*  bytes )
501 {
502     const uint8_t*  p = packet->cursor;
503 
504     if (p + numBytes > packet->end)
505         return 0;
506 
507     if (memcmp(p, bytes, numBytes) != 0)
508         return 0;
509 
510     packet->cursor = p + numBytes;
511     return 1;
512 }
513 
514 /* parse and skip a given QNAME stored in a query packet,
515  * from the current cursor position. returns 1 on success,
516  * or 0 for malformed data.
517  */
518 static int
_dnsPacket_checkQName(DnsPacket * packet)519 _dnsPacket_checkQName( DnsPacket*  packet )
520 {
521     const uint8_t*  p   = packet->cursor;
522     const uint8_t*  end = packet->end;
523 
524     for (;;) {
525         int  c;
526 
527         if (p >= end)
528             break;
529 
530         c = *p++;
531 
532         if (c == 0) {
533             packet->cursor = p;
534             return 1;
535         }
536 
537         /* we don't expect label compression in QNAMEs */
538         if (c >= 64)
539             break;
540 
541         p += c;
542         /* we rely on the bound check at the start
543          * of the loop here */
544     }
545     /* malformed data */
546     XLOG("malformed QNAME");
547     return 0;
548 }
549 
550 /* parse and skip a given QR stored in a packet.
551  * returns 1 on success, and 0 on failure
552  */
553 static int
_dnsPacket_checkQR(DnsPacket * packet)554 _dnsPacket_checkQR( DnsPacket*  packet )
555 {
556     if (!_dnsPacket_checkQName(packet))
557         return 0;
558 
559     /* TYPE must be one of the things we support */
560     if (!_dnsPacket_checkBytes(packet, 2, DNS_TYPE_A) &&
561         !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_PTR) &&
562         !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_MX) &&
563         !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_AAAA) &&
564         !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_ALL))
565     {
566         XLOG("unsupported TYPE");
567         return 0;
568     }
569     /* CLASS must be IN */
570     if (!_dnsPacket_checkBytes(packet, 2, DNS_CLASS_IN)) {
571         XLOG("unsupported CLASS");
572         return 0;
573     }
574 
575     return 1;
576 }
577 
578 /* check the header of a DNS Query packet, return 1 if it is one
579  * type of query we can cache, or 0 otherwise
580  */
581 static int
_dnsPacket_checkQuery(DnsPacket * packet)582 _dnsPacket_checkQuery( DnsPacket*  packet )
583 {
584     const uint8_t*  p = packet->base;
585     int             qdCount, anCount, dnCount, arCount;
586 
587     if (p + DNS_HEADER_SIZE > packet->end) {
588         XLOG("query packet too small");
589         return 0;
590     }
591 
592     /* QR must be set to 0, opcode must be 0 and AA must be 0 */
593     /* RA, Z, and RCODE must be 0 */
594     if ((p[2] & 0xFC) != 0 || (p[3] & 0xCF) != 0) {
595         XLOG("query packet flags unsupported");
596         return 0;
597     }
598 
599     /* Note that we ignore the TC, RD, CD, and AD bits here for the
600      * following reasons:
601      *
602      * - there is no point for a query packet sent to a server
603      *   to have the TC bit set, but the implementation might
604      *   set the bit in the query buffer for its own needs
605      *   between a _resolv_cache_lookup and a
606      *   _resolv_cache_add. We should not freak out if this
607      *   is the case.
608      *
609      * - we consider that the result from a query might depend on
610      *   the RD, AD, and CD bits, so these bits
611      *   should be used to differentiate cached result.
612      *
613      *   this implies that these bits are checked when hashing or
614      *   comparing query packets, but not TC
615      */
616 
617     /* ANCOUNT, DNCOUNT and ARCOUNT must be 0 */
618     qdCount = (p[4] << 8) | p[5];
619     anCount = (p[6] << 8) | p[7];
620     dnCount = (p[8] << 8) | p[9];
621     arCount = (p[10]<< 8) | p[11];
622 
623     if (anCount != 0 || dnCount != 0 || arCount > 1) {
624         XLOG("query packet contains non-query records");
625         return 0;
626     }
627 
628     if (qdCount == 0) {
629         XLOG("query packet doesn't contain query record");
630         return 0;
631     }
632 
633     /* Check QDCOUNT QRs */
634     packet->cursor = p + DNS_HEADER_SIZE;
635 
636     for (;qdCount > 0; qdCount--)
637         if (!_dnsPacket_checkQR(packet))
638             return 0;
639 
640     return 1;
641 }
642 
643 /** QUERY DEBUGGING
644  **/
645 #if DEBUG
646 static char*
_dnsPacket_bprintQName(DnsPacket * packet,char * bp,char * bend)647 _dnsPacket_bprintQName(DnsPacket*  packet, char*  bp, char*  bend)
648 {
649     const uint8_t*  p   = packet->cursor;
650     const uint8_t*  end = packet->end;
651     int             first = 1;
652 
653     for (;;) {
654         int  c;
655 
656         if (p >= end)
657             break;
658 
659         c = *p++;
660 
661         if (c == 0) {
662             packet->cursor = p;
663             return bp;
664         }
665 
666         /* we don't expect label compression in QNAMEs */
667         if (c >= 64)
668             break;
669 
670         if (first)
671             first = 0;
672         else
673             bp = _bprint_c(bp, bend, '.');
674 
675         bp = _bprint_b(bp, bend, (const char*)p, c);
676 
677         p += c;
678         /* we rely on the bound check at the start
679          * of the loop here */
680     }
681     /* malformed data */
682     bp = _bprint_s(bp, bend, "<MALFORMED>");
683     return bp;
684 }
685 
686 static char*
_dnsPacket_bprintQR(DnsPacket * packet,char * p,char * end)687 _dnsPacket_bprintQR(DnsPacket*  packet, char*  p, char*  end)
688 {
689 #define  QQ(x)   { DNS_TYPE_##x, #x }
690     static const struct {
691         const char*  typeBytes;
692         const char*  typeString;
693     } qTypes[] =
694     {
695         QQ(A), QQ(PTR), QQ(MX), QQ(AAAA), QQ(ALL),
696         { NULL, NULL }
697     };
698     int          nn;
699     const char*  typeString = NULL;
700 
701     /* dump QNAME */
702     p = _dnsPacket_bprintQName(packet, p, end);
703 
704     /* dump TYPE */
705     p = _bprint_s(p, end, " (");
706 
707     for (nn = 0; qTypes[nn].typeBytes != NULL; nn++) {
708         if (_dnsPacket_checkBytes(packet, 2, qTypes[nn].typeBytes)) {
709             typeString = qTypes[nn].typeString;
710             break;
711         }
712     }
713 
714     if (typeString != NULL)
715         p = _bprint_s(p, end, typeString);
716     else {
717         int  typeCode = _dnsPacket_readInt16(packet);
718         p = _bprint(p, end, "UNKNOWN-%d", typeCode);
719     }
720 
721     p = _bprint_c(p, end, ')');
722 
723     /* skip CLASS */
724     _dnsPacket_skip(packet, 2);
725     return p;
726 }
727 
728 /* this function assumes the packet has already been checked */
729 static char*
_dnsPacket_bprintQuery(DnsPacket * packet,char * p,char * end)730 _dnsPacket_bprintQuery( DnsPacket*  packet, char*  p, char*  end )
731 {
732     int   qdCount;
733 
734     if (packet->base[2] & 0x1) {
735         p = _bprint_s(p, end, "RECURSIVE ");
736     }
737 
738     _dnsPacket_skip(packet, 4);
739     qdCount = _dnsPacket_readInt16(packet);
740     _dnsPacket_skip(packet, 6);
741 
742     for ( ; qdCount > 0; qdCount-- ) {
743         p = _dnsPacket_bprintQR(packet, p, end);
744     }
745     return p;
746 }
747 #endif
748 
749 
750 /** QUERY HASHING SUPPORT
751  **
752  ** THE FOLLOWING CODE ASSUMES THAT THE INPUT PACKET HAS ALREADY
753  ** BEEN SUCCESFULLY CHECKED.
754  **/
755 
756 /* use 32-bit FNV hash function */
757 #define  FNV_MULT   16777619U
758 #define  FNV_BASIS  2166136261U
759 
760 static unsigned
_dnsPacket_hashBytes(DnsPacket * packet,int numBytes,unsigned hash)761 _dnsPacket_hashBytes( DnsPacket*  packet, int  numBytes, unsigned  hash )
762 {
763     const uint8_t*  p   = packet->cursor;
764     const uint8_t*  end = packet->end;
765 
766     while (numBytes > 0 && p < end) {
767         hash = hash*FNV_MULT ^ *p++;
768     }
769     packet->cursor = p;
770     return hash;
771 }
772 
773 
774 static unsigned
_dnsPacket_hashQName(DnsPacket * packet,unsigned hash)775 _dnsPacket_hashQName( DnsPacket*  packet, unsigned  hash )
776 {
777     const uint8_t*  p   = packet->cursor;
778     const uint8_t*  end = packet->end;
779 
780     for (;;) {
781         int  c;
782 
783         if (p >= end) {  /* should not happen */
784             XLOG("%s: INTERNAL_ERROR: read-overflow !!\n", __FUNCTION__);
785             break;
786         }
787 
788         c = *p++;
789 
790         if (c == 0)
791             break;
792 
793         if (c >= 64) {
794             XLOG("%s: INTERNAL_ERROR: malformed domain !!\n", __FUNCTION__);
795             break;
796         }
797         if (p + c >= end) {
798             XLOG("%s: INTERNAL_ERROR: simple label read-overflow !!\n",
799                     __FUNCTION__);
800             break;
801         }
802         while (c > 0) {
803             hash = hash*FNV_MULT ^ *p++;
804             c   -= 1;
805         }
806     }
807     packet->cursor = p;
808     return hash;
809 }
810 
811 static unsigned
_dnsPacket_hashQR(DnsPacket * packet,unsigned hash)812 _dnsPacket_hashQR( DnsPacket*  packet, unsigned  hash )
813 {
814     hash = _dnsPacket_hashQName(packet, hash);
815     hash = _dnsPacket_hashBytes(packet, 4, hash); /* TYPE and CLASS */
816     return hash;
817 }
818 
819 static unsigned
_dnsPacket_hashRR(DnsPacket * packet,unsigned hash)820 _dnsPacket_hashRR( DnsPacket*  packet, unsigned  hash )
821 {
822     int rdlength;
823     hash = _dnsPacket_hashQR(packet, hash);
824     hash = _dnsPacket_hashBytes(packet, 4, hash); /* TTL */
825     rdlength = _dnsPacket_readInt16(packet);
826     hash = _dnsPacket_hashBytes(packet, rdlength, hash); /* RDATA */
827     return hash;
828 }
829 
830 static unsigned
_dnsPacket_hashQuery(DnsPacket * packet)831 _dnsPacket_hashQuery( DnsPacket*  packet )
832 {
833     unsigned  hash = FNV_BASIS;
834     int       count, arcount;
835     _dnsPacket_rewind(packet);
836 
837     /* ignore the ID */
838     _dnsPacket_skip(packet, 2);
839 
840     /* we ignore the TC bit for reasons explained in
841      * _dnsPacket_checkQuery().
842      *
843      * however we hash the RD bit to differentiate
844      * between answers for recursive and non-recursive
845      * queries.
846      */
847     hash = hash*FNV_MULT ^ (packet->base[2] & 1);
848 
849     /* mark the first header byte as processed */
850     _dnsPacket_skip(packet, 1);
851 
852     /* process the second header byte */
853     hash = _dnsPacket_hashBytes(packet, 1, hash);
854 
855     /* read QDCOUNT */
856     count = _dnsPacket_readInt16(packet);
857 
858     /* assume: ANcount and NScount are 0 */
859     _dnsPacket_skip(packet, 4);
860 
861     /* read ARCOUNT */
862     arcount = _dnsPacket_readInt16(packet);
863 
864     /* hash QDCOUNT QRs */
865     for ( ; count > 0; count-- )
866         hash = _dnsPacket_hashQR(packet, hash);
867 
868     /* hash ARCOUNT RRs */
869     for ( ; arcount > 0; arcount-- )
870         hash = _dnsPacket_hashRR(packet, hash);
871 
872     return hash;
873 }
874 
875 
876 /** QUERY COMPARISON
877  **
878  ** THE FOLLOWING CODE ASSUMES THAT THE INPUT PACKETS HAVE ALREADY
879  ** BEEN SUCCESFULLY CHECKED.
880  **/
881 
882 static int
_dnsPacket_isEqualDomainName(DnsPacket * pack1,DnsPacket * pack2)883 _dnsPacket_isEqualDomainName( DnsPacket*  pack1, DnsPacket*  pack2 )
884 {
885     const uint8_t*  p1   = pack1->cursor;
886     const uint8_t*  end1 = pack1->end;
887     const uint8_t*  p2   = pack2->cursor;
888     const uint8_t*  end2 = pack2->end;
889 
890     for (;;) {
891         int  c1, c2;
892 
893         if (p1 >= end1 || p2 >= end2) {
894             XLOG("%s: INTERNAL_ERROR: read-overflow !!\n", __FUNCTION__);
895             break;
896         }
897         c1 = *p1++;
898         c2 = *p2++;
899         if (c1 != c2)
900             break;
901 
902         if (c1 == 0) {
903             pack1->cursor = p1;
904             pack2->cursor = p2;
905             return 1;
906         }
907         if (c1 >= 64) {
908             XLOG("%s: INTERNAL_ERROR: malformed domain !!\n", __FUNCTION__);
909             break;
910         }
911         if ((p1+c1 > end1) || (p2+c1 > end2)) {
912             XLOG("%s: INTERNAL_ERROR: simple label read-overflow !!\n",
913                     __FUNCTION__);
914             break;
915         }
916         if (memcmp(p1, p2, c1) != 0)
917             break;
918         p1 += c1;
919         p2 += c1;
920         /* we rely on the bound checks at the start of the loop */
921     }
922     /* not the same, or one is malformed */
923     XLOG("different DN");
924     return 0;
925 }
926 
927 static int
_dnsPacket_isEqualBytes(DnsPacket * pack1,DnsPacket * pack2,int numBytes)928 _dnsPacket_isEqualBytes( DnsPacket*  pack1, DnsPacket*  pack2, int  numBytes )
929 {
930     const uint8_t*  p1 = pack1->cursor;
931     const uint8_t*  p2 = pack2->cursor;
932 
933     if ( p1 + numBytes > pack1->end || p2 + numBytes > pack2->end )
934         return 0;
935 
936     if ( memcmp(p1, p2, numBytes) != 0 )
937         return 0;
938 
939     pack1->cursor += numBytes;
940     pack2->cursor += numBytes;
941     return 1;
942 }
943 
944 static int
_dnsPacket_isEqualQR(DnsPacket * pack1,DnsPacket * pack2)945 _dnsPacket_isEqualQR( DnsPacket*  pack1, DnsPacket*  pack2 )
946 {
947     /* compare domain name encoding + TYPE + CLASS */
948     if ( !_dnsPacket_isEqualDomainName(pack1, pack2) ||
949          !_dnsPacket_isEqualBytes(pack1, pack2, 2+2) )
950         return 0;
951 
952     return 1;
953 }
954 
955 static int
_dnsPacket_isEqualRR(DnsPacket * pack1,DnsPacket * pack2)956 _dnsPacket_isEqualRR( DnsPacket*  pack1, DnsPacket*  pack2 )
957 {
958     int rdlength1, rdlength2;
959     /* compare query + TTL */
960     if ( !_dnsPacket_isEqualQR(pack1, pack2) ||
961          !_dnsPacket_isEqualBytes(pack1, pack2, 4) )
962         return 0;
963 
964     /* compare RDATA */
965     rdlength1 = _dnsPacket_readInt16(pack1);
966     rdlength2 = _dnsPacket_readInt16(pack2);
967     if ( rdlength1 != rdlength2 ||
968          !_dnsPacket_isEqualBytes(pack1, pack2, rdlength1) )
969         return 0;
970 
971     return 1;
972 }
973 
974 static int
_dnsPacket_isEqualQuery(DnsPacket * pack1,DnsPacket * pack2)975 _dnsPacket_isEqualQuery( DnsPacket*  pack1, DnsPacket*  pack2 )
976 {
977     int  count1, count2, arcount1, arcount2;
978 
979     /* compare the headers, ignore most fields */
980     _dnsPacket_rewind(pack1);
981     _dnsPacket_rewind(pack2);
982 
983     /* compare RD, ignore TC, see comment in _dnsPacket_checkQuery */
984     if ((pack1->base[2] & 1) != (pack2->base[2] & 1)) {
985         XLOG("different RD");
986         return 0;
987     }
988 
989     if (pack1->base[3] != pack2->base[3]) {
990         XLOG("different CD or AD");
991         return 0;
992     }
993 
994     /* mark ID and header bytes as compared */
995     _dnsPacket_skip(pack1, 4);
996     _dnsPacket_skip(pack2, 4);
997 
998     /* compare QDCOUNT */
999     count1 = _dnsPacket_readInt16(pack1);
1000     count2 = _dnsPacket_readInt16(pack2);
1001     if (count1 != count2 || count1 < 0) {
1002         XLOG("different QDCOUNT");
1003         return 0;
1004     }
1005 
1006     /* assume: ANcount and NScount are 0 */
1007     _dnsPacket_skip(pack1, 4);
1008     _dnsPacket_skip(pack2, 4);
1009 
1010     /* compare ARCOUNT */
1011     arcount1 = _dnsPacket_readInt16(pack1);
1012     arcount2 = _dnsPacket_readInt16(pack2);
1013     if (arcount1 != arcount2 || arcount1 < 0) {
1014         XLOG("different ARCOUNT");
1015         return 0;
1016     }
1017 
1018     /* compare the QDCOUNT QRs */
1019     for ( ; count1 > 0; count1-- ) {
1020         if (!_dnsPacket_isEqualQR(pack1, pack2)) {
1021             XLOG("different QR");
1022             return 0;
1023         }
1024     }
1025 
1026     /* compare the ARCOUNT RRs */
1027     for ( ; arcount1 > 0; arcount1-- ) {
1028         if (!_dnsPacket_isEqualRR(pack1, pack2)) {
1029             XLOG("different additional RR");
1030             return 0;
1031         }
1032     }
1033     return 1;
1034 }
1035 
1036 /****************************************************************************/
1037 /****************************************************************************/
1038 /*****                                                                  *****/
1039 /*****                                                                  *****/
1040 /*****                                                                  *****/
1041 /****************************************************************************/
1042 /****************************************************************************/
1043 
1044 /* cache entry. for simplicity, 'hash' and 'hlink' are inlined in this
1045  * structure though they are conceptually part of the hash table.
1046  *
1047  * similarly, mru_next and mru_prev are part of the global MRU list
1048  */
1049 typedef struct Entry {
1050     unsigned int     hash;   /* hash value */
1051     struct Entry*    hlink;  /* next in collision chain */
1052     struct Entry*    mru_prev;
1053     struct Entry*    mru_next;
1054 
1055     const uint8_t*   query;
1056     int              querylen;
1057     const uint8_t*   answer;
1058     int              answerlen;
1059     time_t           expires;   /* time_t when the entry isn't valid any more */
1060     int              id;        /* for debugging purpose */
1061 } Entry;
1062 
1063 /**
1064  * Find the TTL for a negative DNS result.  This is defined as the minimum
1065  * of the SOA records TTL and the MINIMUM-TTL field (RFC-2308).
1066  *
1067  * Return 0 if not found.
1068  */
1069 static u_long
answer_getNegativeTTL(ns_msg handle)1070 answer_getNegativeTTL(ns_msg handle) {
1071     int n, nscount;
1072     u_long result = 0;
1073     ns_rr rr;
1074 
1075     nscount = ns_msg_count(handle, ns_s_ns);
1076     for (n = 0; n < nscount; n++) {
1077         if ((ns_parserr(&handle, ns_s_ns, n, &rr) == 0) && (ns_rr_type(rr) == ns_t_soa)) {
1078             const u_char *rdata = ns_rr_rdata(rr); // find the data
1079             const u_char *edata = rdata + ns_rr_rdlen(rr); // add the len to find the end
1080             int len;
1081             u_long ttl, rec_result = ns_rr_ttl(rr);
1082 
1083             // find the MINIMUM-TTL field from the blob of binary data for this record
1084             // skip the server name
1085             len = dn_skipname(rdata, edata);
1086             if (len == -1) continue; // error skipping
1087             rdata += len;
1088 
1089             // skip the admin name
1090             len = dn_skipname(rdata, edata);
1091             if (len == -1) continue; // error skipping
1092             rdata += len;
1093 
1094             if (edata - rdata != 5*NS_INT32SZ) continue;
1095             // skip: serial number + refresh interval + retry interval + expiry
1096             rdata += NS_INT32SZ * 4;
1097             // finally read the MINIMUM TTL
1098             ttl = ns_get32(rdata);
1099             if (ttl < rec_result) {
1100                 rec_result = ttl;
1101             }
1102             // Now that the record is read successfully, apply the new min TTL
1103             if (n == 0 || rec_result < result) {
1104                 result = rec_result;
1105             }
1106         }
1107     }
1108     return result;
1109 }
1110 
1111 /**
1112  * Parse the answer records and find the appropriate
1113  * smallest TTL among the records.  This might be from
1114  * the answer records if found or from the SOA record
1115  * if it's a negative result.
1116  *
1117  * The returned TTL is the number of seconds to
1118  * keep the answer in the cache.
1119  *
1120  * In case of parse error zero (0) is returned which
1121  * indicates that the answer shall not be cached.
1122  */
1123 static u_long
answer_getTTL(const void * answer,int answerlen)1124 answer_getTTL(const void* answer, int answerlen)
1125 {
1126     ns_msg handle;
1127     int ancount, n;
1128     u_long result, ttl;
1129     ns_rr rr;
1130 
1131     result = 0;
1132     if (ns_initparse(answer, answerlen, &handle) >= 0) {
1133         // get number of answer records
1134         ancount = ns_msg_count(handle, ns_s_an);
1135 
1136         if (ancount == 0) {
1137             // a response with no answers?  Cache this negative result.
1138             result = answer_getNegativeTTL(handle);
1139         } else {
1140             for (n = 0; n < ancount; n++) {
1141                 if (ns_parserr(&handle, ns_s_an, n, &rr) == 0) {
1142                     ttl = ns_rr_ttl(rr);
1143                     if (n == 0 || ttl < result) {
1144                         result = ttl;
1145                     }
1146                 } else {
1147                     XLOG("ns_parserr failed ancount no = %d. errno = %s\n", n, strerror(errno));
1148                 }
1149             }
1150         }
1151     } else {
1152         XLOG("ns_parserr failed. %s\n", strerror(errno));
1153     }
1154 
1155     XLOG("TTL = %lu\n", result);
1156 
1157     return result;
1158 }
1159 
1160 static void
entry_free(Entry * e)1161 entry_free( Entry*  e )
1162 {
1163     /* everything is allocated in a single memory block */
1164     if (e) {
1165         free(e);
1166     }
1167 }
1168 
entry_mru_remove(Entry * e)1169 static __inline__ void entry_mru_remove(Entry* e) {
1170   e->mru_prev->mru_next = e->mru_next;
1171   e->mru_next->mru_prev = e->mru_prev;
1172 }
1173 
entry_mru_add(Entry * e,Entry * list)1174 static __inline__ void entry_mru_add(Entry* e, Entry* list) {
1175   Entry* first = list->mru_next;
1176 
1177   e->mru_next = first;
1178   e->mru_prev = list;
1179 
1180   list->mru_next = e;
1181   first->mru_prev = e;
1182 }
1183 
1184 /* compute the hash of a given entry, this is a hash of most
1185  * data in the query (key) */
1186 static unsigned
entry_hash(const Entry * e)1187 entry_hash( const Entry*  e )
1188 {
1189     DnsPacket  pack[1];
1190 
1191     _dnsPacket_init(pack, e->query, e->querylen);
1192     return _dnsPacket_hashQuery(pack);
1193 }
1194 
1195 /* initialize an Entry as a search key, this also checks the input query packet
1196  * returns 1 on success, or 0 in case of unsupported/malformed data */
1197 static int
entry_init_key(Entry * e,const void * query,int querylen)1198 entry_init_key( Entry*  e, const void*  query, int  querylen )
1199 {
1200     DnsPacket  pack[1];
1201 
1202     memset(e, 0, sizeof(*e));
1203 
1204     e->query    = query;
1205     e->querylen = querylen;
1206     e->hash     = entry_hash(e);
1207 
1208     _dnsPacket_init(pack, query, querylen);
1209 
1210     return _dnsPacket_checkQuery(pack);
1211 }
1212 
1213 /* allocate a new entry as a cache node */
1214 static Entry*
entry_alloc(const Entry * init,const void * answer,int answerlen)1215 entry_alloc( const Entry*  init, const void*  answer, int  answerlen )
1216 {
1217     Entry*  e;
1218     int     size;
1219 
1220     size = sizeof(*e) + init->querylen + answerlen;
1221     e    = calloc(size, 1);
1222     if (e == NULL)
1223         return e;
1224 
1225     e->hash     = init->hash;
1226     e->query    = (const uint8_t*)(e+1);
1227     e->querylen = init->querylen;
1228 
1229     memcpy( (char*)e->query, init->query, e->querylen );
1230 
1231     e->answer    = e->query + e->querylen;
1232     e->answerlen = answerlen;
1233 
1234     memcpy( (char*)e->answer, answer, e->answerlen );
1235 
1236     return e;
1237 }
1238 
1239 static int
entry_equals(const Entry * e1,const Entry * e2)1240 entry_equals( const Entry*  e1, const Entry*  e2 )
1241 {
1242     DnsPacket  pack1[1], pack2[1];
1243 
1244     if (e1->querylen != e2->querylen) {
1245         return 0;
1246     }
1247     _dnsPacket_init(pack1, e1->query, e1->querylen);
1248     _dnsPacket_init(pack2, e2->query, e2->querylen);
1249 
1250     return _dnsPacket_isEqualQuery(pack1, pack2);
1251 }
1252 
1253 /****************************************************************************/
1254 /****************************************************************************/
1255 /*****                                                                  *****/
1256 /*****                                                                  *****/
1257 /*****                                                                  *****/
1258 /****************************************************************************/
1259 /****************************************************************************/
1260 
1261 /* We use a simple hash table with external collision lists
1262  * for simplicity, the hash-table fields 'hash' and 'hlink' are
1263  * inlined in the Entry structure.
1264  */
1265 
1266 /* Maximum time for a thread to wait for an pending request */
1267 #define PENDING_REQUEST_TIMEOUT 20;
1268 
1269 typedef struct pending_req_info {
1270     unsigned int                hash;
1271     pthread_cond_t              cond;
1272     struct pending_req_info*    next;
1273 } PendingReqInfo;
1274 
1275 typedef struct resolv_cache {
1276     int              max_entries;
1277     int              num_entries;
1278     Entry            mru_list;
1279     int              last_id;
1280     Entry*           entries;
1281     PendingReqInfo   pending_requests;
1282 } Cache;
1283 
1284 struct resolv_cache_info {
1285     unsigned                    netid;
1286     Cache*                      cache;
1287     struct resolv_cache_info*   next;
1288     int                         nscount;
1289     char*                       nameservers[MAXNS];
1290     struct addrinfo*            nsaddrinfo[MAXNS];
1291     int                         revision_id; // # times the nameservers have been replaced
1292     struct __res_params         params;
1293     struct __res_stats          nsstats[MAXNS];
1294     char                        defdname[MAXDNSRCHPATH];
1295     int                         dnsrch_offset[MAXDNSRCH+1];  // offsets into defdname
1296 };
1297 
1298 #define  HTABLE_VALID(x)  ((x) != NULL && (x) != HTABLE_DELETED)
1299 
1300 static pthread_once_t        _res_cache_once = PTHREAD_ONCE_INIT;
1301 static void _res_cache_init(void);
1302 
1303 // lock protecting everything in the _resolve_cache_info structs (next ptr, etc)
1304 static pthread_mutex_t _res_cache_list_lock;
1305 
1306 /* gets cache associated with a network, or NULL if none exists */
1307 static struct resolv_cache* _find_named_cache_locked(unsigned netid);
1308 
1309 static void
_cache_flush_pending_requests_locked(struct resolv_cache * cache)1310 _cache_flush_pending_requests_locked( struct resolv_cache* cache )
1311 {
1312     struct pending_req_info *ri, *tmp;
1313     if (cache) {
1314         ri = cache->pending_requests.next;
1315 
1316         while (ri) {
1317             tmp = ri;
1318             ri = ri->next;
1319             pthread_cond_broadcast(&tmp->cond);
1320 
1321             pthread_cond_destroy(&tmp->cond);
1322             free(tmp);
1323         }
1324 
1325         cache->pending_requests.next = NULL;
1326     }
1327 }
1328 
1329 /* Return 0 if no pending request is found matching the key.
1330  * If a matching request is found the calling thread will wait until
1331  * the matching request completes, then update *cache and return 1. */
1332 static int
_cache_check_pending_request_locked(struct resolv_cache ** cache,Entry * key,unsigned netid)1333 _cache_check_pending_request_locked( struct resolv_cache** cache, Entry* key, unsigned netid )
1334 {
1335     struct pending_req_info *ri, *prev;
1336     int exist = 0;
1337 
1338     if (*cache && key) {
1339         ri = (*cache)->pending_requests.next;
1340         prev = &(*cache)->pending_requests;
1341         while (ri) {
1342             if (ri->hash == key->hash) {
1343                 exist = 1;
1344                 break;
1345             }
1346             prev = ri;
1347             ri = ri->next;
1348         }
1349 
1350         if (!exist) {
1351             ri = calloc(1, sizeof(struct pending_req_info));
1352             if (ri) {
1353                 ri->hash = key->hash;
1354                 pthread_cond_init(&ri->cond, NULL);
1355                 prev->next = ri;
1356             }
1357         } else {
1358             struct timespec ts = {0,0};
1359             XLOG("Waiting for previous request");
1360             ts.tv_sec = _time_now() + PENDING_REQUEST_TIMEOUT;
1361             pthread_cond_timedwait(&ri->cond, &_res_cache_list_lock, &ts);
1362             /* Must update *cache as it could have been deleted. */
1363             *cache = _find_named_cache_locked(netid);
1364         }
1365     }
1366 
1367     return exist;
1368 }
1369 
1370 /* notify any waiting thread that waiting on a request
1371  * matching the key has been added to the cache */
1372 static void
_cache_notify_waiting_tid_locked(struct resolv_cache * cache,Entry * key)1373 _cache_notify_waiting_tid_locked( struct resolv_cache* cache, Entry* key )
1374 {
1375     struct pending_req_info *ri, *prev;
1376 
1377     if (cache && key) {
1378         ri = cache->pending_requests.next;
1379         prev = &cache->pending_requests;
1380         while (ri) {
1381             if (ri->hash == key->hash) {
1382                 pthread_cond_broadcast(&ri->cond);
1383                 break;
1384             }
1385             prev = ri;
1386             ri = ri->next;
1387         }
1388 
1389         // remove item from list and destroy
1390         if (ri) {
1391             prev->next = ri->next;
1392             pthread_cond_destroy(&ri->cond);
1393             free(ri);
1394         }
1395     }
1396 }
1397 
1398 /* notify the cache that the query failed */
1399 void
_resolv_cache_query_failed(unsigned netid,const void * query,int querylen)1400 _resolv_cache_query_failed( unsigned    netid,
1401                    const void* query,
1402                    int         querylen)
1403 {
1404     Entry    key[1];
1405     Cache*   cache;
1406 
1407     if (!entry_init_key(key, query, querylen))
1408         return;
1409 
1410     pthread_mutex_lock(&_res_cache_list_lock);
1411 
1412     cache = _find_named_cache_locked(netid);
1413 
1414     if (cache) {
1415         _cache_notify_waiting_tid_locked(cache, key);
1416     }
1417 
1418     pthread_mutex_unlock(&_res_cache_list_lock);
1419 }
1420 
1421 static struct resolv_cache_info* _find_cache_info_locked(unsigned netid);
1422 
1423 static void
_cache_flush_locked(Cache * cache)1424 _cache_flush_locked( Cache*  cache )
1425 {
1426     int     nn;
1427 
1428     for (nn = 0; nn < cache->max_entries; nn++)
1429     {
1430         Entry**  pnode = (Entry**) &cache->entries[nn];
1431 
1432         while (*pnode != NULL) {
1433             Entry*  node = *pnode;
1434             *pnode = node->hlink;
1435             entry_free(node);
1436         }
1437     }
1438 
1439     // flush pending request
1440     _cache_flush_pending_requests_locked(cache);
1441 
1442     cache->mru_list.mru_next = cache->mru_list.mru_prev = &cache->mru_list;
1443     cache->num_entries       = 0;
1444     cache->last_id           = 0;
1445 
1446     XLOG("*************************\n"
1447          "*** DNS CACHE FLUSHED ***\n"
1448          "*************************");
1449 }
1450 
1451 static int
_res_cache_get_max_entries(void)1452 _res_cache_get_max_entries( void )
1453 {
1454     int cache_size = CONFIG_MAX_ENTRIES;
1455 
1456     const char* cache_mode = getenv("ANDROID_DNS_MODE");
1457     if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
1458         // Don't use the cache in local mode. This is used by the proxy itself.
1459         cache_size = 0;
1460     }
1461 
1462     XLOG("cache size: %d", cache_size);
1463     return cache_size;
1464 }
1465 
1466 static struct resolv_cache*
_resolv_cache_create(void)1467 _resolv_cache_create( void )
1468 {
1469     struct resolv_cache*  cache;
1470 
1471     cache = calloc(sizeof(*cache), 1);
1472     if (cache) {
1473         cache->max_entries = _res_cache_get_max_entries();
1474         cache->entries = calloc(sizeof(*cache->entries), cache->max_entries);
1475         if (cache->entries) {
1476             cache->mru_list.mru_prev = cache->mru_list.mru_next = &cache->mru_list;
1477             XLOG("%s: cache created\n", __FUNCTION__);
1478         } else {
1479             free(cache);
1480             cache = NULL;
1481         }
1482     }
1483     return cache;
1484 }
1485 
1486 
1487 #if DEBUG
1488 static void
_dump_query(const uint8_t * query,int querylen)1489 _dump_query( const uint8_t*  query, int  querylen )
1490 {
1491     char       temp[256], *p=temp, *end=p+sizeof(temp);
1492     DnsPacket  pack[1];
1493 
1494     _dnsPacket_init(pack, query, querylen);
1495     p = _dnsPacket_bprintQuery(pack, p, end);
1496     XLOG("QUERY: %s", temp);
1497 }
1498 
1499 static void
_cache_dump_mru(Cache * cache)1500 _cache_dump_mru( Cache*  cache )
1501 {
1502     char    temp[512], *p=temp, *end=p+sizeof(temp);
1503     Entry*  e;
1504 
1505     p = _bprint(temp, end, "MRU LIST (%2d): ", cache->num_entries);
1506     for (e = cache->mru_list.mru_next; e != &cache->mru_list; e = e->mru_next)
1507         p = _bprint(p, end, " %d", e->id);
1508 
1509     XLOG("%s", temp);
1510 }
1511 
1512 static void
_dump_answer(const void * answer,int answerlen)1513 _dump_answer(const void* answer, int answerlen)
1514 {
1515     res_state statep;
1516     FILE* fp;
1517     char* buf;
1518     int fileLen;
1519 
1520     fp = fopen("/data/reslog.txt", "w+e");
1521     if (fp != NULL) {
1522         statep = __res_get_state();
1523 
1524         res_pquery(statep, answer, answerlen, fp);
1525 
1526         //Get file length
1527         fseek(fp, 0, SEEK_END);
1528         fileLen=ftell(fp);
1529         fseek(fp, 0, SEEK_SET);
1530         buf = (char *)malloc(fileLen+1);
1531         if (buf != NULL) {
1532             //Read file contents into buffer
1533             fread(buf, fileLen, 1, fp);
1534             XLOG("%s\n", buf);
1535             free(buf);
1536         }
1537         fclose(fp);
1538         remove("/data/reslog.txt");
1539     }
1540     else {
1541         errno = 0; // else debug is introducing error signals
1542         XLOG("%s: can't open file\n", __FUNCTION__);
1543     }
1544 }
1545 #endif
1546 
1547 #if DEBUG
1548 #  define  XLOG_QUERY(q,len)   _dump_query((q), (len))
1549 #  define  XLOG_ANSWER(a, len) _dump_answer((a), (len))
1550 #else
1551 #  define  XLOG_QUERY(q,len)   ((void)0)
1552 #  define  XLOG_ANSWER(a,len)  ((void)0)
1553 #endif
1554 
1555 /* This function tries to find a key within the hash table
1556  * In case of success, it will return a *pointer* to the hashed key.
1557  * In case of failure, it will return a *pointer* to NULL
1558  *
1559  * So, the caller must check '*result' to check for success/failure.
1560  *
1561  * The main idea is that the result can later be used directly in
1562  * calls to _resolv_cache_add or _resolv_cache_remove as the 'lookup'
1563  * parameter. This makes the code simpler and avoids re-searching
1564  * for the key position in the htable.
1565  *
1566  * The result of a lookup_p is only valid until you alter the hash
1567  * table.
1568  */
1569 static Entry**
_cache_lookup_p(Cache * cache,Entry * key)1570 _cache_lookup_p( Cache*   cache,
1571                  Entry*   key )
1572 {
1573     int      index = key->hash % cache->max_entries;
1574     Entry**  pnode = (Entry**) &cache->entries[ index ];
1575 
1576     while (*pnode != NULL) {
1577         Entry*  node = *pnode;
1578 
1579         if (node == NULL)
1580             break;
1581 
1582         if (node->hash == key->hash && entry_equals(node, key))
1583             break;
1584 
1585         pnode = &node->hlink;
1586     }
1587     return pnode;
1588 }
1589 
1590 /* Add a new entry to the hash table. 'lookup' must be the
1591  * result of an immediate previous failed _lookup_p() call
1592  * (i.e. with *lookup == NULL), and 'e' is the pointer to the
1593  * newly created entry
1594  */
1595 static void
_cache_add_p(Cache * cache,Entry ** lookup,Entry * e)1596 _cache_add_p( Cache*   cache,
1597               Entry**  lookup,
1598               Entry*   e )
1599 {
1600     *lookup = e;
1601     e->id = ++cache->last_id;
1602     entry_mru_add(e, &cache->mru_list);
1603     cache->num_entries += 1;
1604 
1605     XLOG("%s: entry %d added (count=%d)", __FUNCTION__,
1606          e->id, cache->num_entries);
1607 }
1608 
1609 /* Remove an existing entry from the hash table,
1610  * 'lookup' must be the result of an immediate previous
1611  * and succesful _lookup_p() call.
1612  */
1613 static void
_cache_remove_p(Cache * cache,Entry ** lookup)1614 _cache_remove_p( Cache*   cache,
1615                  Entry**  lookup )
1616 {
1617     Entry*  e  = *lookup;
1618 
1619     XLOG("%s: entry %d removed (count=%d)", __FUNCTION__,
1620          e->id, cache->num_entries-1);
1621 
1622     entry_mru_remove(e);
1623     *lookup = e->hlink;
1624     entry_free(e);
1625     cache->num_entries -= 1;
1626 }
1627 
1628 /* Remove the oldest entry from the hash table.
1629  */
1630 static void
_cache_remove_oldest(Cache * cache)1631 _cache_remove_oldest( Cache*  cache )
1632 {
1633     Entry*   oldest = cache->mru_list.mru_prev;
1634     Entry**  lookup = _cache_lookup_p(cache, oldest);
1635 
1636     if (*lookup == NULL) { /* should not happen */
1637         XLOG("%s: OLDEST NOT IN HTABLE ?", __FUNCTION__);
1638         return;
1639     }
1640     if (DEBUG) {
1641         XLOG("Cache full - removing oldest");
1642         XLOG_QUERY(oldest->query, oldest->querylen);
1643     }
1644     _cache_remove_p(cache, lookup);
1645 }
1646 
1647 /* Remove all expired entries from the hash table.
1648  */
_cache_remove_expired(Cache * cache)1649 static void _cache_remove_expired(Cache* cache) {
1650     Entry* e;
1651     time_t now = _time_now();
1652 
1653     for (e = cache->mru_list.mru_next; e != &cache->mru_list;) {
1654         // Entry is old, remove
1655         if (now >= e->expires) {
1656             Entry** lookup = _cache_lookup_p(cache, e);
1657             if (*lookup == NULL) { /* should not happen */
1658                 XLOG("%s: ENTRY NOT IN HTABLE ?", __FUNCTION__);
1659                 return;
1660             }
1661             e = e->mru_next;
1662             _cache_remove_p(cache, lookup);
1663         } else {
1664             e = e->mru_next;
1665         }
1666     }
1667 }
1668 
1669 ResolvCacheStatus
_resolv_cache_lookup(unsigned netid,const void * query,int querylen,void * answer,int answersize,int * answerlen)1670 _resolv_cache_lookup( unsigned              netid,
1671                       const void*           query,
1672                       int                   querylen,
1673                       void*                 answer,
1674                       int                   answersize,
1675                       int                  *answerlen )
1676 {
1677     Entry      key[1];
1678     Entry**    lookup;
1679     Entry*     e;
1680     time_t     now;
1681     Cache*     cache;
1682 
1683     ResolvCacheStatus  result = RESOLV_CACHE_NOTFOUND;
1684 
1685     XLOG("%s: lookup", __FUNCTION__);
1686     XLOG_QUERY(query, querylen);
1687 
1688     /* we don't cache malformed queries */
1689     if (!entry_init_key(key, query, querylen)) {
1690         XLOG("%s: unsupported query", __FUNCTION__);
1691         return RESOLV_CACHE_UNSUPPORTED;
1692     }
1693     /* lookup cache */
1694     pthread_once(&_res_cache_once, _res_cache_init);
1695     pthread_mutex_lock(&_res_cache_list_lock);
1696 
1697     cache = _find_named_cache_locked(netid);
1698     if (cache == NULL) {
1699         result = RESOLV_CACHE_UNSUPPORTED;
1700         goto Exit;
1701     }
1702 
1703     /* see the description of _lookup_p to understand this.
1704      * the function always return a non-NULL pointer.
1705      */
1706     lookup = _cache_lookup_p(cache, key);
1707     e      = *lookup;
1708 
1709     if (e == NULL) {
1710         XLOG( "NOT IN CACHE");
1711         // calling thread will wait if an outstanding request is found
1712         // that matching this query
1713         if (!_cache_check_pending_request_locked(&cache, key, netid) || cache == NULL) {
1714             goto Exit;
1715         } else {
1716             lookup = _cache_lookup_p(cache, key);
1717             e = *lookup;
1718             if (e == NULL) {
1719                 goto Exit;
1720             }
1721         }
1722     }
1723 
1724     now = _time_now();
1725 
1726     /* remove stale entries here */
1727     if (now >= e->expires) {
1728         XLOG( " NOT IN CACHE (STALE ENTRY %p DISCARDED)", *lookup );
1729         XLOG_QUERY(e->query, e->querylen);
1730         _cache_remove_p(cache, lookup);
1731         goto Exit;
1732     }
1733 
1734     *answerlen = e->answerlen;
1735     if (e->answerlen > answersize) {
1736         /* NOTE: we return UNSUPPORTED if the answer buffer is too short */
1737         result = RESOLV_CACHE_UNSUPPORTED;
1738         XLOG(" ANSWER TOO LONG");
1739         goto Exit;
1740     }
1741 
1742     memcpy( answer, e->answer, e->answerlen );
1743 
1744     /* bump up this entry to the top of the MRU list */
1745     if (e != cache->mru_list.mru_next) {
1746         entry_mru_remove( e );
1747         entry_mru_add( e, &cache->mru_list );
1748     }
1749 
1750     XLOG( "FOUND IN CACHE entry=%p", e );
1751     result = RESOLV_CACHE_FOUND;
1752 
1753 Exit:
1754     pthread_mutex_unlock(&_res_cache_list_lock);
1755     return result;
1756 }
1757 
1758 
1759 void
_resolv_cache_add(unsigned netid,const void * query,int querylen,const void * answer,int answerlen)1760 _resolv_cache_add( unsigned              netid,
1761                    const void*           query,
1762                    int                   querylen,
1763                    const void*           answer,
1764                    int                   answerlen )
1765 {
1766     Entry    key[1];
1767     Entry*   e;
1768     Entry**  lookup;
1769     u_long   ttl;
1770     Cache*   cache = NULL;
1771 
1772     /* don't assume that the query has already been cached
1773      */
1774     if (!entry_init_key( key, query, querylen )) {
1775         XLOG( "%s: passed invalid query ?", __FUNCTION__);
1776         return;
1777     }
1778 
1779     pthread_mutex_lock(&_res_cache_list_lock);
1780 
1781     cache = _find_named_cache_locked(netid);
1782     if (cache == NULL) {
1783         goto Exit;
1784     }
1785 
1786     XLOG( "%s: query:", __FUNCTION__ );
1787     XLOG_QUERY(query,querylen);
1788     XLOG_ANSWER(answer, answerlen);
1789 #if DEBUG_DATA
1790     XLOG( "answer:");
1791     XLOG_BYTES(answer,answerlen);
1792 #endif
1793 
1794     lookup = _cache_lookup_p(cache, key);
1795     e      = *lookup;
1796 
1797     if (e != NULL) { /* should not happen */
1798         XLOG("%s: ALREADY IN CACHE (%p) ? IGNORING ADD",
1799              __FUNCTION__, e);
1800         goto Exit;
1801     }
1802 
1803     if (cache->num_entries >= cache->max_entries) {
1804         _cache_remove_expired(cache);
1805         if (cache->num_entries >= cache->max_entries) {
1806             _cache_remove_oldest(cache);
1807         }
1808         /* need to lookup again */
1809         lookup = _cache_lookup_p(cache, key);
1810         e      = *lookup;
1811         if (e != NULL) {
1812             XLOG("%s: ALREADY IN CACHE (%p) ? IGNORING ADD",
1813                 __FUNCTION__, e);
1814             goto Exit;
1815         }
1816     }
1817 
1818     ttl = answer_getTTL(answer, answerlen);
1819     if (ttl > 0) {
1820         e = entry_alloc(key, answer, answerlen);
1821         if (e != NULL) {
1822             e->expires = ttl + _time_now();
1823             _cache_add_p(cache, lookup, e);
1824         }
1825     }
1826 #if DEBUG
1827     _cache_dump_mru(cache);
1828 #endif
1829 Exit:
1830     if (cache != NULL) {
1831       _cache_notify_waiting_tid_locked(cache, key);
1832     }
1833     pthread_mutex_unlock(&_res_cache_list_lock);
1834 }
1835 
1836 /****************************************************************************/
1837 /****************************************************************************/
1838 /*****                                                                  *****/
1839 /*****                                                                  *****/
1840 /*****                                                                  *****/
1841 /****************************************************************************/
1842 /****************************************************************************/
1843 
1844 // Head of the list of caches.  Protected by _res_cache_list_lock.
1845 static struct resolv_cache_info _res_cache_list;
1846 
1847 /* insert resolv_cache_info into the list of resolv_cache_infos */
1848 static void _insert_cache_info_locked(struct resolv_cache_info* cache_info);
1849 /* creates a resolv_cache_info */
1850 static struct resolv_cache_info* _create_cache_info( void );
1851 /* gets a resolv_cache_info associated with a network, or NULL if not found */
1852 static struct resolv_cache_info* _find_cache_info_locked(unsigned netid);
1853 /* look up the named cache, and creates one if needed */
1854 static struct resolv_cache* _get_res_cache_for_net_locked(unsigned netid);
1855 /* empty the named cache */
1856 static void _flush_cache_for_net_locked(unsigned netid);
1857 /* empty the nameservers set for the named cache */
1858 static void _free_nameservers_locked(struct resolv_cache_info* cache_info);
1859 /* return 1 if the provided list of name servers differs from the list of name servers
1860  * currently attached to the provided cache_info */
1861 static int _resolv_is_nameservers_equal_locked(struct resolv_cache_info* cache_info,
1862         const char** servers, int numservers);
1863 /* clears the stats samples contained withing the given cache_info */
1864 static void _res_cache_clear_stats_locked(struct resolv_cache_info* cache_info);
1865 
1866 static void
_res_cache_init(void)1867 _res_cache_init(void)
1868 {
1869     memset(&_res_cache_list, 0, sizeof(_res_cache_list));
1870     pthread_mutex_init(&_res_cache_list_lock, NULL);
1871 }
1872 
1873 static struct resolv_cache*
_get_res_cache_for_net_locked(unsigned netid)1874 _get_res_cache_for_net_locked(unsigned netid)
1875 {
1876     struct resolv_cache* cache = _find_named_cache_locked(netid);
1877     if (!cache) {
1878         struct resolv_cache_info* cache_info = _create_cache_info();
1879         if (cache_info) {
1880             cache = _resolv_cache_create();
1881             if (cache) {
1882                 cache_info->cache = cache;
1883                 cache_info->netid = netid;
1884                 _insert_cache_info_locked(cache_info);
1885             } else {
1886                 free(cache_info);
1887             }
1888         }
1889     }
1890     return cache;
1891 }
1892 
1893 void
_resolv_flush_cache_for_net(unsigned netid)1894 _resolv_flush_cache_for_net(unsigned netid)
1895 {
1896     pthread_once(&_res_cache_once, _res_cache_init);
1897     pthread_mutex_lock(&_res_cache_list_lock);
1898 
1899     _flush_cache_for_net_locked(netid);
1900 
1901     pthread_mutex_unlock(&_res_cache_list_lock);
1902 }
1903 
1904 static void
_flush_cache_for_net_locked(unsigned netid)1905 _flush_cache_for_net_locked(unsigned netid)
1906 {
1907     struct resolv_cache* cache = _find_named_cache_locked(netid);
1908     if (cache) {
1909         _cache_flush_locked(cache);
1910     }
1911 
1912     // Also clear the NS statistics.
1913     struct resolv_cache_info* cache_info = _find_cache_info_locked(netid);
1914     _res_cache_clear_stats_locked(cache_info);
1915 }
1916 
_resolv_delete_cache_for_net(unsigned netid)1917 void _resolv_delete_cache_for_net(unsigned netid)
1918 {
1919     pthread_once(&_res_cache_once, _res_cache_init);
1920     pthread_mutex_lock(&_res_cache_list_lock);
1921 
1922     struct resolv_cache_info* prev_cache_info = &_res_cache_list;
1923 
1924     while (prev_cache_info->next) {
1925         struct resolv_cache_info* cache_info = prev_cache_info->next;
1926 
1927         if (cache_info->netid == netid) {
1928             prev_cache_info->next = cache_info->next;
1929             _cache_flush_locked(cache_info->cache);
1930             free(cache_info->cache->entries);
1931             free(cache_info->cache);
1932             _free_nameservers_locked(cache_info);
1933             free(cache_info);
1934             break;
1935         }
1936 
1937         prev_cache_info = prev_cache_info->next;
1938     }
1939 
1940     pthread_mutex_unlock(&_res_cache_list_lock);
1941 }
1942 
1943 static struct resolv_cache_info*
_create_cache_info(void)1944 _create_cache_info(void)
1945 {
1946     struct resolv_cache_info* cache_info;
1947 
1948     cache_info = calloc(sizeof(*cache_info), 1);
1949     return cache_info;
1950 }
1951 
1952 static void
_insert_cache_info_locked(struct resolv_cache_info * cache_info)1953 _insert_cache_info_locked(struct resolv_cache_info* cache_info)
1954 {
1955     struct resolv_cache_info* last;
1956 
1957     for (last = &_res_cache_list; last->next; last = last->next);
1958 
1959     last->next = cache_info;
1960 
1961 }
1962 
1963 static struct resolv_cache*
_find_named_cache_locked(unsigned netid)1964 _find_named_cache_locked(unsigned netid) {
1965 
1966     struct resolv_cache_info* info = _find_cache_info_locked(netid);
1967 
1968     if (info != NULL) return info->cache;
1969 
1970     return NULL;
1971 }
1972 
1973 static struct resolv_cache_info*
_find_cache_info_locked(unsigned netid)1974 _find_cache_info_locked(unsigned netid)
1975 {
1976     struct resolv_cache_info* cache_info = _res_cache_list.next;
1977 
1978     while (cache_info) {
1979         if (cache_info->netid == netid) {
1980             break;
1981         }
1982 
1983         cache_info = cache_info->next;
1984     }
1985     return cache_info;
1986 }
1987 
1988 void
_resolv_set_default_params(struct __res_params * params)1989 _resolv_set_default_params(struct __res_params* params) {
1990     params->sample_validity = NSSAMPLE_VALIDITY;
1991     params->success_threshold = SUCCESS_THRESHOLD;
1992     params->min_samples = 0;
1993     params->max_samples = 0;
1994     params->base_timeout_msec = 0;  // 0 = legacy algorithm
1995 }
1996 
1997 int
_resolv_set_nameservers_for_net(unsigned netid,const char ** servers,unsigned numservers,const char * domains,const struct __res_params * params)1998 _resolv_set_nameservers_for_net(unsigned netid, const char** servers, unsigned numservers,
1999         const char *domains, const struct __res_params* params)
2000 {
2001     char sbuf[NI_MAXSERV];
2002     register char *cp;
2003     int *offset;
2004     struct addrinfo* nsaddrinfo[MAXNS];
2005 
2006     if (numservers > MAXNS) {
2007         XLOG("%s: numservers=%u, MAXNS=%u", __FUNCTION__, numservers, MAXNS);
2008         return E2BIG;
2009     }
2010 
2011     // Parse the addresses before actually locking or changing any state, in case there is an error.
2012     // As a side effect this also reduces the time the lock is kept.
2013     struct addrinfo hints = {
2014         .ai_family = AF_UNSPEC,
2015         .ai_socktype = SOCK_DGRAM,
2016         .ai_flags = AI_NUMERICHOST
2017     };
2018     snprintf(sbuf, sizeof(sbuf), "%u", NAMESERVER_PORT);
2019     for (unsigned i = 0; i < numservers; i++) {
2020         // The addrinfo structures allocated here are freed in _free_nameservers_locked().
2021         int rt = getaddrinfo(servers[i], sbuf, &hints, &nsaddrinfo[i]);
2022         if (rt != 0) {
2023             for (unsigned j = 0 ; j < i ; j++) {
2024                 freeaddrinfo(nsaddrinfo[j]);
2025                 nsaddrinfo[j] = NULL;
2026             }
2027             XLOG("%s: getaddrinfo(%s)=%s", __FUNCTION__, servers[i], gai_strerror(rt));
2028             return EINVAL;
2029         }
2030     }
2031 
2032     pthread_once(&_res_cache_once, _res_cache_init);
2033     pthread_mutex_lock(&_res_cache_list_lock);
2034 
2035     // creates the cache if not created
2036     _get_res_cache_for_net_locked(netid);
2037 
2038     struct resolv_cache_info* cache_info = _find_cache_info_locked(netid);
2039 
2040     if (cache_info != NULL) {
2041         uint8_t old_max_samples = cache_info->params.max_samples;
2042         if (params != NULL) {
2043             cache_info->params = *params;
2044         } else {
2045             _resolv_set_default_params(&cache_info->params);
2046         }
2047 
2048         if (!_resolv_is_nameservers_equal_locked(cache_info, servers, numservers)) {
2049             // free current before adding new
2050             _free_nameservers_locked(cache_info);
2051             unsigned i;
2052             for (i = 0; i < numservers; i++) {
2053                 cache_info->nsaddrinfo[i] = nsaddrinfo[i];
2054                 cache_info->nameservers[i] = strdup(servers[i]);
2055                 XLOG("%s: netid = %u, addr = %s\n", __FUNCTION__, netid, servers[i]);
2056             }
2057             cache_info->nscount = numservers;
2058 
2059             // Clear the NS statistics because the mapping to nameservers might have changed.
2060             _res_cache_clear_stats_locked(cache_info);
2061 
2062             // increment the revision id to ensure that sample state is not written back if the
2063             // servers change; in theory it would suffice to do so only if the servers or
2064             // max_samples actually change, in practice the overhead of checking is higher than the
2065             // cost, and overflows are unlikely
2066             ++cache_info->revision_id;
2067         } else {
2068             if (cache_info->params.max_samples != old_max_samples) {
2069                 // If the maximum number of samples changes, the overhead of keeping the most recent
2070                 // samples around is not considered worth the effort, so they are cleared instead.
2071                 // All other parameters do not affect shared state: Changing these parameters does
2072                 // not invalidate the samples, as they only affect aggregation and the conditions
2073                 // under which servers are considered usable.
2074                 _res_cache_clear_stats_locked(cache_info);
2075                 ++cache_info->revision_id;
2076             }
2077             for (unsigned j = 0; j < numservers; j++) {
2078                 freeaddrinfo(nsaddrinfo[j]);
2079             }
2080         }
2081 
2082         // Always update the search paths, since determining whether they actually changed is
2083         // complex due to the zero-padding, and probably not worth the effort. Cache-flushing
2084         // however is not // necessary, since the stored cache entries do contain the domain, not
2085         // just the host name.
2086         // code moved from res_init.c, load_domain_search_list
2087         strlcpy(cache_info->defdname, domains, sizeof(cache_info->defdname));
2088         if ((cp = strchr(cache_info->defdname, '\n')) != NULL)
2089             *cp = '\0';
2090 
2091         cp = cache_info->defdname;
2092         offset = cache_info->dnsrch_offset;
2093         while (offset < cache_info->dnsrch_offset + MAXDNSRCH) {
2094             while (*cp == ' ' || *cp == '\t') /* skip leading white space */
2095                 cp++;
2096             if (*cp == '\0') /* stop if nothing more to do */
2097                 break;
2098             *offset++ = cp - cache_info->defdname; /* record this search domain */
2099             while (*cp) { /* zero-terminate it */
2100                 if (*cp == ' '|| *cp == '\t') {
2101                     *cp++ = '\0';
2102                     break;
2103                 }
2104                 cp++;
2105             }
2106         }
2107         *offset = -1; /* cache_info->dnsrch_offset has MAXDNSRCH+1 items */
2108     }
2109 
2110     pthread_mutex_unlock(&_res_cache_list_lock);
2111     return 0;
2112 }
2113 
2114 static int
_resolv_is_nameservers_equal_locked(struct resolv_cache_info * cache_info,const char ** servers,int numservers)2115 _resolv_is_nameservers_equal_locked(struct resolv_cache_info* cache_info,
2116         const char** servers, int numservers)
2117 {
2118     if (cache_info->nscount != numservers) {
2119         return 0;
2120     }
2121 
2122     // Compare each name server against current name servers.
2123     // TODO: this is incorrect if the list of current or previous nameservers
2124     // contains duplicates. This does not really matter because the framework
2125     // filters out duplicates, but we should probably fix it. It's also
2126     // insensitive to the order of the nameservers; we should probably fix that
2127     // too.
2128     for (int i = 0; i < numservers; i++) {
2129         for (int j = 0 ; ; j++) {
2130             if (j >= numservers) {
2131                 return 0;
2132             }
2133             if (strcmp(cache_info->nameservers[i], servers[j]) == 0) {
2134                 break;
2135             }
2136         }
2137     }
2138 
2139     return 1;
2140 }
2141 
2142 static void
_free_nameservers_locked(struct resolv_cache_info * cache_info)2143 _free_nameservers_locked(struct resolv_cache_info* cache_info)
2144 {
2145     int i;
2146     for (i = 0; i < cache_info->nscount; i++) {
2147         free(cache_info->nameservers[i]);
2148         cache_info->nameservers[i] = NULL;
2149         if (cache_info->nsaddrinfo[i] != NULL) {
2150             freeaddrinfo(cache_info->nsaddrinfo[i]);
2151             cache_info->nsaddrinfo[i] = NULL;
2152         }
2153         cache_info->nsstats[i].sample_count =
2154             cache_info->nsstats[i].sample_next = 0;
2155     }
2156     cache_info->nscount = 0;
2157     _res_cache_clear_stats_locked(cache_info);
2158     ++cache_info->revision_id;
2159 }
2160 
2161 void
_resolv_populate_res_for_net(res_state statp)2162 _resolv_populate_res_for_net(res_state statp)
2163 {
2164     if (statp == NULL) {
2165         return;
2166     }
2167 
2168     pthread_once(&_res_cache_once, _res_cache_init);
2169     pthread_mutex_lock(&_res_cache_list_lock);
2170 
2171     struct resolv_cache_info* info = _find_cache_info_locked(statp->netid);
2172     if (info != NULL) {
2173         int nserv;
2174         struct addrinfo* ai;
2175         XLOG("%s: %u\n", __FUNCTION__, statp->netid);
2176         for (nserv = 0; nserv < MAXNS; nserv++) {
2177             ai = info->nsaddrinfo[nserv];
2178             if (ai == NULL) {
2179                 break;
2180             }
2181 
2182             if ((size_t) ai->ai_addrlen <= sizeof(statp->_u._ext.ext->nsaddrs[0])) {
2183                 if (statp->_u._ext.ext != NULL) {
2184                     memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen);
2185                     statp->nsaddr_list[nserv].sin_family = AF_UNSPEC;
2186                 } else {
2187                     if ((size_t) ai->ai_addrlen
2188                             <= sizeof(statp->nsaddr_list[0])) {
2189                         memcpy(&statp->nsaddr_list[nserv], ai->ai_addr,
2190                                 ai->ai_addrlen);
2191                     } else {
2192                         statp->nsaddr_list[nserv].sin_family = AF_UNSPEC;
2193                     }
2194                 }
2195             } else {
2196                 XLOG("%s: found too long addrlen", __FUNCTION__);
2197             }
2198         }
2199         statp->nscount = nserv;
2200         // now do search domains.  Note that we cache the offsets as this code runs alot
2201         // but the setting/offset-computer only runs when set/changed
2202         // WARNING: Don't use str*cpy() here, this string contains zeroes.
2203         memcpy(statp->defdname, info->defdname, sizeof(statp->defdname));
2204         register char **pp = statp->dnsrch;
2205         register int *p = info->dnsrch_offset;
2206         while (pp < statp->dnsrch + MAXDNSRCH && *p != -1) {
2207             *pp++ = &statp->defdname[0] + *p++;
2208         }
2209     }
2210     pthread_mutex_unlock(&_res_cache_list_lock);
2211 }
2212 
2213 /* Resolver reachability statistics. */
2214 
2215 static void
_res_cache_add_stats_sample_locked(struct __res_stats * stats,const struct __res_sample * sample,int max_samples)2216 _res_cache_add_stats_sample_locked(struct __res_stats* stats, const struct __res_sample* sample,
2217         int max_samples) {
2218     // Note: This function expects max_samples > 0, otherwise a (harmless) modification of the
2219     // allocated but supposedly unused memory for samples[0] will happen
2220     XLOG("%s: adding sample to stats, next = %d, count = %d", __FUNCTION__,
2221             stats->sample_next, stats->sample_count);
2222     stats->samples[stats->sample_next] = *sample;
2223     if (stats->sample_count < max_samples) {
2224         ++stats->sample_count;
2225     }
2226     if (++stats->sample_next >= max_samples) {
2227         stats->sample_next = 0;
2228     }
2229 }
2230 
2231 static void
_res_cache_clear_stats_locked(struct resolv_cache_info * cache_info)2232 _res_cache_clear_stats_locked(struct resolv_cache_info* cache_info) {
2233     if (cache_info) {
2234         for (int i = 0 ; i < MAXNS ; ++i) {
2235             cache_info->nsstats->sample_count = cache_info->nsstats->sample_next = 0;
2236         }
2237     }
2238 }
2239 
2240 int
android_net_res_stats_get_info_for_net(unsigned netid,int * nscount,struct sockaddr_storage servers[MAXNS],int * dcount,char domains[MAXDNSRCH][MAXDNSRCHPATH],struct __res_params * params,struct __res_stats stats[MAXNS])2241 android_net_res_stats_get_info_for_net(unsigned netid, int* nscount,
2242         struct sockaddr_storage servers[MAXNS], int* dcount, char domains[MAXDNSRCH][MAXDNSRCHPATH],
2243         struct __res_params* params, struct __res_stats stats[MAXNS]) {
2244     int revision_id = -1;
2245     pthread_mutex_lock(&_res_cache_list_lock);
2246 
2247     struct resolv_cache_info* info = _find_cache_info_locked(netid);
2248     if (info) {
2249         if (info->nscount > MAXNS) {
2250             pthread_mutex_unlock(&_res_cache_list_lock);
2251             XLOG("%s: nscount %d > MAXNS %d", __FUNCTION__, info->nscount, MAXNS);
2252             errno = EFAULT;
2253             return -1;
2254         }
2255         int i;
2256         for (i = 0; i < info->nscount; i++) {
2257             // Verify that the following assumptions are held, failure indicates corruption:
2258             //  - getaddrinfo() may never return a sockaddr > sockaddr_storage
2259             //  - all addresses are valid
2260             //  - there is only one address per addrinfo thanks to numeric resolution
2261             int addrlen = info->nsaddrinfo[i]->ai_addrlen;
2262             if (addrlen < (int) sizeof(struct sockaddr) ||
2263                     addrlen > (int) sizeof(servers[0])) {
2264                 pthread_mutex_unlock(&_res_cache_list_lock);
2265                 XLOG("%s: nsaddrinfo[%d].ai_addrlen == %d", __FUNCTION__, i, addrlen);
2266                 errno = EMSGSIZE;
2267                 return -1;
2268             }
2269             if (info->nsaddrinfo[i]->ai_addr == NULL) {
2270                 pthread_mutex_unlock(&_res_cache_list_lock);
2271                 XLOG("%s: nsaddrinfo[%d].ai_addr == NULL", __FUNCTION__, i);
2272                 errno = ENOENT;
2273                 return -1;
2274             }
2275             if (info->nsaddrinfo[i]->ai_next != NULL) {
2276                 pthread_mutex_unlock(&_res_cache_list_lock);
2277                 XLOG("%s: nsaddrinfo[%d].ai_next != NULL", __FUNCTION__, i);
2278                 errno = ENOTUNIQ;
2279                 return -1;
2280             }
2281         }
2282         *nscount = info->nscount;
2283         for (i = 0; i < info->nscount; i++) {
2284             memcpy(&servers[i], info->nsaddrinfo[i]->ai_addr, info->nsaddrinfo[i]->ai_addrlen);
2285             stats[i] = info->nsstats[i];
2286         }
2287         for (i = 0; i < MAXDNSRCH; i++) {
2288             const char* cur_domain = info->defdname + info->dnsrch_offset[i];
2289             // dnsrch_offset[i] can either be -1 or point to an empty string to indicate the end
2290             // of the search offsets. Checking for < 0 is not strictly necessary, but safer.
2291             // TODO: Pass in a search domain array instead of a string to
2292             // _resolv_set_nameservers_for_net() and make this double check unnecessary.
2293             if (info->dnsrch_offset[i] < 0 ||
2294                     ((size_t)info->dnsrch_offset[i]) >= sizeof(info->defdname) || !cur_domain[0]) {
2295                 break;
2296             }
2297             strlcpy(domains[i], cur_domain, MAXDNSRCHPATH);
2298         }
2299         *dcount = i;
2300         *params = info->params;
2301         revision_id = info->revision_id;
2302     }
2303 
2304     pthread_mutex_unlock(&_res_cache_list_lock);
2305     return revision_id;
2306 }
2307 
2308 int
_resolv_cache_get_resolver_stats(unsigned netid,struct __res_params * params,struct __res_stats stats[MAXNS])2309 _resolv_cache_get_resolver_stats( unsigned netid, struct __res_params* params,
2310         struct __res_stats stats[MAXNS]) {
2311     int revision_id = -1;
2312     pthread_mutex_lock(&_res_cache_list_lock);
2313 
2314     struct resolv_cache_info* info = _find_cache_info_locked(netid);
2315     if (info) {
2316         memcpy(stats, info->nsstats, sizeof(info->nsstats));
2317         *params = info->params;
2318         revision_id = info->revision_id;
2319     }
2320 
2321     pthread_mutex_unlock(&_res_cache_list_lock);
2322     return revision_id;
2323 }
2324 
2325 void
_resolv_cache_add_resolver_stats_sample(unsigned netid,int revision_id,int ns,const struct __res_sample * sample,int max_samples)2326 _resolv_cache_add_resolver_stats_sample( unsigned netid, int revision_id, int ns,
2327        const struct __res_sample* sample, int max_samples) {
2328     if (max_samples <= 0) return;
2329 
2330     pthread_mutex_lock(&_res_cache_list_lock);
2331 
2332     struct resolv_cache_info* info = _find_cache_info_locked(netid);
2333 
2334     if (info && info->revision_id == revision_id) {
2335         _res_cache_add_stats_sample_locked(&info->nsstats[ns], sample, max_samples);
2336     }
2337 
2338     pthread_mutex_unlock(&_res_cache_list_lock);
2339 }
2340