blob: 5a38c21857f3d7491936a54e926c9ed59c843ab6 [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 Kelley611ebc52012-07-16 16:23:46 +0100828 (crec = whine_malloc(sizeof(struct crec))))
829 {
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 Kelley9009d742008-11-14 20:04:27 +00001032 (cache = whine_malloc(sizeof(struct crec) +
Simon Kelley1f15b812009-10-13 17:49:32 +01001033 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +00001034 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001035 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +00001036 strcat(cache->name.sname, ".");
1037 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +00001038 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001039 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001040 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001041 name_count++;
1042 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001043 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +00001044 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001045 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +00001046 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001047 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001048 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001049 name_count++;
1050 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001051 free(canon);
1052
Simon Kelley9009d742008-11-14 20:04:27 +00001053 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001054 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +00001055 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1056 }
1057 }
1058
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001059 fclose(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001060
Simon Kelley70d18732015-01-31 19:59:29 +00001061 if (rhash)
Simon Kelleyf9c86372015-02-03 21:52:48 +00001062 rehash(name_count);
1063
1064 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1065
Simon Kelley4011c4e2006-10-28 16:26:19 +01001066 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001067}
1068
Simon Kelley7622fc02009-06-04 20:32:05 +01001069void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001070{
1071 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001072 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +01001073 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +00001074 struct host_record *hr;
1075 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001076 struct cname *a;
1077 struct interface_name *intr;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001078#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001079 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001080#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001081
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001082 daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
1083 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 0;
Simon Kelley59353a62004-11-21 19:34:28 +00001084
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001085 for (i=0; i<hash_size; i++)
1086 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1087 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001088#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +00001089 cache_blockdata_free(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001090#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001091 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001092 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001093 {
1094 *up = cache->hash_next;
1095 free(cache);
1096 }
1097 else if (!(cache->flags & F_DHCP))
1098 {
1099 *up = cache->hash_next;
1100 if (cache->flags & F_BIGNAME)
1101 {
1102 cache->name.bname->next = big_free;
1103 big_free = cache->name.bname;
1104 }
1105 cache->flags = 0;
1106 }
1107 else
1108 up = &cache->hash_next;
1109 }
1110
Simon Kelleyd56a6042013-10-11 14:39:03 +01001111 /* Add CNAMEs to interface_names to the cache */
1112 for (a = daemon->cnames; a; a = a->next)
1113 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001114 if (a->alias[1] != '*' &&
1115 hostname_isequal(a->target, intr->name) &&
Simon Kelley532066e2013-11-26 10:14:47 +00001116 ((cache = whine_malloc(sizeof(struct crec)))))
Simon Kelleyd56a6042013-10-11 14:39:03 +01001117 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001118 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001119 cache->ttd = a->ttl;
Simon Kelley532066e2013-11-26 10:14:47 +00001120 cache->name.namep = a->alias;
1121 cache->addr.cname.target.int_name = intr;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001122 cache->addr.cname.uid = SRC_INTERFACE;
Simon Kelley45d8a242018-07-17 21:01:14 +01001123 cache->uid = UID_NONE;
Simon Kelley532066e2013-11-26 10:14:47 +00001124 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001125 make_non_terminals(cache);
Simon Kelley532066e2013-11-26 10:14:47 +00001126 add_hosts_cname(cache); /* handle chains */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001127 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001128
1129#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001130 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001131 if ((cache = whine_malloc(sizeof(struct crec))) &&
Simon Kelleyee415862014-02-11 11:07:22 +00001132 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001133 {
Simon Kelleyee415862014-02-11 11:07:22 +00001134 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001135 cache->ttd = daemon->local_ttl;
Simon Kelleyee415862014-02-11 11:07:22 +00001136 cache->name.namep = ds->name;
1137 cache->addr.ds.keylen = ds->digestlen;
1138 cache->addr.ds.algo = ds->algo;
1139 cache->addr.ds.keytag = ds->keytag;
1140 cache->addr.ds.digest = ds->digest_type;
1141 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001142 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001143 make_non_terminals(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001144 }
1145#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001146
Simon Kelleye759d422012-03-16 13:18:57 +00001147 /* borrow the packet buffer for a temporary by-address hash */
1148 memset(daemon->packet, 0, daemon->packet_buff_sz);
1149 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1150 /* we overwrote the buffer... */
1151 daemon->srv_save = NULL;
1152
1153 /* Do host_records in config. */
1154 for (hr = daemon->host_records; hr; hr = hr->next)
1155 for (nl = hr->names; nl; nl = nl->next)
1156 {
1157 if (hr->addr.s_addr != 0 &&
1158 (cache = whine_malloc(sizeof(struct crec))))
1159 {
1160 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001161 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001162 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001163 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001164 }
1165#ifdef HAVE_IPV6
1166 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
1167 (cache = whine_malloc(sizeof(struct crec))))
1168 {
1169 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001170 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001171 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001172 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001173 }
1174#endif
1175 }
1176
Simon Kelley28866e92011-02-14 20:19:14 +00001177 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001178 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001179 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001180 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001181 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001182 else
1183 {
1184 if (!option_bool(OPT_NO_HOSTS))
1185 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1186
1187 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1188 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1189 if (!(ah->flags & AH_INACTIVE))
1190 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1191 }
1192
Simon Kelley70d18732015-01-31 19:59:29 +00001193#ifdef HAVE_INOTIFY
1194 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1195#endif
1196
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001197}
1198
Simon Kelley7622fc02009-06-04 20:32:05 +01001199#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001200struct in_addr a_record_from_hosts(char *name, time_t now)
1201{
1202 struct crec *crecp = NULL;
1203 struct in_addr ret;
1204
1205 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1206 if (crecp->flags & F_HOSTS)
1207 return *(struct in_addr *)&crecp->addr;
1208
1209 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1210
1211 ret.s_addr = 0;
1212 return ret;
1213}
1214
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001215void cache_unhash_dhcp(void)
1216{
Simon Kelley6b010842007-02-12 20:32:07 +00001217 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001218 int i;
1219
1220 for (i=0; i<hash_size; i++)
1221 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1222 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001223 {
1224 *up = cache->hash_next;
1225 cache->next = dhcp_spare;
1226 dhcp_spare = cache;
1227 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001228 else
1229 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001230}
1231
Simon Kelley611ebc52012-07-16 16:23:46 +01001232static void add_dhcp_cname(struct crec *target, time_t ttd)
1233{
1234 struct crec *aliasc;
1235 struct cname *a;
1236
1237 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001238 if (a->alias[1] != '*' &&
1239 hostname_isequal(cache_get_name(target), a->target))
Simon Kelley611ebc52012-07-16 16:23:46 +01001240 {
1241 if ((aliasc = dhcp_spare))
1242 dhcp_spare = dhcp_spare->next;
1243 else /* need new one */
1244 aliasc = whine_malloc(sizeof(struct crec));
1245
1246 if (aliasc)
1247 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001248 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
Simon Kelley611ebc52012-07-16 16:23:46 +01001249 if (ttd == 0)
1250 aliasc->flags |= F_IMMORTAL;
1251 else
1252 aliasc->ttd = ttd;
1253 aliasc->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001254 aliasc->addr.cname.target.cache = target;
Simon Kelley45d8a242018-07-17 21:01:14 +01001255 next_uid(target);
Simon Kelley611ebc52012-07-16 16:23:46 +01001256 aliasc->addr.cname.uid = target->uid;
Simon Kelley45d8a242018-07-17 21:01:14 +01001257 aliasc->uid = UID_NONE;
Simon Kelley611ebc52012-07-16 16:23:46 +01001258 cache_hash(aliasc);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001259 make_non_terminals(aliasc);
Simon Kelley611ebc52012-07-16 16:23:46 +01001260 add_dhcp_cname(aliasc, ttd);
1261 }
1262 }
1263}
1264
Simon Kelley4cb1b322012-02-06 14:30:41 +00001265void cache_add_dhcp_entry(char *host_name, int prot,
1266 struct all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001267{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001268 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001269 unsigned short flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001270 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001271 size_t addrlen = sizeof(struct in_addr);
1272
1273#ifdef HAVE_IPV6
1274 if (prot == AF_INET6)
1275 {
1276 flags = F_IPV6;
1277 addrlen = sizeof(struct in6_addr);
1278 }
1279#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001280
Simon Kelley12d71ed2012-08-30 15:16:41 +01001281 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1282
Simon Kelley4cb1b322012-02-06 14:30:41 +00001283 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001284 {
Simon Kelley824af852008-02-12 20:43:05 +00001285 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001286 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001287 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001288 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001289 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001290 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001291 host_name, daemon->addrbuff);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001292 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1293 in_hosts = 1;
1294 else
1295 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001296 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001297 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001298 {
Simon Kelleyeb1fe152018-07-18 20:59:52 +01001299 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD), NULL, NULL);
Simon Kelley824af852008-02-12 20:43:05 +00001300 /* scan_free deletes all addresses associated with name */
1301 break;
1302 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001303 }
Simon Kelley824af852008-02-12 20:43:05 +00001304
Simon Kelley12d71ed2012-08-30 15:16:41 +01001305 /* if in hosts, don't need DHCP record */
1306 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001307 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001308
1309 /* Name in hosts, address doesn't match */
1310 if (fail_crec)
1311 {
1312 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1313 my_syslog(MS_DHCP | LOG_WARNING,
1314 _("not giving name %s to the DHCP lease of %s because "
1315 "the name exists in %s with address %s"),
1316 host_name, daemon->addrbuff,
1317 record_source(fail_crec->uid), daemon->namebuff);
1318 return;
1319 }
1320
1321 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1322 {
1323 if (crec->flags & F_NEG)
1324 {
1325 flags |= F_REVERSE;
Simon Kelleyeb1fe152018-07-18 20:59:52 +01001326 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags, NULL, NULL);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001327 }
1328 }
1329 else
1330 flags |= F_REVERSE;
1331
1332 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001333 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001334 else /* need new one */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001335 crec = whine_malloc(sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001336
1337 if (crec) /* malloc may fail */
1338 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001339 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001340 if (ttd == 0)
1341 crec->flags |= F_IMMORTAL;
1342 else
1343 crec->ttd = ttd;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001344 crec->addr.addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001345 crec->name.namep = host_name;
Simon Kelley45d8a242018-07-17 21:01:14 +01001346 crec->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001347 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001348 make_non_terminals(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001349
Simon Kelley611ebc52012-07-16 16:23:46 +01001350 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001351 }
1352}
Simon Kelley7622fc02009-06-04 20:32:05 +01001353#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001354
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001355/* Called when we put a local or DHCP name into the cache.
1356 Creates empty cache entries for subnames (ie,
1357 for three.two.one, for two.one and one), without
1358 F_IPV4 or F_IPV6 or F_CNAME set. These convert
1359 NXDOMAIN answers to NoData ones. */
1360static void make_non_terminals(struct crec *source)
1361{
1362 char *name = cache_get_name(source);
Simon Kelleyea6cc332018-09-18 23:21:17 +01001363 struct crec *crecp, *tmp, **up;
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001364 int type = F_HOSTS | F_CONFIG;
1365#ifdef HAVE_DHCP
1366 if (source->flags & F_DHCP)
1367 type = F_DHCP;
1368#endif
1369
1370 /* First delete any empty entries for our new real name. Note that
1371 we only delete empty entries deriving from DHCP for a new DHCP-derived
1372 entry and vice-versa for HOSTS and CONFIG. This ensures that
1373 non-terminals from DHCP go when we reload DHCP and
1374 for HOSTS/CONFIG when we re-read. */
1375 for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
1376 {
1377 tmp = crecp->hash_next;
1378
1379 if (!is_outdated_cname_pointer(crecp) &&
1380 (crecp->flags & F_FORWARD) &&
1381 (crecp->flags & type) &&
Simon Kelleycbfbd172018-08-21 18:25:18 +01001382 !(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS)) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001383 hostname_isequal(name, cache_get_name(crecp)))
1384 {
1385 *up = crecp->hash_next;
1386#ifdef HAVE_DHCP
1387 if (type & F_DHCP)
1388 {
1389 crecp->next = dhcp_spare;
1390 dhcp_spare = crecp;
1391 }
1392 else
1393#endif
1394 free(crecp);
1395 break;
1396 }
1397 else
1398 up = &crecp->hash_next;
1399 }
1400
1401 while ((name = strchr(name, '.')))
1402 {
1403 name++;
1404
1405 /* Look for one existing, don't need another */
1406 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
1407 if (!is_outdated_cname_pointer(crecp) &&
1408 (crecp->flags & F_FORWARD) &&
1409 (crecp->flags & type) &&
1410 hostname_isequal(name, cache_get_name(crecp)))
1411 break;
1412
1413 if (crecp)
1414 {
1415 /* If the new name expires later, transfer that time to
1416 empty non-terminal entry. */
1417 if (!(crecp->flags & F_IMMORTAL))
1418 {
1419 if (source->flags & F_IMMORTAL)
1420 crecp->flags |= F_IMMORTAL;
1421 else if (difftime(crecp->ttd, source->ttd) < 0)
1422 crecp->ttd = source->ttd;
1423 }
1424 continue;
1425 }
1426
1427#ifdef HAVE_DHCP
1428 if ((source->flags & F_DHCP) && dhcp_spare)
1429 {
1430 crecp = dhcp_spare;
1431 dhcp_spare = dhcp_spare->next;
1432 }
1433 else
1434#endif
1435 crecp = whine_malloc(sizeof(struct crec));
1436
Simon Kelleyea6cc332018-09-18 23:21:17 +01001437 if (crecp)
1438 {
1439 *crecp = *source;
1440 crecp->flags &= ~(F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS | F_REVERSE);
1441 crecp->flags |= F_NAMEP;
1442 crecp->name.namep = name;
1443
1444 cache_hash(crecp);
1445 }
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001446 }
1447}
1448
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001449#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001450int cache_make_stat(struct txt_record *t)
1451{
1452 static char *buff = NULL;
1453 static int bufflen = 60;
1454 int len;
1455 struct server *serv, *serv1;
1456 char *p;
1457
1458 if (!buff && !(buff = whine_malloc(60)))
1459 return 0;
1460
1461 p = buff;
1462
1463 switch (t->stat)
1464 {
1465 case TXT_STAT_CACHESIZE:
1466 sprintf(buff+1, "%d", daemon->cachesize);
1467 break;
1468
1469 case TXT_STAT_INSERTS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001470 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001471 break;
1472
1473 case TXT_STAT_EVICTIONS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001474 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001475 break;
1476
1477 case TXT_STAT_MISSES:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001478 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001479 break;
1480
1481 case TXT_STAT_HITS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001482 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001483 break;
1484
1485#ifdef HAVE_AUTH
1486 case TXT_STAT_AUTH:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001487 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001488 break;
1489#endif
1490
1491 case TXT_STAT_SERVERS:
1492 /* sum counts from different records for same server */
1493 for (serv = daemon->servers; serv; serv = serv->next)
1494 serv->flags &= ~SERV_COUNTED;
1495
1496 for (serv = daemon->servers; serv; serv = serv->next)
1497 if (!(serv->flags &
1498 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1499 {
1500 char *new, *lenp;
1501 int port, newlen, bytes_avail, bytes_needed;
1502 unsigned int queries = 0, failed_queries = 0;
1503 for (serv1 = serv; serv1; serv1 = serv1->next)
1504 if (!(serv1->flags &
1505 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1506 sockaddr_isequal(&serv->addr, &serv1->addr))
1507 {
1508 serv1->flags |= SERV_COUNTED;
1509 queries += serv1->queries;
1510 failed_queries += serv1->failed_queries;
1511 }
1512 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1513 lenp = p++; /* length */
Simon Kelley04b0ac02015-04-06 17:19:13 +01001514 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001515 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1516 if (bytes_needed >= bytes_avail)
1517 {
1518 /* expand buffer if necessary */
1519 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1520 if (!(new = whine_malloc(newlen)))
1521 return 0;
1522 memcpy(new, buff, bufflen);
1523 free(buff);
1524 p = new + (p - buff);
1525 lenp = p - 1;
1526 buff = new;
1527 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001528 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001529 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1530 }
1531 *lenp = bytes_needed;
1532 p += bytes_needed;
1533 }
1534 t->txt = (unsigned char *)buff;
1535 t->len = p - buff;
1536 return 1;
1537 }
1538
1539 len = strlen(buff+1);
1540 t->txt = (unsigned char *)buff;
1541 t->len = len + 1;
1542 *buff = len;
1543 return 1;
1544}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001545#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001546
Simon Kelley394ff492015-03-29 22:17:14 +01001547/* There can be names in the cache containing control chars, don't
1548 mess up logging or open security holes. */
1549static char *sanitise(char *name)
1550{
1551 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001552 if (name)
1553 for (r = (unsigned char *)name; *r; r++)
1554 if (!isprint((int)*r))
1555 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001556
1557 return name;
1558}
1559
1560
Simon Kelley5aabfc72007-08-29 11:24:47 +01001561void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001562{
Simon Kelley824af852008-02-12 20:43:05 +00001563 struct server *serv, *serv1;
1564
1565 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1566 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001567 daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelley824af852008-02-12 20:43:05 +00001568 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001569 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001570#ifdef HAVE_AUTH
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001571 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001572#endif
Simon Kelleyc2207682014-01-08 18:04:20 +00001573#ifdef HAVE_DNSSEC
1574 blockdata_report();
1575#endif
Simon Kelley824af852008-02-12 20:43:05 +00001576
Simon Kelley824af852008-02-12 20:43:05 +00001577 /* sum counts from different records for same server */
1578 for (serv = daemon->servers; serv; serv = serv->next)
1579 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001580
Simon Kelley824af852008-02-12 20:43:05 +00001581 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001582 if (!(serv->flags &
1583 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001584 {
1585 int port;
1586 unsigned int queries = 0, failed_queries = 0;
1587 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001588 if (!(serv1->flags &
1589 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1590 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001591 {
1592 serv1->flags |= SERV_COUNTED;
1593 queries += serv1->queries;
1594 failed_queries += serv1->failed_queries;
1595 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001596 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1597 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 +00001598 }
1599
Simon Kelley28866e92011-02-14 20:19:14 +00001600 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001601 {
1602 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001603 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001604 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001605
1606 for (i=0; i<hash_size; i++)
1607 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1608 {
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001609 char *t = " ";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001610 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1611 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001612 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001613 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001614 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001615 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001616 a = sanitise(cache_get_cname_target(cache));
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001617#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001618 else if (cache->flags & F_DS)
1619 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001620 if (!(cache->flags & F_NEG))
Simon Kelleyb8eac192014-02-27 14:30:03 +00001621 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1622 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001623 }
1624 else if (cache->flags & F_DNSKEY)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001625 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1626 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001627#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001628 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001629 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001630 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001631 if (cache->flags & F_IPV4)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001632 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001633#ifdef HAVE_IPV6
Simon Kelleyf2621c72007-04-29 19:47:21 +01001634 else if (cache->flags & F_IPV6)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001635 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001636#endif
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001637 }
1638
Simon Kelleye7829ae2014-01-22 22:21:51 +00001639 if (cache->flags & F_IPV4)
1640 t = "4";
1641 else if (cache->flags & F_IPV6)
1642 t = "6";
1643 else if (cache->flags & F_CNAME)
1644 t = "C";
1645#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001646 else if (cache->flags & F_DS)
1647 t = "S";
1648 else if (cache->flags & F_DNSKEY)
1649 t = "K";
1650#endif
Simon Kelley32678042014-12-17 20:38:20 +00001651 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001652 cache->flags & F_FORWARD ? "F" : " ",
1653 cache->flags & F_REVERSE ? "R" : " ",
1654 cache->flags & F_IMMORTAL ? "I" : " ",
1655 cache->flags & F_DHCP ? "D" : " ",
1656 cache->flags & F_NEG ? "N" : " ",
1657 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001658 cache->flags & F_HOSTS ? "H" : " ",
1659 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001660#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001661 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001662#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001663 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1664 /* ctime includes trailing \n - eat it */
1665 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001666#endif
Rosen Penevcbd29e52017-06-27 22:29:51 +01001667 my_syslog(LOG_INFO, "%s", daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001668 }
1669 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001670}
1671
Simon Kelley19c51cf2014-03-18 22:38:30 +00001672char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001673{
Simon Kelley7622fc02009-06-04 20:32:05 +01001674 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001675
Simon Kelley19c51cf2014-03-18 22:38:30 +00001676 if (index == SRC_CONFIG)
1677 return "config";
1678 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001679 return HOSTSFILE;
1680
1681 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1682 if (ah->index == index)
1683 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001684
1685#ifdef HAVE_INOTIFY
1686 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1687 if (ah->index == index)
1688 return ah->fname;
1689#endif
1690
Simon Kelley7622fc02009-06-04 20:32:05 +01001691 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001692}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001693
Simon Kelley610e7822014-02-06 14:45:17 +00001694char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001695{
1696 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001697 int len = 10; /* strlen("type=xxxxx") */
1698 const char *types = NULL;
1699 static char *buff = NULL;
1700 static int bufflen = 0;
1701
Simon Kelley1a6bca82008-07-11 11:11:42 +01001702 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1703 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001704 {
1705 types = typestr[i].name;
1706 len = strlen(types);
1707 break;
1708 }
1709
Simon Kelleyb758b672018-08-23 21:41:23 +01001710 if (desc)
1711 {
1712 len += 2; /* braces */
1713 len += strlen(desc);
1714 }
1715 len++; /* terminator */
1716
Simon Kelley610e7822014-02-06 14:45:17 +00001717 if (!buff || bufflen < len)
1718 {
1719 if (buff)
1720 free(buff);
1721 else if (len < 20)
1722 len = 20;
1723
1724 buff = whine_malloc(len);
1725 bufflen = len;
1726 }
1727
1728 if (buff)
1729 {
Simon Kelleyb758b672018-08-23 21:41:23 +01001730 if (desc)
1731 {
1732 if (types)
1733 sprintf(buff, "%s[%s]", desc, types);
1734 else
1735 sprintf(buff, "%s[type=%d]", desc, type);
1736 }
Simon Kelley610e7822014-02-06 14:45:17 +00001737 else
Simon Kelleyb758b672018-08-23 21:41:23 +01001738 {
1739 if (types)
1740 sprintf(buff, "<%s>", types);
1741 else
1742 sprintf(buff, "type=%d", type);
1743 }
Simon Kelley610e7822014-02-06 14:45:17 +00001744 }
Simon Kelleyb758b672018-08-23 21:41:23 +01001745
Simon Kelley610e7822014-02-06 14:45:17 +00001746 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001747}
1748
Simon Kelley28866e92011-02-14 20:19:14 +00001749void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001750{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001751 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001752 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001753
Simon Kelley28866e92011-02-14 20:19:14 +00001754 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001755 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001756
Simon Kelley394ff492015-03-29 22:17:14 +01001757 name = sanitise(name);
1758
Simon Kelley5aabfc72007-08-29 11:24:47 +01001759 if (addr)
1760 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001761 if (flags & F_KEYTAG)
Simon Kelley15379ea2015-12-21 18:31:55 +00001762 sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
Simon Kelley07ed5852018-05-04 21:52:22 +01001763 else if (flags & F_RCODE)
1764 {
1765 unsigned int rcode = addr->addr.rcode.rcode;
1766
1767 if (rcode == SERVFAIL)
1768 dest = "SERVFAIL";
1769 else if (rcode == REFUSED)
1770 dest = "REFUSED";
1771 else if (rcode == NOTIMP)
1772 dest = "not implemented";
1773 else
1774 sprintf(daemon->addrbuff, "%u", rcode);
1775 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001776 else
1777 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001778#ifdef HAVE_IPV6
Simon Kelley0fc2f312014-01-08 10:26:58 +00001779 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1780 addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001781#else
Simon Kelley0fc2f312014-01-08 10:26:58 +00001782 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001783#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001784 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001785 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001786 else
1787 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001788
1789 if (flags & F_REVERSE)
1790 {
1791 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001792 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001793 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001794
1795 if (flags & F_NEG)
1796 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001797 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001798 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001799 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001800 {
1801 if (flags & F_IPV4)
1802 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001803 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001804 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001805 else
1806 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001807 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001808 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001809 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001810 dest = "<CNAME>";
1811 else if (flags & F_RRNAME)
1812 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001813
Simon Kelley1f15b812009-10-13 17:49:32 +01001814 if (flags & F_CONFIG)
1815 source = "config";
1816 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001817 source = "DHCP";
1818 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001819 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001820 else if (flags & F_UPSTREAM)
1821 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001822 else if (flags & F_SECSTAT)
1823 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001824 else if (flags & F_AUTH)
1825 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001826 else if (flags & F_SERVER)
1827 {
1828 source = "forwarded";
1829 verb = "to";
1830 }
1831 else if (flags & F_QUERY)
1832 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001833 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001834 verb = "from";
1835 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001836 else if (flags & F_DNSSEC)
1837 {
1838 source = arg;
1839 verb = "to";
1840 }
Wang Jian49752b92014-03-28 20:52:47 +00001841 else if (flags & F_IPSET)
1842 {
1843 source = "ipset add";
1844 dest = name;
1845 name = arg;
1846 verb = daemon->addrbuff;
1847 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001848 else
1849 source = "cached";
1850
Simon Kelley3d8df262005-08-29 12:19:27 +01001851 if (strlen(name) == 0)
1852 name = ".";
1853
Simon Kelley25cf5e32015-01-09 15:53:03 +00001854 if (option_bool(OPT_EXTRALOG))
1855 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001856 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001857 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001858 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001859 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001860 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 +00001861 }
1862 else
1863 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001864}
1865
Simon Kelley98c098b2014-01-08 17:31:16 +00001866