blob: 6daaf3e07822ed18bde5670254f5ff3ff80d2dcf [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
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
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 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.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 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/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
17#include "dnsmasq.h"
18
Simon Kelley5aabfc72007-08-29 11:24:47 +010019static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +010020#ifdef HAVE_DHCP
21static struct crec *dhcp_spare = NULL;
22#endif
23static struct crec *new_chain = NULL;
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +010024static int insert_error;
Simon Kelley5aabfc72007-08-29 11:24:47 +010025static union bigname *big_free = NULL;
26static int bignames_left, hash_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000027
Simon Kelleyb6f926f2018-08-21 17:46:52 +010028static void make_non_terminals(struct crec *source);
29
Simon Kelley16972692006-10-16 20:04:18 +010030/* type->string mapping: this is also used by the name-hash function as a mixing table. */
31static const struct {
32 unsigned int type;
33 const char * const name;
34} typestr[] = {
35 { 1, "A" },
36 { 2, "NS" },
37 { 5, "CNAME" },
38 { 6, "SOA" },
39 { 10, "NULL" },
40 { 11, "WKS" },
41 { 12, "PTR" },
42 { 13, "HINFO" },
43 { 15, "MX" },
44 { 16, "TXT" },
45 { 22, "NSAP" },
46 { 23, "NSAP_PTR" },
47 { 24, "SIG" },
48 { 25, "KEY" },
49 { 28, "AAAA" },
Simon Kelleyaa6f8322017-10-27 22:52:26 +010050 { 29, "LOC" },
Simon Kelley16972692006-10-16 20:04:18 +010051 { 33, "SRV" },
Simon Kelley1a6bca82008-07-11 11:11:42 +010052 { 35, "NAPTR" },
Simon Kelley16972692006-10-16 20:04:18 +010053 { 36, "KX" },
54 { 37, "CERT" },
55 { 38, "A6" },
56 { 39, "DNAME" },
57 { 41, "OPT" },
Simon Kelley0fc2f312014-01-08 10:26:58 +000058 { 43, "DS" },
59 { 46, "RRSIG" },
Simon Kelley610e7822014-02-06 14:45:17 +000060 { 47, "NSEC" },
Simon Kelley832af0b2007-01-21 20:01:28 +000061 { 48, "DNSKEY" },
Simon Kelley610e7822014-02-06 14:45:17 +000062 { 50, "NSEC3" },
Simon Kelleyaa6f8322017-10-27 22:52:26 +010063 { 51, "NSEC3PARAM" },
64 { 52, "TLSA" },
65 { 53, "SMIMEA" },
66 { 55, "HIP" },
Simon Kelley832af0b2007-01-21 20:01:28 +000067 { 249, "TKEY" },
Simon Kelley16972692006-10-16 20:04:18 +010068 { 250, "TSIG" },
69 { 251, "IXFR" },
70 { 252, "AXFR" },
71 { 253, "MAILB" },
72 { 254, "MAILA" },
Simon Kelleyb758b672018-08-23 21:41:23 +010073 { 255, "ANY" },
74 { 257, "CAA" }
Simon Kelley16972692006-10-16 20:04:18 +010075};
76
Simon Kelley9e4abcb2004-01-22 19:47:41 +000077static void cache_free(struct crec *crecp);
78static void cache_unlink(struct crec *crecp);
79static void cache_link(struct crec *crecp);
Simon Kelley4011c4e2006-10-28 16:26:19 +010080static void rehash(int size);
81static void cache_hash(struct crec *crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000082
Simon Kelley45d8a242018-07-17 21:01:14 +010083void next_uid(struct crec *crecp)
Simon Kelley3f7483e2014-03-16 22:56:58 +000084{
Andyd5082152014-03-17 19:50:29 +000085 static unsigned int uid = 0;
Simon Kelley3f7483e2014-03-16 22:56:58 +000086
Simon Kelley45d8a242018-07-17 21:01:14 +010087 if (crecp->uid == UID_NONE)
88 {
89 uid++;
Andyd5082152014-03-17 19:50:29 +000090
Simon Kelley45d8a242018-07-17 21:01:14 +010091 /* uid == 0 used to indicate CNAME to interface name. */
92 if (uid == UID_NONE)
93 uid++;
94
95 crecp->uid = uid;
96 }
Simon Kelley3f7483e2014-03-16 22:56:58 +000097}
98
Simon Kelley5aabfc72007-08-29 11:24:47 +010099void cache_init(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000100{
101 struct crec *crecp;
102 int i;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100103
Simon Kelley5aabfc72007-08-29 11:24:47 +0100104 bignames_left = daemon->cachesize/10;
105
106 if (daemon->cachesize > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000107 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100108 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109
Simon Kelley5aabfc72007-08-29 11:24:47 +0100110 for (i=0; i < daemon->cachesize; i++, crecp++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000111 {
112 cache_link(crecp);
113 crecp->flags = 0;
Simon Kelley45d8a242018-07-17 21:01:14 +0100114 crecp->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000115 }
116 }
117
Simon Kelley4011c4e2006-10-28 16:26:19 +0100118 /* create initial hash table*/
Simon Kelley5aabfc72007-08-29 11:24:47 +0100119 rehash(daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000120}
121
Simon Kelley4011c4e2006-10-28 16:26:19 +0100122/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
123 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
124 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
125 expand the table. */
126static void rehash(int size)
127{
128 struct crec **new, **old, *p, *tmp;
129 int i, new_size, old_size;
130
131 /* hash_size is a power of two. */
132 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
133
134 /* must succeed in getting first instance, failure later is non-fatal */
135 if (!hash_table)
136 new = safe_malloc(new_size * sizeof(struct crec *));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100137 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
Simon Kelley4011c4e2006-10-28 16:26:19 +0100138 return;
139
140 for(i = 0; i < new_size; i++)
141 new[i] = NULL;
142
143 old = hash_table;
144 old_size = hash_size;
145 hash_table = new;
146 hash_size = new_size;
147
148 if (old)
149 {
150 for (i = 0; i < old_size; i++)
151 for (p = old[i]; p ; p = tmp)
152 {
153 tmp = p->hash_next;
154 cache_hash(p);
155 }
156 free(old);
157 }
158}
159
Simon Kelley3d8df262005-08-29 12:19:27 +0100160static struct crec **hash_bucket(char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000161{
Simon Kelley4011c4e2006-10-28 16:26:19 +0100162 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
Simon Kelley16972692006-10-16 20:04:18 +0100163 const unsigned char *mix_tab = (const unsigned char*)typestr;
164
Simon Kelley3d8df262005-08-29 12:19:27 +0100165 while((c = (unsigned char) *name++))
Simon Kelley16972692006-10-16 20:04:18 +0100166 {
167 /* don't use tolower and friends here - they may be messed up by LOCALE */
168 if (c >= 'A' && c <= 'Z')
169 c += 'a' - 'A';
Simon Kelley4011c4e2006-10-28 16:26:19 +0100170 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
Simon Kelley16972692006-10-16 20:04:18 +0100171 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000172
173 /* hash_size is a power of two */
Simon Kelley16972692006-10-16 20:04:18 +0100174 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000175}
176
177static void cache_hash(struct crec *crecp)
178{
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000179 /* maintain an invariant that all entries with F_REVERSE set
180 are at the start of the hash-chain and all non-reverse
181 immortal entries are at the end of the hash-chain.
182 This allows reverse searches and garbage collection to be optimised */
183
184 struct crec **up = hash_bucket(cache_get_name(crecp));
185
186 if (!(crecp->flags & F_REVERSE))
187 {
188 while (*up && ((*up)->flags & F_REVERSE))
189 up = &((*up)->hash_next);
190
191 if (crecp->flags & F_IMMORTAL)
Simon Kelley6b010842007-02-12 20:32:07 +0000192 while (*up && !((*up)->flags & F_IMMORTAL))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000193 up = &((*up)->hash_next);
194 }
195 crecp->hash_next = *up;
196 *up = crecp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000197}
Simon Kelley82e3f452014-01-31 21:05:48 +0000198
199#ifdef HAVE_DNSSEC
200static void cache_blockdata_free(struct crec *crecp)
201{
202 if (crecp->flags & F_DNSKEY)
Simon Kelley93be5b12015-12-15 12:04:40 +0000203 blockdata_free(crecp->addr.key.keydata);
Simon Kelleye3f14552014-03-01 17:58:28 +0000204 else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
Simon Kelley82e3f452014-01-31 21:05:48 +0000205 blockdata_free(crecp->addr.ds.keydata);
206}
207#endif
208
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000209static void cache_free(struct crec *crecp)
210{
211 crecp->flags &= ~F_FORWARD;
212 crecp->flags &= ~F_REVERSE;
Simon Kelley45d8a242018-07-17 21:01:14 +0100213 crecp->uid = UID_NONE; /* invalidate CNAMES pointing to this. */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100214
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000215 if (cache_tail)
216 cache_tail->next = crecp;
217 else
218 cache_head = crecp;
219 crecp->prev = cache_tail;
220 crecp->next = NULL;
221 cache_tail = crecp;
222
223 /* retrieve big name for further use. */
224 if (crecp->flags & F_BIGNAME)
225 {
226 crecp->name.bname->next = big_free;
227 big_free = crecp->name.bname;
228 crecp->flags &= ~F_BIGNAME;
229 }
Simon Kelley072e81b2014-01-31 12:42:54 +0000230
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100231#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +0000232 cache_blockdata_free(crecp);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100233#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000234}
235
236/* insert a new cache entry at the head of the list (youngest entry) */
237static void cache_link(struct crec *crecp)
238{
239 if (cache_head) /* check needed for init code */
240 cache_head->prev = crecp;
241 crecp->next = cache_head;
242 crecp->prev = NULL;
243 cache_head = crecp;
244 if (!cache_tail)
245 cache_tail = crecp;
246}
247
248/* remove an arbitrary cache entry for promotion */
249static void cache_unlink (struct crec *crecp)
250{
251 if (crecp->prev)
252 crecp->prev->next = crecp->next;
253 else
254 cache_head = crecp->next;
255
256 if (crecp->next)
257 crecp->next->prev = crecp->prev;
258 else
259 cache_tail = crecp->prev;
260}
261
262char *cache_get_name(struct crec *crecp)
263{
264 if (crecp->flags & F_BIGNAME)
265 return crecp->name.bname->name;
Simon Kelley28866e92011-02-14 20:19:14 +0000266 else if (crecp->flags & F_NAMEP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000267 return crecp->name.namep;
268
269 return crecp->name.sname;
270}
271
Simon Kelleyd56a6042013-10-11 14:39:03 +0100272char *cache_get_cname_target(struct crec *crecp)
273{
Simon Kelley19c51cf2014-03-18 22:38:30 +0000274 if (crecp->addr.cname.uid != SRC_INTERFACE)
Simon Kelleyd56a6042013-10-11 14:39:03 +0100275 return cache_get_name(crecp->addr.cname.target.cache);
276
277 return crecp->addr.cname.target.int_name->name;
278}
279
280
281
Simon Kelleyb75e9362012-12-07 11:50:41 +0000282struct crec *cache_enumerate(int init)
283{
284 static int bucket;
285 static struct crec *cache;
286
287 if (init)
288 {
289 bucket = 0;
290 cache = NULL;
291 }
292 else if (cache && cache->hash_next)
293 cache = cache->hash_next;
294 else
295 {
296 cache = NULL;
297 while (bucket < hash_size)
298 if ((cache = hash_table[bucket++]))
299 break;
300 }
301
302 return cache;
303}
304
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100305static int is_outdated_cname_pointer(struct crec *crecp)
306{
Andy3e21a1a2014-03-22 19:10:07 +0000307 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100308 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100309
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100310 /* NB. record may be reused as DS or DNSKEY, where uid is
311 overloaded for something completely different */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100312 if (crecp->addr.cname.target.cache &&
313 (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
314 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100315 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100316
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100317 return 1;
318}
319
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000320static int is_expired(time_t now, struct crec *crecp)
321{
322 if (crecp->flags & F_IMMORTAL)
323 return 0;
324
325 if (difftime(now, crecp->ttd) < 0)
326 return 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100327
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000328 return 1;
329}
330
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100331static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags,
332 struct crec **target_crec, unsigned int *target_uid)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000333{
334 /* Scan and remove old entries.
335 If (flags & F_FORWARD) then remove any forward entries for name and any expired
336 entries but only in the same hash bucket as name.
337 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
338 entries in the whole cache.
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000339 If (flags == 0) remove any expired entries in the whole cache.
340
Simon Kelleycbc65242014-12-21 21:21:53 +0000341 In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
342 to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000343
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000344 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100345 so that when we hit an entry which isn't reverse and is immortal, we're done.
346
347 If we free a crec which is a CNAME target, return the entry and uid in target_crec and target_uid.
348 This entry will get re-used with the same name, to preserve CNAMEs. */
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000349
350 struct crec *crecp, **up;
351
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000352 if (flags & F_FORWARD)
353 {
Simon Kelley6b010842007-02-12 20:32:07 +0000354 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000355 {
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000356 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
357 {
Simon Kelleye7829ae2014-01-22 22:21:51 +0000358 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
359 if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
Simon Kelley6429e422014-01-23 12:09:36 +0000360 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000361 {
362 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelleycbc65242014-12-21 21:21:53 +0000363 return crecp;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000364 *up = crecp->hash_next;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100365 /* If this record is for the name we're inserting and is the target
366 of a CNAME record. Make the new record for the same name, in the same
367 crec, with the same uid to avoid breaking the existing CNAME. */
368 if (crecp->uid != UID_NONE)
369 {
370 if (target_crec)
371 *target_crec = crecp;
372 if (target_uid)
373 *target_uid = crecp->uid;
374 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000375 cache_unlink(crecp);
376 cache_free(crecp);
377 continue;
378 }
379
380#ifdef HAVE_DNSSEC
Simon Kelley93be5b12015-12-15 12:04:40 +0000381 /* Deletion has to be class-sensitive for DS and DNSKEY */
382 if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000383 {
Simon Kelley824202e2014-01-23 20:59:46 +0000384 if (crecp->flags & F_CONFIG)
Simon Kelleycbc65242014-12-21 21:21:53 +0000385 return crecp;
Simon Kelley824202e2014-01-23 20:59:46 +0000386 *up = crecp->hash_next;
387 cache_unlink(crecp);
388 cache_free(crecp);
389 continue;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000390 }
391#endif
392 }
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100393
394 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
395 {
396 *up = crecp->hash_next;
397 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
398 {
399 cache_unlink(crecp);
400 cache_free(crecp);
401 }
402 continue;
403 }
404
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000405 up = &crecp->hash_next;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000406 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000407 }
408 else
409 {
410 int i;
411#ifdef HAVE_IPV6
412 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
413#else
414 int addrlen = INADDRSZ;
415#endif
416 for (i = 0; i < hash_size; i++)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000417 for (crecp = hash_table[i], up = &hash_table[i];
418 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
419 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000420 if (is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000421 {
422 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000423 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000424 {
425 cache_unlink(crecp);
426 cache_free(crecp);
427 }
428 }
Simon Kelley25439062013-11-25 21:14:51 +0000429 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000430 (flags & crecp->flags & F_REVERSE) &&
431 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
432 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
433 {
434 *up = crecp->hash_next;
435 cache_unlink(crecp);
436 cache_free(crecp);
437 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000438 else
439 up = &crecp->hash_next;
440 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000441
Simon Kelleycbc65242014-12-21 21:21:53 +0000442 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000443}
444
445/* Note: The normal calling sequence is
446 cache_start_insert
447 cache_insert * n
448 cache_end_insert
449
450 but an abort can cause the cache_end_insert to be missed
451 in which can the next cache_start_insert cleans things up. */
452
453void cache_start_insert(void)
454{
455 /* Free any entries which didn't get committed during the last
456 insert due to error.
457 */
458 while (new_chain)
459 {
460 struct crec *tmp = new_chain->next;
461 cache_free(new_chain);
462 new_chain = tmp;
463 }
464 new_chain = NULL;
465 insert_error = 0;
466}
467
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100468struct crec *cache_insert(char *name, struct all_addr *addr,
469 time_t now, unsigned long ttl, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000470{
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100471 struct crec *new, *target_crec = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000472 union bigname *big_name = NULL;
473 int freed_all = flags & F_REVERSE;
Simon Kelley9e038942008-05-30 20:06:34 +0100474 int free_avail = 0;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100475 unsigned int target_uid;
476
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000477 /* Don't log DNSSEC records here, done elsewhere */
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000478 if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000479 {
480 log_query(flags | F_UPSTREAM, name, addr, NULL);
RinSatsuki28de3872015-01-10 15:22:21 +0000481 /* Don't mess with TTL for DNSSEC records. */
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000482 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
483 ttl = daemon->max_cache_ttl;
RinSatsuki28de3872015-01-10 15:22:21 +0000484 if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
485 ttl = daemon->min_cache_ttl;
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000486 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000487
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000488 /* if previous insertion failed give up now. */
489 if (insert_error)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100490 return NULL;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000491
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000492 /* First remove any expired entries and entries for the name/address we
Simon Kelleycbc65242014-12-21 21:21:53 +0000493 are currently inserting. */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100494 if ((new = cache_scan_free(name, addr, now, flags, &target_crec, &target_uid)))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000495 {
Simon Kelleycbc65242014-12-21 21:21:53 +0000496 /* We're trying to insert a record over one from
497 /etc/hosts or DHCP, or other config. If the
498 existing record is for an A or AAAA and
499 the record we're trying to insert is the same,
500 just drop the insert, but don't error the whole process. */
Edwin Török41a8d9e2015-11-14 17:45:48 +0000501 if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000502 {
503 if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
504 new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
505 return new;
506#ifdef HAVE_IPV6
507 else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
508 IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
509 return new;
510#endif
511 }
512
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000513 insert_error = 1;
514 return NULL;
515 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000516
517 /* Now get a cache entry from the end of the LRU list */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100518 if (!target_crec)
519 while (1) {
520 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
521 {
522 insert_error = 1;
523 return NULL;
524 }
525
526 /* Free entry at end of LRU list, use it. */
527 if (!(new->flags & (F_FORWARD | F_REVERSE)))
528 break;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000529
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100530 /* End of LRU list is still in use: if we didn't scan all the hash
531 chains for expired entries do that now. If we already tried that
532 then it's time to start spilling things. */
533
534 /* If free_avail set, we believe that an entry has been freed.
535 Bugs have been known to make this not true, resulting in
536 a tight loop here. If that happens, abandon the
537 insert. Once in this state, all inserts will probably fail. */
538 if (free_avail)
539 {
540 static int warned = 0;
541 if (!warned)
542 {
543 my_syslog(LOG_ERR, _("Internal error in cache."));
544 warned = 1;
545 }
546 insert_error = 1;
547 return NULL;
548 }
549
550 if (freed_all)
551 {
552 struct all_addr free_addr = new->addr.addr;;
553
Simon Kelley8d718cb2014-02-03 16:27:37 +0000554#ifdef HAVE_DNSSEC
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100555 /* For DNSSEC records, addr holds class. */
556 if (new->flags & (F_DS | F_DNSKEY))
557 free_addr.addr.dnssec.class = new->uid;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000558#endif
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100559
560 free_avail = 1; /* Must be free space now. */
561 cache_scan_free(cache_get_name(new), &free_addr, now, new->flags, NULL, NULL);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100562 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100563 }
564 else
565 {
566 cache_scan_free(NULL, NULL, now, 0, NULL, NULL);
567 freed_all = 1;
568 }
569 }
570
571 /* Check if we need to and can allocate extra memory for a long name.
572 If that fails, give up now, always succeed for DNSSEC records. */
573 if (name && (strlen(name) > SMALLDNAME-1))
574 {
575 if (big_free)
576 {
577 big_name = big_free;
578 big_free = big_free->next;
579 }
580 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
581 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
582 {
583 insert_error = 1;
584 return NULL;
585 }
586 else if (bignames_left != 0)
587 bignames_left--;
588
589 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000590
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100591 /* If we freed a cache entry for our name which was a CNAME target, use that.
592 and preserve the uid, so that existing CNAMES are not broken. */
593 if (target_crec)
594 {
595 new = target_crec;
596 new->uid = target_uid;
597 }
598
599 /* Got the rest: finally grab entry. */
600 cache_unlink(new);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000601
602 new->flags = flags;
603 if (big_name)
604 {
605 new->name.bname = big_name;
606 new->flags |= F_BIGNAME;
607 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100608
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000609 if (name)
610 strcpy(cache_get_name(new), name);
611 else
612 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100613
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000614 if (addr)
Simon Kelleyb8eac192014-02-27 14:30:03 +0000615 {
616#ifdef HAVE_DNSSEC
617 if (flags & (F_DS | F_DNSKEY))
618 new->uid = addr->addr.dnssec.class;
619 else
620#endif
621 new->addr.addr = *addr;
622 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100623
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000624 new->ttd = now + (time_t)ttl;
625 new->next = new_chain;
626 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100627
628 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000629}
630
631/* after end of insertion, commit the new entries */
632void cache_end_insert(void)
633{
634 if (insert_error)
635 return;
636
637 while (new_chain)
638 {
639 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100640 /* drop CNAMEs which didn't find a target. */
641 if (is_outdated_cname_pointer(new_chain))
642 cache_free(new_chain);
643 else
644 {
645 cache_hash(new_chain);
646 cache_link(new_chain);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100647 daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100648 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000649 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000650 }
651 new_chain = NULL;
652}
653
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100654int cache_find_non_terminal(char *name, time_t now)
655{
656 struct crec *crecp;
657
658 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
659 if (!is_outdated_cname_pointer(crecp) &&
660 !is_expired(now, crecp) &&
661 (crecp->flags & F_FORWARD) &&
662 hostname_isequal(name, cache_get_name(crecp)))
663 return 1;
664
665 return 0;
666}
667
Simon Kelley12fae492014-02-04 22:03:06 +0000668struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000669{
670 struct crec *ans;
Simon Kelley12fae492014-02-04 22:03:06 +0000671 int no_rr = prot & F_NO_RR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000672
Simon Kelley12fae492014-02-04 22:03:06 +0000673 prot &= ~F_NO_RR;
674
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000675 if (crecp) /* iterating */
676 ans = crecp->next;
677 else
678 {
679 /* first search, look for relevant entries and push to top of list
680 also free anything which has expired */
681 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley28866e92011-02-14 20:19:14 +0000682 unsigned short ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000683
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000684 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
685 {
686 next = crecp->hash_next;
687
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000688 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000689 {
690 if ((crecp->flags & F_FORWARD) &&
691 (crecp->flags & prot) &&
692 hostname_isequal(cache_get_name(crecp), name))
693 {
Simon Kelley25439062013-11-25 21:14:51 +0000694 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000695 {
696 *chainp = crecp;
697 chainp = &crecp->next;
698 }
699 else
700 {
701 cache_unlink(crecp);
702 cache_link(crecp);
703 }
704
Simon Kelley824af852008-02-12 20:43:05 +0000705 /* Move all but the first entry up the hash chain
706 this implements round-robin.
707 Make sure that re-ordering doesn't break the hash-chain
708 order invariants.
709 */
Simon Kelley9e038942008-05-30 20:06:34 +0100710 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000711 {
712 *up = crecp->hash_next;
713 crecp->hash_next = *insert;
714 *insert = crecp;
715 insert = &crecp->hash_next;
716 }
Simon Kelley9e038942008-05-30 20:06:34 +0100717 else
718 {
Simon Kelley12fae492014-02-04 22:03:06 +0000719 if (!insert && !no_rr)
Simon Kelley9e038942008-05-30 20:06:34 +0100720 {
721 insert = up;
722 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
723 }
724 up = &crecp->hash_next;
725 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000726 }
727 else
728 /* case : not expired, incorrect entry. */
729 up = &crecp->hash_next;
730 }
731 else
732 {
733 /* expired entry, free it */
734 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000735 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000736 {
737 cache_unlink(crecp);
738 cache_free(crecp);
739 }
740 }
741 }
742
743 *chainp = cache_head;
744 }
745
746 if (ans &&
747 (ans->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000748 (ans->flags & prot) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000749 hostname_isequal(cache_get_name(ans), name))
750 return ans;
751
752 return NULL;
753}
754
755struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
Simon Kelley12fae492014-02-04 22:03:06 +0000756 time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000757{
758 struct crec *ans;
759#ifdef HAVE_IPV6
760 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
761#else
762 int addrlen = INADDRSZ;
763#endif
764
765 if (crecp) /* iterating */
766 ans = crecp->next;
767 else
768 {
769 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000770 also free anything which has expired. All the reverse entries are at the
771 start of the hash chain, so we can give up when we find the first
772 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000773 int i;
774 struct crec **up, **chainp = &ans;
775
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000776 for (i=0; i<hash_size; i++)
777 for (crecp = hash_table[i], up = &hash_table[i];
778 crecp && (crecp->flags & F_REVERSE);
779 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000780 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000781 {
Simon Kelley6b010842007-02-12 20:32:07 +0000782 if ((crecp->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100783 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000784 {
Simon Kelley25439062013-11-25 21:14:51 +0000785 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000786 {
787 *chainp = crecp;
788 chainp = &crecp->next;
789 }
790 else
791 {
792 cache_unlink(crecp);
793 cache_link(crecp);
794 }
795 }
796 up = &crecp->hash_next;
797 }
798 else
799 {
800 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000801 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000802 {
803 cache_unlink(crecp);
804 cache_free(crecp);
805 }
806 }
807
808 *chainp = cache_head;
809 }
810
811 if (ans &&
812 (ans->flags & F_REVERSE) &&
813 (ans->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100814 memcmp(&ans->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000815 return ans;
816
817 return NULL;
818}
819
Simon Kelley611ebc52012-07-16 16:23:46 +0100820static void add_hosts_cname(struct crec *target)
821{
822 struct crec *crec;
823 struct cname *a;
824
825 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +0000826 if (a->alias[1] != '*' &&
827 hostname_isequal(cache_get_name(target), a->target) &&
Simon Kelley3a610a02018-09-26 16:50:35 +0100828 (crec = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelley611ebc52012-07-16 16:23:46 +0100829 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000830 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000831 crec->ttd = a->ttl;
Simon Kelley611ebc52012-07-16 16:23:46 +0100832 crec->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100833 crec->addr.cname.target.cache = target;
Simon Kelley45d8a242018-07-17 21:01:14 +0100834 next_uid(target);
Simon Kelley611ebc52012-07-16 16:23:46 +0100835 crec->addr.cname.uid = target->uid;
Simon Kelley45d8a242018-07-17 21:01:14 +0100836 crec->uid = UID_NONE;
Simon Kelley611ebc52012-07-16 16:23:46 +0100837 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100838 make_non_terminals(crec);
839
Simon Kelley611ebc52012-07-16 16:23:46 +0100840 add_hosts_cname(crec); /* handle chains */
841 }
842}
843
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100844static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
Simon Kelley19c51cf2014-03-18 22:38:30 +0000845 unsigned int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000846{
Simon Kelleye759d422012-03-16 13:18:57 +0000847 struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
Simon Kelley9009d742008-11-14 20:04:27 +0000848 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000849 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000850
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000851 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000852 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000853 {
Simon Kelley9009d742008-11-14 20:04:27 +0000854 nameexists = 1;
855 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
856 {
857 free(cache);
858 return;
859 }
860 }
861
862 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000863 We do this by steam here, The entries are kept in hash chains, linked
864 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000865 the array rhash, hashed on address. Note that rhash and the values
866 in ->next are only valid whilst reading hosts files: the buckets are
867 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +0000868
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000869 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000870
871 This complexity avoids O(n^2) divergent CPU use whilst reading
Simon Kelley70d18732015-01-31 19:59:29 +0000872 large (10000 entry) hosts files.
873
874 Note that we only do this process when bulk-reading hosts files,
875 for incremental reads, rhash is NULL, and we use cache lookups
876 instead.
877 */
Simon Kelley9009d742008-11-14 20:04:27 +0000878
Simon Kelley70d18732015-01-31 19:59:29 +0000879 if (rhash)
Simon Kelley915363f2012-01-11 22:00:48 +0000880 {
Simon Kelley70d18732015-01-31 19:59:29 +0000881 /* hash address */
882 for (j = 0, i = 0; i < addrlen; i++)
883 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
884
885 for (lookup = rhash[j]; lookup; lookup = lookup->next)
886 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
887 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
888 {
889 cache->flags &= ~F_REVERSE;
890 break;
891 }
892
893 /* maintain address hash chain, insert new unique address */
894 if (!lookup)
895 {
896 cache->next = rhash[j];
897 rhash[j] = cache;
898 }
Simon Kelley915363f2012-01-11 22:00:48 +0000899 }
Simon Kelley70d18732015-01-31 19:59:29 +0000900 else
901 {
902 /* incremental read, lookup in cache */
903 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
904 if (lookup && lookup->flags & F_HOSTS)
905 cache->flags &= ~F_REVERSE;
906 }
907
Simon Kelley9009d742008-11-14 20:04:27 +0000908 cache->uid = index;
Simon Kelley915363f2012-01-11 22:00:48 +0000909 memcpy(&cache->addr.addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +0000910 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100911 make_non_terminals(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000912
913 /* don't need to do alias stuff for second and subsequent addresses. */
914 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +0100915 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000916}
917
918static int eatspace(FILE *f)
919{
920 int c, nl = 0;
921
922 while (1)
923 {
924 if ((c = getc(f)) == '#')
925 while (c != '\n' && c != EOF)
926 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +0000927
Simon Kelley9009d742008-11-14 20:04:27 +0000928 if (c == EOF)
929 return 1;
930
931 if (!isspace(c))
932 {
933 ungetc(c, f);
934 return nl;
935 }
936
937 if (c == '\n')
938 nl = 1;
939 }
940}
941
942static int gettok(FILE *f, char *token)
943{
944 int c, count = 0;
945
946 while (1)
947 {
948 if ((c = getc(f)) == EOF)
949 return (count == 0) ? EOF : 1;
950
951 if (isspace(c) || c == '#')
952 {
953 ungetc(c, f);
954 return eatspace(f);
955 }
956
957 if (count < (MAXDNAME - 1))
958 {
959 token[count++] = c;
960 token[count] = 0;
961 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000962 }
963}
964
Simon Kelley70d18732015-01-31 19:59:29 +0000965int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000966{
967 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +0000968 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100969 int addr_count = 0, name_count = cache_size, lineno = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000970 unsigned short flags = 0;
971 struct all_addr addr;
972 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100973
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000974 if (!f)
975 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100976 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
André Glüpkereddf3652016-01-12 12:54:17 +0000977 return cache_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000978 }
Simon Kelley9009d742008-11-14 20:04:27 +0000979
980 eatspace(f);
981
982 while ((atnl = gettok(f, token)) != EOF)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000983 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000984 lineno++;
Simon Kelley9009d742008-11-14 20:04:27 +0000985
Simon Kelley3d8df262005-08-29 12:19:27 +0100986 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000987 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000988 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000989 addrlen = INADDRSZ;
Simon Kelley9009d742008-11-14 20:04:27 +0000990 domain_suffix = get_domain(addr.addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000991 }
Simon Kelleye759d422012-03-16 13:18:57 +0000992#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +0100993 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000994 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000995 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000996 addrlen = IN6ADDRSZ;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000997 domain_suffix = get_domain6(&addr.addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000998 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000999#endif
1000 else
Simon Kelleyb8187c82005-11-26 21:46:27 +00001001 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001002 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +00001003 while (atnl == 0)
1004 atnl = gettok(f, token);
Simon Kelleyb8187c82005-11-26 21:46:27 +00001005 continue;
1006 }
Simon Kelley9009d742008-11-14 20:04:27 +00001007
Simon Kelley9009d742008-11-14 20:04:27 +00001008 addr_count++;
1009
1010 /* rehash every 1000 names. */
Simon Kelley70d18732015-01-31 19:59:29 +00001011 if (rhash && ((name_count - cache_size) > 1000))
Simon Kelley9009d742008-11-14 20:04:27 +00001012 {
1013 rehash(name_count);
1014 cache_size = name_count;
1015 }
1016
1017 while (atnl == 0)
1018 {
1019 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +01001020 int fqdn, nomem;
1021 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +00001022
1023 if ((atnl = gettok(f, token)) == EOF)
1024 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001025
Simon Kelley9009d742008-11-14 20:04:27 +00001026 fqdn = !!strchr(token, '.');
1027
Simon Kelley1f15b812009-10-13 17:49:32 +01001028 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +00001029 {
1030 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +00001031 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001032 (cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
Simon Kelley9009d742008-11-14 20:04:27 +00001033 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001034 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +00001035 strcat(cache->name.sname, ".");
1036 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +00001037 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001038 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001039 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001040 name_count++;
1041 }
Simon Kelley3a610a02018-09-26 16:50:35 +01001042 if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
Simon Kelley9009d742008-11-14 20:04:27 +00001043 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001044 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +00001045 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001046 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001047 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001048 name_count++;
1049 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001050 free(canon);
1051
Simon Kelley9009d742008-11-14 20:04:27 +00001052 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001053 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +00001054 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1055 }
1056 }
1057
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001058 fclose(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001059
Simon Kelley70d18732015-01-31 19:59:29 +00001060 if (rhash)
Simon Kelleyf9c86372015-02-03 21:52:48 +00001061 rehash(name_count);
1062
1063 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1064
Simon Kelley4011c4e2006-10-28 16:26:19 +01001065 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001066}
1067
Simon Kelley7622fc02009-06-04 20:32:05 +01001068void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001069{
1070 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001071 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +01001072 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +00001073 struct host_record *hr;
1074 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001075 struct cname *a;
1076 struct interface_name *intr;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001077#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001078 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001079#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001080
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001081 daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
1082 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 0;
Simon Kelley59353a62004-11-21 19:34:28 +00001083
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001084 for (i=0; i<hash_size; i++)
1085 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1086 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001087#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +00001088 cache_blockdata_free(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001089#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001090 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001091 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001092 {
1093 *up = cache->hash_next;
1094 free(cache);
1095 }
1096 else if (!(cache->flags & F_DHCP))
1097 {
1098 *up = cache->hash_next;
1099 if (cache->flags & F_BIGNAME)
1100 {
1101 cache->name.bname->next = big_free;
1102 big_free = cache->name.bname;
1103 }
1104 cache->flags = 0;
1105 }
1106 else
1107 up = &cache->hash_next;
1108 }
1109
Simon Kelleyd56a6042013-10-11 14:39:03 +01001110 /* Add CNAMEs to interface_names to the cache */
1111 for (a = daemon->cnames; a; a = a->next)
1112 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001113 if (a->alias[1] != '*' &&
1114 hostname_isequal(a->target, intr->name) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001115 ((cache = whine_malloc(SIZEOF_POINTER_CREC))))
Simon Kelleyd56a6042013-10-11 14:39:03 +01001116 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001117 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001118 cache->ttd = a->ttl;
Simon Kelley532066e2013-11-26 10:14:47 +00001119 cache->name.namep = a->alias;
1120 cache->addr.cname.target.int_name = intr;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001121 cache->addr.cname.uid = SRC_INTERFACE;
Simon Kelley45d8a242018-07-17 21:01:14 +01001122 cache->uid = UID_NONE;
Simon Kelley532066e2013-11-26 10:14:47 +00001123 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001124 make_non_terminals(cache);
Simon Kelley532066e2013-11-26 10:14:47 +00001125 add_hosts_cname(cache); /* handle chains */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001126 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001127
1128#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001129 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley3a610a02018-09-26 16:50:35 +01001130 if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
Simon Kelleyee415862014-02-11 11:07:22 +00001131 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001132 {
Simon Kelleyee415862014-02-11 11:07:22 +00001133 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001134 cache->ttd = daemon->local_ttl;
Simon Kelleyee415862014-02-11 11:07:22 +00001135 cache->name.namep = ds->name;
1136 cache->addr.ds.keylen = ds->digestlen;
1137 cache->addr.ds.algo = ds->algo;
1138 cache->addr.ds.keytag = ds->keytag;
1139 cache->addr.ds.digest = ds->digest_type;
1140 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001141 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001142 make_non_terminals(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001143 }
1144#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001145
Simon Kelleye759d422012-03-16 13:18:57 +00001146 /* borrow the packet buffer for a temporary by-address hash */
1147 memset(daemon->packet, 0, daemon->packet_buff_sz);
1148 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1149 /* we overwrote the buffer... */
1150 daemon->srv_save = NULL;
1151
1152 /* Do host_records in config. */
1153 for (hr = daemon->host_records; hr; hr = hr->next)
1154 for (nl = hr->names; nl; nl = nl->next)
1155 {
1156 if (hr->addr.s_addr != 0 &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001157 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001158 {
1159 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001160 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001161 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001162 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001163 }
1164#ifdef HAVE_IPV6
1165 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001166 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001167 {
1168 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001169 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001170 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001171 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001172 }
1173#endif
1174 }
1175
Simon Kelley28866e92011-02-14 20:19:14 +00001176 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001177 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001178 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001179 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001180 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001181 else
1182 {
1183 if (!option_bool(OPT_NO_HOSTS))
1184 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1185
1186 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1187 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1188 if (!(ah->flags & AH_INACTIVE))
1189 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1190 }
1191
Simon Kelley70d18732015-01-31 19:59:29 +00001192#ifdef HAVE_INOTIFY
1193 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1194#endif
1195
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001196}
1197
Simon Kelley7622fc02009-06-04 20:32:05 +01001198#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001199struct in_addr a_record_from_hosts(char *name, time_t now)
1200{
1201 struct crec *crecp = NULL;
1202 struct in_addr ret;
1203
1204 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1205 if (crecp->flags & F_HOSTS)
1206 return *(struct in_addr *)&crecp->addr;
1207
1208 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1209
1210 ret.s_addr = 0;
1211 return ret;
1212}
1213
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001214void cache_unhash_dhcp(void)
1215{
Simon Kelley6b010842007-02-12 20:32:07 +00001216 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001217 int i;
1218
1219 for (i=0; i<hash_size; i++)
1220 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1221 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001222 {
1223 *up = cache->hash_next;
1224 cache->next = dhcp_spare;
1225 dhcp_spare = cache;
1226 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001227 else
1228 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001229}
1230
Simon Kelley611ebc52012-07-16 16:23:46 +01001231static void add_dhcp_cname(struct crec *target, time_t ttd)
1232{
1233 struct crec *aliasc;
1234 struct cname *a;
1235
1236 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001237 if (a->alias[1] != '*' &&
1238 hostname_isequal(cache_get_name(target), a->target))
Simon Kelley611ebc52012-07-16 16:23:46 +01001239 {
1240 if ((aliasc = dhcp_spare))
1241 dhcp_spare = dhcp_spare->next;
1242 else /* need new one */
Simon Kelley3a610a02018-09-26 16:50:35 +01001243 aliasc = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelley611ebc52012-07-16 16:23:46 +01001244
1245 if (aliasc)
1246 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001247 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
Simon Kelley611ebc52012-07-16 16:23:46 +01001248 if (ttd == 0)
1249 aliasc->flags |= F_IMMORTAL;
1250 else
1251 aliasc->ttd = ttd;
1252 aliasc->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001253 aliasc->addr.cname.target.cache = target;
Simon Kelley45d8a242018-07-17 21:01:14 +01001254 next_uid(target);
Simon Kelley611ebc52012-07-16 16:23:46 +01001255 aliasc->addr.cname.uid = target->uid;
Simon Kelley45d8a242018-07-17 21:01:14 +01001256 aliasc->uid = UID_NONE;
Simon Kelley611ebc52012-07-16 16:23:46 +01001257 cache_hash(aliasc);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001258 make_non_terminals(aliasc);
Simon Kelley611ebc52012-07-16 16:23:46 +01001259 add_dhcp_cname(aliasc, ttd);
1260 }
1261 }
1262}
1263
Simon Kelley4cb1b322012-02-06 14:30:41 +00001264void cache_add_dhcp_entry(char *host_name, int prot,
1265 struct all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001266{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001267 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001268 unsigned short flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001269 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001270 size_t addrlen = sizeof(struct in_addr);
1271
1272#ifdef HAVE_IPV6
1273 if (prot == AF_INET6)
1274 {
1275 flags = F_IPV6;
1276 addrlen = sizeof(struct in6_addr);
1277 }
1278#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001279
Simon Kelley12d71ed2012-08-30 15:16:41 +01001280 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1281
Simon Kelley4cb1b322012-02-06 14:30:41 +00001282 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001283 {
Simon Kelley824af852008-02-12 20:43:05 +00001284 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001285 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001286 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001287 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001288 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001289 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001290 host_name, daemon->addrbuff);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001291 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1292 in_hosts = 1;
1293 else
1294 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001295 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001296 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001297 {
Simon Kelleyeb1fe152018-07-18 20:59:52 +01001298 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD), NULL, NULL);
Simon Kelley824af852008-02-12 20:43:05 +00001299 /* scan_free deletes all addresses associated with name */
1300 break;
1301 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001302 }
Simon Kelley824af852008-02-12 20:43:05 +00001303
Simon Kelley12d71ed2012-08-30 15:16:41 +01001304 /* if in hosts, don't need DHCP record */
1305 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001306 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001307
1308 /* Name in hosts, address doesn't match */
1309 if (fail_crec)
1310 {
1311 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1312 my_syslog(MS_DHCP | LOG_WARNING,
1313 _("not giving name %s to the DHCP lease of %s because "
1314 "the name exists in %s with address %s"),
1315 host_name, daemon->addrbuff,
1316 record_source(fail_crec->uid), daemon->namebuff);
1317 return;
1318 }
1319
1320 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1321 {
1322 if (crec->flags & F_NEG)
1323 {
1324 flags |= F_REVERSE;
Simon Kelleyeb1fe152018-07-18 20:59:52 +01001325 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags, NULL, NULL);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001326 }
1327 }
1328 else
1329 flags |= F_REVERSE;
1330
1331 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001332 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001333 else /* need new one */
Simon Kelley3a610a02018-09-26 16:50:35 +01001334 crec = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001335
1336 if (crec) /* malloc may fail */
1337 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001338 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001339 if (ttd == 0)
1340 crec->flags |= F_IMMORTAL;
1341 else
1342 crec->ttd = ttd;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001343 crec->addr.addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001344 crec->name.namep = host_name;
Simon Kelley45d8a242018-07-17 21:01:14 +01001345 crec->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001346 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001347 make_non_terminals(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001348
Simon Kelley611ebc52012-07-16 16:23:46 +01001349 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001350 }
1351}
Simon Kelley7622fc02009-06-04 20:32:05 +01001352#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001353
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001354/* Called when we put a local or DHCP name into the cache.
1355 Creates empty cache entries for subnames (ie,
1356 for three.two.one, for two.one and one), without
1357 F_IPV4 or F_IPV6 or F_CNAME set. These convert
1358 NXDOMAIN answers to NoData ones. */
1359static void make_non_terminals(struct crec *source)
1360{
1361 char *name = cache_get_name(source);
Simon Kelleyea6cc332018-09-18 23:21:17 +01001362 struct crec *crecp, *tmp, **up;
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001363 int type = F_HOSTS | F_CONFIG;
1364#ifdef HAVE_DHCP
1365 if (source->flags & F_DHCP)
1366 type = F_DHCP;
1367#endif
1368
1369 /* First delete any empty entries for our new real name. Note that
1370 we only delete empty entries deriving from DHCP for a new DHCP-derived
1371 entry and vice-versa for HOSTS and CONFIG. This ensures that
1372 non-terminals from DHCP go when we reload DHCP and
1373 for HOSTS/CONFIG when we re-read. */
1374 for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
1375 {
1376 tmp = crecp->hash_next;
1377
1378 if (!is_outdated_cname_pointer(crecp) &&
1379 (crecp->flags & F_FORWARD) &&
1380 (crecp->flags & type) &&
Simon Kelleycbfbd172018-08-21 18:25:18 +01001381 !(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS)) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001382 hostname_isequal(name, cache_get_name(crecp)))
1383 {
1384 *up = crecp->hash_next;
1385#ifdef HAVE_DHCP
1386 if (type & F_DHCP)
1387 {
1388 crecp->next = dhcp_spare;
1389 dhcp_spare = crecp;
1390 }
1391 else
1392#endif
1393 free(crecp);
1394 break;
1395 }
1396 else
1397 up = &crecp->hash_next;
1398 }
1399
1400 while ((name = strchr(name, '.')))
1401 {
1402 name++;
1403
1404 /* Look for one existing, don't need another */
1405 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
1406 if (!is_outdated_cname_pointer(crecp) &&
1407 (crecp->flags & F_FORWARD) &&
1408 (crecp->flags & type) &&
1409 hostname_isequal(name, cache_get_name(crecp)))
1410 break;
1411
1412 if (crecp)
1413 {
1414 /* If the new name expires later, transfer that time to
1415 empty non-terminal entry. */
1416 if (!(crecp->flags & F_IMMORTAL))
1417 {
1418 if (source->flags & F_IMMORTAL)
1419 crecp->flags |= F_IMMORTAL;
1420 else if (difftime(crecp->ttd, source->ttd) < 0)
1421 crecp->ttd = source->ttd;
1422 }
1423 continue;
1424 }
1425
1426#ifdef HAVE_DHCP
1427 if ((source->flags & F_DHCP) && dhcp_spare)
1428 {
1429 crecp = dhcp_spare;
1430 dhcp_spare = dhcp_spare->next;
1431 }
1432 else
1433#endif
Simon Kelley3a610a02018-09-26 16:50:35 +01001434 crecp = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001435
Simon Kelleyea6cc332018-09-18 23:21:17 +01001436 if (crecp)
1437 {
Simon Kelley48b090c2018-09-26 12:53:59 +01001438 crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS | F_REVERSE);
1439 crecp->ttd = source->ttd;
Simon Kelleyea6cc332018-09-18 23:21:17 +01001440 crecp->name.namep = name;
1441
1442 cache_hash(crecp);
1443 }
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001444 }
1445}
1446
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001447#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001448int cache_make_stat(struct txt_record *t)
1449{
1450 static char *buff = NULL;
1451 static int bufflen = 60;
1452 int len;
1453 struct server *serv, *serv1;
1454 char *p;
1455
1456 if (!buff && !(buff = whine_malloc(60)))
1457 return 0;
1458
1459 p = buff;
1460
1461 switch (t->stat)
1462 {
1463 case TXT_STAT_CACHESIZE:
1464 sprintf(buff+1, "%d", daemon->cachesize);
1465 break;
1466
1467 case TXT_STAT_INSERTS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001468 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001469 break;
1470
1471 case TXT_STAT_EVICTIONS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001472 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001473 break;
1474
1475 case TXT_STAT_MISSES:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001476 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001477 break;
1478
1479 case TXT_STAT_HITS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001480 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001481 break;
1482
1483#ifdef HAVE_AUTH
1484 case TXT_STAT_AUTH:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001485 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001486 break;
1487#endif
1488
1489 case TXT_STAT_SERVERS:
1490 /* sum counts from different records for same server */
1491 for (serv = daemon->servers; serv; serv = serv->next)
1492 serv->flags &= ~SERV_COUNTED;
1493
1494 for (serv = daemon->servers; serv; serv = serv->next)
1495 if (!(serv->flags &
1496 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1497 {
1498 char *new, *lenp;
1499 int port, newlen, bytes_avail, bytes_needed;
1500 unsigned int queries = 0, failed_queries = 0;
1501 for (serv1 = serv; serv1; serv1 = serv1->next)
1502 if (!(serv1->flags &
1503 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1504 sockaddr_isequal(&serv->addr, &serv1->addr))
1505 {
1506 serv1->flags |= SERV_COUNTED;
1507 queries += serv1->queries;
1508 failed_queries += serv1->failed_queries;
1509 }
1510 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1511 lenp = p++; /* length */
Simon Kelley04b0ac02015-04-06 17:19:13 +01001512 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001513 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1514 if (bytes_needed >= bytes_avail)
1515 {
1516 /* expand buffer if necessary */
1517 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1518 if (!(new = whine_malloc(newlen)))
1519 return 0;
1520 memcpy(new, buff, bufflen);
1521 free(buff);
1522 p = new + (p - buff);
1523 lenp = p - 1;
1524 buff = new;
1525 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001526 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001527 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1528 }
1529 *lenp = bytes_needed;
1530 p += bytes_needed;
1531 }
1532 t->txt = (unsigned char *)buff;
1533 t->len = p - buff;
1534 return 1;
1535 }
1536
1537 len = strlen(buff+1);
1538 t->txt = (unsigned char *)buff;
1539 t->len = len + 1;
1540 *buff = len;
1541 return 1;
1542}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001543#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001544
Simon Kelley394ff492015-03-29 22:17:14 +01001545/* There can be names in the cache containing control chars, don't
1546 mess up logging or open security holes. */
1547static char *sanitise(char *name)
1548{
1549 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001550 if (name)
1551 for (r = (unsigned char *)name; *r; r++)
1552 if (!isprint((int)*r))
1553 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001554
1555 return name;
1556}
1557
1558
Simon Kelley5aabfc72007-08-29 11:24:47 +01001559void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001560{
Simon Kelley824af852008-02-12 20:43:05 +00001561 struct server *serv, *serv1;
1562
1563 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1564 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001565 daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelley824af852008-02-12 20:43:05 +00001566 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001567 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001568#ifdef HAVE_AUTH
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001569 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001570#endif
Simon Kelleyc2207682014-01-08 18:04:20 +00001571#ifdef HAVE_DNSSEC
1572 blockdata_report();
1573#endif
Simon Kelley824af852008-02-12 20:43:05 +00001574
Simon Kelley824af852008-02-12 20:43:05 +00001575 /* sum counts from different records for same server */
1576 for (serv = daemon->servers; serv; serv = serv->next)
1577 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001578
Simon Kelley824af852008-02-12 20:43:05 +00001579 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001580 if (!(serv->flags &
1581 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001582 {
1583 int port;
1584 unsigned int queries = 0, failed_queries = 0;
1585 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001586 if (!(serv1->flags &
1587 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1588 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001589 {
1590 serv1->flags |= SERV_COUNTED;
1591 queries += serv1->queries;
1592 failed_queries += serv1->failed_queries;
1593 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001594 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1595 my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
Simon Kelley824af852008-02-12 20:43:05 +00001596 }
1597
Simon Kelley28866e92011-02-14 20:19:14 +00001598 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001599 {
1600 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001601 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001602 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001603
1604 for (i=0; i<hash_size; i++)
1605 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1606 {
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001607 char *t = " ";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001608 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1609 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001610 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001611 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001612 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001613 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001614 a = sanitise(cache_get_cname_target(cache));
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001615#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001616 else if (cache->flags & F_DS)
1617 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001618 if (!(cache->flags & F_NEG))
Simon Kelleyb8eac192014-02-27 14:30:03 +00001619 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1620 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001621 }
1622 else if (cache->flags & F_DNSKEY)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001623 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1624 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001625#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001626 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001627 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001628 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001629 if (cache->flags & F_IPV4)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001630 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001631#ifdef HAVE_IPV6
Simon Kelleyf2621c72007-04-29 19:47:21 +01001632 else if (cache->flags & F_IPV6)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001633 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001634#endif
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001635 }
1636
Simon Kelleye7829ae2014-01-22 22:21:51 +00001637 if (cache->flags & F_IPV4)
1638 t = "4";
1639 else if (cache->flags & F_IPV6)
1640 t = "6";
1641 else if (cache->flags & F_CNAME)
1642 t = "C";
1643#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001644 else if (cache->flags & F_DS)
1645 t = "S";
1646 else if (cache->flags & F_DNSKEY)
1647 t = "K";
1648#endif
Simon Kelley32678042014-12-17 20:38:20 +00001649 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001650 cache->flags & F_FORWARD ? "F" : " ",
1651 cache->flags & F_REVERSE ? "R" : " ",
1652 cache->flags & F_IMMORTAL ? "I" : " ",
1653 cache->flags & F_DHCP ? "D" : " ",
1654 cache->flags & F_NEG ? "N" : " ",
1655 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001656 cache->flags & F_HOSTS ? "H" : " ",
1657 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001658#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001659 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001660#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001661 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1662 /* ctime includes trailing \n - eat it */
1663 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001664#endif
Rosen Penevcbd29e52017-06-27 22:29:51 +01001665 my_syslog(LOG_INFO, "%s", daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001666 }
1667 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001668}
1669
Simon Kelley19c51cf2014-03-18 22:38:30 +00001670char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001671{
Simon Kelley7622fc02009-06-04 20:32:05 +01001672 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001673
Simon Kelley19c51cf2014-03-18 22:38:30 +00001674 if (index == SRC_CONFIG)
1675 return "config";
1676 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001677 return HOSTSFILE;
1678
1679 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1680 if (ah->index == index)
1681 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001682
1683#ifdef HAVE_INOTIFY
1684 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1685 if (ah->index == index)
1686 return ah->fname;
1687#endif
1688
Simon Kelley7622fc02009-06-04 20:32:05 +01001689 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001690}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001691
Simon Kelley610e7822014-02-06 14:45:17 +00001692char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001693{
1694 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001695 int len = 10; /* strlen("type=xxxxx") */
1696 const char *types = NULL;
1697 static char *buff = NULL;
1698 static int bufflen = 0;
1699
Simon Kelley1a6bca82008-07-11 11:11:42 +01001700 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1701 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001702 {
1703 types = typestr[i].name;
1704 len = strlen(types);
1705 break;
1706 }
1707
Simon Kelleyb758b672018-08-23 21:41:23 +01001708 if (desc)
1709 {
1710 len += 2; /* braces */
1711 len += strlen(desc);
1712 }
1713 len++; /* terminator */
1714
Simon Kelley610e7822014-02-06 14:45:17 +00001715 if (!buff || bufflen < len)
1716 {
1717 if (buff)
1718 free(buff);
1719 else if (len < 20)
1720 len = 20;
1721
1722 buff = whine_malloc(len);
1723 bufflen = len;
1724 }
1725
1726 if (buff)
1727 {
Simon Kelleyb758b672018-08-23 21:41:23 +01001728 if (desc)
1729 {
1730 if (types)
1731 sprintf(buff, "%s[%s]", desc, types);
1732 else
1733 sprintf(buff, "%s[type=%d]", desc, type);
1734 }
Simon Kelley610e7822014-02-06 14:45:17 +00001735 else
Simon Kelleyb758b672018-08-23 21:41:23 +01001736 {
1737 if (types)
1738 sprintf(buff, "<%s>", types);
1739 else
1740 sprintf(buff, "type=%d", type);
1741 }
Simon Kelley610e7822014-02-06 14:45:17 +00001742 }
Simon Kelleyb758b672018-08-23 21:41:23 +01001743
Simon Kelley610e7822014-02-06 14:45:17 +00001744 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001745}
1746
Simon Kelley28866e92011-02-14 20:19:14 +00001747void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001748{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001749 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001750 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001751
Simon Kelley28866e92011-02-14 20:19:14 +00001752 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001753 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001754
Simon Kelley394ff492015-03-29 22:17:14 +01001755 name = sanitise(name);
1756
Simon Kelley5aabfc72007-08-29 11:24:47 +01001757 if (addr)
1758 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001759 if (flags & F_KEYTAG)
Simon Kelley15379ea2015-12-21 18:31:55 +00001760 sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
Simon Kelley07ed5852018-05-04 21:52:22 +01001761 else if (flags & F_RCODE)
1762 {
1763 unsigned int rcode = addr->addr.rcode.rcode;
1764
1765 if (rcode == SERVFAIL)
1766 dest = "SERVFAIL";
1767 else if (rcode == REFUSED)
1768 dest = "REFUSED";
1769 else if (rcode == NOTIMP)
1770 dest = "not implemented";
1771 else
1772 sprintf(daemon->addrbuff, "%u", rcode);
1773 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001774 else
1775 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001776#ifdef HAVE_IPV6
Simon Kelley0fc2f312014-01-08 10:26:58 +00001777 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1778 addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001779#else
Simon Kelley0fc2f312014-01-08 10:26:58 +00001780 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001781#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001782 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001783 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001784 else
1785 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001786
1787 if (flags & F_REVERSE)
1788 {
1789 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001790 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001791 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001792
1793 if (flags & F_NEG)
1794 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001795 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001796 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001797 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001798 {
1799 if (flags & F_IPV4)
1800 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001801 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001802 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001803 else
1804 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001805 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001806 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001807 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001808 dest = "<CNAME>";
1809 else if (flags & F_RRNAME)
1810 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001811
Simon Kelley1f15b812009-10-13 17:49:32 +01001812 if (flags & F_CONFIG)
1813 source = "config";
1814 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001815 source = "DHCP";
1816 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001817 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001818 else if (flags & F_UPSTREAM)
1819 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001820 else if (flags & F_SECSTAT)
1821 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001822 else if (flags & F_AUTH)
1823 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001824 else if (flags & F_SERVER)
1825 {
1826 source = "forwarded";
1827 verb = "to";
1828 }
1829 else if (flags & F_QUERY)
1830 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001831 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001832 verb = "from";
1833 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001834 else if (flags & F_DNSSEC)
1835 {
1836 source = arg;
1837 verb = "to";
1838 }
Wang Jian49752b92014-03-28 20:52:47 +00001839 else if (flags & F_IPSET)
1840 {
1841 source = "ipset add";
1842 dest = name;
1843 name = arg;
1844 verb = daemon->addrbuff;
1845 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001846 else
1847 source = "cached";
1848
Simon Kelley3d8df262005-08-29 12:19:27 +01001849 if (strlen(name) == 0)
1850 name = ".";
1851
Simon Kelley25cf5e32015-01-09 15:53:03 +00001852 if (option_bool(OPT_EXTRALOG))
1853 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001854 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001855 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001856 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001857 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001858 my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001859 }
1860 else
1861 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001862}
1863
Simon Kelley98c098b2014-01-08 17:31:16 +00001864