version 1.1.1.4, 2021/03/17 00:56:46
|
version 1.1.1.5, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
Line 28 static int bignames_left, hash_size;
|
Line 28 static int bignames_left, hash_size;
|
static void make_non_terminals(struct crec *source); |
static void make_non_terminals(struct crec *source); |
static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class, |
static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class, |
time_t now, unsigned long ttl, unsigned int flags); |
time_t now, unsigned long ttl, unsigned int flags); |
|
static void dump_cache_entry(struct crec *cache, time_t now); |
|
|
/* type->string mapping: this is also used by the name-hash function as a mixing table. */ |
/* type->string mapping: this is also used by the name-hash function as a mixing table. */ |
|
/* taken from https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml */ |
static const struct { |
static const struct { |
unsigned int type; |
unsigned int type; |
const char * const name; |
const char * const name; |
} typestr[] = { |
} typestr[] = { |
{ 1, "A" }, | { 1, "A" }, /* a host address [RFC1035] */ |
{ 2, "NS" }, | { 2, "NS" }, /* an authoritative name server [RFC1035] */ |
{ 5, "CNAME" }, | { 3, "MD" }, /* a mail destination (OBSOLETE - use MX) [RFC1035] */ |
{ 6, "SOA" }, | { 4, "MF" }, /* a mail forwarder (OBSOLETE - use MX) [RFC1035] */ |
{ 10, "NULL" }, | { 5, "CNAME" }, /* the canonical name for an alias [RFC1035] */ |
{ 11, "WKS" }, | { 6, "SOA" }, /* marks the start of a zone of authority [RFC1035] */ |
{ 12, "PTR" }, | { 7, "MB" }, /* a mailbox domain name (EXPERIMENTAL) [RFC1035] */ |
{ 13, "HINFO" }, | { 8, "MG" }, /* a mail group member (EXPERIMENTAL) [RFC1035] */ |
{ 15, "MX" }, | { 9, "MR" }, /* a mail rename domain name (EXPERIMENTAL) [RFC1035] */ |
{ 16, "TXT" }, | { 10, "NULL" }, /* a null RR (EXPERIMENTAL) [RFC1035] */ |
{ 22, "NSAP" }, | { 11, "WKS" }, /* a well known service description [RFC1035] */ |
{ 23, "NSAP_PTR" }, | { 12, "PTR" }, /* a domain name pointer [RFC1035] */ |
{ 24, "SIG" }, | { 13, "HINFO" }, /* host information [RFC1035] */ |
{ 25, "KEY" }, | { 14, "MINFO" }, /* mailbox or mail list information [RFC1035] */ |
{ 28, "AAAA" }, | { 15, "MX" }, /* mail exchange [RFC1035] */ |
{ 29, "LOC" }, | { 16, "TXT" }, /* text strings [RFC1035] */ |
{ 33, "SRV" }, | { 17, "RP" }, /* for Responsible Person [RFC1183] */ |
{ 35, "NAPTR" }, | { 18, "AFSDB" }, /* for AFS Data Base location [RFC1183][RFC5864] */ |
{ 36, "KX" }, | { 19, "X25" }, /* for X.25 PSDN address [RFC1183] */ |
{ 37, "CERT" }, | { 20, "ISDN" }, /* for ISDN address [RFC1183] */ |
{ 38, "A6" }, | { 21, "RT" }, /* for Route Through [RFC1183] */ |
{ 39, "DNAME" }, | { 22, "NSAP" }, /* for NSAP address, NSAP style A record [RFC1706] */ |
{ 41, "OPT" }, | { 23, "NSAP_PTR" }, /* for domain name pointer, NSAP style [RFC1348][RFC1637][RFC1706] */ |
{ 43, "DS" }, | { 24, "SIG" }, /* for security signature [RFC2535][RFC2536][RFC2537][RFC2931][RFC3008][RFC3110][RFC3755][RFC4034] */ |
{ 46, "RRSIG" }, | { 25, "KEY" }, /* for security key [RFC2535][RFC2536][RFC2537][RFC2539][RFC3008][RFC3110][RFC3755][RFC4034] */ |
{ 47, "NSEC" }, | { 26, "PX" }, /* X.400 mail mapping information [RFC2163] */ |
{ 48, "DNSKEY" }, | { 27, "GPOS" }, /* Geographical Position [RFC1712] */ |
{ 50, "NSEC3" }, | { 28, "AAAA" }, /* IP6 Address [RFC3596] */ |
{ 51, "NSEC3PARAM" }, | { 29, "LOC" }, /* Location Information [RFC1876] */ |
{ 52, "TLSA" }, | { 30, "NXT" }, /* Next Domain (OBSOLETE) [RFC2535][RFC3755] */ |
{ 53, "SMIMEA" }, | { 31, "EID" }, /* Endpoint Identifier [Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/ |
{ 55, "HIP" }, | { 32, "NIMLOC" }, /* Nimrod Locator [1][Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/ |
{ 249, "TKEY" }, | { 33, "SRV" }, /* Server Selection [1][RFC2782] */ |
{ 250, "TSIG" }, | { 34, "ATMA" }, /* ATM Address [ ATM Forum Technical Committee, "ATM Name System, V2.0", Doc ID: AF-DANS-0152.000, July 2000. Available from and held in escrow by IANA.] */ |
{ 251, "IXFR" }, | { 35, "NAPTR" }, /* Naming Authority Pointer [RFC2168][RFC2915][RFC3403] */ |
{ 252, "AXFR" }, | { 36, "KX" }, /* Key Exchanger [RFC2230] */ |
{ 253, "MAILB" }, | { 37, "CERT" }, /* CERT [RFC4398] */ |
{ 254, "MAILA" }, | { 38, "A6" }, /* A6 (OBSOLETE - use AAAA) [RFC2874][RFC3226][RFC6563] */ |
{ 255, "ANY" }, | { 39, "DNAME" }, /* DNAME [RFC6672] */ |
{ 257, "CAA" } | { 40, "SINK" }, /* SINK [Donald_E_Eastlake][http://tools.ietf.org/html/draft-eastlake-kitchen-sink] 1997-11*/ |
| { 41, "OPT" }, /* OPT [RFC3225][RFC6891] */ |
| { 42, "APL" }, /* APL [RFC3123] */ |
| { 43, "DS" }, /* Delegation Signer [RFC3658][RFC4034] */ |
| { 44, "SSHFP" }, /* SSH Key Fingerprint [RFC4255] */ |
| { 45, "IPSECKEY" }, /* IPSECKEY [RFC4025] */ |
| { 46, "RRSIG" }, /* RRSIG [RFC3755][RFC4034] */ |
| { 47, "NSEC" }, /* NSEC [RFC3755][RFC4034][RFC9077] */ |
| { 48, "DNSKEY" }, /* DNSKEY [RFC3755][RFC4034] */ |
| { 49, "DHCID" }, /* DHCID [RFC4701] */ |
| { 50, "NSEC3" }, /* NSEC3 [RFC5155][RFC9077] */ |
| { 51, "NSEC3PARAM" }, /* NSEC3PARAM [RFC5155] */ |
| { 52, "TLSA" }, /* TLSA [RFC6698] */ |
| { 53, "SMIMEA" }, /* S/MIME cert association [RFC8162] SMIMEA/smimea-completed-template 2015-12-01*/ |
| { 55, "HIP" }, /* Host Identity Protocol [RFC8005] */ |
| { 56, "NINFO" }, /* NINFO [Jim_Reid] NINFO/ninfo-completed-template 2008-01-21*/ |
| { 57, "RKEY" }, /* RKEY [Jim_Reid] RKEY/rkey-completed-template 2008-01-21*/ |
| { 58, "TALINK" }, /* Trust Anchor LINK [Wouter_Wijngaards] TALINK/talink-completed-template 2010-02-17*/ |
| { 59, "CDS" }, /* Child DS [RFC7344] CDS/cds-completed-template 2011-06-06*/ |
| { 60, "CDNSKEY" }, /* DNSKEY(s) the Child wants reflected in DS [RFC7344] 2014-06-16*/ |
| { 61, "OPENPGPKEY" }, /* OpenPGP Key [RFC7929] OPENPGPKEY/openpgpkey-completed-template 2014-08-12*/ |
| { 62, "CSYNC" }, /* Child-To-Parent Synchronization [RFC7477] 2015-01-27*/ |
| { 63, "ZONEMD" }, /* Message Digest Over Zone Data [RFC8976] ZONEMD/zonemd-completed-template 2018-12-12*/ |
| { 64, "SVCB" }, /* Service Binding [draft-ietf-dnsop-svcb-https-00] SVCB/svcb-completed-template 2020-06-30*/ |
| { 65, "HTTPS" }, /* HTTPS Binding [draft-ietf-dnsop-svcb-https-00] HTTPS/https-completed-template 2020-06-30*/ |
| { 99, "SPF" }, /* [RFC7208] */ |
| { 100, "UINFO" }, /* [IANA-Reserved] */ |
| { 101, "UID" }, /* [IANA-Reserved] */ |
| { 102, "GID" }, /* [IANA-Reserved] */ |
| { 103, "UNSPEC" }, /* [IANA-Reserved] */ |
| { 104, "NID" }, /* [RFC6742] ILNP/nid-completed-template */ |
| { 105, "L32" }, /* [RFC6742] ILNP/l32-completed-template */ |
| { 106, "L64" }, /* [RFC6742] ILNP/l64-completed-template */ |
| { 107, "LP" }, /* [RFC6742] ILNP/lp-completed-template */ |
| { 108, "EUI48" }, /* an EUI-48 address [RFC7043] EUI48/eui48-completed-template 2013-03-27*/ |
| { 109, "EUI64" }, /* an EUI-64 address [RFC7043] EUI64/eui64-completed-template 2013-03-27*/ |
| { 249, "TKEY" }, /* Transaction Key [RFC2930] */ |
| { 250, "TSIG" }, /* Transaction Signature [RFC8945] */ |
| { 251, "IXFR" }, /* incremental transfer [RFC1995] */ |
| { 252, "AXFR" }, /* transfer of an entire zone [RFC1035][RFC5936] */ |
| { 253, "MAILB" }, /* mailbox-related RRs (MB, MG or MR) [RFC1035] */ |
| { 254, "MAILA" }, /* mail agent RRs (OBSOLETE - see MX) [RFC1035] */ |
| { 255, "ANY" }, /* A request for some or all records the server has available [RFC1035][RFC6895][RFC8482] */ |
| { 256, "URI" }, /* URI [RFC7553] URI/uri-completed-template 2011-02-22*/ |
| { 257, "CAA" }, /* Certification Authority Restriction [RFC8659] CAA/caa-completed-template 2011-04-07*/ |
| { 258, "AVC" }, /* Application Visibility and Control [Wolfgang_Riedel] AVC/avc-completed-template 2016-02-26*/ |
| { 259, "DOA" }, /* Digital Object Architecture [draft-durand-doa-over-dns] DOA/doa-completed-template 2017-08-30*/ |
| { 260, "AMTRELAY" }, /* Automatic Multicast Tunneling Relay [RFC8777] AMTRELAY/amtrelay-completed-template 2019-02-06*/ |
| { 32768, "TA" }, /* DNSSEC Trust Authorities [Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, Information Networking Institute, Carnegie Mellon University, April 2004.] 2005-12-13*/ |
| { 32769, "DLV" }, /* DNSSEC Lookaside Validation (OBSOLETE) [RFC8749][RFC4431] */ |
}; |
}; |
|
|
static void cache_free(struct crec *crecp); |
static void cache_free(struct crec *crecp); |
Line 139 static void rehash(int size)
|
Line 190 static void rehash(int size)
|
else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *)))) |
else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *)))) |
return; |
return; |
|
|
for(i = 0; i < new_size; i++) | for (i = 0; i < new_size; i++) |
new[i] = NULL; |
new[i] = NULL; |
|
|
old = hash_table; |
old = hash_table; |
Line 183 static void cache_hash(struct crec *crecp)
|
Line 234 static void cache_hash(struct crec *crecp)
|
immortal entries are at the end of the hash-chain. |
immortal entries are at the end of the hash-chain. |
This allows reverse searches and garbage collection to be optimised */ |
This allows reverse searches and garbage collection to be optimised */ |
|
|
struct crec **up = hash_bucket(cache_get_name(crecp)); | char *name = cache_get_name(crecp); |
| struct crec **up = hash_bucket(name); |
if (!(crecp->flags & F_REVERSE)) | unsigned int flags = crecp->flags & (F_IMMORTAL | F_REVERSE); |
| |
| if (!(flags & F_REVERSE)) |
{ |
{ |
while (*up && ((*up)->flags & F_REVERSE)) |
while (*up && ((*up)->flags & F_REVERSE)) |
up = &((*up)->hash_next); |
up = &((*up)->hash_next); |
|
|
if (crecp->flags & F_IMMORTAL) | if (flags & F_IMMORTAL) |
while (*up && !((*up)->flags & F_IMMORTAL)) |
while (*up && !((*up)->flags & F_IMMORTAL)) |
up = &((*up)->hash_next); |
up = &((*up)->hash_next); |
} |
} |
|
|
|
/* Preserve order when inserting the same name multiple times. |
|
Do not mess up the flag invariants. */ |
|
while (*up && |
|
hostname_isequal(cache_get_name(*up), name) && |
|
flags == ((*up)->flags & (F_IMMORTAL | F_REVERSE))) |
|
up = &((*up)->hash_next); |
|
|
crecp->hash_next = *up; |
crecp->hash_next = *up; |
*up = crecp; |
*up = crecp; |
} |
} |
Line 324 static int is_outdated_cname_pointer(struct crec *crec
|
Line 385 static int is_outdated_cname_pointer(struct crec *crec
|
|
|
static int is_expired(time_t now, struct crec *crecp) |
static int is_expired(time_t now, struct crec *crecp) |
{ |
{ |
|
/* Don't dump expired entries if they are within the accepted timeout range. |
|
The cache becomes approx. LRU. Never use expired DS or DNSKEY entries. |
|
Possible values for daemon->cache_max_expiry: |
|
-1 == serve cached content regardless how long ago it expired |
|
0 == the option is disabled, expired content isn't served |
|
<n> == serve cached content only if it expire less than <n> seconds |
|
ago (where n is a positive integer) */ |
|
if (daemon->cache_max_expiry != 0 && |
|
(daemon->cache_max_expiry == -1 || |
|
difftime(now, crecp->ttd) < daemon->cache_max_expiry) && |
|
!(crecp->flags & (F_DS | F_DNSKEY))) |
|
return 0; |
|
|
if (crecp->flags & F_IMMORTAL) |
if (crecp->flags & F_IMMORTAL) |
return 0; |
return 0; |
|
|
Line 333 static int is_expired(time_t now, struct crec *crecp)
|
Line 407 static int is_expired(time_t now, struct crec *crecp)
|
return 1; |
return 1; |
} |
} |
|
|
|
/* Remove entries with a given UID from the cache */ |
|
unsigned int cache_remove_uid(const unsigned int uid) |
|
{ |
|
int i; |
|
unsigned int removed = 0; |
|
struct crec *crecp, **up; |
|
|
|
for (i = 0; i < hash_size; i++) |
|
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next) |
|
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && crecp->uid == uid) |
|
{ |
|
*up = crecp->hash_next; |
|
free(crecp); |
|
removed++; |
|
} |
|
else |
|
up = &crecp->hash_next; |
|
|
|
return removed; |
|
} |
|
|
static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned short class, time_t now, |
static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned short class, time_t now, |
unsigned int flags, struct crec **target_crec, unsigned int *target_uid) |
unsigned int flags, struct crec **target_crec, unsigned int *target_uid) |
{ |
{ |
Line 363 static struct crec *cache_scan_free(char *name, union
|
Line 458 static struct crec *cache_scan_free(char *name, union
|
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name)) |
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name)) |
{ |
{ |
/* Don't delete DNSSEC in favour of a CNAME, they can co-exist */ |
/* Don't delete DNSSEC in favour of a CNAME, they can co-exist */ |
if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) || | if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV | F_NXDOMAIN)) || |
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS)))) |
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS)))) |
{ |
{ |
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) |
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) |
Line 433 static struct crec *cache_scan_free(char *name, union
|
Line 528 static struct crec *cache_scan_free(char *name, union
|
else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && |
else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && |
(flags & crecp->flags & F_REVERSE) && |
(flags & crecp->flags & F_REVERSE) && |
(flags & crecp->flags & (F_IPV4 | F_IPV6)) && |
(flags & crecp->flags & (F_IPV4 | F_IPV6)) && |
memcmp(&crecp->addr, addr, addrlen) == 0) | addr && memcmp(&crecp->addr, addr, addrlen) == 0) |
{ |
{ |
*up = crecp->hash_next; |
*up = crecp->hash_next; |
cache_unlink(crecp); |
cache_unlink(crecp); |
Line 488 struct crec *cache_insert(char *name, union all_addr *
|
Line 583 struct crec *cache_insert(char *name, union all_addr *
|
else |
else |
#endif |
#endif |
{ |
{ |
/* Don't log DNSSEC records here, done elsewhere */ |
|
log_query(flags | F_UPSTREAM, name, addr, NULL); |
|
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl) |
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl) |
ttl = daemon->max_cache_ttl; |
ttl = daemon->max_cache_ttl; |
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl) |
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl) |
Line 505 static struct crec *really_insert(char *name, union al
|
Line 598 static struct crec *really_insert(char *name, union al
|
{ |
{ |
struct crec *new, *target_crec = NULL; |
struct crec *new, *target_crec = NULL; |
union bigname *big_name = NULL; |
union bigname *big_name = NULL; |
int freed_all = flags & F_REVERSE; | int freed_all = (flags & F_REVERSE); |
int free_avail = 0; | struct crec *free_avail = NULL; |
unsigned int target_uid; |
unsigned int target_uid; |
|
|
/* if previous insertion failed give up now. */ |
/* if previous insertion failed give up now. */ |
Line 554 static struct crec *really_insert(char *name, union al
|
Line 647 static struct crec *really_insert(char *name, union al
|
|
|
/* Free entry at end of LRU list, use it. */ |
/* Free entry at end of LRU list, use it. */ |
if (!(new->flags & (F_FORWARD | F_REVERSE))) |
if (!(new->flags & (F_FORWARD | F_REVERSE))) |
break; | break; |
|
|
/* End of LRU list is still in use: if we didn't scan all the hash |
/* End of LRU list is still in use: if we didn't scan all the hash |
chains for expired entries do that now. If we already tried that |
chains for expired entries do that now. If we already tried that |
Line 566 static struct crec *really_insert(char *name, union al
|
Line 659 static struct crec *really_insert(char *name, union al
|
insert. Once in this state, all inserts will probably fail. */ |
insert. Once in this state, all inserts will probably fail. */ |
if (free_avail) |
if (free_avail) |
{ |
{ |
static int warned = 0; | my_syslog(LOG_ERR, _("Internal error in cache.")); |
if (!warned) | /* Log the entry we tried to delete. */ |
{ | dump_cache_entry(free_avail, now); |
my_syslog(LOG_ERR, _("Internal error in cache.")); | |
warned = 1; | |
} | |
insert_error = 1; |
insert_error = 1; |
return NULL; |
return NULL; |
} |
} |
Line 579 static struct crec *really_insert(char *name, union al
|
Line 669 static struct crec *really_insert(char *name, union al
|
if (freed_all) |
if (freed_all) |
{ |
{ |
/* For DNSSEC records, uid holds class. */ |
/* For DNSSEC records, uid holds class. */ |
free_avail = 1; /* Must be free space now. */ | free_avail = new; /* Must be free space now. */ |
cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->flags, NULL, NULL); | |
daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++; | /* condition valid when stale-caching */ |
| if (difftime(now, new->ttd) < 0) |
| daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++; |
| |
| cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->flags, NULL, NULL); |
} |
} |
else |
else |
{ |
{ |
Line 644 static struct crec *really_insert(char *name, union al
|
Line 738 static struct crec *really_insert(char *name, union al
|
new->ttd = now + (time_t)ttl; |
new->ttd = now + (time_t)ttl; |
new->next = new_chain; |
new->next = new_chain; |
new_chain = new; |
new_chain = new; |
| |
return new; |
return new; |
} |
} |
|
|
Line 822 int cache_find_non_terminal(char *name, time_t now)
|
Line 916 int cache_find_non_terminal(char *name, time_t now)
|
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot) |
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot) |
{ |
{ |
struct crec *ans; |
struct crec *ans; |
int no_rr = prot & F_NO_RR; | int no_rr = (prot & F_NO_RR) || option_bool(OPT_NORR); |
|
|
prot &= ~F_NO_RR; |
prot &= ~F_NO_RR; |
|
|
Line 970 struct crec *cache_find_by_addr(struct crec *crecp, un
|
Line 1064 struct crec *cache_find_by_addr(struct crec *crecp, un
|
static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen, |
static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen, |
unsigned int index, struct crec **rhash, int hashsz) |
unsigned int index, struct crec **rhash, int hashsz) |
{ |
{ |
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6)); |
|
int i; |
int i; |
unsigned int j; |
unsigned int j; |
|
struct crec *lookup = NULL; |
|
|
/* Remove duplicates in hosts files. */ |
/* Remove duplicates in hosts files. */ |
if (lookup && (lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0) | while ((lookup = cache_find_by_name(lookup, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6)))) |
{ | if ((lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0) |
free(cache); | { |
return; | free(cache); |
} | return; |
| } |
|
|
/* Ensure there is only one address -> name mapping (first one trumps) |
/* Ensure there is only one address -> name mapping (first one trumps) |
We do this by steam here, The entries are kept in hash chains, linked |
We do this by steam here, The entries are kept in hash chains, linked |
Line 987 static void add_hosts_entry(struct crec *cache, union
|
Line 1082 static void add_hosts_entry(struct crec *cache, union
|
the array rhash, hashed on address. Note that rhash and the values |
the array rhash, hashed on address. Note that rhash and the values |
in ->next are only valid whilst reading hosts files: the buckets are |
in ->next are only valid whilst reading hosts files: the buckets are |
then freed, and the ->next pointer used for other things. |
then freed, and the ->next pointer used for other things. |
|
|
Only insert each unique address once into this hashing structure. |
Only insert each unique address once into this hashing structure. |
|
|
This complexity avoids O(n^2) divergent CPU use whilst reading |
This complexity avoids O(n^2) divergent CPU use whilst reading |
Line 1084 int read_hostsfile(char *filename, unsigned int index,
|
Line 1178 int read_hostsfile(char *filename, unsigned int index,
|
{ |
{ |
FILE *f = fopen(filename, "r"); |
FILE *f = fopen(filename, "r"); |
char *token = daemon->namebuff, *domain_suffix = NULL; |
char *token = daemon->namebuff, *domain_suffix = NULL; |
int addr_count = 0, name_count = cache_size, lineno = 1; | int names_done = 0, name_count = cache_size, lineno = 1; |
unsigned int flags = 0; |
unsigned int flags = 0; |
union all_addr addr; |
union all_addr addr; |
int atnl, addrlen = 0; |
int atnl, addrlen = 0; |
Line 1120 int read_hostsfile(char *filename, unsigned int index,
|
Line 1214 int read_hostsfile(char *filename, unsigned int index,
|
continue; |
continue; |
} |
} |
|
|
addr_count++; |
|
|
|
/* rehash every 1000 names. */ |
/* rehash every 1000 names. */ |
if (rhash && ((name_count - cache_size) > 1000)) |
if (rhash && ((name_count - cache_size) > 1000)) |
{ |
{ |
Line 1153 int read_hostsfile(char *filename, unsigned int index,
|
Line 1245 int read_hostsfile(char *filename, unsigned int index,
|
cache->ttd = daemon->local_ttl; |
cache->ttd = daemon->local_ttl; |
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
name_count++; |
name_count++; |
|
names_done++; |
} |
} |
if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1))) |
if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1))) |
{ |
{ |
Line 1161 int read_hostsfile(char *filename, unsigned int index,
|
Line 1254 int read_hostsfile(char *filename, unsigned int index,
|
cache->ttd = daemon->local_ttl; |
cache->ttd = daemon->local_ttl; |
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
name_count++; |
name_count++; |
|
names_done++; |
} |
} |
free(canon); |
free(canon); |
|
|
Line 1177 int read_hostsfile(char *filename, unsigned int index,
|
Line 1271 int read_hostsfile(char *filename, unsigned int index,
|
if (rhash) |
if (rhash) |
rehash(name_count); |
rehash(name_count); |
|
|
my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count); | my_syslog(LOG_INFO, _("read %s - %d names"), filename, names_done); |
|
|
return name_count; |
return name_count; |
} |
} |
Line 1351 struct in_addr a_record_from_hosts(char *name, time_t
|
Line 1445 struct in_addr a_record_from_hosts(char *name, time_t
|
struct crec *crecp = NULL; |
struct crec *crecp = NULL; |
struct in_addr ret; |
struct in_addr ret; |
|
|
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4))) | /* If no DNS service, cache not initialised. */ |
if (crecp->flags & F_HOSTS) | if (daemon->port != 0) |
return crecp->addr.addr4; | while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4))) |
| if (crecp->flags & F_HOSTS) |
| return crecp->addr.addr4; |
| |
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name); |
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name); |
|
|
ret.s_addr = 0; |
ret.s_addr = 0; |
Line 1549 static void make_non_terminals(struct crec *source)
|
Line 1645 static void make_non_terminals(struct crec *source)
|
if (crecp) |
if (crecp) |
{ |
{ |
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE); |
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE); |
crecp->ttd = source->ttd; | if (!(crecp->flags & F_IMMORTAL)) |
| crecp->ttd = source->ttd; |
crecp->name.namep = name; |
crecp->name.namep = name; |
|
|
cache_hash(crecp); |
cache_hash(crecp); |
Line 1602 int cache_make_stat(struct txt_record *t)
|
Line 1699 int cache_make_stat(struct txt_record *t)
|
case TXT_STAT_SERVERS: |
case TXT_STAT_SERVERS: |
/* sum counts from different records for same server */ |
/* sum counts from different records for same server */ |
for (serv = daemon->servers; serv; serv = serv->next) |
for (serv = daemon->servers; serv; serv = serv->next) |
serv->flags &= ~SERV_COUNTED; | serv->flags &= ~SERV_MARK; |
|
|
for (serv = daemon->servers; serv; serv = serv->next) |
for (serv = daemon->servers; serv; serv = serv->next) |
if (!(serv->flags & | if (!(serv->flags & SERV_MARK)) |
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND))) | |
{ |
{ |
char *new, *lenp; |
char *new, *lenp; |
int port, newlen, bytes_avail, bytes_needed; |
int port, newlen, bytes_avail, bytes_needed; |
unsigned int queries = 0, failed_queries = 0; |
unsigned int queries = 0, failed_queries = 0; |
for (serv1 = serv; serv1; serv1 = serv1->next) |
for (serv1 = serv; serv1; serv1 = serv1->next) |
if (!(serv1->flags & | if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr)) |
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) && | |
sockaddr_isequal(&serv->addr, &serv1->addr)) | |
{ |
{ |
serv1->flags |= SERV_COUNTED; | serv1->flags |= SERV_MARK; |
queries += serv1->queries; |
queries += serv1->queries; |
failed_queries += serv1->failed_queries; |
failed_queries += serv1->failed_queries; |
} |
} |
Line 1628 int cache_make_stat(struct txt_record *t)
|
Line 1722 int cache_make_stat(struct txt_record *t)
|
{ |
{ |
/* expand buffer if necessary */ |
/* expand buffer if necessary */ |
newlen = bytes_needed + 1 + bufflen - bytes_avail; |
newlen = bytes_needed + 1 + bufflen - bytes_avail; |
if (!(new = whine_malloc(newlen))) | if (!(new = whine_realloc(buff, newlen))) |
return 0; |
return 0; |
memcpy(new, buff, bufflen); |
|
free(buff); |
|
p = new + (p - buff); |
p = new + (p - buff); |
lenp = p - 1; |
lenp = p - 1; |
buff = new; |
buff = new; |
Line 1644 int cache_make_stat(struct txt_record *t)
|
Line 1736 int cache_make_stat(struct txt_record *t)
|
} |
} |
t->txt = (unsigned char *)buff; |
t->txt = (unsigned char *)buff; |
t->len = p - buff; |
t->len = p - buff; |
|
|
return 1; |
return 1; |
} |
} |
|
|
Line 1668 static char *sanitise(char *name)
|
Line 1761 static char *sanitise(char *name)
|
return name; |
return name; |
} |
} |
|
|
|
static void dump_cache_entry(struct crec *cache, time_t now) |
|
{ |
|
(void)now; |
|
static char *buff = NULL; |
|
|
|
char *p, *t = " "; |
|
char *a = daemon->addrbuff, *n = cache_get_name(cache); |
|
|
|
/* String length is limited below */ |
|
if (!buff && !(buff = whine_malloc(150))) |
|
return; |
|
|
|
p = buff; |
|
|
|
*a = 0; |
|
if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) |
|
n = "<Root>"; |
|
p += sprintf(p, "%-30.30s ", sanitise(n)); |
|
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) |
|
a = sanitise(cache_get_cname_target(cache)); |
|
else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG)) |
|
{ |
|
int targetlen = cache->addr.srv.targetlen; |
|
ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority, |
|
cache->addr.srv.weight, cache->addr.srv.srvport); |
|
|
|
if (targetlen > (40 - len)) |
|
targetlen = 40 - len; |
|
blockdata_retrieve(cache->addr.srv.target, targetlen, a + len); |
|
a[len + targetlen] = 0; |
|
} |
|
#ifdef HAVE_DNSSEC |
|
else if (cache->flags & F_DS) |
|
{ |
|
if (!(cache->flags & F_NEG)) |
|
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag, |
|
cache->addr.ds.algo, cache->addr.ds.digest); |
|
} |
|
else if (cache->flags & F_DNSKEY) |
|
sprintf(a, "%5u %3u %3u", cache->addr.key.keytag, |
|
cache->addr.key.algo, cache->addr.key.flags); |
|
#endif |
|
else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD)) |
|
{ |
|
a = daemon->addrbuff; |
|
if (cache->flags & F_IPV4) |
|
inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN); |
|
else if (cache->flags & F_IPV6) |
|
inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN); |
|
} |
|
|
|
if (cache->flags & F_IPV4) |
|
t = "4"; |
|
else if (cache->flags & F_IPV6) |
|
t = "6"; |
|
else if (cache->flags & F_CNAME) |
|
t = "C"; |
|
else if (cache->flags & F_SRV) |
|
t = "V"; |
|
#ifdef HAVE_DNSSEC |
|
else if (cache->flags & F_DS) |
|
t = "S"; |
|
else if (cache->flags & F_DNSKEY) |
|
t = "K"; |
|
#endif |
|
else if (!(cache->flags & F_NXDOMAIN)) /* non-terminal */ |
|
t = "!"; |
|
|
|
p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s%s ", a, t, |
|
cache->flags & F_FORWARD ? "F" : " ", |
|
cache->flags & F_REVERSE ? "R" : " ", |
|
cache->flags & F_IMMORTAL ? "I" : " ", |
|
cache->flags & F_DHCP ? "D" : " ", |
|
cache->flags & F_NEG ? "N" : " ", |
|
cache->flags & F_NXDOMAIN ? "X" : " ", |
|
cache->flags & F_HOSTS ? "H" : " ", |
|
cache->flags & F_CONFIG ? "C" : " ", |
|
cache->flags & F_DNSSECOK ? "V" : " "); |
|
#ifdef HAVE_BROKEN_RTC |
|
p += sprintf(p, "%-24lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now)); |
|
#else |
|
p += sprintf(p, "%-24.24s", cache->flags & F_IMMORTAL ? "" : ctime(&(cache->ttd))); |
|
#endif |
|
if(cache->flags & (F_HOSTS | F_CONFIG) && cache->uid > 0) |
|
p += sprintf(p, " %-40.40s", record_source(cache->uid)); |
|
|
|
my_syslog(LOG_INFO, "%s", buff); |
|
} |
|
|
void dump_cache(time_t now) |
void dump_cache(time_t now) |
{ |
{ |
struct server *serv, *serv1; |
struct server *serv, *serv1; |
Line 1678 void dump_cache(time_t now)
|
Line 1859 void dump_cache(time_t now)
|
daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]); |
daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]); |
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"), |
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"), |
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]); |
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]); |
|
if (daemon->cache_max_expiry != 0) |
|
my_syslog(LOG_INFO, _("queries answered from stale cache %u"), daemon->metrics[METRIC_DNS_STALE_ANSWERED]); |
#ifdef HAVE_AUTH |
#ifdef HAVE_AUTH |
my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]); |
my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]); |
#endif |
#endif |
Line 1686 void dump_cache(time_t now)
|
Line 1869 void dump_cache(time_t now)
|
|
|
/* sum counts from different records for same server */ |
/* sum counts from different records for same server */ |
for (serv = daemon->servers; serv; serv = serv->next) |
for (serv = daemon->servers; serv; serv = serv->next) |
serv->flags &= ~SERV_COUNTED; | serv->flags &= ~SERV_MARK; |
|
|
for (serv = daemon->servers; serv; serv = serv->next) |
for (serv = daemon->servers; serv; serv = serv->next) |
if (!(serv->flags & | if (!(serv->flags & SERV_MARK)) |
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND))) | |
{ |
{ |
int port; |
int port; |
unsigned int queries = 0, failed_queries = 0; | unsigned int queries = 0, failed_queries = 0, nxdomain_replies = 0, retrys = 0; |
| unsigned int sigma_latency = 0, count_latency = 0; |
| |
for (serv1 = serv; serv1; serv1 = serv1->next) |
for (serv1 = serv; serv1; serv1 = serv1->next) |
if (!(serv1->flags & | if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr)) |
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) && | |
sockaddr_isequal(&serv->addr, &serv1->addr)) | |
{ |
{ |
serv1->flags |= SERV_COUNTED; | serv1->flags |= SERV_MARK; |
queries += serv1->queries; |
queries += serv1->queries; |
failed_queries += serv1->failed_queries; |
failed_queries += serv1->failed_queries; |
|
nxdomain_replies += serv1->nxdomain_replies; |
|
retrys += serv1->retrys; |
|
sigma_latency += serv1->query_latency; |
|
count_latency++; |
} |
} |
port = prettyprint_addr(&serv->addr, daemon->addrbuff); |
port = prettyprint_addr(&serv->addr, daemon->addrbuff); |
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries); | my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried %u, failed %u, nxdomain replies %u, avg. latency %ums"), |
| daemon->addrbuff, port, queries, retrys, failed_queries, nxdomain_replies, sigma_latency/count_latency); |
} |
} |
| |
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG)) |
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG)) |
{ |
{ |
struct crec *cache ; | struct crec *cache; |
int i; |
int i; |
my_syslog(LOG_INFO, "Host Address Flags Expires"); | my_syslog(LOG_INFO, "Host Address Flags Expires Source"); |
| my_syslog(LOG_INFO, "------------------------------ ---------------------------------------- ---------- ------------------------ ------------"); |
|
|
for (i=0; i<hash_size; i++) |
for (i=0; i<hash_size; i++) |
for (cache = hash_table[i]; cache; cache = cache->hash_next) |
for (cache = hash_table[i]; cache; cache = cache->hash_next) |
{ | dump_cache_entry(cache, now); |
char *t = " "; | |
char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache); | |
*a = 0; | |
if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) | |
n = "<Root>"; | |
p += sprintf(p, "%-30.30s ", sanitise(n)); | |
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) | |
a = sanitise(cache_get_cname_target(cache)); | |
else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG)) | |
{ | |
int targetlen = cache->addr.srv.targetlen; | |
ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority, | |
cache->addr.srv.weight, cache->addr.srv.srvport); | |
| |
if (targetlen > (40 - len)) | |
targetlen = 40 - len; | |
blockdata_retrieve(cache->addr.srv.target, targetlen, a + len); | |
a[len + targetlen] = 0; | |
} | |
#ifdef HAVE_DNSSEC | |
else if (cache->flags & F_DS) | |
{ | |
if (!(cache->flags & F_NEG)) | |
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag, | |
cache->addr.ds.algo, cache->addr.ds.digest); | |
} | |
else if (cache->flags & F_DNSKEY) | |
sprintf(a, "%5u %3u %3u", cache->addr.key.keytag, | |
cache->addr.key.algo, cache->addr.key.flags); | |
#endif | |
else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD)) | |
{ | |
a = daemon->addrbuff; | |
if (cache->flags & F_IPV4) | |
inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN); | |
else if (cache->flags & F_IPV6) | |
inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN); | |
} | |
| |
if (cache->flags & F_IPV4) | |
t = "4"; | |
else if (cache->flags & F_IPV6) | |
t = "6"; | |
else if (cache->flags & F_CNAME) | |
t = "C"; | |
else if (cache->flags & F_SRV) | |
t = "V"; | |
#ifdef HAVE_DNSSEC | |
else if (cache->flags & F_DS) | |
t = "S"; | |
else if (cache->flags & F_DNSKEY) | |
t = "K"; | |
#endif | |
p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t, | |
cache->flags & F_FORWARD ? "F" : " ", | |
cache->flags & F_REVERSE ? "R" : " ", | |
cache->flags & F_IMMORTAL ? "I" : " ", | |
cache->flags & F_DHCP ? "D" : " ", | |
cache->flags & F_NEG ? "N" : " ", | |
cache->flags & F_NXDOMAIN ? "X" : " ", | |
cache->flags & F_HOSTS ? "H" : " ", | |
cache->flags & F_DNSSECOK ? "V" : " "); | |
#ifdef HAVE_BROKEN_RTC | |
p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now)); | |
#else | |
p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))); | |
/* ctime includes trailing \n - eat it */ | |
*(p-1) = 0; | |
#endif | |
my_syslog(LOG_INFO, "%s", daemon->namebuff); | |
} | |
} |
} |
} |
} |
|
|
char *record_source(unsigned int index) |
char *record_source(unsigned int index) |
{ |
{ |
struct hostsfile *ah; |
struct hostsfile *ah; |
| #ifdef HAVE_INOTIFY |
| struct dyndir *dd; |
| #endif |
| |
if (index == SRC_CONFIG) |
if (index == SRC_CONFIG) |
return "config"; |
return "config"; |
else if (index == SRC_HOSTS) |
else if (index == SRC_HOSTS) |
Line 1804 char *record_source(unsigned int index)
|
Line 1924 char *record_source(unsigned int index)
|
return ah->fname; |
return ah->fname; |
|
|
#ifdef HAVE_INOTIFY |
#ifdef HAVE_INOTIFY |
for (ah = daemon->dynamic_dirs; ah; ah = ah->next) | /* Dynamic directories contain multiple files */ |
if (ah->index == index) | for (dd = daemon->dynamic_dirs; dd; dd = dd->next) |
return ah->fname; | for (ah = dd->files; ah; ah = ah->next) |
| if (ah->index == index) |
| return ah->fname; |
#endif |
#endif |
|
|
return "<unknown>"; |
return "<unknown>"; |
} |
} |
|
|
char *querystr(char *desc, unsigned short type) | static char *querystr(char *desc, unsigned short type) |
{ |
{ |
unsigned int i; |
unsigned int i; |
int len = 10; /* strlen("type=xxxxx") */ |
int len = 10; /* strlen("type=xxxxx") */ |
Line 1860 char *querystr(char *desc, unsigned short type)
|
Line 1982 char *querystr(char *desc, unsigned short type)
|
if (types) |
if (types) |
sprintf(buff, "<%s>", types); |
sprintf(buff, "<%s>", types); |
else |
else |
sprintf(buff, "type=%d", type); | sprintf(buff, "<type=%d>", type); |
} |
} |
} |
} |
|
|
return buff ? buff : ""; |
return buff ? buff : ""; |
} |
} |
|
|
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg) | static char *edestr(int ede) |
{ |
{ |
char *source, *dest = daemon->addrbuff; | switch (ede) |
| { |
| case EDE_OTHER: return "other"; |
| case EDE_USUPDNSKEY: return "unsupported DNSKEY algorithm"; |
| case EDE_USUPDS: return "unsupported DS digest"; |
| case EDE_STALE: return "stale answer"; |
| case EDE_FORGED: return "forged"; |
| case EDE_DNSSEC_IND: return "DNSSEC indeterminate"; |
| case EDE_DNSSEC_BOGUS: return "DNSSEC bogus"; |
| case EDE_SIG_EXP: return "DNSSEC signature expired"; |
| case EDE_SIG_NYV: return "DNSSEC sig not yet valid"; |
| case EDE_NO_DNSKEY: return "DNSKEY missing"; |
| case EDE_NO_RRSIG: return "RRSIG missing"; |
| case EDE_NO_ZONEKEY: return "no zone key bit set"; |
| case EDE_NO_NSEC: return "NSEC(3) missing"; |
| case EDE_CACHED_ERR: return "cached error"; |
| case EDE_NOT_READY: return "not ready"; |
| case EDE_BLOCKED: return "blocked"; |
| case EDE_CENSORED: return "censored"; |
| case EDE_FILTERED: return "filtered"; |
| case EDE_PROHIBITED: return "prohibited"; |
| case EDE_STALE_NXD: return "stale NXDOMAIN"; |
| case EDE_NOT_AUTH: return "not authoritative"; |
| case EDE_NOT_SUP: return "not supported"; |
| case EDE_NO_AUTH: return "no reachable authority"; |
| case EDE_NETERR: return "network error"; |
| case EDE_INVALID_DATA: return "invalid data"; |
| default: return "unknown"; |
| } |
| } |
| |
| void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type) |
| { |
| char *source, *dest = arg; |
char *verb = "is"; |
char *verb = "is"; |
|
char *extra = ""; |
|
char portstring[7]; /* space for #<portnum> */ |
|
|
if (!option_bool(OPT_LOG)) |
if (!option_bool(OPT_LOG)) |
return; |
return; |
|
|
|
/* build query type string if requested */ |
|
if (!(flags & (F_SERVER | F_IPSET)) && type > 0) |
|
arg = querystr(arg, type); |
|
|
|
#ifdef HAVE_DNSSEC |
|
if ((flags & F_DNSSECOK) && option_bool(OPT_EXTRALOG)) |
|
extra = " (DNSSEC signed)"; |
|
#endif |
|
|
name = sanitise(name); |
name = sanitise(name); |
|
|
if (addr) |
if (addr) |
{ |
{ |
|
dest = daemon->addrbuff; |
|
|
if (flags & F_KEYTAG) |
if (flags & F_KEYTAG) |
sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest); |
sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest); |
else if (flags & F_RCODE) |
else if (flags & F_RCODE) |
{ |
{ |
unsigned int rcode = addr->log.rcode; |
unsigned int rcode = addr->log.rcode; |
|
|
if (rcode == SERVFAIL) | if (rcode == SERVFAIL) |
dest = "SERVFAIL"; | dest = "SERVFAIL"; |
else if (rcode == REFUSED) | else if (rcode == REFUSED) |
dest = "REFUSED"; | dest = "REFUSED"; |
else if (rcode == NOTIMP) | else if (rcode == NOTIMP) |
dest = "not implemented"; | dest = "not implemented"; |
else | else |
sprintf(daemon->addrbuff, "%u", rcode); | sprintf(daemon->addrbuff, "%u", rcode); |
| |
| if (addr->log.ede != EDE_UNSET) |
| { |
| extra = daemon->addrbuff; |
| sprintf(extra, " (EDE: %s)", edestr(addr->log.ede)); |
| } |
} |
} |
|
else if (flags & (F_IPV4 | F_IPV6)) |
|
{ |
|
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, |
|
addr, daemon->addrbuff, ADDRSTRLEN); |
|
if ((flags & F_SERVER) && type != NAMESERVER_PORT) |
|
{ |
|
extra = portstring; |
|
sprintf(portstring, "#%u", type); |
|
} |
|
} |
else |
else |
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, | dest = arg; |
addr, daemon->addrbuff, ADDRSTRLEN); | |
| |
} |
} |
else |
|
dest = arg; |
|
|
|
if (flags & F_REVERSE) |
if (flags & F_REVERSE) |
{ |
{ |
Line 1938 void log_query(unsigned int flags, char *name, union a
|
Line 2118 void log_query(unsigned int flags, char *name, union a
|
else if (flags & F_UPSTREAM) |
else if (flags & F_UPSTREAM) |
source = "reply"; |
source = "reply"; |
else if (flags & F_SECSTAT) |
else if (flags & F_SECSTAT) |
source = "validation"; | { |
| if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG)) |
| { |
| extra = daemon->addrbuff; |
| sprintf(extra, " (EDE: %s)", edestr(addr->log.ede)); |
| } |
| source = "validation"; |
| dest = arg; |
| } |
else if (flags & F_AUTH) |
else if (flags & F_AUTH) |
source = "auth"; |
source = "auth"; |
else if (flags & F_SERVER) | else if (flags & F_DNSSEC) |
{ |
{ |
|
source = arg; |
|
verb = "to"; |
|
} |
|
else if (flags & F_SERVER) |
|
{ |
source = "forwarded"; |
source = "forwarded"; |
verb = "to"; |
verb = "to"; |
} |
} |
Line 1951 void log_query(unsigned int flags, char *name, union a
|
Line 2144 void log_query(unsigned int flags, char *name, union a
|
source = arg; |
source = arg; |
verb = "from"; |
verb = "from"; |
} |
} |
else if (flags & F_DNSSEC) |
|
{ |
|
source = arg; |
|
verb = "to"; |
|
} |
|
else if (flags & F_IPSET) |
else if (flags & F_IPSET) |
{ |
{ |
source = "ipset add"; | source = type ? "ipset add" : "nftset add"; |
dest = name; |
dest = name; |
name = arg; |
name = arg; |
verb = daemon->addrbuff; |
verb = daemon->addrbuff; |
} |
} |
|
else if (flags & F_STALE) |
|
source = "cached-stale"; |
else |
else |
source = "cached"; |
source = "cached"; |
|
|
if (strlen(name) == 0) | if (name && !name[0]) |
name = "."; |
name = "."; |
|
|
if (option_bool(OPT_EXTRALOG)) |
if (option_bool(OPT_EXTRALOG)) |
{ |
{ |
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2); |
|
if (flags & F_NOEXTRA) |
if (flags & F_NOEXTRA) |
my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest); | my_syslog(LOG_INFO, "%u %s %s %s %s%s", daemon->log_display_id, source, name, verb, dest, extra); |
else |
else |
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest); | { |
| int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2); |
| my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s%s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest, extra); |
| } |
} |
} |
else |
else |
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest); | my_syslog(LOG_INFO, "%s %s %s %s%s", source, name, verb, dest, extra); |
} |
} |
|
|
|
|