DNS functions reference (part 1)
DNS functions reference (part 1)
DNS functions reference (part 2)
DNS functions (example program)
DNS functions reference (part 1)
Hi, this first part of the article is intended for you to know how to make a DNS query on linux without having to do all the hard work (UDP and all those kinds of things). This part will cover the DNS query part. Part 2 covers how to parse the query into data you can handle easily.
- dn_comp(unsigned char *exp_dn, unsigned char *comp_dn, int length, unsigned char **dnptrs, unsigned char *exp_dn, unsigned char **lastdnptr);
- dn_expand(unsigned char *msg, unsigned char *eomorig, unsigned char *comp_dn, unsigned char *exp_dn, int length);
- ns_* (NameServer) functions, as they will be covered on the next file release.
res_init(void) : This function reads /etc/resolv.conf and initializes the structure called _res (which will contain a lot of information regarding your current setup).
res_query(const char *dname, int class, int type, unsigned char *answer, int anslen) : This function queries DNS servers for the specified domain name(const char *dname) for a certain type(int type) and class(int class). The query answer is buffered on answer(unsigned char *answer), which has got a size of anslen(int anslen).
res_search(const char *dname, int class, int type, unsigned char *answer, int anslen) : Queries domain name servers using res_query() until it receives a successful response. The domain name(const char *dname) will be completed if it's not a valid FQDN.
res_querydomain(const char *name, const char *domain, int class, int type, unsigned char *answer, int anslen) : This function makes a query by using res_query(), it concatenates name(const char *name) and domain(const char *domain) before doing the query.
The following functions are low level functions and shouldn't be used unless you seriously need to do something that you can't do using high level functions.
res_mkquery(int op, const char *dname, int class, int type, char *data, int datalen, struct rrec *newrr, char *buf, int buflen) : This functions creates a DNS query on the buffer(char *buf), with a specified maximum length(int buflen). The op(int op) shall be any of the defined on the header <arpa/nameser.h>. Argument number 7(struct rrec *newrr) is usually unused and should be set to NULL unless you need some security, which won't be discussed in this post.
res_send(const char *msg, int msglen, char *answer, int anslen) : This function will send the already formated query(by res_mkquery()), which should be specified in the first argument(const char *msg), while its length must be specified in the second argument(int msglen). The answer will be pulled into the answer character(char *answer) and the answer's maximum length should be sent on the last argument(int anslen).
The function res_init() will return 0 on success and -1 if it failed, of course, it will set h_errno. res_query(), res_search(), res_querydomain(), res_mkquery() and res_send() will return the length of the response if there wasn't any error, or they will return -1 and set h_errno if there was an error.
List of headers required for the use of these functions:
<netinet/in.h> <arpa/nameser.h> <resolv.h>
Note that for the code to compile, you must link with the resolver library, located at /usr/lib/libresolv.a (-lresolv will work if you don't use NS parser functions).
The _res structure, from <resolv.h> (/usr/include/resolv.h):
struct __res_state {
int retrans; /* retransmition time interval */
int retry; /* number of times to retransmit */
u_long options; /* option flags - see below. */
int nscount; /* number of name servers */
struct sockaddr_in
nsaddr_list[MAXNS]; /* address of name server */
# define nsaddr nsaddr_list[0] /* for backward compatibility */
u_short id; /* current message id */
char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */
char defdname[256]; /* default domain (deprecated) */
u_long pfcode; /* RES_PRF_ flags - see below. */
unsigned ndots:4; /* threshold for initial abs. query */
unsigned nsort:4; /* number of elements in sort_list[] */
char unused[3];
struct {
struct in_addr addr;
u_int32_t mask;
} sort_list[MAXRESOLVSORT];
res_send_qhook qhook; /* query hook */
res_send_rhook rhook; /* response hook */
int res_h_errno; /* last one set for this context */
int _vcsock; /* PRIVATE: for res_send VC i/o */
u_int _flags; /* PRIVATE: see below */
union {
char pad[52]; /* On an i386 this means 512b total. */
struct {
u_int16_t nscount;
u_int16_t nsmap[MAXNS];
int nssocks[MAXNS];
u_int16_t nscount6;
u_int16_t nsinit;
struct sockaddr_in6 *nsaddrs[MAXNS];
#ifdef _LIBC
unsigned long long int initstamp
__attribute__((packed));
#else
unsigned int _initstamp[2];
#endif
} _ext;
} _u;
};
Possible values for "int class", from <arpa/nameser.h> (/usr/include/arpa/nameser.h):
typedef enum __ns_class {
ns_c_invalid = 0, /* Cookie. */
ns_c_in = 1, /* Internet. */
ns_c_2 = 2, /* unallocated/unsupported. */
ns_c_chaos = 3, /* MIT Chaos-net. */
ns_c_hs = 4, /* MIT Hesiod. */
/* Query class values which do not appear in resource records */
ns_c_none = 254, /* for prereq. sections in update requests
*/
ns_c_any = 255, /* Wildcard match. */
ns_c_max = 65536
} ns_class;
Possible values for "int type", from <arpa/nameser.h> (/usr/include/arpa/nameser.h):
typedef enum __ns_type {
ns_t_invalid = 0, /* Cookie. */
ns_t_a = 1, /* Host address. */
ns_t_ns = 2, /* Authoritative server. */
ns_t_md = 3, /* Mail destination. */
ns_t_mf = 4, /* Mail forwarder. */
ns_t_cname = 5, /* Canonical name. */
ns_t_soa = 6, /* Start of authority zone. */
ns_t_mb = 7, /* Mailbox domain name. */
ns_t_mg = 8, /* Mail group member. */
ns_t_mr = 9, /* Mail rename name. */
ns_t_null = 10, /* Null resource record. */
ns_t_wks = 11, /* Well known service. */
ns_t_ptr = 12, /* Domain name pointer. */
ns_t_hinfo = 13, /* Host information. */
ns_t_minfo = 14, /* Mailbox information. */
ns_t_mx = 15, /* Mail routing information. */
ns_t_txt = 16, /* Text strings. */
ns_t_rp = 17, /* Responsible person. */
ns_t_afsdb = 18, /* AFS cell database. */
ns_t_x25 = 19, /* X_25 calling address. */
ns_t_isdn = 20, /* ISDN calling address. */
ns_t_rt = 21, /* Router. */
ns_t_nsap = 22, /* NSAP address. */
ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */
ns_t_sig = 24, /* Security signature. */
ns_t_key = 25, /* Security key. */
ns_t_px = 26, /* X.400 mail mapping. */
ns_t_gpos = 27, /* Geographical position (withdrawn). */
ns_t_aaaa = 28, /* Ip6 Address. */
ns_t_loc = 29, /* Location Information. */
ns_t_nxt = 30, /* Next domain (security). */
ns_t_eid = 31, /* Endpoint identifier. */
ns_t_nimloc = 32, /* Nimrod Locator. */
ns_t_srv = 33, /* Server Selection. */
ns_t_atma = 34, /* ATM Address */
ns_t_naptr = 35, /* Naming Authority PoinTeR */
ns_t_kx = 36, /* Key Exchange */
ns_t_cert = 37, /* Certification record */
ns_t_a6 = 38, /* IPv6 address (deprecated, use ns_t_aaaa) */
ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */
ns_t_sink = 40, /* Kitchen sink (experimentatl) */
ns_t_opt = 41, /* EDNS0 option (meta-RR) */
ns_t_tsig = 250, /* Transaction signature. */
ns_t_ixfr = 251, /* Incremental zone transfer. */
ns_t_axfr = 252, /* Transfer zone of authority. */
ns_t_mailb = 253, /* Transfer mailbox records. */
ns_t_maila = 254, /* Transfer mail agent records. */
ns_t_any = 255, /* Wildcard match. */
ns_t_zxfr = 256, /* BIND-specific, nonstandard. */
ns_t_max = 65536
} ns_type;
Op codes (for res_mkquery()), from <arpa/nameser.h> (/usr/include/arpa/nameser.h):
typedef enum __ns_opcode {
ns_o_query = 0, /* Standard query. */
ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */
ns_o_status = 2, /* Name server status query (unsupported). */
/* Opcode 3 is undefined/reserved. */
ns_o_notify = 4, /* Zone change notification. */
ns_o_update = 5, /* Zone update message. */
ns_o_max = 6
} ns_opcode;