/*
* dns.c
*
* Created on: Feb 8, 2012
* Author: Shaun
*/
extern int errno; /* general system errors */
int dnsquery(DNSQUERY *pdnsquery)
{
union {
HEADER hdr; /*DNS query packet header, defined
in
resolv.h*/
u_char buf[NS_PACKETSZ];/*default UDP packet size, usually 512 bytes, defined
in
arpa
/nameser
.h */
} query, response; /*query and response buffers*/
int querylen, responselen; /*buffer length*/
int rrnum; /*resource record number*/
int packet_id; /*packet identifier*/
u_char *
cp
; /*point to parse DNS packet*/
ns_msg handle; /*handle
for
response packet*/
ns_rr rr; /*expanded resource record*/
/*check the params that passed
in
*/
if
(pdnsquery == NULL)
{
SYS_LOG(
"dnsquery:invalid params\n"
);
return
-1;
}
/*query default domain:
"."
*/
if
(pdnsquery->domain == NULL)
{
pdnsquery->domain =
"."
;
}
/*
* first, we use the res_init() to initialize the global _res struct
* the lib will
read
the
/etc/resolv
.conf and fill the _res
*/
res_init();
/*
* turn off the RES_DEFNAMES and RES_DNSRCH
* the RES_RECURSE bit was on,
in
default
*/
_res.options &= ~(RES_DNSRCH | RES_DEFNAMES);
/*
* turn on this bit, tell the resolver
do
not
* try tcp If the name server response has the truncation bit
set
*/
_res.options |= RES_IGNTC;
/*
* store the server address
in
_res struct
for
later use
*
if
no server was given, use system default
*/
if
(pdnsquery->server != NULL)
{
if
(inet_pton(AF_INET, pdnsquery->server, &(_res.nsaddr_list[0].sin_addr)) != 1)
{
SYS_LOG(
"inet_aton: %s\n"
, strerror(errno));
return
-1;
}
}
/* only use one server */
_res.nscount = 1;
/*
* _res.retrans is the base
time
-out period
in
seconds
* between queries to the name servers
*/
_res.retrans = 1;
/*
* number of retry
times
, default is 4,
* _res.retrans is 1s,with 2 retries and we have only one address to query,
* we'll wait at most 2 seconds
*/
_res.retry = 2;
/*
* we
make
a DNS query packet with
* specified domain
*/
if
((querylen = res_mkquery(
ns_o_query, /*Standard query*/
pdnsquery->domain, /*the domain to query*/
ns_c_in, /*Internet*/
ns_t_a, /*Host address*/
(u_char *)NULL, /*always NULL*/
0, /*length of NULL*/
(u_char *)NULL, /*always NULL*/
(u_char *)&query, /*query buffer*/
sizeof(query) /*size of buffer*/
)) < 0)
{
SYS_LOG(
"res_mkquery: %s\n"
, strerror(errno));
return
-1;
}
/*save the packet
id
*/
packet_id = query.hdr.
id
;
/*send the packet*/
if
((responselen = res_send(
(u_char *)&query, /*query buffer*/
querylen, /*
true
length*/
(u_char *)&response,/*response buffer*/
sizeof(response))) < 0) /*length*/
{
SYS_LOG(
"res_send: %s\n"
, strerror(errno));
return
-1;
}
/*check whether it is our packet*/
if
(response.hdr.
id
!= packet_id)
{
SYS_LOG(
"not our packet\n"
);
return
-1;
}
/*
* initialize a handle
for
this response, the handle will be
* used later
for
extract data from the response buffer
*/
if
((ns_initparse(response.buf, responselen, &handle)) < 0)
{
SYS_LOG(
"ns_initparse: %s\n"
, strerror(errno));
return
-1;
}
/*
*
if
the server response an error, log the error message
* note: these error was caused by remote server,
* so perror or h_error
do
not work
*/
if
(ns_msg_getflag(handle, ns_f_rcode) != ns_r_noerror)
{
switch (ns_msg_getflag(handle, ns_f_rcode))
{
case
ns_r_formerr:
SYS_LOG(
"ns_msg_getflag: format error\n"
);
break
;
case
ns_r_servfail:
SYS_LOG(
"ns_msg_getflag: server failer\n"
);
break
;
case
ns_r_nxdomain:
SYS_LOG(
"ns_msg_getflag: Name error.\n"
);
break
;
case
ns_r_notimpl:
SYS_LOG(
"ns_msg_getflag: Unimplemented.\n"
);
break
;
case
ns_r_refused:
SYS_LOG(
"ns_msg_getflag: Operation refused\n"
);
break
;
default:
SYS_LOG(
"ns_msg_getflag: Unexpected error\n"
);
break
;
}
return
-1;
}
/*
*
if
the domain has
alias
, server will
return
us
* all information, so iterate all items
in
handle.sections
*/
for
(rrnum = 0; rrnum <= ns_msg_count(handle, ns_s_an); rrnum++)
{
if
(ns_parserr(&handle, ns_s_an, rrnum, &rr))
{
SYS_LOG(
"ns_parserr: %s\n"
, strerror(errno));
return
-1;
}
/*
* we only care about the A name(Host address)
*/
if
(ns_rr_type(rr) == ns_t_a)
{
/*
* now,
make
cp
point to the real ip address
*/
cp
= (u_char *)ns_rr_rdata(rr);
if
(inet_ntop(AF_INET,
cp
, pdnsquery->addr, NS_MAXDNAME) != NULL)
{
/* success, */
return
0;
}
else
{
SYS_LOG(
"inet_ntop:%s\n"
, strerror(errno));
return
-1;
}
}
}
return
-1;
}