/*
* dns.c
*
* Created on: Feb 8, 2012
* Author: Shaun
*/
#include "dns.h"
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;
}