-
February 6th, 2005, 07:24 AM
#1
DNS Question
Hello,
I have been trying to determine the differences between res_query and res_search. From the standpint of programming and results given by both, thus far I am not seeing a difference.
Can someone illuminate the differences? ie: which is faster, more robust (fault tolerant), and so on.
Thank you in advance.
-
February 6th, 2005, 07:40 AM
#2
-
February 6th, 2005, 09:33 AM
#3
Hello,
I've read the man pages multiple times, but still not getting the significance of RES_DEFNAMES and RES_DNSRCH options in the practical context of resolving an ip address or domain name. For this context which is better to use?
Thank you in advance.
-
February 6th, 2005, 05:46 PM
#4
Hi
res_search is a bit more powerful than res_query, although they
do in principle the same job. All you can resolve with res_query
you can with res_search, but not the other way around.
In order to answer the question, of which one to use, you have
to include performance/restrictions/simplicity into your equation.
Res_query makes a query for
Code:
testmachine.test.com
, able to handle "full" requests like these only.
Res_search in addition is able to handle queries like
This testmachine can be interpreted as an alias (search_aliases)
or, if RES_DEFNAMES is set, the default DNS suffix (local setting)
is appended, like
Code:
testmachine.test.com
Based on some specific order, the query is resolved.
Cheers!
If the only tool you have is a hammer, you tend to see every problem as a nail.
(Abraham Maslow, Psychologist, 1908-70)
-
February 7th, 2005, 12:14 AM
#5
Hello,
Thank you for explaining the suddleties. Does res_search incur a speed penalty versus res_query for large number of resolutions, say in the order of a thousand? Which would yielf the best performance in a high demand situation?
Thank you in advance.
-
February 7th, 2005, 01:25 AM
#6
that seems to depend on the implementation.
As sec_ware suggested the search has a different function then the query..
If you know the full domain and don't want to use it to get the info about lan machines without a .doman.tld part going with query would have to give less overhead..
ASCII stupid question, get a stupid ANSI.
When in Russia, pet a PETSCII.
Get your ass over to SLAYRadio the best station for C64 Remixes !
-
February 7th, 2005, 05:44 AM
#7
Hello,
Prehaps the implementation would help refine the choice. I am the author of BullDog Firewall. A large aspect of its operations is rapid doman scans and updates. All data to be looked up are IP addresses only. I am emulating a recursive reverse dif methodology that does use donain name lookups. The system processes thousans of ip addresses and domains per hour.
I will demonstrate this with two dig commands that yield the data I am interested in:
$ dig -t any -x 129.250.159.173
; <<>> DiG 9.2.2 <<>> -t any -x 129.250.159.173
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40174
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;173.159.250.129.in-addr.arpa. IN ANY
;; ANSWER SECTION:
173.159.250.129.in-addr.arpa. 86375 IN CNAME 173.128-26.159.250.129.in-addr.arpa.
;; Query time: 5 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Feb 6 22:40:31 2005
;; MSG SIZE rcvd: 71
$ dig -t any 173.128-26.159.250.129.in-addr.arpa
; <<>> DiG 9.2.2 <<>> -t any 173.128-26.159.250.129.in-addr.arpa
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10311
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;173.128-26.159.250.129.in-addr.arpa. IN ANY
;; ANSWER SECTION:
173.128-26.159.250.129.in-addr.arpa. 604757 IN PTR tournaments.playsite.com.
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Feb 6 22:40:59 2005
;; MSG SIZE rcvd: 91
From this, my result is derived as 129.250.159.173 is resolved to tournaments.playsite.com.
It took 2 lookup for this one IP address. I have some IP addresses that require hundreds on lookup to produce the complete result.
Hopefully this will narrow the scope a bit.
Thank you in advance.
-
February 7th, 2005, 09:14 AM
#8
Hi
The performance depends, as the_JinX said, on the implementation,
and furthermore, on the task to perform.
If HOSTALIASES are set, getenv(), which is used by res_search,
is obviously faster than a query to a name server.
Otherwise: res_search usually performs a call to res_query in the end.
Hence, in addition to the actual query, there are some string manipulations
and additional function calls. In some implementations, several
res_query'ies are performed by res_search before the final decision,
if I recall correctly.
If this is really somewhat crucial, I'd perform a serious benchmark and/or
a profiling (gprof, ...) based on the "average" query. If you do so, please keep
us updated.
Cheers.
If the only tool you have is a hammer, you tend to see every problem as a nail.
(Abraham Maslow, Psychologist, 1908-70)
-
February 10th, 2005, 09:28 AM
#9
Hello,
I did the testing and found the results (under a thousand IP's or so) to be very close, in some cases too close to make a distinction. 1000+ ips though clearly show (in my tests run) the res_query has a slight adavtage or res_search. A lot of the advantage seems to depend on the domain server being called. In one case, 256 IP addresses where scanned in approximately 5 minutes. Worse case took 1 hour 57 minutes.
I am putting my code here for others to test and evaluate. the C code is similar to what I am using in my research. It probably could use optimization...
First is the script I used to generate the IP addresses:
--- [ start
#!/bin/bash
ip=$1
let ip4=0
while [ $ip4 -lt 256 ] ; do
echo $ip.$ip4
let ip4=ip4+1
done
--- [ end
The next message will have the C code.
I compiled with
gcc -o Resolver Resolver.c -static -lresolv
Expect warnings. It runs on my machine quite well.
-
February 10th, 2005, 09:31 AM
#10
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
/* Common headers to simplify typing */
#define C unsigned char
#define D double
#define F float
#define I int
#define L long
#define UL2 unsigned long long
#define L2 long long
#define LD long double
#define S struct
#define SC signed char
#define SI int
#define STR string
#define STR2 longstring
#define STR3 string16384
#define TEXT textline
#define U union
#define UC unsigned char
#define UI unsigned int
#define UL unsigned long
#define US unsigned short
#define V void
/* for conditionals */
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
/* type defs */
typedef unsigned char string[256];
typedef unsigned char longstring[65536];
// DNSRES should be either res_search or res_query
#define DNSRES res_query
// Need a large buffer
#define DNS_MAX_ANSWER_LEN 65536
typedef struct queue_node Queue;
struct queue_node
{
char *item;
Queue *next;
};
typedef S _DNSRESOLVER
{
I SavedNS; // Number of save DNS entries from original list
S in_addr sns[MAXNS]; // Original DNS entries
Queue *DNSListH, *DNSListT; // List of valid DNS resolvers to use, should be in in_addr
Queue *DNSListC; // Current DNSList ptr;
} DNSRESOLVER;
DNSRESOLVER DNSResolver;
// Common routines
US dstrcmp(C *s1, C *s2);
C *dstrcopy(C *d, C *s);
UL dstrlen(C *s);
C *trim(C *d, C *s);
I IsIP(C *sp);
// DNS Digging
V InitializeResolver(V);
V RotateDNS(V);
C *Resolver(C *d, C *sp);
Queue *BindResolver(C *ipn, Queue *head);
// Queue
Queue *AddQueue(V *str, I size, Queue *q);
Queue *DelQueue(Queue *h, Queue *q);
// Global variables
Queue *reslist=NULL;
I ResolverInitialized=FALSE;
I main(I argc, C *argv[])
{
time_t start, progstart,now;
STR line;
C *d;
I ipcount=0;
progstart=time(NULL);
d=malloc(DNS_MAX_ANSWER_LEN+1);
while(fgets(line,sizeof(line),stdin)!=NULL)
{
memset(d,'\0',DNS_MAX_ANSWER_LEN);
line[dstrlen(line)-1]='\0';
trim(line,line);
start=time(NULL);
Resolver(d,line);
now=time(NULL);
printf("%8i %8i %-16s %s\n",now-progstart,now-start,line,d);
ipcount++;
}
reslist=DelQueue(reslist,reslist);
free(d);
printf("Total run time for %i ip addresses: %i seconds\n",ipcount,time(NULL)-progstart);
return(0);
}
// Advanced resolver routines
// Initialize our resolver and save initial information
V InitializeResolver(V)
{
Queue *ptr;
STR d1;
I i;
if(ResolverInitialized==FALSE) // Only Initialize once
{
res_init();
// Set up resolver to basic defaults
_res.retry=3;
_res.options=RES_DNSRCH|RES_RECURSE|RES_DEFNAMES;
DNSResolver.SavedNS=_res.nscount;
DNSResolver.DNSListH=NULL;
DNSResolver.DNSListT=NULL;
for(i=0;i<DNSResolver.SavedNS;i++)
{
DNSResolver.sns[i]=_res.nsaddr_list[i].sin_addr;
DNSResolver.DNSListT=AddQueue((V *)&_res.nsaddr_list[i].sin_addr,sizeof(S in_addr)+1,DNSResolver.DNSListT);
if(DNSResolver.DNSListH==NULL)
DNSResolver.DNSListH=DNSResolver.DNSListT;
}
DNSResolver.DNSListC=DNSResolver.DNSListH; // Set the Current DNS ptr to the list head
dstrcopy(d1,"QueueTracer");
reslist=AddQueue((V *)d1,dstrlen(d1)+1,reslist);
ResolverInitialized=TRUE;
}
else // Reset the resolver list to first entry
{
DNSResolver.DNSListC=DNSResolver.DNSListH;
ptr=DNSResolver.DNSListC;
for(i=0;i<DNSResolver.SavedNS;i++)
{
memcpy(&_res.nsaddr_list[i].sin_addr,ptr->item,sizeof(_res.nsaddr_list[i].sin_addr));
if(ptr->next!=NULL)
ptr=ptr->next;
else
ptr=DNSResolver.DNSListH;
}
}
}
// Rotate the Current DNS Entries
V RotateDNS(V)
{
Queue *ptr;
I i;
ptr=DNSResolver.DNSListC;
for(i=0;i<DNSResolver.SavedNS;i++)
{
memcpy(&_res.nsaddr_list[i].sin_addr,ptr->item,sizeof(_res.nsaddr_list[i].sin_addr));
if(ptr->next!=NULL)
ptr=ptr->next;
else
ptr=DNSResolver.DNSListH;
}
if(DNSResolver.DNSListC->next!=NULL)
DNSResolver.DNSListC=DNSResolver.DNSListC->next;
else
DNSResolver.DNSListC=DNSResolver.DNSListH;
}
// Emulate dig -x ip.ad.re.ss -t any
C *Resolver(C *d, C *sp)
{
Queue *rptr, *rtmp;
STR ipn;
I ip1, ip2, ip3, ip4;
if(sp[0]=='\0')
return("\0");
if(IsIP(sp)==FALSE)
return("\0");
InitializeResolver();
sscanf(sp,"%d.%d.%d.%d",&ip1, &ip2, &ip3, &ip4);
sprintf(ipn,"%i.%i.%i.%i.in-addr.arpa.",ip4,ip3,ip2,ip1);
reslist=BindResolver(ipn,reslist);
rptr=reslist->next; // Tracer is first entry in list
while(rptr)
{
if(rptr->item[0]!='\\')
{
if(IsIP(rptr->item)==FALSE)
{
strcat(d,rptr->item);
strcat(d," ");
}
}
rtmp=rptr;
rptr=rptr->next;
if(rtmp->item)
free(rtmp->item);
if(rtmp)
free(rtmp);
}
reslist->next=NULL;
trim(d,d);
if(d[0]=='.' || d[0]==' ')
d[0]='\0';
return(d);
}
// Advanced recursive Dig resolver - REQUIRES libbind if compiled shared,
// libbind may require libpthread
Queue *BindResolver(C *ipn, Queue *head)
{
Queue *tail;
C *buffer;
ns_msg handle;
I r, retry=_res.retry;
I InList(C *s, Queue *head)
{
Queue *ptr;
I done=FALSE;
ptr=head;
while(ptr!=NULL && done==FALSE)
{
done=dstrcmp(s,ptr->item);
ptr=ptr->next;
}
return(done);
}
Queue *scan_rr(ns_sect sect, Queue *head)
{
ns_rr rr;
C d1[2048];
I i;
for(i=0;i<ns_msg_count(handle, sect);i++)
{
ns_parserr(&handle, sect, i, &rr);
if(ns_rr_type(rr)==ns_t_ns || ns_rr_type(rr)==ns_t_ptr
|| ns_rr_type(rr)==ns_t_cname || ns_rr_type(rr)==ns_t_mx
|| ns_rr_type(rr)==ns_t_a)
{
if(ns_rr_type(rr)==ns_t_a)
dstrcopy(d1,(C *)inet_ntoa(*((struct in_addr *)rr.rdata)));
else
{
if(ns_rr_type(rr)!=ns_t_mx)
ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), ns_rr_rdata(rr), d1, sizeof(d1));
else
ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), ns_rr_rdata(rr)+2, d1, sizeof(d1));
}
trim(d1,d1);
if(d1[dstrlen(d1)-1]=='.')
d1[dstrlen(d1)-1]='\0';
if(d1[0]!='\0')
{
if(InList(d1,head)==FALSE)
{
tail=head;
if(head)
{
while(tail->next!=NULL)
tail=tail->next;
}
tail=AddQueue((V *)d1,dstrlen(d1)+1,tail);
strcat(d1,".");
head=BindResolver(d1,head);
}
}
}
}
return(head);
}
if(dstrcmp(ipn,".")==TRUE) // Root sever flaw, avoid
return(head);
buffer=malloc(DNS_MAX_ANSWER_LEN+1);
memset(buffer,'\0',DNS_MAX_ANSWER_LEN);
do {
r=DNSRES(ipn,C_IN,T_ANY,buffer,DNS_MAX_ANSWER_LEN);
if(r>0)
{
retry=-1;
ns_initparse(buffer, r, &handle);
head=scan_rr(ns_s_an,head);
head=scan_rr(ns_s_ns,head);
head=scan_rr(ns_s_ar,head);
}
else
{
RotateDNS();
retry--;
}
} while(retry>0);
free(buffer);
return(head);
}
I IsIP(C *sp)
{
I ip1, ip2, ip3, ip4;
STR d1;
I ChkIP(I ip)
{
if(ip<0 || ip>255)
return(FALSE);
return(TRUE);
}
if(!sp)
return(FALSE);
sscanf(sp,"%d.%d.%d.%d",&ip1, &ip2, &ip3, &ip4);
if(ChkIP(ip1)==FALSE || ChkIP(ip2)==FALSE
|| ChkIP(ip3)==FALSE || ChkIP(ip4)==FALSE)
return(FALSE);
sprintf(d1,"%i.%i.%i.%i",ip1, ip2, ip3, ip4);
if(dstrcmp(d1,sp)==FALSE)
return(FALSE);
return(TRUE);
}
Queue *AddQueue(V *str, I size, Queue *q)
{
Queue *n;
n=malloc(sizeof(Queue));
n->item=malloc(size+1);
n->next=NULL;
memset(n->item,'\0',size);
memcpy(n->item,str,size);
if(q==NULL)
return(n);
q->next=n;
q=q->next;
return(q);
}
Queue *DelQueue(Queue *h, Queue *q)
{
Queue *tmp=h;
if(q==NULL)
return(q);
if(q!=h)
{
while(tmp->next!=q)
tmp=tmp->next;
}
else
h=h->next;
tmp->next=q->next;
if(q->item!=NULL)
free(q->item);
if(q!=NULL)
free(q);
return(h);
}
/* Copy a string to a new variable */
C *dstrcopy(C *d, C *s)
{
UL l;
if(!*s)
{
d[0]='\0';
return(d);
}
for(l=0;s[l]!='\0';l++)
d[l]=s[l];
d[l]='\0';
return(d);
}
/* Compare w/ no case */
US dstrcmp(C *s1, C *s2)
{
UL i, l;
C d1, d2;
if(!*s1)
return(FALSE);
if(!*s2)
return(FALSE);
if(dstrlen(s1)!=dstrlen(s2))
return(FALSE);
l=dstrlen(s1);
for(i=0;i<l;i++)
{
d1=s1[i];
if((d1>='a')&&(d1<='z'))
d1-=32;
d2=s2[i];
if((d2>='a')&&(d2<='z'))
d2-=32;
if(d1!=d2)
return(FALSE);
}
return(TRUE);
}
/* Trim leading and trailing spaces */
C *trim(C *d, C *s)
{
UL i=0, j, l;
if(!*s)
return(d=s);
for(i=0; (s[i]==' ' || s[i]=='\t') && s[i]!='\0'; i++);
if(s[i]=='\0')
{
d[0]='\0';
return(d);
}
for(j=0;s[i]!='\0';j++,i++)
d[j]=s[i];
d[j]='\0';
l=dstrlen(d);
for(i=l-1; (d[i]==' ' || d[i]=='\t') && i>0; i--);
d[i+1]='\0';
return(d);
}
/* Return the length of a string */
UL dstrlen(C *s)
{
UL i=0;
for(i=0; s[i]!='\0'; i++);
return(i);
}
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
|