mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Merge branch 'aws'
This commit is contained in:
28
src/cache.c
28
src/cache.c
@@ -374,6 +374,11 @@ static int is_outdated_cname_pointer(struct crec *crecp)
|
||||
|
||||
static int is_expired(time_t now, struct crec *crecp)
|
||||
{
|
||||
/* Don't dump expired entries if we're using them, cache becomes strictly LRU in that case.
|
||||
Never use expired DS or DNSKEY entries. */
|
||||
if (option_bool(OPT_STALE_CACHE) && !(crecp->flags & (F_DS | F_DNSKEY)))
|
||||
return 0;
|
||||
|
||||
if (crecp->flags & F_IMMORTAL)
|
||||
return 0;
|
||||
|
||||
@@ -553,7 +558,7 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho
|
||||
{
|
||||
struct crec *new, *target_crec = NULL;
|
||||
union bigname *big_name = NULL;
|
||||
int freed_all = flags & F_REVERSE;
|
||||
int freed_all = (flags & F_REVERSE);
|
||||
int free_avail = 0;
|
||||
unsigned int target_uid;
|
||||
|
||||
@@ -628,8 +633,12 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho
|
||||
{
|
||||
/* For DNSSEC records, uid holds class. */
|
||||
free_avail = 1; /* Must be free space now. */
|
||||
|
||||
/* 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);
|
||||
daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1725,6 +1734,8 @@ void dump_cache(time_t now)
|
||||
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"),
|
||||
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
|
||||
if (option_bool(OPT_STALE_CACHE))
|
||||
my_syslog(LOG_INFO, _("queries answered from stale cache %u"), daemon->metrics[METRIC_DNS_STALE_ANSWERED]);
|
||||
#ifdef HAVE_AUTH
|
||||
my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
|
||||
#endif
|
||||
@@ -1739,16 +1750,23 @@ void dump_cache(time_t now)
|
||||
if (!(serv->flags & SERV_MARK))
|
||||
{
|
||||
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)
|
||||
if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_MARK;
|
||||
queries += serv1->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);
|
||||
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))
|
||||
@@ -2079,6 +2097,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
name = arg;
|
||||
verb = daemon->addrbuff;
|
||||
}
|
||||
else if (flags & F_STALE)
|
||||
source = "cached-stale";
|
||||
else
|
||||
source = "cached";
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
|
||||
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define SMALL_PORT_RANGE 30 /* If DNS port range is smaller than this, use different allocation. */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */
|
||||
@@ -58,6 +59,7 @@
|
||||
#define SOA_EXPIRY 1209600 /* SOA expiry default */
|
||||
#define LOOP_TEST_DOMAIN "test" /* domain for loop testing, "test" is reserved by RFC 2606 and won't therefore clash */
|
||||
#define LOOP_TEST_TYPE T_TXT
|
||||
#define DEFAULT_FAST_RETRY 1000 /* ms, default delay before fast retry */
|
||||
|
||||
/* compile-time options: uncomment below to enable or do eg.
|
||||
make COPTS=-DHAVE_BROKEN_RTC
|
||||
|
||||
84
src/dbus.c
84
src/dbus.c
@@ -91,6 +91,11 @@ const char* introspection_xml_template =
|
||||
" <method name=\"GetMetrics\">\n"
|
||||
" <arg name=\"metrics\" direction=\"out\" type=\"a{su}\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"GetServerMetrics\">\n"
|
||||
" <arg name=\"metrics\" direction=\"out\" type=\"a{ss}\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"ClearMetrics\">\n"
|
||||
" </method>\n"
|
||||
" </interface>\n"
|
||||
"</node>\n";
|
||||
|
||||
@@ -644,6 +649,77 @@ static DBusMessage *dbus_get_metrics(DBusMessage* message)
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void add_dict_entry(DBusMessageIter *container, const char *key, const char *val)
|
||||
{
|
||||
DBusMessageIter dict;
|
||||
|
||||
dbus_message_iter_open_container(container, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
|
||||
dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &key);
|
||||
dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &val);
|
||||
dbus_message_iter_close_container(container, &dict);
|
||||
}
|
||||
|
||||
static void add_dict_int(DBusMessageIter *container, const char *key, const unsigned int val)
|
||||
{
|
||||
snprintf(daemon->namebuff, MAXDNAME, "%u", val);
|
||||
|
||||
add_dict_entry(container, key, daemon->namebuff);
|
||||
}
|
||||
|
||||
static DBusMessage *dbus_get_server_metrics(DBusMessage* message)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(message);
|
||||
DBusMessageIter server_array, dict_array, server_iter;
|
||||
struct server *serv;
|
||||
|
||||
dbus_message_iter_init_append(reply, &server_iter);
|
||||
dbus_message_iter_open_container(&server_iter, DBUS_TYPE_ARRAY, "a{ss}", &server_array);
|
||||
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags & SERV_MARK))
|
||||
{
|
||||
unsigned int port;
|
||||
unsigned int queries = 0, failed_queries = 0, nxdomain_replies = 0, retrys = 0;
|
||||
unsigned int sigma_latency = 0, count_latency = 0;
|
||||
|
||||
struct server *serv1;
|
||||
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_MARK;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
nxdomain_replies += serv1->nxdomain_replies;
|
||||
retrys += serv1->retrys;
|
||||
sigma_latency += serv1->query_latency;
|
||||
count_latency++;
|
||||
}
|
||||
|
||||
dbus_message_iter_open_container(&server_array, DBUS_TYPE_ARRAY, "{ss}", &dict_array);
|
||||
|
||||
port = prettyprint_addr(&serv->addr, daemon->namebuff);
|
||||
add_dict_entry(&dict_array, "address", daemon->namebuff);
|
||||
|
||||
add_dict_int(&dict_array, "port", port);
|
||||
add_dict_int(&dict_array, "queries", serv->queries);
|
||||
add_dict_int(&dict_array, "failed_queries", serv->failed_queries);
|
||||
add_dict_int(&dict_array, "nxdomain", serv->nxdomain_replies);
|
||||
add_dict_int(&dict_array, "retries", serv->retrys);
|
||||
add_dict_int(&dict_array, "latency", sigma_latency/count_latency);
|
||||
|
||||
dbus_message_iter_close_container(&server_array, &dict_array);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(&server_iter, &server_array);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
DBusMessage *message,
|
||||
void *user_data)
|
||||
@@ -719,6 +795,14 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
{
|
||||
reply = dbus_get_metrics(message);
|
||||
}
|
||||
else if (strcmp(method, "GetServerMetrics") == 0)
|
||||
{
|
||||
reply = dbus_get_server_metrics(message);
|
||||
}
|
||||
else if (strcmp(method, "ClearMetrics") == 0)
|
||||
{
|
||||
clear_metrics();
|
||||
}
|
||||
else if (strcmp(method, "ClearCache") == 0)
|
||||
clear_cache = 1;
|
||||
else
|
||||
|
||||
@@ -265,6 +265,10 @@ int main (int argc, char **argv)
|
||||
|
||||
if (daemon->max_port < daemon->min_port)
|
||||
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
|
||||
|
||||
if (daemon->max_port != 0 &&
|
||||
daemon->max_port - daemon->min_port + 1 < daemon->randport_limit)
|
||||
die(_("port_limit must not be larger than available port range"), NULL, EC_BADCONF);
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
@@ -1055,19 +1059,20 @@ int main (int argc, char **argv)
|
||||
|
||||
while (1)
|
||||
{
|
||||
int timeout = -1;
|
||||
int timeout = fast_retry(now);
|
||||
|
||||
poll_reset();
|
||||
|
||||
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
|
||||
if (daemon->tftp_trans ||
|
||||
(option_bool(OPT_DBUS) && !daemon->dbus))
|
||||
if ((daemon->tftp_trans || (option_bool(OPT_DBUS) && !daemon->dbus)) &&
|
||||
(timeout == -1 || timeout > 250))
|
||||
timeout = 250;
|
||||
|
||||
|
||||
/* Wake every second whilst waiting for DAD to complete */
|
||||
else if (is_dad_listeners())
|
||||
else if (is_dad_listeners() &&
|
||||
(timeout == -1 || timeout > 1000))
|
||||
timeout = 1000;
|
||||
|
||||
|
||||
set_dns_listeners();
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
@@ -2014,9 +2019,6 @@ static void check_dns_listeners(time_t now)
|
||||
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
|
||||
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
|
||||
if (buff)
|
||||
free(buff);
|
||||
|
||||
|
||||
@@ -279,7 +279,8 @@ struct event_desc {
|
||||
#define OPT_FILTER_AAAA 68
|
||||
#define OPT_STRIP_ECS 69
|
||||
#define OPT_STRIP_MAC 70
|
||||
#define OPT_LAST 71
|
||||
#define OPT_STALE_CACHE 71
|
||||
#define OPT_LAST 72
|
||||
|
||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||
@@ -510,6 +511,7 @@ struct crec {
|
||||
#define F_DOMAINSRV (1u<<28)
|
||||
#define F_RCODE (1u<<29)
|
||||
#define F_SRV (1u<<30)
|
||||
#define F_STALE (1u<<31)
|
||||
|
||||
#define UID_NONE 0
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
@@ -584,7 +586,8 @@ struct server {
|
||||
struct serverfd *sfd;
|
||||
int tcpfd, edns_pktsz;
|
||||
time_t pktsz_reduced;
|
||||
unsigned int queries, failed_queries;
|
||||
unsigned int queries, failed_queries, nxdomain_replies, retrys;
|
||||
unsigned int query_latency, mma_latency;
|
||||
time_t forwardtime;
|
||||
int forwardcount;
|
||||
#ifdef HAVE_LOOP
|
||||
@@ -755,11 +758,13 @@ struct frec {
|
||||
unsigned short new_id;
|
||||
int forwardall, flags;
|
||||
time_t time;
|
||||
u32 forward_timestamp;
|
||||
int forward_delay;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
int class, work_counter;
|
||||
struct blockdata *stash; /* Saved reply, whilst we validate */
|
||||
size_t stash_len;
|
||||
#ifdef HAVE_DNSSEC
|
||||
int class, work_counter;
|
||||
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
|
||||
struct frec *next_dependent; /* list of above. */
|
||||
struct frec *blocking_query; /* Query which is blocking us. */
|
||||
@@ -1139,6 +1144,7 @@ extern struct daemon {
|
||||
int log_fac; /* log facility */
|
||||
char *log_file; /* optional log file */
|
||||
int max_logs; /* queue limit */
|
||||
int randport_limit; /* Maximum number of source ports for query. */
|
||||
int cachesize, ftabsize;
|
||||
int port, query_port, min_port, max_port;
|
||||
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
|
||||
@@ -1183,6 +1189,7 @@ extern struct daemon {
|
||||
int dump_mask;
|
||||
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
|
||||
u32 metrics[__METRIC_MAX];
|
||||
int fast_retry_time, fast_retry_timeout;
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct ds_config *ds;
|
||||
char *timestamp_file;
|
||||
@@ -1337,7 +1344,8 @@ void report_addresses(struct dns_header *header, size_t len, u32 mark);
|
||||
#endif
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader,
|
||||
int *stale);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
time_t now);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen);
|
||||
@@ -1399,10 +1407,12 @@ void *whine_malloc(size_t size);
|
||||
void *whine_realloc(void *ptr, size_t size);
|
||||
int sa_len(union mysockaddr *addr);
|
||||
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
|
||||
int sockaddr_isnull(const union mysockaddr *s);
|
||||
int hostname_order(const char *a, const char *b);
|
||||
int hostname_isequal(const char *a, const char *b);
|
||||
int hostname_issubdomain(char *a, char *b);
|
||||
time_t dnsmasq_time(void);
|
||||
u32 dnsmasq_milliseconds(void);
|
||||
int netmask_length(struct in_addr mask);
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||
int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix);
|
||||
@@ -1462,6 +1472,7 @@ int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
void resend_query(void);
|
||||
int allocate_rfd(struct randfd_list **fdlp, struct server *serv);
|
||||
void free_rfds(struct randfd_list **fdlp);
|
||||
int fast_retry(time_t now);
|
||||
|
||||
/* network.c */
|
||||
int indextoname(int fd, int index, char *name);
|
||||
|
||||
524
src/forward.c
524
src/forward.c
@@ -170,7 +170,7 @@ static int domain_no_rebind(char *domain)
|
||||
static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
union all_addr *dst_addr, unsigned int dst_iface,
|
||||
struct dns_header *header, size_t plen, char *limit, time_t now,
|
||||
struct frec *forward, int ad_reqd, int do_bit)
|
||||
struct frec *forward, int ad_reqd, int do_bit, int fast_retry)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
unsigned int fwd_flags = 0;
|
||||
@@ -313,6 +313,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
goto reply;
|
||||
/* table full - flags == 0, return REFUSED */
|
||||
|
||||
/* Keep copy of query if we're doing fast retry. */
|
||||
if (daemon->fast_retry_time != 0)
|
||||
{
|
||||
forward->stash = blockdata_alloc((char *)header, plen);
|
||||
forward->stash_len = plen;
|
||||
}
|
||||
|
||||
forward->frec_src.log_id = daemon->log_id;
|
||||
forward->frec_src.source = *udpaddr;
|
||||
forward->frec_src.orig_id = ntohs(header->id);
|
||||
@@ -360,14 +367,14 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* If we've already got an answer to this query, but we're awaiting keys for validation,
|
||||
there's no point retrying the query, retry the key query instead...... */
|
||||
if (forward->blocking_query)
|
||||
while (forward->blocking_query)
|
||||
forward = forward->blocking_query;
|
||||
|
||||
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
||||
{
|
||||
int is_sign;
|
||||
unsigned char *pheader;
|
||||
|
||||
while (forward->blocking_query)
|
||||
forward = forward->blocking_query;
|
||||
|
||||
/* log_id should match previous DNSSEC query. */
|
||||
daemon->log_display_id = forward->frec_src.log_id;
|
||||
|
||||
@@ -390,7 +397,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
#endif
|
||||
{
|
||||
/* retry on existing query, from original source. Send to all available servers */
|
||||
forward->sentto->failed_queries++;
|
||||
if (udpfd == -1 && !fast_retry)
|
||||
forward->sentto->failed_queries++;
|
||||
else
|
||||
forward->sentto->retrys++;
|
||||
|
||||
if (!filter_servers(forward->sentto->arrayposn, F_SERVER, &first, &last))
|
||||
goto reply;
|
||||
@@ -398,13 +408,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
master = daemon->serverarray[first];
|
||||
|
||||
/* Forward to all available servers on retry of query from same host. */
|
||||
if (!option_bool(OPT_ORDER) && old_src)
|
||||
if (!option_bool(OPT_ORDER) && old_src && !fast_retry)
|
||||
forward->forwardall = 1;
|
||||
else
|
||||
{
|
||||
start = forward->sentto->arrayposn;
|
||||
|
||||
if (option_bool(OPT_ORDER))
|
||||
if (option_bool(OPT_ORDER) && !fast_retry)
|
||||
{
|
||||
/* In strict order mode, there must be a server later in the list
|
||||
left to send to, otherwise without the forwardall mechanism,
|
||||
@@ -553,7 +563,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
|
||||
if (forwarded || is_dnssec)
|
||||
return 1;
|
||||
{
|
||||
forward->forward_timestamp = dnsmasq_milliseconds();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* could not send on, prepare to return */
|
||||
header->id = htons(forward->frec_src.orig_id);
|
||||
@@ -592,6 +605,61 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if any frecs need to do a retry, and action that if so.
|
||||
Return time in milliseconds until he next retry will be required,
|
||||
or -1 if none. */
|
||||
int fast_retry(time_t now)
|
||||
{
|
||||
struct frec *f;
|
||||
int ret = -1;
|
||||
|
||||
if (daemon->fast_retry_time != 0)
|
||||
{
|
||||
u32 millis = dnsmasq_milliseconds();
|
||||
|
||||
for (f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto && f->stash && difftime(now, f->time) < daemon->fast_retry_timeout)
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (f->blocking_query)
|
||||
continue;
|
||||
#endif
|
||||
/* t is milliseconds since last query sent. */
|
||||
int to_run, t = (int)(millis - f->forward_timestamp);
|
||||
|
||||
if (t < f->forward_delay)
|
||||
to_run = f->forward_delay - t;
|
||||
else
|
||||
{
|
||||
unsigned char *udpsz;
|
||||
unsigned short udp_size = PACKETSZ; /* default if no EDNS0 */
|
||||
struct dns_header *header = (struct dns_header *)daemon->packet;
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
blockdata_retrieve(f->stash, f->stash_len, (void *)header);
|
||||
|
||||
/* UDP size already set in saved query. */
|
||||
if (find_pseudoheader(header, f->stash_len, NULL, &udpsz, NULL, NULL))
|
||||
GETSHORT(udp_size, udpsz);
|
||||
|
||||
daemon->log_display_id = f->frec_src.log_id;
|
||||
|
||||
forward_query(-1, NULL, NULL, 0, header, f->stash_len, ((char *) header) + udp_size, now, f,
|
||||
f->flags & FREC_AD_QUESTION, f->flags & FREC_DO_QUESTION, 1);
|
||||
|
||||
to_run = f->forward_delay = 2 * f->forward_delay;
|
||||
}
|
||||
|
||||
if (ret == -1 || ret > to_run)
|
||||
ret = to_run;
|
||||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ipsets *domain_find_sets(struct ipsets *setlist, const char *domain) {
|
||||
/* Similar algorithm to search_servers. */
|
||||
struct ipsets *ipset_pos, *ret = NULL;
|
||||
@@ -807,6 +875,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
n = add_pseudoheader(header, n, limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
|
||||
}
|
||||
|
||||
if (RCODE(header) == NXDOMAIN)
|
||||
server->nxdomain_replies++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -949,6 +1020,8 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
/* Save query for retransmission and de-dup */
|
||||
new->stash = blockdata_alloc((char *)header, nn);
|
||||
new->stash_len = nn;
|
||||
if (daemon->fast_retry_time != 0)
|
||||
new->forward_timestamp = dnsmasq_milliseconds();
|
||||
|
||||
/* Don't resend this. */
|
||||
daemon->srv_save = NULL;
|
||||
@@ -1066,7 +1139,7 @@ void reply_query(int fd, time_t now)
|
||||
if (daemon->ignore_addr && RCODE(header) == NOERROR &&
|
||||
check_for_ignored_address(header, n))
|
||||
return;
|
||||
|
||||
|
||||
/* Note: if we send extra options in the EDNS0 header, we can't recreate
|
||||
the query from the reply. */
|
||||
if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
|
||||
@@ -1097,38 +1170,50 @@ void reply_query(int fd, time_t now)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* recreate query from reply */
|
||||
if ((pheader = find_pseudoheader(header, (size_t)n, &plen, &udpsz, &is_sign, NULL)))
|
||||
GETSHORT(udp_size, udpsz);
|
||||
|
||||
/* If the client provides an EDNS0 UDP size, use that to limit our reply.
|
||||
(bounded by the maximum configured). If no EDNS0, then it
|
||||
defaults to 512 */
|
||||
if (udp_size > daemon->edns_pktsz)
|
||||
udp_size = daemon->edns_pktsz;
|
||||
else if (udp_size < PACKETSZ)
|
||||
udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
|
||||
|
||||
if (!is_sign &&
|
||||
(nn = resize_packet(header, (size_t)n, pheader, plen)) &&
|
||||
(forward->flags & FREC_DO_QUESTION))
|
||||
add_do_bit(header, nn, (unsigned char *)pheader + plen);
|
||||
/* in fast retry mode, we have a copy of the query. */
|
||||
if (daemon->fast_retry_time != 0 && forward->stash)
|
||||
{
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
nn = forward->stash_len;
|
||||
/* UDP size already set in saved query. */
|
||||
if (find_pseudoheader(header, (size_t)n, NULL, &udpsz, NULL, NULL))
|
||||
GETSHORT(udp_size, udpsz);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* recreate query from reply */
|
||||
if ((pheader = find_pseudoheader(header, (size_t)n, &plen, &udpsz, &is_sign, NULL)))
|
||||
GETSHORT(udp_size, udpsz);
|
||||
|
||||
/* If the client provides an EDNS0 UDP size, use that to limit our reply.
|
||||
(bounded by the maximum configured). If no EDNS0, then it
|
||||
defaults to 512 */
|
||||
if (udp_size > daemon->edns_pktsz)
|
||||
udp_size = daemon->edns_pktsz;
|
||||
else if (udp_size < PACKETSZ)
|
||||
udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
|
||||
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
|
||||
header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
|
||||
if (forward->flags & FREC_CHECKING_DISABLED)
|
||||
header->hb4 |= HB4_CD;
|
||||
if (forward->flags & FREC_AD_QUESTION)
|
||||
header->hb4 |= HB4_AD;
|
||||
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
|
||||
header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
|
||||
if (forward->flags & FREC_CHECKING_DISABLED)
|
||||
header->hb4 |= HB4_CD;
|
||||
if (forward->flags & FREC_AD_QUESTION)
|
||||
header->hb4 |= HB4_AD;
|
||||
if (!is_sign &&
|
||||
(nn = resize_packet(header, (size_t)n, pheader, plen)) &&
|
||||
(forward->flags & FREC_DO_QUESTION))
|
||||
add_do_bit(header, nn, (unsigned char *)pheader + plen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (nn)
|
||||
{
|
||||
forward_query(-1, NULL, NULL, 0, header, nn, ((char *) header) + udp_size, now, forward,
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1162,6 +1247,15 @@ void reply_query(int fd, time_t now)
|
||||
answers, to conserve file descriptors, and to save work reading and
|
||||
discarding answers for other upstreams. */
|
||||
free_rfds(&forward->rfds);
|
||||
|
||||
/* calculate modified moving average of server latency */
|
||||
if (server->query_latency == 0)
|
||||
server->mma_latency = (dnsmasq_milliseconds() - forward->forward_timestamp) * 128; /* init */
|
||||
else
|
||||
server->mma_latency += dnsmasq_milliseconds() - forward->forward_timestamp - server->query_latency;
|
||||
/* denominator controls how many queries we average over. */
|
||||
server->query_latency = server->mma_latency/128;
|
||||
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
|
||||
@@ -1268,10 +1362,6 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
{
|
||||
header->id = htons(src->orig_id);
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, src->fd);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||
if (option_bool(OPT_CMARK_ALST_EN))
|
||||
{
|
||||
@@ -1282,14 +1372,20 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
}
|
||||
#endif
|
||||
|
||||
send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
&src->source, &src->dest, src->iface);
|
||||
|
||||
if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
|
||||
if (src->fd != -1)
|
||||
{
|
||||
daemon->log_display_id = src->log_id;
|
||||
daemon->log_source_addr = &src->source;
|
||||
log_query(F_UPSTREAM, "query", NULL, "duplicate", 0);
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, src->fd);
|
||||
#endif
|
||||
send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
&src->source, &src->dest, src->iface);
|
||||
|
||||
if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
|
||||
{
|
||||
daemon->log_display_id = src->log_id;
|
||||
daemon->log_source_addr = &src->source;
|
||||
log_query(F_UPSTREAM, "query", NULL, "duplicate", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1379,7 +1475,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
int family = listen->addr.sa.sa_family;
|
||||
/* Can always get recvd interface for IPv6 */
|
||||
int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
|
||||
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
@@ -1702,16 +1798,27 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#endif
|
||||
else
|
||||
{
|
||||
int stale;
|
||||
int ad_reqd = do_bit;
|
||||
u16 hb3 = header->hb3, hb4 = header->hb4;
|
||||
int fd = listen->fd;
|
||||
|
||||
/* RFC 6840 5.7 */
|
||||
if (header->hb4 & HB4_AD)
|
||||
ad_reqd = 1;
|
||||
|
||||
m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale);
|
||||
|
||||
if (m >= 1)
|
||||
{
|
||||
if (stale && have_pseudoheader)
|
||||
{
|
||||
u16 swap = htons(EDE_STALE);
|
||||
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + udp_size, daemon->edns_pktsz,
|
||||
EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
}
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, listen->fd);
|
||||
#endif
|
||||
@@ -1722,12 +1829,39 @@ void receive_query(struct listener *listen, time_t now)
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||
(char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
||||
if (stale)
|
||||
daemon->metrics[METRIC_DNS_STALE_ANSWERED]++;
|
||||
}
|
||||
|
||||
if (m == 0 || stale)
|
||||
{
|
||||
if (m != 0)
|
||||
{
|
||||
size_t plen;
|
||||
|
||||
/* We answered with stale cache data, so forward the query anyway to
|
||||
refresh that. Restore the query from the answer packet. */
|
||||
pheader = find_pseudoheader(header, (size_t)m, &plen, NULL, NULL, NULL);
|
||||
|
||||
header->hb3 = hb3;
|
||||
header->hb4 = hb4;
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
|
||||
m = resize_packet(header, m, pheader, plen);
|
||||
|
||||
/* We've already answered the client, so don't send it the answer
|
||||
when it comes back. */
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
if (forward_query(fd, &source_addr, &dst_addr, if_index,
|
||||
header, (size_t)n, ((char *) header) + udp_size, now, NULL, ad_reqd, do_bit, 0))
|
||||
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
|
||||
else
|
||||
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
||||
}
|
||||
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, (size_t)n, ((char *) header) + udp_size, now, NULL, ad_reqd, do_bit))
|
||||
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
|
||||
else
|
||||
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1954,8 +2088,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
unsigned char *pheader;
|
||||
unsigned int mark = 0;
|
||||
int have_mark = 0;
|
||||
int first, last;
|
||||
int first, last, stale, do_stale = 0;
|
||||
unsigned int flags = 0;
|
||||
u16 hb3, hb4;
|
||||
|
||||
if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
return packet;
|
||||
@@ -2010,13 +2145,37 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
{
|
||||
int ede = EDE_UNSET;
|
||||
|
||||
if (query_count == TCP_MAX_QUERIES ||
|
||||
!packet ||
|
||||
!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
|
||||
!(size = c1 << 8 | c2) ||
|
||||
!read_write(confd, payload, size, 1))
|
||||
return packet;
|
||||
|
||||
if (query_count == TCP_MAX_QUERIES)
|
||||
return packet;
|
||||
|
||||
if (do_stale)
|
||||
{
|
||||
size_t plen;
|
||||
|
||||
/* We answered the last query with stale data. Now try and get fresh data.
|
||||
Restore query from answer. */
|
||||
pheader = find_pseudoheader(header, m, &plen, NULL, NULL, NULL);
|
||||
|
||||
header->hb3 = hb3;
|
||||
header->hb4 = hb4;
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
|
||||
size = resize_packet(header, m, pheader, plen);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
|
||||
!(size = c1 << 8 | c2) ||
|
||||
!read_write(confd, payload, size, 1))
|
||||
return packet;
|
||||
|
||||
/* for stale-answer processing. */
|
||||
hb3 = header->hb3;
|
||||
hb4 = header->hb4;
|
||||
}
|
||||
|
||||
if (size < (int)sizeof(struct dns_header))
|
||||
continue;
|
||||
|
||||
@@ -2041,24 +2200,27 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
struct auth_zone *zone;
|
||||
#endif
|
||||
|
||||
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&peer_addr, auth_dns ? "auth" : "query", qtype);
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
is_single_query = 1;
|
||||
#endif
|
||||
|
||||
|
||||
if (!do_stale)
|
||||
{
|
||||
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&peer_addr, auth_dns ? "auth" : "query", qtype);
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
/* find queries for zones we're authoritative for, and answer them directly */
|
||||
if (!auth_dns && !option_bool(OPT_LOCALISE))
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if (in_zone(zone, daemon->namebuff, NULL))
|
||||
{
|
||||
auth_dns = 1;
|
||||
local_auth = 1;
|
||||
break;
|
||||
}
|
||||
/* find queries for zones we're authoritative for, and answer them directly */
|
||||
if (!auth_dns && !option_bool(OPT_LOCALISE))
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if (in_zone(zone, daemon->namebuff, NULL))
|
||||
{
|
||||
auth_dns = 1;
|
||||
local_auth = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
norebind = domain_no_rebind(daemon->namebuff);
|
||||
@@ -2114,11 +2276,14 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
/* RFC 6840 5.7 */
|
||||
if (header->hb4 & HB4_AD)
|
||||
ad_reqd = 1;
|
||||
|
||||
if (do_stale)
|
||||
m = 0;
|
||||
else
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale);
|
||||
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
|
||||
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(1);
|
||||
|
||||
@@ -2236,6 +2401,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
}
|
||||
}
|
||||
|
||||
if (do_stale)
|
||||
break;
|
||||
|
||||
/* In case of local answer or no connections made. */
|
||||
if (m == 0)
|
||||
{
|
||||
@@ -2246,13 +2414,19 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (have_pseudoheader)
|
||||
{
|
||||
u16 swap = htons((u16)ede);
|
||||
|
||||
if (ede != EDE_UNSET)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
else
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
|
||||
if (ede != EDE_UNSET)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
else
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
}
|
||||
}
|
||||
else if (stale)
|
||||
{
|
||||
u16 swap = htons((u16)EDE_STALE);
|
||||
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
}
|
||||
|
||||
check_log_writer(1);
|
||||
|
||||
@@ -2267,8 +2441,26 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#endif
|
||||
if (!read_write(confd, packet, m + sizeof(u16), 0))
|
||||
break;
|
||||
|
||||
/* If we answered with stale data, this process will now try and get fresh data into
|
||||
the cache then and cannot therefore accept new queries. Close the incoming
|
||||
connection to signal that to the client. Then set do_stale and loop round
|
||||
once more to try and get fresh data, after which we exit. */
|
||||
if (stale)
|
||||
{
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
do_stale = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If we ran once to get fresh data, confd is already closed. */
|
||||
if (!do_stale)
|
||||
{
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
@@ -2280,16 +2472,36 @@ static int random_sock(struct server *s)
|
||||
|
||||
if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
|
||||
{
|
||||
/* We need to set IPV6ONLY so we can use the same ports
|
||||
for IPv4 and IPV6, otherwise, in restriced port situations,
|
||||
we can end up with all our available ports in use for
|
||||
one address family, and the other address family cannot be used. */
|
||||
if (s->source_addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
int opt = 1;
|
||||
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
|
||||
return fd;
|
||||
|
||||
if (s->interface[0] == 0)
|
||||
(void)prettyprint_addr(&s->source_addr, daemon->namebuff);
|
||||
else
|
||||
strcpy(daemon->namebuff, s->interface);
|
||||
|
||||
my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
|
||||
daemon->namebuff, strerror(errno));
|
||||
/* don't log errors due to running out of available ports, we handle those. */
|
||||
if (!sockaddr_isnull(&s->source_addr) || errno != EADDRINUSE)
|
||||
{
|
||||
if (s->interface[0] == 0)
|
||||
(void)prettyprint_addr(&s->source_addr, daemon->addrbuff);
|
||||
else
|
||||
safe_strncpy(daemon->addrbuff, s->interface, ADDRSTRLEN);
|
||||
|
||||
my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
|
||||
daemon->addrbuff, strerror(errno));
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@@ -2319,39 +2531,93 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
|
||||
{
|
||||
static int finger = 0;
|
||||
int i, j = 0;
|
||||
struct randfd_list *rfl;
|
||||
int ports_full = 0;
|
||||
struct randfd_list **up, *rfl, *found, **found_link;
|
||||
struct randfd *rfd = NULL;
|
||||
int fd = 0;
|
||||
int ports_avail = 0;
|
||||
|
||||
/* We can't have more randomsocks for this AF available than ports in our port range,
|
||||
so check that here, to avoid trying and failing to bind every port
|
||||
in local_bind(), called from random_sock(). The actual check is below when
|
||||
ports_avail != 0 */
|
||||
if (daemon->max_port != 0)
|
||||
{
|
||||
ports_avail = daemon->max_port - daemon->min_port + 1;
|
||||
if (ports_avail >= SMALL_PORT_RANGE)
|
||||
ports_avail = 0;
|
||||
}
|
||||
|
||||
/* If server has a pre-allocated fd, use that. */
|
||||
if (serv->sfd)
|
||||
return serv->sfd->fd;
|
||||
|
||||
/* existing suitable random port socket linked to this transaction? */
|
||||
for (rfl = *fdlp; rfl; rfl = rfl->next)
|
||||
/* existing suitable random port socket linked to this transaction?
|
||||
Find the last one in the list and count how many there are. */
|
||||
for (found = NULL, found_link = NULL, i = 0, up = fdlp, rfl = *fdlp; rfl; up = &rfl->next, rfl = rfl->next)
|
||||
if (server_isequal(serv, rfl->rfd->serv))
|
||||
return rfl->rfd->fd;
|
||||
{
|
||||
i++;
|
||||
found = rfl;
|
||||
found_link = up;
|
||||
}
|
||||
|
||||
/* No. need new link. */
|
||||
/* We have the maximum number for this query already. Promote
|
||||
the last one on the list to the head, to circulate them,
|
||||
and return it. */
|
||||
if (found && i >= daemon->randport_limit)
|
||||
{
|
||||
*found_link = found->next;
|
||||
found->next = *fdlp;
|
||||
*fdlp = found;
|
||||
return found->rfd->fd;
|
||||
}
|
||||
|
||||
/* check for all available ports in use. */
|
||||
if (ports_avail != 0)
|
||||
{
|
||||
int ports_inuse;
|
||||
|
||||
for (ports_inuse = 0, i = 0; i < daemon->numrrand; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0 &&
|
||||
daemon->randomsocks[i].serv->source_addr.sa.sa_family == serv->source_addr.sa.sa_family &&
|
||||
++ports_inuse >= ports_avail)
|
||||
{
|
||||
ports_full = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* limit the number of sockets we have open to avoid starvation of
|
||||
(eg) TFTP. Once we have a reasonable number, randomness should be OK */
|
||||
if (!ports_full)
|
||||
for (i = 0; i < daemon->numrrand; i++)
|
||||
if (daemon->randomsocks[i].refcount == 0)
|
||||
{
|
||||
if ((fd = random_sock(serv)) != -1)
|
||||
{
|
||||
rfd = &daemon->randomsocks[i];
|
||||
rfd->serv = serv;
|
||||
rfd->fd = fd;
|
||||
rfd->refcount = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* No good existing. Need new link. */
|
||||
if ((rfl = daemon->rfl_spare))
|
||||
daemon->rfl_spare = rfl->next;
|
||||
else if (!(rfl = whine_malloc(sizeof(struct randfd_list))))
|
||||
return -1;
|
||||
|
||||
/* limit the number of sockets we have open to avoid starvation of
|
||||
(eg) TFTP. Once we have a reasonable number, randomness should be OK */
|
||||
for (i = 0; i < daemon->numrrand; i++)
|
||||
if (daemon->randomsocks[i].refcount == 0)
|
||||
{
|
||||
if ((fd = random_sock(serv)) != -1)
|
||||
{
|
||||
rfd = &daemon->randomsocks[i];
|
||||
rfd->serv = serv;
|
||||
rfd->fd = fd;
|
||||
rfd->refcount = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
{
|
||||
/* malloc failed, don't leak allocated sock */
|
||||
if (rfd)
|
||||
{
|
||||
close(rfd->fd);
|
||||
rfd->refcount = 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* No free ones or cannot get new socket, grab an existing one */
|
||||
if (!rfd)
|
||||
@@ -2362,10 +2628,19 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
|
||||
server_isequal(serv, daemon->randomsocks[i].serv) &&
|
||||
daemon->randomsocks[i].refcount != 0xfffe)
|
||||
{
|
||||
finger = i + 1;
|
||||
rfd = &daemon->randomsocks[i];
|
||||
rfd->refcount++;
|
||||
break;
|
||||
struct randfd_list *rl;
|
||||
/* Don't pick one we already have. */
|
||||
for (rl = *fdlp; rl; rl = rl->next)
|
||||
if (rl->rfd == &daemon->randomsocks[i])
|
||||
break;
|
||||
|
||||
if (!rl)
|
||||
{
|
||||
finger = i + 1;
|
||||
rfd = &daemon->randomsocks[i];
|
||||
rfd->refcount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2477,13 +2752,13 @@ static void free_frec(struct frec *f)
|
||||
f->sentto = NULL;
|
||||
f->flags = 0;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (f->stash)
|
||||
{
|
||||
blockdata_free(f->stash);
|
||||
f->stash = NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Anything we're waiting on is pointless now, too */
|
||||
if (f->blocking_query)
|
||||
{
|
||||
@@ -2539,6 +2814,7 @@ static struct frec *get_new_frec(time_t now, struct server *master, int force)
|
||||
{
|
||||
if (difftime(now, f->time) >= 4*TIMEOUT)
|
||||
{
|
||||
daemon->metrics[METRIC_DNS_UNANSWERED_QUERY]++;
|
||||
free_frec(f);
|
||||
target = f;
|
||||
}
|
||||
@@ -2560,6 +2836,7 @@ static struct frec *get_new_frec(time_t now, struct server *master, int force)
|
||||
if (!target && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
|
||||
{
|
||||
/* can't find empty one, use oldest if there is one and it's older than timeout */
|
||||
daemon->metrics[METRIC_DNS_UNANSWERED_QUERY]++;
|
||||
free_frec(oldest);
|
||||
target = oldest;
|
||||
}
|
||||
@@ -2571,8 +2848,11 @@ static struct frec *get_new_frec(time_t now, struct server *master, int force)
|
||||
}
|
||||
|
||||
if (target)
|
||||
target->time = now;
|
||||
|
||||
{
|
||||
target->time = now;
|
||||
target->forward_delay = daemon->fast_retry_time;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ const char * metric_names[] = {
|
||||
"dns_queries_forwarded",
|
||||
"dns_auth_answered",
|
||||
"dns_local_answered",
|
||||
"dns_stale_answered",
|
||||
"dns_unanswered",
|
||||
"bootp",
|
||||
"pxe",
|
||||
"dhcp_ack",
|
||||
@@ -42,3 +44,23 @@ const char * metric_names[] = {
|
||||
const char* get_metric_name(int i) {
|
||||
return metric_names[i];
|
||||
}
|
||||
|
||||
void clear_metrics(void)
|
||||
{
|
||||
int i;
|
||||
struct server *serv;
|
||||
|
||||
for (i = 0; i < __METRIC_MAX; i++)
|
||||
daemon->metrics[i] = 0;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
{
|
||||
serv->queries = 0;
|
||||
serv->failed_queries = 0;
|
||||
serv->failed_queries = 0;
|
||||
serv->retrys = 0;
|
||||
serv->nxdomain_replies = 0;
|
||||
serv->query_latency = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ enum {
|
||||
METRIC_DNS_QUERIES_FORWARDED,
|
||||
METRIC_DNS_AUTH_ANSWERED,
|
||||
METRIC_DNS_LOCAL_ANSWERED,
|
||||
METRIC_DNS_STALE_ANSWERED,
|
||||
METRIC_DNS_UNANSWERED_QUERY,
|
||||
METRIC_BOOTP,
|
||||
METRIC_PXE,
|
||||
METRIC_DHCPACK,
|
||||
@@ -41,3 +43,4 @@ enum {
|
||||
};
|
||||
|
||||
const char* get_metric_name(int);
|
||||
void clear_metrics(void);
|
||||
|
||||
@@ -1371,7 +1371,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
|
||||
or both are set. Otherwise use the OS's random ephemeral port allocation by
|
||||
leaving port == 0 and tries == 1 */
|
||||
ports_avail = daemon->max_port - daemon->min_port + 1;
|
||||
tries = ports_avail < 30 ? 3 * ports_avail : 100;
|
||||
tries = (ports_avail < SMALL_PORT_RANGE) ? ports_avail : 100;
|
||||
port = htons(daemon->min_port + (rand16() % ports_avail));
|
||||
}
|
||||
|
||||
@@ -1400,7 +1400,16 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
|
||||
if (--tries == 0)
|
||||
return 0;
|
||||
|
||||
port = htons(daemon->min_port + (rand16() % ports_avail));
|
||||
/* For small ranges, do a systematic search, not a random one. */
|
||||
if (ports_avail < SMALL_PORT_RANGE)
|
||||
{
|
||||
unsigned short hport = ntohs(port);
|
||||
if (hport++ == daemon->max_port)
|
||||
hport = daemon->min_port;
|
||||
port = htons(hport);
|
||||
}
|
||||
else
|
||||
port = htons(daemon->min_port + (rand16() % ports_avail));
|
||||
}
|
||||
|
||||
if (!is_tcp && ifindex > 0)
|
||||
|
||||
40
src/option.c
40
src/option.c
@@ -181,6 +181,9 @@ struct myoption {
|
||||
#define LOPT_STRIP_MAC 372
|
||||
#define LOPT_CONF_OPT 373
|
||||
#define LOPT_CONF_SCRIPT 374
|
||||
#define LOPT_RANDPORT_LIM 375
|
||||
#define LOPT_FAST_RETRY 376
|
||||
#define LOPT_STALE_CACHE 377
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -366,6 +369,9 @@ static const struct myoption opts[] =
|
||||
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
|
||||
{ "umbrella", 2, 0, LOPT_UMBRELLA },
|
||||
{ "quiet-tftp", 0, 0, LOPT_QUIET_TFTP },
|
||||
{ "port-limit", 1, 0, LOPT_RANDPORT_LIM },
|
||||
{ "fast-dns-retry", 2, 0, LOPT_FAST_RETRY },
|
||||
{ "use-stale-cache", 0, 0 , LOPT_STALE_CACHE },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -423,6 +429,7 @@ static struct {
|
||||
{ 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
|
||||
{ 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
|
||||
{ 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
|
||||
{ LOPT_STALE_CACHE, OPT_STALE_CACHE, NULL, gettext_noop("Use expired cache data for faster reply."), NULL },
|
||||
{ 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
|
||||
{ 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
|
||||
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
|
||||
@@ -430,6 +437,7 @@ static struct {
|
||||
{ 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
|
||||
{ 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
|
||||
{ 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
|
||||
{ LOPT_RANDPORT_LIM, ARG_ONE, "#ports", gettext_noop("Set maximum number of random originating ports for a query."), NULL },
|
||||
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
|
||||
{ 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
|
||||
{ LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL },
|
||||
@@ -443,6 +451,7 @@ static struct {
|
||||
{ LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
|
||||
{ LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
|
||||
{ LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
|
||||
{ LOPT_FAST_RETRY, ARG_ONE, "<milliseconds>", gettext_noop("Retry DNS queries after this many milliseconds."), NULL},
|
||||
{ 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
|
||||
{ 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
|
||||
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
|
||||
@@ -3179,6 +3188,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (daemon->query_port == 0)
|
||||
daemon->osport = 1;
|
||||
break;
|
||||
|
||||
case LOPT_RANDPORT_LIM: /* --port-limit */
|
||||
if (!atoi_check(arg, &daemon->randport_limit) || (daemon->randport_limit < 1))
|
||||
ret_err(gen_err);
|
||||
break;
|
||||
|
||||
case 'T': /* --local-ttl */
|
||||
case LOPT_NEGTTL: /* --neg-ttl */
|
||||
@@ -3214,7 +3228,30 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
daemon->local_ttl = (unsigned long)ttl;
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_FAST_RETRY:
|
||||
daemon->fast_retry_timeout = TIMEOUT;
|
||||
|
||||
if (!arg)
|
||||
daemon->fast_retry_time = DEFAULT_FAST_RETRY;
|
||||
else
|
||||
{
|
||||
int retry;
|
||||
|
||||
comma = split(arg);
|
||||
if (!atoi_check(arg, &retry) || retry < 50)
|
||||
ret_err(gen_err);
|
||||
daemon->fast_retry_time = retry;
|
||||
|
||||
if (comma)
|
||||
{
|
||||
if (!atoi_check(comma, &retry))
|
||||
ret_err(gen_err);
|
||||
daemon->fast_retry_timeout = retry/1000;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
case 'X': /* --dhcp-lease-max */
|
||||
if (!atoi_check(arg, &daemon->dhcp_max))
|
||||
@@ -5494,7 +5531,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
daemon->soa_refresh = SOA_REFRESH;
|
||||
daemon->soa_retry = SOA_RETRY;
|
||||
daemon->soa_expiry = SOA_EXPIRY;
|
||||
|
||||
daemon->randport_limit = 1;
|
||||
|
||||
#ifndef NO_ID
|
||||
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
|
||||
add_txt("authors.bind", "Simon Kelley", 0);
|
||||
|
||||
@@ -1360,8 +1360,15 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
#undef CHECK_LIMIT
|
||||
}
|
||||
|
||||
static int crec_isstale(struct crec *crecp, time_t now)
|
||||
{
|
||||
return (!(crecp->flags & F_IMMORTAL)) && difftime(crecp->ttd, now) < 0;
|
||||
}
|
||||
|
||||
static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
{
|
||||
signed long ttl = difftime(crecp->ttd, now);
|
||||
|
||||
/* Return 0 ttl for DHCP entries, which might change
|
||||
before the lease expires, unless configured otherwise. */
|
||||
|
||||
@@ -1370,8 +1377,8 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
|
||||
|
||||
/* Apply ceiling of actual lease length to configured TTL. */
|
||||
if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl)
|
||||
return crecp->ttd - now;
|
||||
if (!(crecp->flags & F_IMMORTAL) && ttl < conf_ttl)
|
||||
return ttl;
|
||||
|
||||
return conf_ttl;
|
||||
}
|
||||
@@ -1380,9 +1387,13 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
if (crecp->flags & F_IMMORTAL)
|
||||
return crecp->ttd;
|
||||
|
||||
/* Stale cache entries. */
|
||||
if (ttl < 0)
|
||||
return 0;
|
||||
|
||||
/* Return the Max TTL value if it is lower than the actual TTL */
|
||||
if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
|
||||
return crecp->ttd - now;
|
||||
if (daemon->max_ttl == 0 || ((unsigned)ttl < daemon->max_ttl))
|
||||
return ttl;
|
||||
else
|
||||
return daemon->max_ttl;
|
||||
}
|
||||
@@ -1395,7 +1406,8 @@ static int cache_validated(const struct crec *crecp)
|
||||
/* return zero if we can't answer from cache, or packet size if we can */
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader)
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader,
|
||||
int *stale)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp;
|
||||
@@ -1411,6 +1423,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
size_t len;
|
||||
int rd_bit = (header->hb3 & HB3_RD);
|
||||
|
||||
if (stale)
|
||||
*stale = 0;
|
||||
|
||||
/* never answer queries with RD unset, to avoid cache snooping. */
|
||||
if (ntohs(header->ancount) != 0 ||
|
||||
ntohs(header->nscount) != 0 ||
|
||||
@@ -1459,13 +1474,22 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
while (--count != 0 && (crecp = cache_find_by_name(NULL, name, now, F_CNAME | F_NXDOMAIN)))
|
||||
{
|
||||
char *cname_target;
|
||||
|
||||
int stale_flag = 0;
|
||||
|
||||
if (crec_isstale(crecp, now))
|
||||
{
|
||||
if (stale)
|
||||
*stale = 1;
|
||||
|
||||
stale_flag = F_STALE;
|
||||
}
|
||||
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
{
|
||||
if (qtype == T_CNAME)
|
||||
{
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags, name, NULL, record_source(crecp->uid), 0);
|
||||
log_query(stale_flag | crecp->flags, name, NULL, record_source(crecp->uid), 0);
|
||||
auth = 0;
|
||||
nxdomain = 1;
|
||||
ans = 1;
|
||||
@@ -1487,7 +1511,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags, name, NULL, record_source(crecp->uid), 0);
|
||||
log_query(stale_flag | crecp->flags, name, NULL, record_source(crecp->uid), 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), &nameoffset,
|
||||
T_CNAME, C_IN, "d", cname_target))
|
||||
@@ -1656,22 +1680,33 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
{
|
||||
do
|
||||
{
|
||||
int stale_flag = 0;
|
||||
|
||||
if (crec_isstale(crecp, now))
|
||||
{
|
||||
if (stale)
|
||||
*stale = 1;
|
||||
|
||||
stale_flag = F_STALE;
|
||||
}
|
||||
|
||||
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
continue;
|
||||
|
||||
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
|
||||
|
||||
ans = 1;
|
||||
|
||||
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
auth = 0;
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL, 0);
|
||||
log_query(stale_flag | (crecp->flags & ~F_FORWARD), name, &addr, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1679,7 +1714,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
auth = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
|
||||
log_query(stale_flag | (crecp->flags & ~F_FORWARD), cache_get_name(crecp), &addr,
|
||||
record_source(crecp->uid), 0);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -1788,7 +1823,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_NXDOMAIN | (dryrun ? F_NO_RR : 0))))
|
||||
{
|
||||
int localise = 0;
|
||||
|
||||
|
||||
/* See if a putative address is on the network from which we received
|
||||
the query, is so we'll filter other answers. */
|
||||
if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
|
||||
@@ -1810,6 +1845,16 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
(rd_bit && (!do_bit || cache_validated(crecp)) ))
|
||||
do
|
||||
{
|
||||
int stale_flag = 0;
|
||||
|
||||
if (crec_isstale(crecp, now))
|
||||
{
|
||||
if (stale)
|
||||
*stale = 1;
|
||||
|
||||
stale_flag = F_STALE;
|
||||
}
|
||||
|
||||
/* don't answer wildcard queries with data not from /etc/hosts
|
||||
or DHCP leases */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
@@ -1825,7 +1870,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags, name, NULL, NULL, 0);
|
||||
log_query(stale_flag | crecp->flags, name, NULL, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1842,7 +1887,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr,
|
||||
log_query(stale_flag | (crecp->flags & ~F_REVERSE), name, &crecp->addr,
|
||||
record_source(crecp->uid), 0);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -1953,6 +1998,15 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
rd_bit && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
|
||||
do
|
||||
{
|
||||
int stale_flag = 0;
|
||||
|
||||
if (crec_isstale(crecp, now))
|
||||
{
|
||||
if (stale)
|
||||
*stale = 1;
|
||||
|
||||
stale_flag = F_STALE;
|
||||
}
|
||||
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases, except for NXDOMAIN */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_NXDOMAIN)))
|
||||
break;
|
||||
@@ -1968,12 +2022,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags, name, NULL, NULL, 0);
|
||||
log_query(stale_flag | crecp->flags, name, NULL, NULL, 0);
|
||||
}
|
||||
else if (!dryrun)
|
||||
{
|
||||
char *target = blockdata_retrieve(crecp->addr.srv.target, crecp->addr.srv.targetlen, NULL);
|
||||
log_query(crecp->flags, name, NULL, NULL, 0);
|
||||
log_query(stale_flag | crecp->flags, name, NULL, NULL, 0);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), NULL, T_SRV, C_IN, "sssd",
|
||||
|
||||
22
src/util.c
22
src/util.c
@@ -364,6 +364,19 @@ int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sockaddr_isnull(const union mysockaddr *s)
|
||||
{
|
||||
if (s->sa.sa_family == AF_INET &&
|
||||
s->in.sin_addr.s_addr == 0)
|
||||
return 1;
|
||||
|
||||
if (s->sa.sa_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&s->in6.sin6_addr))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sa_len(union mysockaddr *addr)
|
||||
{
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -457,6 +470,15 @@ time_t dnsmasq_time(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 dnsmasq_milliseconds(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
return (tv.tv_sec) * 1000 + (tv.tv_usec / 1000);
|
||||
}
|
||||
|
||||
int netmask_length(struct in_addr mask)
|
||||
{
|
||||
int zero_count = 0;
|
||||
|
||||
Reference in New Issue
Block a user