blob: e64335af4a467fe2d2e66d5b89fa72d45754e880 [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" },
73 { 255, "ANY" }
74};
75
Simon Kelley9e4abcb2004-01-22 19:47:41 +000076static void cache_free(struct crec *crecp);
77static void cache_unlink(struct crec *crecp);
78static void cache_link(struct crec *crecp);
Simon Kelley4011c4e2006-10-28 16:26:19 +010079static void rehash(int size);
80static void cache_hash(struct crec *crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000081
Simon Kelley45d8a242018-07-17 21:01:14 +010082void next_uid(struct crec *crecp)
Simon Kelley3f7483e2014-03-16 22:56:58 +000083{
Andyd5082152014-03-17 19:50:29 +000084 static unsigned int uid = 0;
Simon Kelley3f7483e2014-03-16 22:56:58 +000085
Simon Kelley45d8a242018-07-17 21:01:14 +010086 if (crecp->uid == UID_NONE)
87 {
88 uid++;
Andyd5082152014-03-17 19:50:29 +000089
Simon Kelley45d8a242018-07-17 21:01:14 +010090 /* uid == 0 used to indicate CNAME to interface name. */
91 if (uid == UID_NONE)
92 uid++;
93
94 crecp->uid = uid;
95 }
Simon Kelley3f7483e2014-03-16 22:56:58 +000096}
97
Simon Kelley5aabfc72007-08-29 11:24:47 +010098void cache_init(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000099{
100 struct crec *crecp;
101 int i;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100102
Simon Kelley5aabfc72007-08-29 11:24:47 +0100103 bignames_left = daemon->cachesize/10;
104
105 if (daemon->cachesize > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000106 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100107 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000108
Simon Kelley5aabfc72007-08-29 11:24:47 +0100109 for (i=0; i < daemon->cachesize; i++, crecp++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000110 {
111 cache_link(crecp);
112 crecp->flags = 0;
Simon Kelley45d8a242018-07-17 21:01:14 +0100113 crecp->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000114 }
115 }
116
Simon Kelley4011c4e2006-10-28 16:26:19 +0100117 /* create initial hash table*/
Simon Kelley5aabfc72007-08-29 11:24:47 +0100118 rehash(daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000119}
120
Simon Kelley4011c4e2006-10-28 16:26:19 +0100121/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
122 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
123 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
124 expand the table. */
125static void rehash(int size)
126{
127 struct crec **new, **old, *p, *tmp;
128 int i, new_size, old_size;
129
130 /* hash_size is a power of two. */
131 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
132
133 /* must succeed in getting first instance, failure later is non-fatal */
134 if (!hash_table)
135 new = safe_malloc(new_size * sizeof(struct crec *));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100136 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
Simon Kelley4011c4e2006-10-28 16:26:19 +0100137 return;
138
139 for(i = 0; i < new_size; i++)
140 new[i] = NULL;
141
142 old = hash_table;
143 old_size = hash_size;
144 hash_table = new;
145 hash_size = new_size;
146
147 if (old)
148 {
149 for (i = 0; i < old_size; i++)
150 for (p = old[i]; p ; p = tmp)
151 {
152 tmp = p->hash_next;
153 cache_hash(p);
154 }
155 free(old);
156 }
157}
158
Simon Kelley3d8df262005-08-29 12:19:27 +0100159static struct crec **hash_bucket(char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000160{
Simon Kelley4011c4e2006-10-28 16:26:19 +0100161 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
Simon Kelley16972692006-10-16 20:04:18 +0100162 const unsigned char *mix_tab = (const unsigned char*)typestr;
163
Simon Kelley3d8df262005-08-29 12:19:27 +0100164 while((c = (unsigned char) *name++))
Simon Kelley16972692006-10-16 20:04:18 +0100165 {
166 /* don't use tolower and friends here - they may be messed up by LOCALE */
167 if (c >= 'A' && c <= 'Z')
168 c += 'a' - 'A';
Simon Kelley4011c4e2006-10-28 16:26:19 +0100169 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
Simon Kelley16972692006-10-16 20:04:18 +0100170 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000171
172 /* hash_size is a power of two */
Simon Kelley16972692006-10-16 20:04:18 +0100173 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000174}
175
176static void cache_hash(struct crec *crecp)
177{
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000178 /* maintain an invariant that all entries with F_REVERSE set
179 are at the start of the hash-chain and all non-reverse
180 immortal entries are at the end of the hash-chain.
181 This allows reverse searches and garbage collection to be optimised */
182
183 struct crec **up = hash_bucket(cache_get_name(crecp));
184
185 if (!(crecp->flags & F_REVERSE))
186 {
187 while (*up && ((*up)->flags & F_REVERSE))
188 up = &((*up)->hash_next);
189
190 if (crecp->flags & F_IMMORTAL)
Simon Kelley6b010842007-02-12 20:32:07 +0000191 while (*up && !((*up)->flags & F_IMMORTAL))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000192 up = &((*up)->hash_next);
193 }
194 crecp->hash_next = *up;
195 *up = crecp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000196}
Simon Kelley82e3f452014-01-31 21:05:48 +0000197
198#ifdef HAVE_DNSSEC
199static void cache_blockdata_free(struct crec *crecp)
200{
201 if (crecp->flags & F_DNSKEY)
Simon Kelley93be5b12015-12-15 12:04:40 +0000202 blockdata_free(crecp->addr.key.keydata);
Simon Kelleye3f14552014-03-01 17:58:28 +0000203 else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
Simon Kelley82e3f452014-01-31 21:05:48 +0000204 blockdata_free(crecp->addr.ds.keydata);
205}
206#endif
207
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000208static void cache_free(struct crec *crecp)
209{
210 crecp->flags &= ~F_FORWARD;
211 crecp->flags &= ~F_REVERSE;
Simon Kelley45d8a242018-07-17 21:01:14 +0100212 crecp->uid = UID_NONE; /* invalidate CNAMES pointing to this. */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100213
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000214 if (cache_tail)
215 cache_tail->next = crecp;
216 else
217 cache_head = crecp;
218 crecp->prev = cache_tail;
219 crecp->next = NULL;
220 cache_tail = crecp;
221
222 /* retrieve big name for further use. */
223 if (crecp->flags & F_BIGNAME)
224 {
225 crecp->name.bname->next = big_free;
226 big_free = crecp->name.bname;
227 crecp->flags &= ~F_BIGNAME;
228 }
Simon Kelley072e81b2014-01-31 12:42:54 +0000229
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100230#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +0000231 cache_blockdata_free(crecp);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100232#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000233}
234
235/* insert a new cache entry at the head of the list (youngest entry) */
236static void cache_link(struct crec *crecp)
237{
238 if (cache_head) /* check needed for init code */
239 cache_head->prev = crecp;
240 crecp->next = cache_head;
241 crecp->prev = NULL;
242 cache_head = crecp;
243 if (!cache_tail)
244 cache_tail = crecp;
245}
246
247/* remove an arbitrary cache entry for promotion */
248static void cache_unlink (struct crec *crecp)
249{
250 if (crecp->prev)
251 crecp->prev->next = crecp->next;
252 else
253 cache_head = crecp->next;
254
255 if (crecp->next)
256 crecp->next->prev = crecp->prev;
257 else
258 cache_tail = crecp->prev;
259}
260
261char *cache_get_name(struct crec *crecp)
262{
263 if (crecp->flags & F_BIGNAME)
264 return crecp->name.bname->name;
Simon Kelley28866e92011-02-14 20:19:14 +0000265 else if (crecp->flags & F_NAMEP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000266 return crecp->name.namep;
267
268 return crecp->name.sname;
269}
270
Simon Kelleyd56a6042013-10-11 14:39:03 +0100271char *cache_get_cname_target(struct crec *crecp)
272{
Simon Kelley19c51cf2014-03-18 22:38:30 +0000273 if (crecp->addr.cname.uid != SRC_INTERFACE)
Simon Kelleyd56a6042013-10-11 14:39:03 +0100274 return cache_get_name(crecp->addr.cname.target.cache);
275
276 return crecp->addr.cname.target.int_name->name;
277}
278
279
280
Simon Kelleyb75e9362012-12-07 11:50:41 +0000281struct crec *cache_enumerate(int init)
282{
283 static int bucket;
284 static struct crec *cache;
285
286 if (init)
287 {
288 bucket = 0;
289 cache = NULL;
290 }
291 else if (cache && cache->hash_next)
292 cache = cache->hash_next;
293 else
294 {
295 cache = NULL;
296 while (bucket < hash_size)
297 if ((cache = hash_table[bucket++]))
298 break;
299 }
300
301 return cache;
302}
303
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100304static int is_outdated_cname_pointer(struct crec *crecp)
305{
Andy3e21a1a2014-03-22 19:10:07 +0000306 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100307 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100308
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100309 /* NB. record may be reused as DS or DNSKEY, where uid is
310 overloaded for something completely different */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100311 if (crecp->addr.cname.target.cache &&
312 (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
313 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100314 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100315
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100316 return 1;
317}
318
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000319static int is_expired(time_t now, struct crec *crecp)
320{
321 if (crecp->flags & F_IMMORTAL)
322 return 0;
323
324 if (difftime(now, crecp->ttd) < 0)
325 return 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100326
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000327 return 1;
328}
329
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100330static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags,
331 struct crec **target_crec, unsigned int *target_uid)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000332{
333 /* Scan and remove old entries.
334 If (flags & F_FORWARD) then remove any forward entries for name and any expired
335 entries but only in the same hash bucket as name.
336 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
337 entries in the whole cache.
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000338 If (flags == 0) remove any expired entries in the whole cache.
339
Simon Kelleycbc65242014-12-21 21:21:53 +0000340 In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
341 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 +0000342
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000343 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100344 so that when we hit an entry which isn't reverse and is immortal, we're done.
345
346 If we free a crec which is a CNAME target, return the entry and uid in target_crec and target_uid.
347 This entry will get re-used with the same name, to preserve CNAMEs. */
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000348
349 struct crec *crecp, **up;
350
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000351 if (flags & F_FORWARD)
352 {
Simon Kelley6b010842007-02-12 20:32:07 +0000353 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000354 {
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000355 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
356 {
Simon Kelleye7829ae2014-01-22 22:21:51 +0000357 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
358 if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
Simon Kelley6429e422014-01-23 12:09:36 +0000359 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000360 {
361 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelleycbc65242014-12-21 21:21:53 +0000362 return crecp;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000363 *up = crecp->hash_next;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100364 /* If this record is for the name we're inserting and is the target
365 of a CNAME record. Make the new record for the same name, in the same
366 crec, with the same uid to avoid breaking the existing CNAME. */
367 if (crecp->uid != UID_NONE)
368 {
369 if (target_crec)
370 *target_crec = crecp;
371 if (target_uid)
372 *target_uid = crecp->uid;
373 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000374 cache_unlink(crecp);
375 cache_free(crecp);
376 continue;
377 }
378
379#ifdef HAVE_DNSSEC
Simon Kelley93be5b12015-12-15 12:04:40 +0000380 /* Deletion has to be class-sensitive for DS and DNSKEY */
381 if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000382 {
Simon Kelley824202e2014-01-23 20:59:46 +0000383 if (crecp->flags & F_CONFIG)
Simon Kelleycbc65242014-12-21 21:21:53 +0000384 return crecp;
Simon Kelley824202e2014-01-23 20:59:46 +0000385 *up = crecp->hash_next;
386 cache_unlink(crecp);
387 cache_free(crecp);
388 continue;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000389 }
390#endif
391 }
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100392
393 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
394 {
395 *up = crecp->hash_next;
396 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
397 {
398 cache_unlink(crecp);
399 cache_free(crecp);
400 }
401 continue;
402 }
403
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000404 up = &crecp->hash_next;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000405 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000406 }
407 else
408 {
409 int i;
410#ifdef HAVE_IPV6
411 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
412#else
413 int addrlen = INADDRSZ;
414#endif
415 for (i = 0; i < hash_size; i++)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000416 for (crecp = hash_table[i], up = &hash_table[i];
417 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
418 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000419 if (is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000420 {
421 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000422 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000423 {
424 cache_unlink(crecp);
425 cache_free(crecp);
426 }
427 }
Simon Kelley25439062013-11-25 21:14:51 +0000428 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000429 (flags & crecp->flags & F_REVERSE) &&
430 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
431 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
432 {
433 *up = crecp->hash_next;
434 cache_unlink(crecp);
435 cache_free(crecp);
436 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000437 else
438 up = &crecp->hash_next;
439 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000440
Simon Kelleycbc65242014-12-21 21:21:53 +0000441 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000442}
443
444/* Note: The normal calling sequence is
445 cache_start_insert
446 cache_insert * n
447 cache_end_insert
448
449 but an abort can cause the cache_end_insert to be missed
450 in which can the next cache_start_insert cleans things up. */
451
452void cache_start_insert(void)
453{
454 /* Free any entries which didn't get committed during the last
455 insert due to error.
456 */
457 while (new_chain)
458 {
459 struct crec *tmp = new_chain->next;
460 cache_free(new_chain);
461 new_chain = tmp;
462 }
463 new_chain = NULL;
464 insert_error = 0;
465}
466
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100467struct crec *cache_insert(char *name, struct all_addr *addr,
468 time_t now, unsigned long ttl, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000469{
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100470 struct crec *new, *target_crec = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000471 union bigname *big_name = NULL;
472 int freed_all = flags & F_REVERSE;
Simon Kelley9e038942008-05-30 20:06:34 +0100473 int free_avail = 0;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100474 unsigned int target_uid;
475
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000476 /* Don't log DNSSEC records here, done elsewhere */
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000477 if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000478 {
479 log_query(flags | F_UPSTREAM, name, addr, NULL);
RinSatsuki28de3872015-01-10 15:22:21 +0000480 /* Don't mess with TTL for DNSSEC records. */
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000481 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
482 ttl = daemon->max_cache_ttl;
RinSatsuki28de3872015-01-10 15:22:21 +0000483 if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
484 ttl = daemon->min_cache_ttl;
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000485 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000486
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000487 /* if previous insertion failed give up now. */
488 if (insert_error)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100489 return NULL;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000490
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000491 /* First remove any expired entries and entries for the name/address we
Simon Kelleycbc65242014-12-21 21:21:53 +0000492 are currently inserting. */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100493 if ((new = cache_scan_free(name, addr, now, flags, &target_crec, &target_uid)))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000494 {
Simon Kelleycbc65242014-12-21 21:21:53 +0000495 /* We're trying to insert a record over one from
496 /etc/hosts or DHCP, or other config. If the
497 existing record is for an A or AAAA and
498 the record we're trying to insert is the same,
499 just drop the insert, but don't error the whole process. */
Edwin Török41a8d9e2015-11-14 17:45:48 +0000500 if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000501 {
502 if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
503 new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
504 return new;
505#ifdef HAVE_IPV6
506 else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
507 IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
508 return new;
509#endif
510 }
511
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000512 insert_error = 1;
513 return NULL;
514 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000515
516 /* Now get a cache entry from the end of the LRU list */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100517 if (!target_crec)
518 while (1) {
519 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
520 {
521 insert_error = 1;
522 return NULL;
523 }
524
525 /* Free entry at end of LRU list, use it. */
526 if (!(new->flags & (F_FORWARD | F_REVERSE)))
527 break;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000528
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100529 /* End of LRU list is still in use: if we didn't scan all the hash
530 chains for expired entries do that now. If we already tried that
531 then it's time to start spilling things. */
532
533 /* If free_avail set, we believe that an entry has been freed.
534 Bugs have been known to make this not true, resulting in
535 a tight loop here. If that happens, abandon the
536 insert. Once in this state, all inserts will probably fail. */
537 if (free_avail)
538 {
539 static int warned = 0;
540 if (!warned)
541 {
542 my_syslog(LOG_ERR, _("Internal error in cache."));
543 warned = 1;
544 }
545 insert_error = 1;
546 return NULL;
547 }
548
549 if (freed_all)
550 {
551 struct all_addr free_addr = new->addr.addr;;
552
Simon Kelley8d718cb2014-02-03 16:27:37 +0000553#ifdef HAVE_DNSSEC
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100554 /* For DNSSEC records, addr holds class. */
555 if (new->flags & (F_DS | F_DNSKEY))
556 free_addr.addr.dnssec.class = new->uid;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000557#endif
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100558
559 free_avail = 1; /* Must be free space now. */
560 cache_scan_free(cache_get_name(new), &free_addr, now, new->flags, NULL, NULL);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100561 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100562 }
563 else
564 {
565 cache_scan_free(NULL, NULL, now, 0, NULL, NULL);
566 freed_all = 1;
567 }
568 }
569
570 /* Check if we need to and can allocate extra memory for a long name.
571 If that fails, give up now, always succeed for DNSSEC records. */
572 if (name && (strlen(name) > SMALLDNAME-1))
573 {
574 if (big_free)
575 {
576 big_name = big_free;
577 big_free = big_free->next;
578 }
579 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
580 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
581 {
582 insert_error = 1;
583 return NULL;
584 }
585 else if (bignames_left != 0)
586 bignames_left--;
587
588 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000589
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100590 /* If we freed a cache entry for our name which was a CNAME target, use that.
591 and preserve the uid, so that existing CNAMES are not broken. */
592 if (target_crec)
593 {
594 new = target_crec;
595 new->uid = target_uid;
596 }
597
598 /* Got the rest: finally grab entry. */
599 cache_unlink(new);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000600
601 new->flags = flags;
602 if (big_name)
603 {
604 new->name.bname = big_name;
605 new->flags |= F_BIGNAME;
606 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100607
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000608 if (name)
609 strcpy(cache_get_name(new), name);
610 else
611 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100612
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000613 if (addr)
Simon Kelleyb8eac192014-02-27 14:30:03 +0000614 {
615#ifdef HAVE_DNSSEC
616 if (flags & (F_DS | F_DNSKEY))
617 new->uid = addr->addr.dnssec.class;
618 else
619#endif
620 new->addr.addr = *addr;
621 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100622
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000623 new->ttd = now + (time_t)ttl;
624 new->next = new_chain;
625 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100626
627 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000628}
629
630/* after end of insertion, commit the new entries */
631void cache_end_insert(void)
632{
633 if (insert_error)
634 return;
635
636 while (new_chain)
637 {
638 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100639 /* drop CNAMEs which didn't find a target. */
640 if (is_outdated_cname_pointer(new_chain))
641 cache_free(new_chain);
642 else
643 {
644 cache_hash(new_chain);
645 cache_link(new_chain);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100646 daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100647 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000648 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000649 }
650 new_chain = NULL;
651}
652
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100653int cache_find_non_terminal(char *name, time_t now)
654{
655 struct crec *crecp;
656
657 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
658 if (!is_outdated_cname_pointer(crecp) &&
659 !is_expired(now, crecp) &&
660 (crecp->flags & F_FORWARD) &&
661 hostname_isequal(name, cache_get_name(crecp)))
662 return 1;
663
664 return 0;
665}
666
Simon Kelley12fae492014-02-04 22:03:06 +0000667struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000668{
669 struct crec *ans;
Simon Kelley12fae492014-02-04 22:03:06 +0000670 int no_rr = prot & F_NO_RR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000671
Simon Kelley12fae492014-02-04 22:03:06 +0000672 prot &= ~F_NO_RR;
673
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000674 if (crecp) /* iterating */
675 ans = crecp->next;
676 else
677 {
678 /* first search, look for relevant entries and push to top of list
679 also free anything which has expired */
680 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley28866e92011-02-14 20:19:14 +0000681 unsigned short ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000682
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000683 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
684 {
685 next = crecp->hash_next;
686
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000687 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000688 {
689 if ((crecp->flags & F_FORWARD) &&
690 (crecp->flags & prot) &&
691 hostname_isequal(cache_get_name(crecp), name))
692 {
Simon Kelley25439062013-11-25 21:14:51 +0000693 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000694 {
695 *chainp = crecp;
696 chainp = &crecp->next;
697 }
698 else
699 {
700 cache_unlink(crecp);
701 cache_link(crecp);
702 }
703
Simon Kelley824af852008-02-12 20:43:05 +0000704 /* Move all but the first entry up the hash chain
705 this implements round-robin.
706 Make sure that re-ordering doesn't break the hash-chain
707 order invariants.
708 */
Simon Kelley9e038942008-05-30 20:06:34 +0100709 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000710 {
711 *up = crecp->hash_next;
712 crecp->hash_next = *insert;
713 *insert = crecp;
714 insert = &crecp->hash_next;
715 }
Simon Kelley9e038942008-05-30 20:06:34 +0100716 else
717 {
Simon Kelley12fae492014-02-04 22:03:06 +0000718 if (!insert && !no_rr)
Simon Kelley9e038942008-05-30 20:06:34 +0100719 {
720 insert = up;
721 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
722 }
723 up = &crecp->hash_next;
724 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000725 }
726 else
727 /* case : not expired, incorrect entry. */
728 up = &crecp->hash_next;
729 }
730 else
731 {
732 /* expired entry, free it */
733 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000734 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000735 {
736 cache_unlink(crecp);
737 cache_free(crecp);
738 }
739 }
740 }
741
742 *chainp = cache_head;
743 }
744
745 if (ans &&
746 (ans->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000747 (ans->flags & prot) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000748 hostname_isequal(cache_get_name(ans), name))
749 return ans;
750
751 return NULL;
752}
753
754struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
Simon Kelley12fae492014-02-04 22:03:06 +0000755 time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000756{
757 struct crec *ans;
758#ifdef HAVE_IPV6
759 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
760#else
761 int addrlen = INADDRSZ;
762#endif
763
764 if (crecp) /* iterating */
765 ans = crecp->next;
766 else
767 {
768 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000769 also free anything which has expired. All the reverse entries are at the
770 start of the hash chain, so we can give up when we find the first
771 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000772 int i;
773 struct crec **up, **chainp = &ans;
774
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000775 for (i=0; i<hash_size; i++)
776 for (crecp = hash_table[i], up = &hash_table[i];
777 crecp && (crecp->flags & F_REVERSE);
778 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000779 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000780 {
Simon Kelley6b010842007-02-12 20:32:07 +0000781 if ((crecp->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100782 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000783 {
Simon Kelley25439062013-11-25 21:14:51 +0000784 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000785 {
786 *chainp = crecp;
787 chainp = &crecp->next;
788 }
789 else
790 {
791 cache_unlink(crecp);
792 cache_link(crecp);
793 }
794 }
795 up = &crecp->hash_next;
796 }
797 else
798 {
799 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000800 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000801 {
802 cache_unlink(crecp);
803 cache_free(crecp);
804 }
805 }
806
807 *chainp = cache_head;
808 }
809
810 if (ans &&
811 (ans->flags & F_REVERSE) &&
812 (ans->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100813 memcmp(&ans->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000814 return ans;
815
816 return NULL;
817}
818
Simon Kelley611ebc52012-07-16 16:23:46 +0100819static void add_hosts_cname(struct crec *target)
820{
821 struct crec *crec;
822 struct cname *a;
823
824 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +0000825 if (a->alias[1] != '*' &&
826 hostname_isequal(cache_get_name(target), a->target) &&
Simon Kelley611ebc52012-07-16 16:23:46 +0100827 (crec = whine_malloc(sizeof(struct crec))))
828 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000829 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000830 crec->ttd = a->ttl;
Simon Kelley611ebc52012-07-16 16:23:46 +0100831 crec->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100832 crec->addr.cname.target.cache = target;
Simon Kelley45d8a242018-07-17 21:01:14 +0100833 next_uid(target);
Simon Kelley611ebc52012-07-16 16:23:46 +0100834 crec->addr.cname.uid = target->uid;
Simon Kelley45d8a242018-07-17 21:01:14 +0100835 crec->uid = UID_NONE;
Simon Kelley611ebc52012-07-16 16:23:46 +0100836 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100837 make_non_terminals(crec);
838
Simon Kelley611ebc52012-07-16 16:23:46 +0100839 add_hosts_cname(crec); /* handle chains */
840 }
841}
842
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100843static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
Simon Kelley19c51cf2014-03-18 22:38:30 +0000844 unsigned int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000845{
Simon Kelleye759d422012-03-16 13:18:57 +0000846 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 +0000847 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000848 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000849
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000850 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000851 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000852 {
Simon Kelley9009d742008-11-14 20:04:27 +0000853 nameexists = 1;
854 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
855 {
856 free(cache);
857 return;
858 }
859 }
860
861 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000862 We do this by steam here, The entries are kept in hash chains, linked
863 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000864 the array rhash, hashed on address. Note that rhash and the values
865 in ->next are only valid whilst reading hosts files: the buckets are
866 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +0000867
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000868 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000869
870 This complexity avoids O(n^2) divergent CPU use whilst reading
Simon Kelley70d18732015-01-31 19:59:29 +0000871 large (10000 entry) hosts files.
872
873 Note that we only do this process when bulk-reading hosts files,
874 for incremental reads, rhash is NULL, and we use cache lookups
875 instead.
876 */
Simon Kelley9009d742008-11-14 20:04:27 +0000877
Simon Kelley70d18732015-01-31 19:59:29 +0000878 if (rhash)
Simon Kelley915363f2012-01-11 22:00:48 +0000879 {
Simon Kelley70d18732015-01-31 19:59:29 +0000880 /* hash address */
881 for (j = 0, i = 0; i < addrlen; i++)
882 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
883
884 for (lookup = rhash[j]; lookup; lookup = lookup->next)
885 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
886 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
887 {
888 cache->flags &= ~F_REVERSE;
889 break;
890 }
891
892 /* maintain address hash chain, insert new unique address */
893 if (!lookup)
894 {
895 cache->next = rhash[j];
896 rhash[j] = cache;
897 }
Simon Kelley915363f2012-01-11 22:00:48 +0000898 }
Simon Kelley70d18732015-01-31 19:59:29 +0000899 else
900 {
901 /* incremental read, lookup in cache */
902 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
903 if (lookup && lookup->flags & F_HOSTS)
904 cache->flags &= ~F_REVERSE;
905 }
906
Simon Kelley9009d742008-11-14 20:04:27 +0000907 cache->uid = index;
Simon Kelley915363f2012-01-11 22:00:48 +0000908 memcpy(&cache->addr.addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +0000909 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100910 make_non_terminals(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000911
912 /* don't need to do alias stuff for second and subsequent addresses. */
913 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +0100914 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000915}
916
917static int eatspace(FILE *f)
918{
919 int c, nl = 0;
920
921 while (1)
922 {
923 if ((c = getc(f)) == '#')
924 while (c != '\n' && c != EOF)
925 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +0000926
Simon Kelley9009d742008-11-14 20:04:27 +0000927 if (c == EOF)
928 return 1;
929
930 if (!isspace(c))
931 {
932 ungetc(c, f);
933 return nl;
934 }
935
936 if (c == '\n')
937 nl = 1;
938 }
939}
940
941static int gettok(FILE *f, char *token)
942{
943 int c, count = 0;
944
945 while (1)
946 {
947 if ((c = getc(f)) == EOF)
948 return (count == 0) ? EOF : 1;
949
950 if (isspace(c) || c == '#')
951 {
952 ungetc(c, f);
953 return eatspace(f);
954 }
955
956 if (count < (MAXDNAME - 1))
957 {
958 token[count++] = c;
959 token[count] = 0;
960 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000961 }
962}
963
Simon Kelley70d18732015-01-31 19:59:29 +0000964int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000965{
966 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +0000967 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100968 int addr_count = 0, name_count = cache_size, lineno = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000969 unsigned short flags = 0;
970 struct all_addr addr;
971 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100972
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000973 if (!f)
974 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100975 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
André Glüpkereddf3652016-01-12 12:54:17 +0000976 return cache_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000977 }
Simon Kelley9009d742008-11-14 20:04:27 +0000978
979 eatspace(f);
980
981 while ((atnl = gettok(f, token)) != EOF)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000982 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000983 lineno++;
Simon Kelley9009d742008-11-14 20:04:27 +0000984
Simon Kelley3d8df262005-08-29 12:19:27 +0100985 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000986 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000987 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000988 addrlen = INADDRSZ;
Simon Kelley9009d742008-11-14 20:04:27 +0000989 domain_suffix = get_domain(addr.addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000990 }
Simon Kelleye759d422012-03-16 13:18:57 +0000991#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +0100992 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000993 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000994 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000995 addrlen = IN6ADDRSZ;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000996 domain_suffix = get_domain6(&addr.addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000997 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000998#endif
999 else
Simon Kelleyb8187c82005-11-26 21:46:27 +00001000 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001001 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +00001002 while (atnl == 0)
1003 atnl = gettok(f, token);
Simon Kelleyb8187c82005-11-26 21:46:27 +00001004 continue;
1005 }
Simon Kelley9009d742008-11-14 20:04:27 +00001006
Simon Kelley9009d742008-11-14 20:04:27 +00001007 addr_count++;
1008
1009 /* rehash every 1000 names. */
Simon Kelley70d18732015-01-31 19:59:29 +00001010 if (rhash && ((name_count - cache_size) > 1000))
Simon Kelley9009d742008-11-14 20:04:27 +00001011 {
1012 rehash(name_count);
1013 cache_size = name_count;
1014 }
1015
1016 while (atnl == 0)
1017 {
1018 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +01001019 int fqdn, nomem;
1020 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +00001021
1022 if ((atnl = gettok(f, token)) == EOF)
1023 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001024
Simon Kelley9009d742008-11-14 20:04:27 +00001025 fqdn = !!strchr(token, '.');
1026
Simon Kelley1f15b812009-10-13 17:49:32 +01001027 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +00001028 {
1029 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +00001030 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley9009d742008-11-14 20:04:27 +00001031 (cache = whine_malloc(sizeof(struct crec) +
Simon Kelley1f15b812009-10-13 17:49:32 +01001032 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
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 Kelley1f15b812009-10-13 17:49:32 +01001042 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
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 Kelley532066e2013-11-26 10:14:47 +00001115 ((cache = whine_malloc(sizeof(struct 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 Kelley0fc2f312014-01-08 10:26:58 +00001130 if ((cache = whine_malloc(sizeof(struct 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 &&
1157 (cache = whine_malloc(sizeof(struct crec))))
1158 {
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) &&
1166 (cache = whine_malloc(sizeof(struct crec))))
1167 {
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 */
1243 aliasc = whine_malloc(sizeof(struct crec));
1244
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 Kelley5aabfc72007-08-29 11:24:47 +01001334 crec = whine_malloc(sizeof(struct 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);
1362 struct crec* crecp, *tmp, **up;
1363 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) &&
1381 !(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
1382 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
1434 crecp = whine_malloc(sizeof(struct crec));
1435
1436 *crecp = *source;
1437 crecp->flags &= ~(F_IPV4 | F_IPV6 | F_CNAME | F_REVERSE);
1438 crecp->flags |= F_NAMEP;
1439 crecp->name.namep = name;
1440
1441 cache_hash(crecp);
1442 }
1443}
1444
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001445#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001446int cache_make_stat(struct txt_record *t)
1447{
1448 static char *buff = NULL;
1449 static int bufflen = 60;
1450 int len;
1451 struct server *serv, *serv1;
1452 char *p;
1453
1454 if (!buff && !(buff = whine_malloc(60)))
1455 return 0;
1456
1457 p = buff;
1458
1459 switch (t->stat)
1460 {
1461 case TXT_STAT_CACHESIZE:
1462 sprintf(buff+1, "%d", daemon->cachesize);
1463 break;
1464
1465 case TXT_STAT_INSERTS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001466 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001467 break;
1468
1469 case TXT_STAT_EVICTIONS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001470 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001471 break;
1472
1473 case TXT_STAT_MISSES:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001474 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001475 break;
1476
1477 case TXT_STAT_HITS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001478 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001479 break;
1480
1481#ifdef HAVE_AUTH
1482 case TXT_STAT_AUTH:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001483 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001484 break;
1485#endif
1486
1487 case TXT_STAT_SERVERS:
1488 /* sum counts from different records for same server */
1489 for (serv = daemon->servers; serv; serv = serv->next)
1490 serv->flags &= ~SERV_COUNTED;
1491
1492 for (serv = daemon->servers; serv; serv = serv->next)
1493 if (!(serv->flags &
1494 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1495 {
1496 char *new, *lenp;
1497 int port, newlen, bytes_avail, bytes_needed;
1498 unsigned int queries = 0, failed_queries = 0;
1499 for (serv1 = serv; serv1; serv1 = serv1->next)
1500 if (!(serv1->flags &
1501 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1502 sockaddr_isequal(&serv->addr, &serv1->addr))
1503 {
1504 serv1->flags |= SERV_COUNTED;
1505 queries += serv1->queries;
1506 failed_queries += serv1->failed_queries;
1507 }
1508 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1509 lenp = p++; /* length */
Simon Kelley04b0ac02015-04-06 17:19:13 +01001510 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001511 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1512 if (bytes_needed >= bytes_avail)
1513 {
1514 /* expand buffer if necessary */
1515 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1516 if (!(new = whine_malloc(newlen)))
1517 return 0;
1518 memcpy(new, buff, bufflen);
1519 free(buff);
1520 p = new + (p - buff);
1521 lenp = p - 1;
1522 buff = new;
1523 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001524 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001525 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1526 }
1527 *lenp = bytes_needed;
1528 p += bytes_needed;
1529 }
1530 t->txt = (unsigned char *)buff;
1531 t->len = p - buff;
1532 return 1;
1533 }
1534
1535 len = strlen(buff+1);
1536 t->txt = (unsigned char *)buff;
1537 t->len = len + 1;
1538 *buff = len;
1539 return 1;
1540}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001541#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001542
Simon Kelley394ff492015-03-29 22:17:14 +01001543/* There can be names in the cache containing control chars, don't
1544 mess up logging or open security holes. */
1545static char *sanitise(char *name)
1546{
1547 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001548 if (name)
1549 for (r = (unsigned char *)name; *r; r++)
1550 if (!isprint((int)*r))
1551 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001552
1553 return name;
1554}
1555
1556
Simon Kelley5aabfc72007-08-29 11:24:47 +01001557void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001558{
Simon Kelley824af852008-02-12 20:43:05 +00001559 struct server *serv, *serv1;
1560
1561 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1562 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001563 daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelley824af852008-02-12 20:43:05 +00001564 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001565 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001566#ifdef HAVE_AUTH
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001567 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001568#endif
Simon Kelleyc2207682014-01-08 18:04:20 +00001569#ifdef HAVE_DNSSEC
1570 blockdata_report();
1571#endif
Simon Kelley824af852008-02-12 20:43:05 +00001572
Simon Kelley824af852008-02-12 20:43:05 +00001573 /* sum counts from different records for same server */
1574 for (serv = daemon->servers; serv; serv = serv->next)
1575 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001576
Simon Kelley824af852008-02-12 20:43:05 +00001577 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001578 if (!(serv->flags &
1579 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001580 {
1581 int port;
1582 unsigned int queries = 0, failed_queries = 0;
1583 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001584 if (!(serv1->flags &
1585 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1586 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001587 {
1588 serv1->flags |= SERV_COUNTED;
1589 queries += serv1->queries;
1590 failed_queries += serv1->failed_queries;
1591 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001592 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1593 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 +00001594 }
1595
Simon Kelley28866e92011-02-14 20:19:14 +00001596 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001597 {
1598 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001599 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001600 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001601
1602 for (i=0; i<hash_size; i++)
1603 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1604 {
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001605 char *t = " ";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001606 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1607 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001608 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001609 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001610 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001611 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001612 a = sanitise(cache_get_cname_target(cache));
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001613#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001614 else if (cache->flags & F_DS)
1615 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001616 if (!(cache->flags & F_NEG))
Simon Kelleyb8eac192014-02-27 14:30:03 +00001617 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1618 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001619 }
1620 else if (cache->flags & F_DNSKEY)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001621 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1622 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001623#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001624 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001625 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001626 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001627 if (cache->flags & F_IPV4)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001628 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001629#ifdef HAVE_IPV6
Simon Kelleyf2621c72007-04-29 19:47:21 +01001630 else if (cache->flags & F_IPV6)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001631 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001632#endif
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001633 }
1634
Simon Kelleye7829ae2014-01-22 22:21:51 +00001635 if (cache->flags & F_IPV4)
1636 t = "4";
1637 else if (cache->flags & F_IPV6)
1638 t = "6";
1639 else if (cache->flags & F_CNAME)
1640 t = "C";
1641#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001642 else if (cache->flags & F_DS)
1643 t = "S";
1644 else if (cache->flags & F_DNSKEY)
1645 t = "K";
1646#endif
Simon Kelley32678042014-12-17 20:38:20 +00001647 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001648 cache->flags & F_FORWARD ? "F" : " ",
1649 cache->flags & F_REVERSE ? "R" : " ",
1650 cache->flags & F_IMMORTAL ? "I" : " ",
1651 cache->flags & F_DHCP ? "D" : " ",
1652 cache->flags & F_NEG ? "N" : " ",
1653 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001654 cache->flags & F_HOSTS ? "H" : " ",
1655 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001656#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001657 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001658#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001659 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1660 /* ctime includes trailing \n - eat it */
1661 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001662#endif
Rosen Penevcbd29e52017-06-27 22:29:51 +01001663 my_syslog(LOG_INFO, "%s", daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001664 }
1665 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001666}
1667
Simon Kelley19c51cf2014-03-18 22:38:30 +00001668char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001669{
Simon Kelley7622fc02009-06-04 20:32:05 +01001670 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001671
Simon Kelley19c51cf2014-03-18 22:38:30 +00001672 if (index == SRC_CONFIG)
1673 return "config";
1674 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001675 return HOSTSFILE;
1676
1677 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1678 if (ah->index == index)
1679 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001680
1681#ifdef HAVE_INOTIFY
1682 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1683 if (ah->index == index)
1684 return ah->fname;
1685#endif
1686
Simon Kelley7622fc02009-06-04 20:32:05 +01001687 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001688}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001689
Simon Kelley610e7822014-02-06 14:45:17 +00001690char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001691{
1692 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001693 int len = 10; /* strlen("type=xxxxx") */
1694 const char *types = NULL;
1695 static char *buff = NULL;
1696 static int bufflen = 0;
1697
Simon Kelley1a6bca82008-07-11 11:11:42 +01001698 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1699 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001700 {
1701 types = typestr[i].name;
1702 len = strlen(types);
1703 break;
1704 }
1705
1706 len += 3; /* braces, terminator */
1707 len += strlen(desc);
1708
1709 if (!buff || bufflen < len)
1710 {
1711 if (buff)
1712 free(buff);
1713 else if (len < 20)
1714 len = 20;
1715
1716 buff = whine_malloc(len);
1717 bufflen = len;
1718 }
1719
1720 if (buff)
1721 {
1722 if (types)
1723 sprintf(buff, "%s[%s]", desc, types);
1724 else
1725 sprintf(buff, "%s[type=%d]", desc, type);
1726 }
1727
1728 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001729}
1730
Simon Kelley28866e92011-02-14 20:19:14 +00001731void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001732{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001733 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001734 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001735
Simon Kelley28866e92011-02-14 20:19:14 +00001736 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001737 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001738
Simon Kelley394ff492015-03-29 22:17:14 +01001739 name = sanitise(name);
1740
Simon Kelley5aabfc72007-08-29 11:24:47 +01001741 if (addr)
1742 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001743 if (flags & F_KEYTAG)
Simon Kelley15379ea2015-12-21 18:31:55 +00001744 sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
Simon Kelley07ed5852018-05-04 21:52:22 +01001745 else if (flags & F_RCODE)
1746 {
1747 unsigned int rcode = addr->addr.rcode.rcode;
1748
1749 if (rcode == SERVFAIL)
1750 dest = "SERVFAIL";
1751 else if (rcode == REFUSED)
1752 dest = "REFUSED";
1753 else if (rcode == NOTIMP)
1754 dest = "not implemented";
1755 else
1756 sprintf(daemon->addrbuff, "%u", rcode);
1757 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001758 else
1759 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001760#ifdef HAVE_IPV6
Simon Kelley0fc2f312014-01-08 10:26:58 +00001761 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1762 addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001763#else
Simon Kelley0fc2f312014-01-08 10:26:58 +00001764 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001765#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001766 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001767 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001768 else
1769 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001770
1771 if (flags & F_REVERSE)
1772 {
1773 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001774 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001775 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001776
1777 if (flags & F_NEG)
1778 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001779 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001780 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001781 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001782 {
1783 if (flags & F_IPV4)
1784 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001785 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001786 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001787 else
1788 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001789 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001790 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001791 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001792 dest = "<CNAME>";
1793 else if (flags & F_RRNAME)
1794 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001795
Simon Kelley1f15b812009-10-13 17:49:32 +01001796 if (flags & F_CONFIG)
1797 source = "config";
1798 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001799 source = "DHCP";
1800 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001801 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001802 else if (flags & F_UPSTREAM)
1803 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001804 else if (flags & F_SECSTAT)
1805 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001806 else if (flags & F_AUTH)
1807 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001808 else if (flags & F_SERVER)
1809 {
1810 source = "forwarded";
1811 verb = "to";
1812 }
1813 else if (flags & F_QUERY)
1814 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001815 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001816 verb = "from";
1817 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001818 else if (flags & F_DNSSEC)
1819 {
1820 source = arg;
1821 verb = "to";
1822 }
Wang Jian49752b92014-03-28 20:52:47 +00001823 else if (flags & F_IPSET)
1824 {
1825 source = "ipset add";
1826 dest = name;
1827 name = arg;
1828 verb = daemon->addrbuff;
1829 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001830 else
1831 source = "cached";
1832
Simon Kelley3d8df262005-08-29 12:19:27 +01001833 if (strlen(name) == 0)
1834 name = ".";
1835
Simon Kelley25cf5e32015-01-09 15:53:03 +00001836 if (option_bool(OPT_EXTRALOG))
1837 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001838 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001839 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001840 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001841 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001842 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 +00001843 }
1844 else
1845 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001846}
1847
Simon Kelley98c098b2014-01-08 17:31:16 +00001848