Re: [reSIProcate] /etc/hosts is ignored
- From: Dmitry Semyonov <dsemyonov@xxxxxxx>
- Date: Wed, 28 Jun 2006 20:52:14 +0400 (MSD)
On Wed, 14 Jun 2006 at 14:59 +0400, Dmitry Semyonov wrote:
> On Tue, 13 Jun 2006 at 20:02 +0400, Dmitry Semyonov wrote:
>
> > Shouldn't ares_query() be updated with the code similar to
> > ares_gethostby*() functions to use /etc/hosts?
>
> Well, it should not. By design.
>
> But then another question -- shouldn't DNS A queries be performed via
> ares_gethostbyname() rather than via ares_query() inside
> AresDns::lookup() (and LocalDns::lookup()?)?
Finally, I decided to use ares_local_query() for my needs. See the
patch below for reference. Hope it will save some time to others.
/etc/hosts is read into memory during ares initialization, and is not
reloaded afterward. Real network DNS A queries are performed only if
they could not be resolved locally. Lookup algorithm is quite poor, so
don't use it with huge /etc/hosts, and put most used entries to the
top ;)
If somebody knows what 0xc00c mean in the beginning of RR, please
reply.
Index: ares_destroy.c
===================================================================
--- ares_destroy.c (revision 6386)
+++ ares_destroy.c (working copy)
@@ -56,4 +56,6 @@
free(query);
}
free(channel);
+
+ ares_local_destroy();
}
Index: ares_dns.h
===================================================================
--- ares_dns.h (revision 6386)
+++ ares_dns.h (working copy)
@@ -21,10 +21,10 @@
((p)[2] << 8) | (p)[3])
#define DNS__SET16BIT(p, v) (((p)[0] = ((v) >> 8) & 0xff), \
((p)[1] = (v) & 0xff))
-#define DNS__SET32BIT(p, v) (((p)[0] = ((v) >> 24) & 0xff), \
- ((p)[1] = ((v) >> 16) & 0xff), \
- ((p)[2] = ((v) >> 8) & 0xff), \
- ((p)[3] = (v) & 0xff))
+#define DNS__SET32BIT(p, v) (((p)[0] = (unsigned char)((v) >> 24) &
0xff), \
+ ((p)[1] = (unsigned char)((v) >> 16) &
0xff), \
+ ((p)[2] = (unsigned char)((v) >> 8) &
0xff), \
+ ((p)[3] = (unsigned char)(v) & 0xff))
/* Macros for parsing a DNS header */
#define DNS_HEADER_QID(h) DNS__16BIT(h)
Index: ares_init.c
===================================================================
--- ares_init.c (revision 6386)
+++ ares_init.c (working copy)
@@ -42,6 +42,7 @@
#endif
#include "ares.h"
+#include "ares_local.h"
#include "ares_private.h"
static int init_by_options(ares_channel channel, struct ares_options *options,
@@ -127,8 +128,10 @@
RegCloseKey(hKey);
}
}
+ ares_local_init(w32hostspath);
+#else
+ ares_local_init(PATH_HOSTS);
#endif
- // struct timeval tv;
channel = malloc(sizeof(struct ares_channeldata));
if (!channel)
Index: ares_local.c
===================================================================
--- ares_local.c (revision 6386)
+++ ares_local.c (working copy)
@@ -1,8 +1,89 @@
#include "ares.h"
+#include "ares_dns.h"
#include "ares_local.h"
+#include "ares_private.h"
+/* Use simplified structure instead of hostent for efficiency and simplicity */
+typedef struct _hosts_ent {
+ char *name;
+ struct in_addr addr;
+} hosts_ent;
+/* Maximum number of locally defined hosts entries + 1. Remaining entries are
ignored. */
+#define LOCAL_HOSTS_TABLE_SZ 64
+
+static hosts_ent local_hosts[LOCAL_HOSTS_TABLE_SZ];
+
+
+int ares_local_init(const char *etc_hosts)
+{
+ FILE *fp;
+ int status = ARES_ENOMEM;
+ struct hostent *host;
+ hosts_ent *cur_host = local_hosts;
+
+ if (!(fp = fopen(etc_hosts, "r")))
+ return ARES_ENOTFOUND;
+
+ while (cur_host <= local_hosts + LOCAL_HOSTS_TABLE_SZ - 2 /* leave space for
NULL terminator */ &&
+ (status = ares__get_hostent(fp, &host)) == ARES_SUCCESS)
+ {
+ if (host == NULL)
+ continue; /* to be on the safe side */
+
+ cur_host->name = strdup(host->h_name);
+ cur_host->addr.s_addr = *((ULONG *)(host->h_addr));
+
+ ares_free_hostent(host);
+
+ ++cur_host;
+ }
+
+ fclose(fp);
+
+ cur_host->name = NULL;
+
+ if (status != ARES_EOF)
+ status = ARES_ENOMEM;
+ else
+ status = ARES_SUCCESS;
+
+ return status;
+}
+
+void ares_local_destroy()
+{
+ hosts_ent *cur_host = local_hosts;
+
+ while (cur_host->name != NULL)
+ {
+ free(cur_host->name);
+ ++cur_host;
+ }
+}
+
+/* Note: Put most used entries to the top of /etc/hosts file for better
performance. */
+static int ares_local_lookup(const char *name, struct in_addr *addr)
+{
+ hosts_ent *cur_host = local_hosts;
+
+ while (cur_host->name != NULL)
+ {
+ if (strcasecmp(cur_host->name, name) == 0)
+ {
+ *addr = cur_host->addr;
+ break;
+ }
+ ++cur_host;
+ }
+
+ if (cur_host->name == NULL)
+ return ARES_ENOTFOUND;
+
+ return ARES_SUCCESS;
+}
+
int ares_local_gethostbyname(ares_channel channel, const char *name, int
family,
ares_host_callback callback, void *arg)
{
@@ -18,10 +99,56 @@
}
int ares_local_query(ares_channel channel, const char *name, int dnsclass,
- int type, ares_callback callback, void *arg)
+ int type, ares_callback callback, void *arg)
{
- (void)(channel,name,dnsclass,type,callback,arg);
- return 0;
+ unsigned char *qbuf, *abuf, *rr;
+ int qlen, alen, status;
+ struct in_addr addr;
+
+ if (type != T_A || ares_local_lookup(name, &addr) != ARES_SUCCESS)
+ {
+ return 0;
+ }
+
+
+ /* Compose the query. */
+
+ if ((status = ares_mkquery(name, dnsclass, type, channel->next_id++,
+ !(channel->flags & ARES_FLAG_NORECURSE), &qbuf,
&qlen)) != ARES_SUCCESS)
+ {
+ callback(arg, status, NULL, 0);
+ return 1;
+ }
+
+
+ /* Create the answer */
+
+ alen = qlen + 16;
+ if ((abuf = realloc(qbuf, alen)) == NULL)
+ {
+ free(qbuf);
+ callback(arg, ARES_ENOMEM, NULL, 0);
+ return 1;
+ }
+
+ DNS_HEADER_SET_QR(abuf, 1);
+ DNS_HEADER_SET_RCODE(abuf, NOERROR);
+ DNS_HEADER_SET_ANCOUNT(abuf, 1);
+
+ rr = abuf + qlen;
+ DNS__SET16BIT(rr, 0xc00c); /* XXX Copied from A response without
understanding :( */
+ rr += 2;
+ DNS_RR_SET_TYPE(rr, T_A);
+ DNS_RR_SET_CLASS(rr, C_IN);
+ DNS_RR_SET_TTL(rr, 0xFFFFFFFF); /* We don't reload hosts entries
dynamically. So, use maximum TTL. */
+ DNS_RR_SET_LEN(rr, 4);
+
+ DNS__SET32BIT(rr + RRFIXEDSZ, htonl(addr.s_addr));
+
+ callback(arg, ARES_SUCCESS, abuf, alen);
+
+ free(abuf);
+ return 1;
}
void ares_local_process_requests()
Index: ares_local.h
===================================================================
--- ares_local.h (revision 6386)
+++ ares_local.h (working copy)
@@ -1,5 +1,9 @@
#ifndef ARES_LOCAL__H
#define ARES_LOCAL__H
+
+int ares_local_init(const char *etc_hosts);
+void ares_local_destroy();
+
/*
** Define a suite of callbacks that can return locally configured DNS results.
** Very useful for testing or simulation.
--
...Bye..Dmitry.