Skip to content

Instantly share code, notes, and snippets.

@wil
Created August 2, 2013 16:27
Show Gist options
  • Save wil/6141275 to your computer and use it in GitHub Desktop.
Save wil/6141275 to your computer and use it in GitHub Desktop.
Demonstrates how to send a DNS query and parse response in C using libresolv.
/*
* Copyright (c) 2013 by Wil Tan <[email protected]>
*
* Based on dump_dns.c from the dnscap <https://www.dns-oarc.net/tools/dnscap>
* originally written by Paul Vixie.
*
* Copyright (c) 2007 by Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
extern const char *_res_opcodes[];
#define MY_GET16(s, cp) do { \
register const u_char *t_cp = (const u_char *)(cp); \
(s) = ((u_int16_t)t_cp[0] << 8) \
| ((u_int16_t)t_cp[1]) \
; \
(cp) += NS_INT16SZ; \
} while (0)
#define MY_GET32(l, cp) do { \
register const u_char *t_cp = (const u_char *)(cp); \
(l) = ((u_int32_t)t_cp[0] << 24) \
| ((u_int32_t)t_cp[1] << 16) \
| ((u_int32_t)t_cp[2] << 8) \
| ((u_int32_t)t_cp[3]) \
; \
(cp) += NS_INT32SZ; \
} while (0)
static void
dump_dns_rr(ns_msg *msg, ns_rr *rr, ns_sect sect, FILE *trace) {
char buf[NS_MAXDNAME];
u_int class, type;
const u_char *rd;
u_int32_t soa[5];
u_int16_t mx;
int n;
class = ns_rr_class(*rr);
type = ns_rr_type(*rr);
fprintf(trace, "%s,%s,%s",
ns_rr_name(*rr),
p_class(class),
p_type(type));
if (sect == ns_s_qd)
return;
fprintf(trace, ",%lu", (u_long)ns_rr_ttl(*rr));
rd = ns_rr_rdata(*rr);
switch (type) {
case ns_t_soa:
n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg),
rd, buf, sizeof buf);
if (n < 0)
goto error;
putc(',', trace);
fputs(buf, trace);
rd += n;
n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg),
rd, buf, sizeof buf);
if (n < 0)
goto error;
putc(',', trace);
fputs(buf, trace);
rd += n;
if (ns_msg_end(*msg) - rd < 5*NS_INT32SZ)
goto error;
for (n = 0; n < 5; n++)
MY_GET32(soa[n], rd);
sprintf(buf, "%u,%u,%u,%u,%u",
soa[0], soa[1], soa[2], soa[3], soa[4]);
break;
case ns_t_a:
inet_ntop(AF_INET, rd, buf, sizeof buf);
break;
case ns_t_aaaa:
inet_ntop(AF_INET6, rd, buf, sizeof buf);
break;
case ns_t_mx:
MY_GET16(mx, rd);
fprintf(trace, ",%u", mx);
/* FALLTHROUGH */
case ns_t_ns:
case ns_t_ptr:
case ns_t_cname:
n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg),
rd, buf, sizeof buf);
if (n < 0)
goto error;
break;
case ns_t_txt:
snprintf(buf, (size_t)rd[0]+1, "%s", rd+1);
break;
default:
error:
sprintf(buf, "[%u]", ns_rr_rdlen(*rr));
}
if (buf[0] != '\0') {
putc(',', trace);
fputs(buf, trace);
}
}
static void
dump_dns_sect(ns_msg *msg, ns_sect sect, FILE *trace, const char *endline) {
int rrnum, rrmax;
const char *sep;
ns_rr rr;
rrmax = ns_msg_count(*msg, sect);
if (rrmax == 0) {
fputs(" 0", trace);
return;
}
fprintf(trace, " %s%d", endline, rrmax);
sep = "";
for (rrnum = 0; rrnum < rrmax; rrnum++) {
if (ns_parserr(msg, sect, rrnum, &rr)) {
fputs(strerror(errno), trace);
return;
}
fprintf(trace, " %s", sep);
dump_dns_rr(msg, &rr, sect, trace);
sep = endline;
}
}
void
dump_dns(const u_char *payload, size_t paylen,
FILE *trace, const char *endline)
{
u_int opcode, rcode, id;
const char *sep;
ns_msg msg;
fprintf(trace, " %sdns ", endline);
if (ns_initparse(payload, paylen, &msg) < 0) {
fputs(strerror(errno), trace);
return;
}
opcode = ns_msg_getflag(msg, ns_f_opcode);
rcode = ns_msg_getflag(msg, ns_f_rcode);
id = ns_msg_id(msg);
fprintf(trace, "%s,%s,%u", _res_opcodes[opcode], p_rcode(rcode), id);
sep = ",";
#define FLAG(t,f) if (ns_msg_getflag(msg, f)) { \
fprintf(trace, "%s%s", sep, t); \
sep = "|"; \
}
FLAG("qr", ns_f_qr);
FLAG("aa", ns_f_aa);
FLAG("tc", ns_f_tc);
FLAG("rd", ns_f_rd);
FLAG("ra", ns_f_ra);
FLAG("z", ns_f_z);
FLAG("ad", ns_f_ad);
FLAG("cd", ns_f_cd);
#undef FLAG
dump_dns_sect(&msg, ns_s_an, trace, endline);
}
int main() {
u_char answer[1024] = "";
res_init();
int rv = res_query("google.com", ns_c_in, ns_t_txt, answer, sizeof(answer));
printf("rv=%d\n", rv);
dump_dns(answer, rv, stdout, "\n");
printf("\n");
}
@yarshure
Copy link

yarshure commented Jul 1, 2014

rmbp:~ yarshure$ cc dns.c -lresolv -v
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.3.0
Thread model: posix
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.9.0 -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name dns.c -mrelocation-model pic -pic-level 2 -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu core2 -target-linker-version 236.3 -v -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/5.1 -fdebug-compilation-dir /Users/yarshure -ferror-limit 19 -fmessage-length 112 -stack-protector 1 -mstackrealign -fblocks -fobjc-runtime=macosx-10.9.0 -fencode-extended-block-signature -fdiagnostics-show-option -fcolor-diagnostics -vectorize-slp -o /var/folders/bk/j1vyw0wd1nx8lldrzc4z8z300000gn/T/dns-dcc4e8.o -x c dns.c
clang -cc1 version 5.1 based upon LLVM 3.4svn default target x86_64-apple-darwin13.3.0

include "..." search starts here:

include <...> search starts here:

/usr/local/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/5.1/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
/usr/include
/System/Library/Frameworks (framework directory)
/Library/Frameworks (framework directory)
End of search list.
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.9.0 -o a.out /var/folders/bk/j1vyw0wd1nx8lldrzc4z8z300000gn/T/dns-dcc4e8.o -lresolv -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/5.1/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture x86_64:
"__res_opcodes", referenced from:
_dump_dns in dns-dcc4e8.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

@vineyyadav
Copy link

Is it possible to specify the DNS server to be used for the query?

@xjuric29
Copy link

Is it possible to specify the DNS server to be used for the query?

Yes. All you need is to modify the global variable "_res" initialized by "res_init" function. In this structure is an array of used nameservers called "nsaddr_list" with IP addresses of nameservers from the "/etc/resolv.conf" file. You can easily replace them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment