• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; version 2 dated June, 1991, or
6    (at your option) version 3 dated 29 June, 2007.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 */
16 
17 #include "dnsmasq.h"
18 
19 static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
20 #ifdef HAVE_DHCP
21 static struct crec* dhcp_spare = NULL;
22 #endif
23 static struct crec* new_chain = NULL;
24 static int cache_inserted = 0, cache_live_freed = 0, insert_error;
25 static union bigname* big_free = NULL;
26 static int bignames_left, hash_size;
27 static int uid = 0;
28 static char* addrbuff = NULL;
29 
30 /* type->string mapping: this is also used by the name-hash function as a mixing table. */
31 static const struct {
32     unsigned int type;
33     const char* const name;
34 } typestr[] = {{1, "A"},      {2, "NS"},        {5, "CNAME"},   {6, "SOA"},     {10, "NULL"},
35                {11, "WKS"},   {12, "PTR"},      {13, "HINFO"},  {15, "MX"},     {16, "TXT"},
36                {22, "NSAP"},  {23, "NSAP_PTR"}, {24, "SIG"},    {25, "KEY"},    {28, "AAAA"},
37                {33, "SRV"},   {35, "NAPTR"},    {36, "KX"},     {37, "CERT"},   {38, "A6"},
38                {39, "DNAME"}, {41, "OPT"},      {48, "DNSKEY"}, {249, "TKEY"},  {250, "TSIG"},
39                {251, "IXFR"}, {252, "AXFR"},    {253, "MAILB"}, {254, "MAILA"}, {255, "ANY"}};
40 
41 static void cache_free(struct crec* crecp);
42 static void cache_unlink(struct crec* crecp);
43 static void cache_link(struct crec* crecp);
44 static void rehash(int size);
45 static void cache_hash(struct crec* crecp);
46 
cache_init(void)47 void cache_init(void) {
48     struct crec* crecp;
49     int i;
50 
51     if (daemon->options & OPT_LOG) addrbuff = safe_malloc(ADDRSTRLEN);
52 
53     bignames_left = daemon->cachesize / 10;
54 
55     if (daemon->cachesize > 0) {
56         crecp = safe_malloc(daemon->cachesize * sizeof(struct crec));
57 
58         for (i = 0; i < daemon->cachesize; i++, crecp++) {
59             cache_link(crecp);
60             crecp->flags = 0;
61             crecp->uid = uid++;
62         }
63     }
64 
65     /* create initial hash table*/
66     rehash(daemon->cachesize);
67 }
68 
69 /* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
70    but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
71    will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
72    expand the table. */
rehash(int size)73 static void rehash(int size) {
74     struct crec** new, **old, *p, *tmp;
75     int i, new_size, old_size;
76 
77     /* hash_size is a power of two. */
78     for (new_size = 64; new_size < size / 10; new_size = new_size << 1)
79         ;
80 
81     /* must succeed in getting first instance, failure later is non-fatal */
82     if (!hash_table)
83         new = safe_malloc(new_size * sizeof(struct crec*));
84     else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec*))))
85         return;
86 
87     for (i = 0; i < new_size; i++) new[i] = NULL;
88 
89     old = hash_table;
90     old_size = hash_size;
91     hash_table = new;
92     hash_size = new_size;
93 
94     if (old) {
95         for (i = 0; i < old_size; i++)
96             for (p = old[i]; p; p = tmp) {
97                 tmp = p->hash_next;
98                 cache_hash(p);
99             }
100         free(old);
101     }
102 }
103 
hash_bucket(char * name)104 static struct crec** hash_bucket(char* name) {
105     unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
106     const unsigned char* mix_tab = (const unsigned char*) typestr;
107 
108     while ((c = (unsigned char) *name++)) {
109         /* don't use tolower and friends here - they may be messed up by LOCALE */
110         if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
111         val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
112     }
113 
114     /* hash_size is a power of two */
115     return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
116 }
117 
cache_hash(struct crec * crecp)118 static void cache_hash(struct crec* crecp) {
119     /* maintain an invariant that all entries with F_REVERSE set
120        are at the start of the hash-chain  and all non-reverse
121        immortal entries are at the end of the hash-chain.
122        This allows reverse searches and garbage collection to be optimised */
123 
124     struct crec** up = hash_bucket(cache_get_name(crecp));
125 
126     if (!(crecp->flags & F_REVERSE)) {
127         while (*up && ((*up)->flags & F_REVERSE)) up = &((*up)->hash_next);
128 
129         if (crecp->flags & F_IMMORTAL)
130             while (*up && !((*up)->flags & F_IMMORTAL)) up = &((*up)->hash_next);
131     }
132     crecp->hash_next = *up;
133     *up = crecp;
134 }
135 
cache_free(struct crec * crecp)136 static void cache_free(struct crec* crecp) {
137     crecp->flags &= ~F_FORWARD;
138     crecp->flags &= ~F_REVERSE;
139     crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
140 
141     if (cache_tail)
142         cache_tail->next = crecp;
143     else
144         cache_head = crecp;
145     crecp->prev = cache_tail;
146     crecp->next = NULL;
147     cache_tail = crecp;
148 
149     /* retrieve big name for further use. */
150     if (crecp->flags & F_BIGNAME) {
151         crecp->name.bname->next = big_free;
152         big_free = crecp->name.bname;
153         crecp->flags &= ~F_BIGNAME;
154     }
155 }
156 
157 /* insert a new cache entry at the head of the list (youngest entry) */
cache_link(struct crec * crecp)158 static void cache_link(struct crec* crecp) {
159     if (cache_head) /* check needed for init code */
160         cache_head->prev = crecp;
161     crecp->next = cache_head;
162     crecp->prev = NULL;
163     cache_head = crecp;
164     if (!cache_tail) cache_tail = crecp;
165 }
166 
167 /* remove an arbitrary cache entry for promotion */
cache_unlink(struct crec * crecp)168 static void cache_unlink(struct crec* crecp) {
169     if (crecp->prev)
170         crecp->prev->next = crecp->next;
171     else
172         cache_head = crecp->next;
173 
174     if (crecp->next)
175         crecp->next->prev = crecp->prev;
176     else
177         cache_tail = crecp->prev;
178 }
179 
cache_get_name(struct crec * crecp)180 char* cache_get_name(struct crec* crecp) {
181     if (crecp->flags & F_BIGNAME)
182         return crecp->name.bname->name;
183     else if (crecp->flags & (F_DHCP | F_CONFIG))
184         return crecp->name.namep;
185 
186     return crecp->name.sname;
187 }
188 
is_outdated_cname_pointer(struct crec * crecp)189 static int is_outdated_cname_pointer(struct crec* crecp) {
190     if (!(crecp->flags & F_CNAME)) return 0;
191 
192     if (crecp->addr.cname.cache && crecp->addr.cname.uid == crecp->addr.cname.cache->uid) return 0;
193 
194     return 1;
195 }
196 
is_expired(time_t now,struct crec * crecp)197 static int is_expired(time_t now, struct crec* crecp) {
198     if (crecp->flags & F_IMMORTAL) return 0;
199 
200     if (difftime(now, crecp->ttd) < 0) return 0;
201 
202     return 1;
203 }
204 
cache_scan_free(char * name,struct all_addr * addr,time_t now,unsigned short flags)205 static int cache_scan_free(char* name, struct all_addr* addr, time_t now, unsigned short flags) {
206     /* Scan and remove old entries.
207        If (flags & F_FORWARD) then remove any forward entries for name and any expired
208        entries but only in the same hash bucket as name.
209        If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
210        entries in the whole cache.
211        If (flags == 0) remove any expired entries in the whole cache.
212 
213        In the flags & F_FORWARD case, the return code is valid, and returns zero if the
214        name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
215 
216        We take advantage of the fact that hash chains have stuff in the order
217        <reverse>,<other>,<immortal> so that when we hit an entry which isn't reverse and is
218        immortal, we're done. */
219 
220     struct crec *crecp, **up;
221 
222     if (flags & F_FORWARD) {
223         for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
224             if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp)) {
225                 *up = crecp->hash_next;
226                 if (!(crecp->flags & (F_HOSTS | F_DHCP))) {
227                     cache_unlink(crecp);
228                     cache_free(crecp);
229                 }
230             } else if ((crecp->flags & F_FORWARD) &&
231                        ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
232                         ((crecp->flags | flags) & F_CNAME)) &&
233                        hostname_isequal(cache_get_name(crecp), name)) {
234                 if (crecp->flags & (F_HOSTS | F_DHCP)) return 0;
235                 *up = crecp->hash_next;
236                 cache_unlink(crecp);
237                 cache_free(crecp);
238             } else
239                 up = &crecp->hash_next;
240     } else {
241         int i;
242 #ifdef HAVE_IPV6
243         int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
244 #else
245         int addrlen = INADDRSZ;
246 #endif
247         for (i = 0; i < hash_size; i++)
248             for (crecp = hash_table[i], up = &hash_table[i];
249                  crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
250                  crecp = crecp->hash_next)
251                 if (is_expired(now, crecp)) {
252                     *up = crecp->hash_next;
253                     if (!(crecp->flags & (F_HOSTS | F_DHCP))) {
254                         cache_unlink(crecp);
255                         cache_free(crecp);
256                     }
257                 } else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
258                            (flags & crecp->flags & F_REVERSE) &&
259                            (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
260                            memcmp(&crecp->addr.addr, addr, addrlen) == 0) {
261                     *up = crecp->hash_next;
262                     cache_unlink(crecp);
263                     cache_free(crecp);
264                 } else
265                     up = &crecp->hash_next;
266     }
267 
268     return 1;
269 }
270 
271 /* Note: The normal calling sequence is
272    cache_start_insert
273    cache_insert * n
274    cache_end_insert
275 
276    but an abort can cause the cache_end_insert to be missed
277    in which can the next cache_start_insert cleans things up. */
278 
cache_start_insert(void)279 void cache_start_insert(void) {
280     /* Free any entries which didn't get committed during the last
281        insert due to error.
282     */
283     while (new_chain) {
284         struct crec* tmp = new_chain->next;
285         cache_free(new_chain);
286         new_chain = tmp;
287     }
288     new_chain = NULL;
289     insert_error = 0;
290 }
291 
cache_insert(char * name,struct all_addr * addr,time_t now,unsigned long ttl,unsigned short flags)292 struct crec* cache_insert(char* name, struct all_addr* addr, time_t now, unsigned long ttl,
293                           unsigned short flags) {
294     struct crec* new;
295     union bigname* big_name = NULL;
296     int freed_all = flags & F_REVERSE;
297     int free_avail = 0;
298 
299     log_query(flags | F_UPSTREAM, name, addr, NULL);
300 
301     /* CONFIG bit means something else when stored in cache entries */
302     flags &= ~F_CONFIG;
303 
304     /* if previous insertion failed give up now. */
305     if (insert_error) return NULL;
306 
307     /* First remove any expired entries and entries for the name/address we
308        are currently inserting. Fail is we attempt to delete a name from
309        /etc/hosts or DHCP. */
310     if (!cache_scan_free(name, addr, now, flags)) {
311         insert_error = 1;
312         return NULL;
313     }
314 
315     /* Now get a cache entry from the end of the LRU list */
316     while (1) {
317         if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
318         {
319             insert_error = 1;
320             return NULL;
321         }
322 
323         /* End of LRU list is still in use: if we didn't scan all the hash
324            chains for expired entries do that now. If we already tried that
325            then it's time to start spilling things. */
326 
327         if (new->flags&(F_FORWARD | F_REVERSE)) {
328             /* If free_avail set, we believe that an entry has been freed.
329                Bugs have been known to make this not true, resulting in
330                a tight loop here. If that happens, abandon the
331                insert. Once in this state, all inserts will probably fail. */
332             if (free_avail) {
333                 insert_error = 1;
334                 return NULL;
335             }
336 
337             if (freed_all) {
338                 free_avail = 1; /* Must be free space now. */
339                 cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
340                 cache_live_freed++;
341             } else {
342                 cache_scan_free(NULL, NULL, now, 0);
343                 freed_all = 1;
344             }
345             continue;
346         }
347 
348         /* Check if we need to and can allocate extra memory for a long name.
349            If that fails, give up now. */
350         if (name && (strlen(name) > SMALLDNAME - 1)) {
351             if (big_free) {
352                 big_name = big_free;
353                 big_free = big_free->next;
354             } else if (!bignames_left ||
355                        !(big_name = (union bigname*) whine_malloc(sizeof(union bigname)))) {
356                 insert_error = 1;
357                 return NULL;
358             } else
359                 bignames_left--;
360         }
361 
362         /* Got the rest: finally grab entry. */
363         cache_unlink(new);
364         break;
365     }
366 
367     new->flags = flags;
368     if (big_name) {
369         new->name.bname = big_name;
370         new->flags |= F_BIGNAME;
371     }
372 
373     if (name)
374         strcpy(cache_get_name(new), name);
375     else
376         *cache_get_name(new) = 0;
377 
378     if (addr)
379         new->addr.addr = *addr;
380     else
381         new->addr.cname.cache = NULL;
382 
383     new->ttd = now + (time_t) ttl;
384     new->next = new_chain;
385     new_chain = new;
386 
387     return new;
388 }
389 
390 /* after end of insertion, commit the new entries */
cache_end_insert(void)391 void cache_end_insert(void) {
392     if (insert_error) return;
393 
394     while (new_chain) {
395         struct crec* tmp = new_chain->next;
396         /* drop CNAMEs which didn't find a target. */
397         if (is_outdated_cname_pointer(new_chain))
398             cache_free(new_chain);
399         else {
400             cache_hash(new_chain);
401             cache_link(new_chain);
402             cache_inserted++;
403         }
404         new_chain = tmp;
405     }
406     new_chain = NULL;
407 }
408 
cache_find_by_name(struct crec * crecp,char * name,time_t now,unsigned short prot)409 struct crec* cache_find_by_name(struct crec* crecp, char* name, time_t now, unsigned short prot) {
410     struct crec* ans;
411 
412     if (crecp) /* iterating */
413         ans = crecp->next;
414     else {
415         /* first search, look for relevant entries and push to top of list
416        also free anything which has expired */
417         struct crec *next, **up, **insert = NULL, **chainp = &ans;
418         int ins_flags = 0;
419 
420         for (up = hash_bucket(name), crecp = *up; crecp; crecp = next) {
421             next = crecp->hash_next;
422 
423             if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp)) {
424                 if ((crecp->flags & F_FORWARD) && (crecp->flags & prot) &&
425                     hostname_isequal(cache_get_name(crecp), name)) {
426                     if (crecp->flags & (F_HOSTS | F_DHCP)) {
427                         *chainp = crecp;
428                         chainp = &crecp->next;
429                     } else {
430                         cache_unlink(crecp);
431                         cache_link(crecp);
432                     }
433 
434                     /* Move all but the first entry up the hash chain
435                        this implements round-robin.
436                        Make sure that re-ordering doesn't break the hash-chain
437                        order invariants.
438                     */
439                     if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags) {
440                         *up = crecp->hash_next;
441                         crecp->hash_next = *insert;
442                         *insert = crecp;
443                         insert = &crecp->hash_next;
444                     } else {
445                         if (!insert) {
446                             insert = up;
447                             ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
448                         }
449                         up = &crecp->hash_next;
450                     }
451                 } else
452                     /* case : not expired, incorrect entry. */
453                     up = &crecp->hash_next;
454             } else {
455                 /* expired entry, free it */
456                 *up = crecp->hash_next;
457                 if (!(crecp->flags & (F_HOSTS | F_DHCP))) {
458                     cache_unlink(crecp);
459                     cache_free(crecp);
460                 }
461             }
462         }
463 
464         *chainp = cache_head;
465     }
466 
467     if (ans && (ans->flags & F_FORWARD) && (ans->flags & prot) &&
468         hostname_isequal(cache_get_name(ans), name))
469         return ans;
470 
471     return NULL;
472 }
473 
cache_find_by_addr(struct crec * crecp,struct all_addr * addr,time_t now,unsigned short prot)474 struct crec* cache_find_by_addr(struct crec* crecp, struct all_addr* addr, time_t now,
475                                 unsigned short prot) {
476     struct crec* ans;
477 #ifdef HAVE_IPV6
478     int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
479 #else
480     int addrlen = INADDRSZ;
481 #endif
482 
483     if (crecp) /* iterating */
484         ans = crecp->next;
485     else {
486         /* first search, look for relevant entries and push to top of list
487        also free anything which has expired. All the reverse entries are at the
488        start of the hash chain, so we can give up when we find the first
489        non-REVERSE one.  */
490         int i;
491         struct crec **up, **chainp = &ans;
492 
493         for (i = 0; i < hash_size; i++)
494             for (crecp = hash_table[i], up = &hash_table[i]; crecp && (crecp->flags & F_REVERSE);
495                  crecp = crecp->hash_next)
496                 if (!is_expired(now, crecp)) {
497                     if ((crecp->flags & prot) && memcmp(&crecp->addr.addr, addr, addrlen) == 0) {
498                         if (crecp->flags & (F_HOSTS | F_DHCP)) {
499                             *chainp = crecp;
500                             chainp = &crecp->next;
501                         } else {
502                             cache_unlink(crecp);
503                             cache_link(crecp);
504                         }
505                     }
506                     up = &crecp->hash_next;
507                 } else {
508                     *up = crecp->hash_next;
509                     if (!(crecp->flags & (F_HOSTS | F_DHCP))) {
510                         cache_unlink(crecp);
511                         cache_free(crecp);
512                     }
513                 }
514 
515         *chainp = cache_head;
516     }
517 
518     if (ans && (ans->flags & F_REVERSE) && (ans->flags & prot) &&
519         memcmp(&ans->addr.addr, addr, addrlen) == 0)
520         return ans;
521 
522     return NULL;
523 }
524 
add_hosts_entry(struct crec * cache,struct all_addr * addr,int addrlen,unsigned short flags,int index,int addr_dup)525 static void add_hosts_entry(struct crec* cache, struct all_addr* addr, int addrlen,
526                             unsigned short flags, int index, int addr_dup) {
527     struct crec* lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
528     int i, nameexists = 0;
529     struct cname* a;
530 
531     /* Remove duplicates in hosts files. */
532     if (lookup && (lookup->flags & F_HOSTS)) {
533         nameexists = 1;
534         if (memcmp(&lookup->addr.addr, addr, addrlen) == 0) {
535             free(cache);
536             return;
537         }
538     }
539 
540     /* Ensure there is only one address -> name mapping (first one trumps)
541        We do this by steam here, first we see if the address is the same as
542        the last one we saw, which eliminates most in the case of an ad-block
543        file with thousands of entries for the same address.
544        Then we search and bail at the first matching address that came from
545        a HOSTS file. Since the first host entry gets reverse, we know
546        then that it must exist without searching exhaustively for it. */
547 
548     if (addr_dup)
549         flags &= ~F_REVERSE;
550     else
551         for (i = 0; i < hash_size; i++) {
552             for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
553                 if ((lookup->flags & F_HOSTS) && (lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
554                     memcmp(&lookup->addr.addr, addr, addrlen) == 0) {
555                     flags &= ~F_REVERSE;
556                     break;
557                 }
558             if (lookup) break;
559         }
560 
561     cache->flags = flags;
562     cache->uid = index;
563     memcpy(&cache->addr.addr, addr, addrlen);
564     cache_hash(cache);
565 
566     /* don't need to do alias stuff for second and subsequent addresses. */
567     if (!nameexists)
568         for (a = daemon->cnames; a; a = a->next)
569             if (hostname_isequal(cache->name.sname, a->target) &&
570                 (lookup = whine_malloc(sizeof(struct crec)))) {
571                 lookup->flags = F_FORWARD | F_IMMORTAL | F_CONFIG | F_HOSTS | F_CNAME;
572                 lookup->name.namep = a->alias;
573                 lookup->addr.cname.cache = cache;
574                 lookup->addr.cname.uid = index;
575                 cache_hash(lookup);
576             }
577 }
578 
eatspace(FILE * f)579 static int eatspace(FILE* f) {
580     int c, nl = 0;
581 
582     while (1) {
583         if ((c = getc(f)) == '#')
584             while (c != '\n' && c != EOF) c = getc(f);
585 
586         if (c == EOF) return 1;
587 
588         if (!isspace(c)) {
589             ungetc(c, f);
590             return nl;
591         }
592 
593         if (c == '\n') nl = 1;
594     }
595 }
596 
gettok(FILE * f,char * token)597 static int gettok(FILE* f, char* token) {
598     int c, count = 0;
599 
600     while (1) {
601         if ((c = getc(f)) == EOF) return (count == 0) ? EOF : 1;
602 
603         if (isspace(c) || c == '#') {
604             ungetc(c, f);
605             return eatspace(f);
606         }
607 
608         if (count < (MAXDNAME - 1)) {
609             token[count++] = c;
610             token[count] = 0;
611         }
612     }
613 }
614 
read_hostsfile(char * filename,int index,int cache_size)615 static int read_hostsfile(char* filename, int index, int cache_size) {
616     FILE* f = fopen(filename, "r");
617     char *token = daemon->namebuff, *domain_suffix = NULL;
618     int addr_count = 0, name_count = cache_size, lineno = 0;
619     unsigned short flags = 0, saved_flags = 0;
620     struct all_addr addr, saved_addr;
621     int atnl, addrlen = 0, addr_dup;
622 
623     if (!f) {
624         my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
625         return 0;
626     }
627 
628     eatspace(f);
629 
630     while ((atnl = gettok(f, token)) != EOF) {
631         addr_dup = 0;
632         lineno++;
633 
634 #ifdef HAVE_IPV6
635         if (inet_pton(AF_INET, token, &addr) > 0) {
636             flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
637             addrlen = INADDRSZ;
638             domain_suffix = get_domain(addr.addr.addr4);
639         } else if (inet_pton(AF_INET6, token, &addr) > 0) {
640             flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
641             addrlen = IN6ADDRSZ;
642             domain_suffix = daemon->domain_suffix;
643         }
644 #else
645         if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1) {
646             flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
647             addrlen = INADDRSZ;
648             domain_suffix = get_domain(addr.addr.addr4);
649         }
650 #endif
651         else {
652             my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
653             while (atnl == 0) atnl = gettok(f, token);
654             continue;
655         }
656 
657         if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
658             addr_dup = 1;
659         else {
660             saved_flags = flags;
661             saved_addr = addr;
662         }
663 
664         addr_count++;
665 
666         /* rehash every 1000 names. */
667         if ((name_count - cache_size) > 1000) {
668             rehash(name_count);
669             cache_size = name_count;
670         }
671 
672         while (atnl == 0) {
673             struct crec* cache;
674             int fqdn, nomem;
675             char* canon;
676 
677             if ((atnl = gettok(f, token)) == EOF) break;
678 
679             fqdn = !!strchr(token, '.');
680 
681             if ((canon = canonicalise(token, &nomem))) {
682                 /* If set, add a version of the name with a default domain appended */
683                 if ((daemon->options & OPT_EXPAND) && domain_suffix && !fqdn &&
684                     (cache = whine_malloc(sizeof(struct crec) + strlen(canon) + 2 +
685                                           strlen(domain_suffix) - SMALLDNAME))) {
686                     strcpy(cache->name.sname, canon);
687                     strcat(cache->name.sname, ".");
688                     strcat(cache->name.sname, domain_suffix);
689                     add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
690                     addr_dup = 1;
691                     name_count++;
692                 }
693                 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon) + 1 - SMALLDNAME))) {
694                     strcpy(cache->name.sname, canon);
695                     add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
696                     name_count++;
697                 }
698                 free(canon);
699 
700             } else if (!nomem)
701                 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
702         }
703     }
704 
705     fclose(f);
706     rehash(name_count);
707 
708     my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
709 
710     return name_count;
711 }
712 
cache_reload(void)713 void cache_reload(void) {
714     struct crec *cache, **up, *tmp;
715     int i, total_size = daemon->cachesize;
716     struct hostsfile* ah;
717 
718     cache_inserted = cache_live_freed = 0;
719 
720     for (i = 0; i < hash_size; i++)
721         for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp) {
722             tmp = cache->hash_next;
723             if (cache->flags & F_HOSTS) {
724                 *up = cache->hash_next;
725                 free(cache);
726             } else if (!(cache->flags & F_DHCP)) {
727                 *up = cache->hash_next;
728                 if (cache->flags & F_BIGNAME) {
729                     cache->name.bname->next = big_free;
730                     big_free = cache->name.bname;
731                 }
732                 cache->flags = 0;
733             } else
734                 up = &cache->hash_next;
735         }
736 
737     if ((daemon->options & OPT_NO_HOSTS) && !daemon->addn_hosts) {
738         if (daemon->cachesize > 0) my_syslog(LOG_INFO, _("cleared cache"));
739         return;
740     }
741 
742     if (!(daemon->options & OPT_NO_HOSTS)) total_size = read_hostsfile(HOSTSFILE, 0, total_size);
743 
744     for (i = 0, ah = daemon->addn_hosts; ah; ah = ah->next) {
745         if (i <= ah->index) i = ah->index + 1;
746 
747         if (ah->flags & AH_DIR)
748             ah->flags |= AH_INACTIVE;
749         else
750             ah->flags &= ~AH_INACTIVE;
751     }
752 
753     for (ah = daemon->addn_hosts; ah; ah = ah->next)
754         if (!(ah->flags & AH_INACTIVE)) {
755             struct stat buf;
756             if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode)) {
757                 DIR* dir_stream;
758                 struct dirent* ent;
759 
760                 /* don't read this as a file */
761                 ah->flags |= AH_INACTIVE;
762 
763                 if (!(dir_stream = opendir(ah->fname)))
764                     my_syslog(LOG_ERR, _("cannot access directory %s: %s"), ah->fname,
765                               strerror(errno));
766                 else {
767                     while ((ent = readdir(dir_stream))) {
768                         size_t lendir = strlen(ah->fname);
769                         size_t lenfile = strlen(ent->d_name);
770                         struct hostsfile* ah1;
771                         char* path;
772 
773                         /* ignore emacs backups and dotfiles */
774                         if (lenfile == 0 || ent->d_name[lenfile - 1] == '~' ||
775                             (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
776                             ent->d_name[0] == '.')
777                             continue;
778 
779                         /* see if we have an existing record.
780                            dir is ah->fname
781                            file is ent->d_name
782                            path to match is ah1->fname */
783 
784                         for (ah1 = daemon->addn_hosts; ah1; ah1 = ah1->next) {
785                             if (lendir < strlen(ah1->fname) &&
786                                 strstr(ah1->fname, ah->fname) == ah1->fname &&
787                                 ah1->fname[lendir] == '/' &&
788                                 strcmp(ah1->fname + lendir + 1, ent->d_name) == 0) {
789                                 ah1->flags &= ~AH_INACTIVE;
790                                 break;
791                             }
792                         }
793 
794                         /* make new record */
795                         if (!ah1) {
796                             if (!(ah1 = whine_malloc(sizeof(struct hostsfile)))) continue;
797 
798                             if (!(path = whine_malloc(lendir + lenfile + 2))) {
799                                 free(ah1);
800                                 continue;
801                             }
802 
803                             strcpy(path, ah->fname);
804                             strcat(path, "/");
805                             strcat(path, ent->d_name);
806                             ah1->fname = path;
807                             ah1->index = i++;
808                             ah1->flags = AH_DIR;
809                             ah1->next = daemon->addn_hosts;
810                             daemon->addn_hosts = ah1;
811                         }
812 
813                         /* inactivate record if not regular file */
814                         if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 &&
815                             !S_ISREG(buf.st_mode))
816                             ah1->flags |= AH_INACTIVE;
817                     }
818                     closedir(dir_stream);
819                 }
820             }
821         }
822 
823     for (ah = daemon->addn_hosts; ah; ah = ah->next)
824         if (!(ah->flags & AH_INACTIVE))
825             total_size = read_hostsfile(ah->fname, ah->index, total_size);
826 }
827 
get_domain(struct in_addr addr)828 char* get_domain(struct in_addr addr) {
829     struct cond_domain* c;
830 
831     for (c = daemon->cond_domain; c; c = c->next)
832         if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
833             ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
834             return c->domain;
835 
836     return daemon->domain_suffix;
837 }
838 
839 #ifdef HAVE_DHCP
cache_unhash_dhcp(void)840 void cache_unhash_dhcp(void) {
841     struct crec *cache, **up;
842     int i;
843 
844     for (i = 0; i < hash_size; i++)
845         for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
846             if (cache->flags & F_DHCP) {
847                 *up = cache->hash_next;
848                 cache->next = dhcp_spare;
849                 dhcp_spare = cache;
850             } else
851                 up = &cache->hash_next;
852 }
853 
cache_add_dhcp_entry(char * host_name,struct in_addr * host_address,time_t ttd)854 void cache_add_dhcp_entry(char* host_name, struct in_addr* host_address, time_t ttd) {
855     struct crec *crec = NULL, *aliasc;
856     unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
857     int in_hosts = 0;
858     struct cname* a;
859 
860     while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME))) {
861         /* check all addresses associated with name */
862         if (crec->flags & F_HOSTS) {
863             if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr) {
864                 strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
865                 my_syslog(LOG_WARNING,
866                           _("not giving name %s to the DHCP lease of %s because "
867                             "the name exists in %s with address %s"),
868                           host_name, inet_ntoa(*host_address), record_source(crec->uid),
869                           daemon->namebuff);
870                 return;
871             } else
872                 /* if in hosts, don't need DHCP record */
873                 in_hosts = 1;
874         } else if (!(crec->flags & F_DHCP)) {
875             cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
876             /* scan_free deletes all addresses associated with name */
877             break;
878         }
879     }
880 
881     if (in_hosts) return;
882 
883     if ((crec = cache_find_by_addr(NULL, (struct all_addr*) host_address, 0, F_IPV4))) {
884         if (crec->flags & F_NEG)
885             cache_scan_free(NULL, (struct all_addr*) host_address, 0, F_IPV4 | F_REVERSE);
886         else
887             /* avoid multiple reverse mappings */
888             flags &= ~F_REVERSE;
889     }
890 
891     if ((crec = dhcp_spare))
892         dhcp_spare = dhcp_spare->next;
893     else /* need new one */
894         crec = whine_malloc(sizeof(struct crec));
895 
896     if (crec) /* malloc may fail */
897     {
898         crec->flags = flags;
899         if (ttd == 0)
900             crec->flags |= F_IMMORTAL;
901         else
902             crec->ttd = ttd;
903         crec->addr.addr.addr.addr4 = *host_address;
904         crec->name.namep = host_name;
905         crec->uid = uid++;
906         cache_hash(crec);
907 
908         for (a = daemon->cnames; a; a = a->next)
909             if (hostname_isequal(host_name, a->target)) {
910                 if ((aliasc = dhcp_spare))
911                     dhcp_spare = dhcp_spare->next;
912                 else /* need new one */
913                     aliasc = whine_malloc(sizeof(struct crec));
914 
915                 if (aliasc) {
916                     aliasc->flags = F_FORWARD | F_CONFIG | F_DHCP | F_CNAME;
917                     if (ttd == 0)
918                         aliasc->flags |= F_IMMORTAL;
919                     else
920                         aliasc->ttd = ttd;
921                     aliasc->name.namep = a->alias;
922                     aliasc->addr.cname.cache = crec;
923                     aliasc->addr.cname.uid = crec->uid;
924                     cache_hash(aliasc);
925                 }
926             }
927     }
928 }
929 #endif
930 
dump_cache(time_t now)931 void dump_cache(time_t now) {
932     struct server *serv, *serv1;
933 
934     my_syslog(LOG_INFO, _("time %lu"), (unsigned long) now);
935     my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
936               daemon->cachesize, cache_live_freed, cache_inserted);
937     my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
938               daemon->queries_forwarded, daemon->local_answer);
939 
940     if (!addrbuff && !(addrbuff = whine_malloc(ADDRSTRLEN))) return;
941 
942     /* sum counts from different records for same server */
943     for (serv = daemon->servers; serv; serv = serv->next) serv->flags &= ~SERV_COUNTED;
944 
945     for (serv = daemon->servers; serv; serv = serv->next)
946         if (!(serv->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED))) {
947             int port;
948             unsigned int queries = 0, failed_queries = 0;
949             for (serv1 = serv; serv1; serv1 = serv1->next)
950                 if (!(serv1->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)) &&
951                     sockaddr_isequal(&serv->addr, &serv1->addr)) {
952                     serv1->flags |= SERV_COUNTED;
953                     queries += serv1->queries;
954                     failed_queries += serv1->failed_queries;
955                 }
956             port = prettyprint_addr(&serv->addr, addrbuff);
957             my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff,
958                       port, queries, failed_queries);
959         }
960 
961     if ((daemon->options & (OPT_DEBUG | OPT_LOG))) {
962         struct crec* cache;
963         int i;
964         my_syslog(LOG_DEBUG,
965                   "Host                                     Address                        Flags   "
966                   "  Expires");
967 
968         for (i = 0; i < hash_size; i++)
969             for (cache = hash_table[i]; cache; cache = cache->hash_next) {
970                 char *a, *p = daemon->namebuff;
971                 p += sprintf(p, "%-40.40s ", cache_get_name(cache));
972                 if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
973                     a = "";
974                 else if (cache->flags & F_CNAME) {
975                     a = "";
976                     if (!is_outdated_cname_pointer(cache))
977                         a = cache_get_name(cache->addr.cname.cache);
978                 }
979 #ifdef HAVE_IPV6
980                 else {
981                     a = addrbuff;
982                     if (cache->flags & F_IPV4)
983                         inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
984                     else if (cache->flags & F_IPV6)
985                         inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
986                 }
987 #else
988                 else
989                     a = inet_ntoa(cache->addr.addr.addr.addr4);
990 #endif
991                 p += sprintf(
992                     p, "%-30.30s %s%s%s%s%s%s%s%s%s%s  ", a, cache->flags & F_IPV4 ? "4" : "",
993                     cache->flags & F_IPV6 ? "6" : "", cache->flags & F_CNAME ? "C" : "",
994                     cache->flags & F_FORWARD ? "F" : " ", cache->flags & F_REVERSE ? "R" : " ",
995                     cache->flags & F_IMMORTAL ? "I" : " ", cache->flags & F_DHCP ? "D" : " ",
996                     cache->flags & F_NEG ? "N" : " ", cache->flags & F_NXDOMAIN ? "X" : " ",
997                     cache->flags & F_HOSTS ? "H" : " ");
998 #ifdef HAVE_BROKEN_RTC
999                 p += sprintf(p, "%lu",
1000                              cache->flags & F_IMMORTAL ? 0 : (unsigned long) (cache->ttd - now));
1001 #else
1002                 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1003                 /* ctime includes trailing \n - eat it */
1004                 *(p - 1) = 0;
1005 #endif
1006                 my_syslog(LOG_DEBUG, daemon->namebuff);
1007             }
1008     }
1009 }
1010 
record_source(int index)1011 char* record_source(int index) {
1012     struct hostsfile* ah;
1013 
1014     if (index == 0) return HOSTSFILE;
1015 
1016     for (ah = daemon->addn_hosts; ah; ah = ah->next)
1017         if (ah->index == index) return ah->fname;
1018 
1019     return "<unknown>";
1020 }
1021 
querystr(char * str,unsigned short type)1022 void querystr(char* str, unsigned short type) {
1023     unsigned int i;
1024 
1025     sprintf(str, "query[type=%d]", type);
1026     for (i = 0; i < (sizeof(typestr) / sizeof(typestr[0])); i++)
1027         if (typestr[i].type == type) sprintf(str, "query[%s]", typestr[i].name);
1028 }
1029 
log_query(unsigned short flags,char * name,struct all_addr * addr,char * arg)1030 void log_query(unsigned short flags, char* name, struct all_addr* addr, char* arg) {
1031     char *source, *dest = addrbuff;
1032     char* verb = "is";
1033 
1034     if (!(daemon->options & OPT_LOG)) return;
1035 
1036     if (addr) {
1037 #ifdef HAVE_IPV6
1038         /* TODO: support scoped addresses. struct all_addr doesn't store scope IDs. */
1039         inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, addr, addrbuff, ADDRSTRLEN);
1040 #else
1041         strncpy(addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
1042 #endif
1043     }
1044 
1045     if (flags & F_REVERSE) {
1046         dest = name;
1047         name = addrbuff;
1048     }
1049 
1050     if (flags & F_NEG) {
1051         if (flags & F_NXDOMAIN) {
1052             if (flags & F_IPV4)
1053                 dest = "NXDOMAIN-IPv4";
1054             else if (flags & F_IPV6)
1055                 dest = "NXDOMAIN-IPv6";
1056             else
1057                 dest = "NXDOMAIN";
1058         } else {
1059             if (flags & F_IPV4)
1060                 dest = "NODATA-IPv4";
1061             else if (flags & F_IPV6)
1062                 dest = "NODATA-IPv6";
1063             else
1064                 dest = "NODATA";
1065         }
1066     } else if (flags & F_CNAME) {
1067         /* nasty abuse of NXDOMAIN and CNAME flags */
1068         if (flags & F_NXDOMAIN)
1069             dest = arg;
1070         else
1071             dest = "<CNAME>";
1072     }
1073 
1074     if (flags & F_CONFIG)
1075         source = "config";
1076     else if (flags & F_DHCP)
1077         source = "DHCP";
1078     else if (flags & F_HOSTS)
1079         source = arg;
1080     else if (flags & F_UPSTREAM)
1081         source = "reply";
1082     else if (flags & F_SERVER) {
1083         source = "forwarded";
1084         verb = "to";
1085     } else if (flags & F_QUERY) {
1086         source = arg;
1087         verb = "from";
1088     } else
1089         source = "cached";
1090 
1091     if (strlen(name) == 0) name = ".";
1092 
1093     my_syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, dest);
1094 }
1095