Developing against libbind - DNS

This is a discussion on Developing against libbind - DNS ; Hi, I apologise if this is the wrong place for this type of question, but I'm developing an application that needs to do DNS lookups, and I cannot find any documentation about how to use libbind. I have build bind ...

+ Reply to Thread
Results 1 to 2 of 2

Thread: Developing against libbind

  1. Developing against libbind

    Hi,

    I apologise if this is the wrong place for this type of question, but
    I'm developing an application that needs to do DNS lookups, and I cannot
    find any documentation about how to use libbind. I have build bind
    9.5.0 with --enable-libbind and cannot find anything helpful (except the
    header files) in the build.

    Can anyone point me in the direction of any documentation available
    showing how to use the Bind library to do DNS lookups from a C application?

    Thanks,

    Andy


  2. Re: Developing against libbind

    Andy Shellam writes:

    > I apologise if this is the wrong place for this type of question, but I'm
    > developing an application that needs to do DNS lookups, and I cannot find
    > any documentation about how to use libbind. I have build bind 9.5.0 with
    > --enable-libbind and cannot find anything helpful (except the header
    > files) in the build.


    no apologies nec'y. libbind has been the fair haired stepchild around here.

    > Can anyone point me in the direction of any documentation available
    > showing how to use the Bind library to do DNS lookups from a C
    > application?


    well, i use it all the time. here's a small demo application called "dnsget"
    which is sort of like a stripped down "dig" but it's specifically meant to be
    called by shell scripts to do dns lookups. it shows the libbind basics.

    [nsa:amd64] ./dnsget
    usage error: missing domain argument
    usage: dnsget [-a] [-d] [-l] [-s server[,...] name type [field[,field...]]
    soa mname rname serial refresh retry expire minimum
    ns nsdname
    a address
    aaaa address
    mx preference exchange
    cname cname
    ptr ptrdname

    [nsa:amd64] ./dnsget mailnetwork.co.uk mx exchange
    NOERROR 1 0 0
    mx.fusemail.net

    [nsa:amd64] ./dnsget mailnetworx.co.uk mx exchange
    NXDOMAIN

    ref:

    # This is a shell archive. Save it in a file, remove anything before
    # this line, and then unpack it by entering "sh file". Note, it may
    # create directories; files and directories will be owned by you and
    # have default permissions.
    #
    # This archive contains:
    #
    # Makefile
    # dnsget.c
    # soacheck.sh
    #
    echo x - Makefile
    sed 's/^X//' >Makefile << 'END-of-Makefile'
    X#BINDROOT= /usr/local/bind
    XCDEBUG= -g -Wall
    XCFLAGS= $(CDEBUG) -I${BINDROOT}/include
    XLDFLAGS= -L${BINDROOT}/lib -L/usr/local/lib
    XLIBS= -lbind
    X
    XALL= dnsget
    X
    Xall: $(ALL)
    X
    Xclean: FRC
    X rm -f $(ALL)
    X rm -f *.o
    X
    Xdistclean: clean
    X rm -f *.CKP *.BAK *~
    X
    XFRC:
    X
    XDNSGET= dnsget.o
    Xdnsget: $(DNSGET)
    X $(CC) $(LDFLAGS) -o dnsget $(DNSGET) $(LIBS)
    END-of-Makefile
    echo x - dnsget.c
    sed 's/^X//' >dnsget.c << 'END-of-dnsget.c'
    X#ifndef lint
    Xstatic const char rcsid[] = "$Id: dnsget.c,v 1.10 2008/07/06 20:35:20 vixie Exp $";
    X#endif
    X
    X/* Import. */
    X
    X#include
    X#include
    X#include
    X#include
    X#include
    X
    X#include
    X#include
    X#include
    X#include
    X#include
    X#include
    X#include
    X#include
    X#include
    X
    X/* Macros. */
    X
    X#define CHK(x,e) if ((x) < 0) { \
    X fprintf(stderr, "%s: %s\n", e, strerror(errno)); \
    X exit(1); \
    X}
    X
    X#define ISSET(x, in) (((in) & (1 << (x))) != 0)
    X
    X/* Types. */
    X
    Xstruct rr {
    X const char *name;
    X ns_type type;
    X const char **fields;
    X int (*get)(ns_msg *, ns_rr *, int);
    X};
    X
    X/* Forward. */
    X
    Xstatic void usage(const char *msg, ...);
    Xstatic const char *setservers(res_state res, const char *servers);
    Xstatic int dnsget(const char *, const struct rr *, res_state, int, int);
    Xstatic int rrget(ns_msg *, ns_rr *);
    X
    Xstatic int soa_get(ns_msg *, ns_rr *, int);
    Xstatic const char *soa_fields[] = {
    X "mname", "rname", "serial", "refresh", "retry",
    X "expire", "minimum", NULL
    X};
    Xenum {
    X soa_mname, soa_rname, soa_serial, soa_refresh, soa_retry,
    X soa_expire, soa_minimum
    X};
    X
    Xstatic int ns_get(ns_msg *, ns_rr *, int);
    Xstatic const char *ns_fields[] = { "nsdname", NULL };
    Xenum { ns_nsdname };
    X
    Xstatic int a_get(ns_msg *, ns_rr *, int);
    Xstatic const char *a_fields[] = { "address", NULL };
    Xenum { a_address };
    X
    Xstatic int aaaa_get(ns_msg *, ns_rr *, int);
    Xstatic const char *aaaa_fields[] = { "address", NULL };
    Xenum { aaaa_address };
    X
    Xstatic int mx_get(ns_msg *, ns_rr *, int);
    Xstatic const char *mx_fields[] = { "preference", "exchange", NULL };
    Xenum { mx_preference, mx_exchange };
    X
    X#define cname_get ns_get
    Xstatic const char *cname_fields[] = { "cname", NULL };
    Xenum { cname_cname = ns_nsdname };
    X
    X#define ptr_get ns_get
    Xstatic const char *ptr_fields[] = { "ptrdname", NULL };
    Xenum { ptr_ptrdname = ns_nsdname };
    X
    X/* Data. */
    X
    Xstatic const char *progname = "amnesia";
    Xstatic struct rr rrs[] = {
    X { "soa", ns_t_soa, soa_fields, soa_get },
    X { "ns", ns_t_ns, ns_fields, ns_get },
    X { "a", ns_t_a, a_fields, a_get },
    X { "aaaa", ns_t_aaaa, aaaa_fields, aaaa_get },
    X { "mx", ns_t_mx, mx_fields, mx_get },
    X { "cname", ns_t_cname, cname_fields, cname_get },
    X { "ptr", ns_t_ptr, ptr_fields, ptr_get },
    X { NULL }
    X};
    X
    X/* Public. */
    X
    Xint
    Xmain(int argc, char **argv) {
    X const char *domain, *cp, *typename;
    X const struct rr *rr;
    X struct __res_state res;
    X int ch, all = 0, fields;
    X char *dot;
    X
    X if ((progname = strrchr(*argv, '/')) == NULL)
    X progname = *argv;
    X else
    X progname++;
    X memset(&res, 0, sizeof res);
    X CHK(res_ninit(&res), "res_ninit");
    X while ((ch = getopt(argc, argv, "adrls:")) != -1) {
    X switch (ch) {
    X case 'a':
    X all++;
    X break;
    X case 'd':
    X res.options |= RES_DEBUG;
    X break;
    X case 'r':
    X res.options &= ~RES_RECURSE;
    X break;
    X case 'l':
    X#ifdef RES_DONTROUTE
    X res._flags |= RES_DONTROUTE;
    X#endif
    X break;
    X case 's':
    X if ((cp = setservers(&res, optarg)) != NULL)
    X usage(cp);
    X break;
    X default:
    X usage("unrecognized argument -%c", ch);
    X }
    X }
    X argv += optind, argc -= optind;
    X if (argc < 1)
    X usage("missing domain argument");
    X domain = *argv++; argc--;
    X dot = strrchr(domain, '.');
    X if (dot != NULL && dot[1] == '\0')
    X *dot = '\0';
    X if (argc < 1)
    X usage("missing rrtype argument");
    X typename = *argv++; argc--;
    X for (rr = rrs; rr->name != NULL; rr++)
    X if (strcasecmp(rr->name, typename) == 0)
    X break;
    X if (rr->name == NULL)
    X usage("unrecognized rr type %s", typename);
    X fields = -1; /* all ones */
    X if (argc > 0) {
    X cp = *argv++; argc--;
    X fields = 0;
    X while (*cp != '\0') {
    X const char *x = strchr(cp, ',');
    X int l = (x != NULL) ? x - cp : strlen(cp);
    X const char **s;
    X
    X for (s = rr->fields; *s != NULL; s++)
    X if (strlen(*s) == l &&
    X strncasecmp(*s, cp, l) == 0)
    X break;
    X if (*s == NULL)
    X usage("unrecognized field name");
    X fields |= (1 << (s - rr->fields));
    X cp += l;
    X if (*cp == ',')
    X cp++;
    X }
    X assert(fields != 0);
    X }
    X if (argc > 1)
    X usage("too many arguments");
    X exit(dnsget(domain, rr, &res, fields, all));
    X}
    X
    X/* Private. */
    X
    Xstatic void
    Xusage(const char *msg, ...) {
    X va_list ap;
    X struct rr *rr;
    X const char **s;
    X
    X va_start(ap, msg);
    X fputs("usage error: ", stderr);
    X vfprintf(stderr, msg, ap);
    X fputc('\n', stderr);
    X va_end(ap);
    X fprintf(stderr, "usage: %s [-a] [-d] [-l] [-s server[,...] "
    X "name type [field[,field...]]\n",
    X progname);
    X for (rr = rrs; rr->name != NULL; rr++) {
    X fprintf(stderr, "\t%s\t", rr->name);
    X for (s = rr->fields; *s != NULL; s++)
    X fprintf(stderr, "%s ", *s);
    X fputc('\n', stderr);
    X }
    X
    X exit(1);
    X}
    X
    Xstatic const char *
    Xsetservers(res_state res, const char *servers) {
    X union res_sockaddr_union serverset[MAXNS];
    X int nscount = 0;
    X
    X while (*servers != '\0') {
    X const char *x = strchr(servers, ',');
    X int l = (x != NULL) ? x - servers : strlen(servers);
    X char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
    X union res_sockaddr_union *s = &serverset[nscount];
    X
    X if (nscount > MAXNS)
    X return ("too many servers specified");
    X if (l + 1 > sizeof t)
    X return ("server literal is too long");
    X memset(t, 0, sizeof t);
    X strncpy(t, servers, l);
    X memset(s, 0, sizeof *s);
    X if (inet_pton(AF_INET6, t, &s->sin6.sin6_addr)) {
    X s->sin6.sin6_family = AF_INET6;
    X s->sin6.sin6_port = htons(NS_DEFAULTPORT);
    X } else if (inet_pton(AF_INET, t, &s->sin.sin_addr)) {
    X s->sin.sin_family = AF_INET;
    X s->sin.sin_port = htons(NS_DEFAULTPORT);
    X } else {
    X return ("server must be valid INET6 or INET literal");
    X }
    X nscount++;
    X servers += l;
    X while (*servers == ',')
    X servers++;
    X }
    X res_setservers(res, serverset, nscount);
    X return (NULL);
    X}
    X
    Xstatic int
    Xdnsget(const char *domain, const struct rr *rr, res_state res,
    X int fields, int all)
    X{
    X char qname[NS_MAXDNAME];
    X u_char buf[NS_MAXMSG];
    X ns_rcode rcode;
    X ns_msg msg;
    X int n, sn;
    X
    X n = res_nquery(res, domain, ns_c_in, rr->type, buf, sizeof buf);
    X if (n <= 0) {
    X switch (res->res_h_errno) {
    X case HOST_NOT_FOUND:
    X fputs("NXDOMAIN", stdout);
    X break;
    X case TRY_AGAIN:
    X fputs("TEMPFAIL", stdout);
    X break;
    X case NO_RECOVERY:
    X fputs("PERMFAIL", stdout);
    X break;
    X case NO_DATA:
    X fputs("NODATA", stdout);
    X break;
    X default:
    X printf("?%d?", res->res_h_errno);
    X break;
    X }
    X fputc('\n', stdout);
    X return (1);
    X }
    X
    X CHK(ns_initparse(buf, n, &msg), "ns_initparse");
    X
    X rcode = ns_msg_getflag(msg, ns_f_rcode);
    X if (rcode == ns_r_noerror &&
    X (res->options & RES_RECURSE) == 0 &&
    X ns_msg_getflag(msg, ns_f_aa) == 0)
    X rcode = ns_r_notauth;
    X printf("%s %d %d %d\n", p_rcode(rcode),
    X ns_msg_count(msg, ns_s_an),
    X ns_msg_count(msg, ns_s_ns),
    X ns_msg_count(msg, ns_s_ar));
    X if (rcode != ns_r_noerror)
    X return (1);
    X
    X strncpy(qname, domain, sizeof qname);
    X qname[sizeof qname - 1] = '\0';
    X for (sn = ns_s_an; sn <= (all ? ns_s_ar : ns_s_an); sn++) {
    X int rrn;
    X
    X for (rrn = 0; rrn < ns_msg_count(msg, sn); rrn++) {
    X int need_newline = 1;
    X ns_rr nsrr;
    X
    X CHK(ns_parserr(&msg, sn, rrn, &nsrr), "ns_parserr");
    X if (all)
    X printf("%s %s %s ",
    X p_section(sn, ns_o_query),
    X ns_rr_name(nsrr),
    X p_type(ns_rr_type(nsrr)));
    X if (sn == ns_s_an) {
    X if (strcasecmp(ns_rr_name(nsrr), qname) != 0) {
    X printf("? %s != %s",
    X ns_rr_name(nsrr), qname);
    X n = 1;
    X } else if (ns_rr_type(nsrr) == ns_t_cname) {
    X n = dn_expand(ns_msg_base(msg),
    X ns_msg_end(msg),
    X ns_rr_rdata(nsrr),
    X qname, sizeof qname);
    X CHK(n, "dn_expand");
    X if (all)
    X n = cname_get(&msg, &nsrr, -1);
    X else
    X need_newline = n = 0;
    X } else if (ns_rr_type(nsrr) != rr->type) {
    X printf("? %d", ns_rr_type(nsrr));
    X n = 1;
    X } else {
    X n = rr->get(&msg, &nsrr, fields);
    X }
    X } else {
    X n = rrget(&msg, &nsrr);
    X }
    X if (need_newline)
    X putchar('\n');
    X if (n != 0)
    X return (n);
    X }
    X }
    X return (0);
    X}
    X
    Xstatic int
    Xrrget(ns_msg *msg, ns_rr *nsrr) {
    X struct rr *rr;
    X
    X for (rr = rrs; rr->name != NULL; rr++)
    X if (rr->type == ns_rr_type(*nsrr))
    X return (rr->get(msg, nsrr, -1)); /* all ones */
    X putchar('?');
    X return (0);
    X}
    X
    X/* Private - SOA. */
    X
    Xstatic int
    Xsoa_get(ns_msg *msg, ns_rr *rr, int fields) {
    X const u_char *base = ns_msg_base(*msg);
    X const u_char *end = ns_msg_end(*msg);
    X const u_char *rdata = ns_rr_rdata(*rr);
    X char domain[NS_MAXDNAME];
    X int n, printed = 0;
    X u_long l;
    X
    X /* Do SOA MNAME. */
    X n = dn_expand(base, end, rdata, domain, sizeof domain);
    X CHK(n, "dn_expand");
    X rdata += n;
    X if (ISSET(soa_mname, fields)) {
    X fputs(domain, stdout);
    X printed = 1;
    X }
    X
    X /* Do SOA RNAME. */
    X n = dn_expand(base, end, rdata, domain, sizeof domain);
    X CHK(n, "dn_expand");
    X rdata += n;
    X if (ISSET(soa_rname, fields)) {
    X if (printed)
    X fputc(' ', stdout);
    X fputs(domain, stdout);
    X printed = 1;
    X }
    X
    X /* Check length all at once. */
    X if (end - rdata < 5 * NS_INT32SZ) {
    X fprintf(stderr, "soa rdlength too short\n");
    X return (1);
    X }
    X
    X /* Do SOA SERIAL. */
    X l = ns_get32(rdata); rdata += NS_INT32SZ;
    X if (ISSET(soa_serial, fields)) {
    X fprintf(stdout, "%s%lu", printed ? " " : "", l);
    X printed = 1;
    X }
    X
    X /* Do SOA REFRESH. */
    X l = ns_get32(rdata); rdata += NS_INT32SZ;
    X if (ISSET(soa_refresh, fields)) {
    X fprintf(stdout, "%s%lu", printed ? " " : "", l);
    X printed = 1;
    X }
    X
    X /* Do SOA RETRY. */
    X l = ns_get32(rdata); rdata += NS_INT32SZ;
    X if (ISSET(soa_retry, fields)) {
    X fprintf(stdout, "%s%lu", printed ? " " : "", l);
    X printed = 1;
    X }
    X
    X /* Do SOA EXPIRE. */
    X l = ns_get32(rdata); rdata += NS_INT32SZ;
    X if (ISSET(soa_expire, fields)) {
    X fprintf(stdout, "%s%lu", printed ? " " : "", l);
    X printed = 1;
    X }
    X
    X /* Do SOA MINIMUM. */
    X l = ns_get32(rdata); rdata += NS_INT32SZ;
    X if (ISSET(soa_minimum, fields)) {
    X fprintf(stdout, "%s%lu", printed ? " " : "", l);
    X printed = 1;
    X }
    X
    X return (0);
    X}
    X
    X/* Private - NS. */
    X
    Xstatic int
    Xns_get(ns_msg *msg, ns_rr *rr, int fields) {
    X const u_char *base = ns_msg_base(*msg);
    X const u_char *end = ns_msg_end(*msg);
    X const u_char *rdata = ns_rr_rdata(*rr);
    X char domain[NS_MAXDNAME];
    X int n;
    X
    X /* Do NS NSDNAME. */
    X n = dn_expand(base, end, rdata, domain, sizeof domain);
    X CHK(n, "dn_expand");
    X rdata += n;
    X if (ISSET(ns_nsdname, fields))
    X fputs(domain, stdout);
    X
    X return (0);
    X}
    X
    X/* Private - A. */
    X
    Xstatic int
    Xa_get(ns_msg *msg, ns_rr *rr, int fields) {
    X const u_char *end = ns_msg_end(*msg);
    X const u_char *rdata = ns_rr_rdata(*rr);
    X struct in_addr addr;
    X
    X /* Do A ADDRESS. */
    X if (end - rdata < NS_INT32SZ) {
    X fprintf(stderr, "a rdlength too short\n");
    X return (1);
    X }
    X addr.s_addr = htonl(ns_get32(rdata)); rdata += NS_INT32SZ;
    X if (ISSET(a_address, fields))
    X printf("%s", inet_ntoa(addr));
    X
    X return (0);
    X}
    X
    X/* Private - AAAA. */
    X
    Xstatic int
    Xaaaa_get(ns_msg *msg, ns_rr *rr, int fields) {
    X const u_char *end = ns_msg_end(*msg);
    X const u_char *rdata = ns_rr_rdata(*rr);
    X const void *addr;
    X
    X /* Do AAAA ADDRESS. */
    X if (end - rdata < 16) {
    X fprintf(stderr, "a rdlength too short\n");
    X return (1);
    X }
    X addr = rdata; rdata += 16;
    X if (ISSET(a_address, fields)) {
    X char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
    X (void) inet_ntop(AF_INET6, addr, t, sizeof t);
    X printf("%s", t);
    X }
    X
    X return (0);
    X}
    X
    X/* Private - MX. */
    X
    Xstatic int
    Xmx_get(ns_msg *msg, ns_rr *rr, int fields) {
    X const u_char *base = ns_msg_base(*msg);
    X const u_char *end = ns_msg_end(*msg);
    X const u_char *rdata = ns_rr_rdata(*rr);
    X char domain[NS_MAXDNAME];
    X int n, printed = 0;
    X u_long l;
    X
    X /* Do MX PREFERENCE. */
    X if (end - rdata < NS_INT16SZ) {
    X fprintf(stderr, "mx rdlength too short\n");
    X return (1);
    X }
    X l = ns_get16(rdata); rdata += NS_INT16SZ;
    X if (ISSET(mx_preference, fields))
    X printf("%s%lu", printed++ ? " " : "", l);
    X
    X /* Do MX EXCHANGE. */
    X n = dn_expand(base, end, rdata, domain, sizeof domain);
    X CHK(n, "dn_expand");
    X rdata += n;
    X if (ISSET(mx_exchange, fields))
    X printf("%s%s", printed++ ? " " : "", domain);
    X
    X return (0);
    X}
    END-of-dnsget.c
    echo x - soacheck.sh
    sed 's/^X//' >soacheck.sh << 'END-of-soacheck.sh'
    X#!/bin/sh
    X
    Xzone=$1
    Xmaster=$2
    X
    Xdnsget -a -s $master $zone ns | {
    X read result
    X case "$result" in
    X NOERROR*)
    X glue=`awk '
    X /^ANSWER/ { ns[$4] = 1 }
    X /^ADDITIONAL/ { if (ns[$2]) {
    X if (a[$2]) a[$2] = a[$2] ",";
    X a[$2] = a[$2] $4
    X } }
    X END { for (x in a) print a[x] }
    X '`
    X ;;
    X *)
    X echo $0: cannot get initial NS RRset - $result
    X exit 1
    X esac
    X for ns in $glue; do
    X echo "$ns: " `dnsget -s $ns $zone soa serial`
    X done
    X}
    X
    Xexit 0
    END-of-soacheck.sh
    exit
    --
    Paul Vixie

    --
    This message has been scanned for viruses and
    dangerous content by MailScanner, and is
    believed to be clean.



+ Reply to Thread