Import Magerya Vitaly's ldns-host, and build it instead of the BIND version
in the WITH_LDNS_UTILS case. Approved by: re (blanket)
This commit is contained in:
commit
ff13bc56dc
23
contrib/ldns-host/Makefile
Normal file
23
contrib/ldns-host/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
PROG=ldns-host
|
||||
SRC=ldns-host.c
|
||||
MAN=ldns-host.1
|
||||
|
||||
LOCALBASE?=/usr/local
|
||||
PREFIX?=${LOCALBASE}
|
||||
MANDIR?=${PREFIX}/man
|
||||
|
||||
XCFLAGS=${CFLAGS} -I${LOCALBASE}/include
|
||||
XLDFLAGS=${LDFLAGS} -L${LOCALBASE}/lib -lldns
|
||||
|
||||
${PROG}: ${SRC}
|
||||
${CC} -o $@ ${XCFLAGS} ${XLDFLAGS} ${SRC}
|
||||
|
||||
clean:
|
||||
rm -f ${PROG}
|
||||
|
||||
install: ${PROG}
|
||||
cp ${PROG} ${PREFIX}/bin/
|
||||
cp ${MAN} ${MANDIR}/man1/
|
||||
|
||||
deinstall:
|
||||
rm -f ${PREFIX}/bin/${PROG} ${MANDIR}/man1/${MAN}
|
246
contrib/ldns-host/ldns-host.1
Normal file
246
contrib/ldns-host/ldns-host.1
Normal file
@ -0,0 +1,246 @@
|
||||
.\" (c) Magerya Vitaly
|
||||
.\"
|
||||
.\" Copying and distribution of this file, with or without modification,
|
||||
.\" are permitted in any medium without royalty provided the copyright
|
||||
.\" notice and this notice are preserved. This file is offered as-is,
|
||||
.\" without any warranty.
|
||||
.Dd Aug 27, 2012
|
||||
.Dt LDNS-HOST 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ldns-host
|
||||
.Nd DNS lookup utility
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl aCdilrsTvw46
|
||||
.Op Fl c Ar class
|
||||
.Op Fl N Ar ndots
|
||||
.Op Fl R Ar number
|
||||
.Op Fl t Ar type
|
||||
.Op Fl W Ar wait
|
||||
.Ar name
|
||||
.Op Ar server
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a simple utility for performing DNS lookups. It is normally
|
||||
used to convert names to IP addresses and vice versa.
|
||||
.Pp
|
||||
.Ar name
|
||||
is the domain name that is to be looked up. It can also be a
|
||||
dotted-decimal IPv4 address or a colon-delimited IPv6 address,
|
||||
in which case
|
||||
.Nm
|
||||
will by default perform a reverse lookup for that address.
|
||||
.Pp
|
||||
When
|
||||
.Ar name
|
||||
is not provided,
|
||||
.Nm
|
||||
prints a short summary of it's usage.
|
||||
.Pp
|
||||
.Ar server
|
||||
is an optional argument which is either a domain name or an IP
|
||||
address of the name server that
|
||||
.Nm
|
||||
should query instead of the server or servers listed in
|
||||
.Pa /etc/resolv.conf .
|
||||
When
|
||||
.Ar server
|
||||
is a domain name, system resolver is used to obtain it's address.
|
||||
.Pp
|
||||
Supported options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl a
|
||||
Make a verbose query of type
|
||||
.Cm ANY .
|
||||
Equivalent to
|
||||
.Fl v Fl t Cm ANY .
|
||||
.It Fl C
|
||||
Query for
|
||||
.Cm SOA
|
||||
records for zone
|
||||
.Ar name
|
||||
from all of it's authoritative name servers. The list of name
|
||||
servers is obtained via
|
||||
.Cm NS
|
||||
query for
|
||||
.Ar name .
|
||||
.It Fl c Ar class
|
||||
Perform DNS query of class
|
||||
.Ar class .
|
||||
Recognized classes are
|
||||
.Cm IN Pq Internet ,
|
||||
.Cm CH Pq Chaosnet ,
|
||||
.Cm HS Pq Hesiod ,
|
||||
.Cm NONE ,
|
||||
.Cm ANY
|
||||
and
|
||||
.Cm CLASS Ns Ar N
|
||||
(where
|
||||
.Ar N
|
||||
is a number from 1 to 255). Default is
|
||||
.Cm IN .
|
||||
.It Fl d
|
||||
Produce verbose output. This is a synonym for
|
||||
.Fl v ,
|
||||
and is provided for backward compatibility.
|
||||
.It Fl i
|
||||
Use IP6.INT domain for reverse lookups of IPv6 addresses (as
|
||||
defined in RFC1886; note that RFC4159 deprecates IP6.INT).
|
||||
By default IP6.ARPA is used.
|
||||
.It Fl l
|
||||
List all
|
||||
.Cm NS, PTR, A
|
||||
and
|
||||
.Cm AAAA
|
||||
records in zone
|
||||
.Ar name
|
||||
by performing a zone transfer
|
||||
.Pq Cm AXFR .
|
||||
You can combine this option with
|
||||
.Fl a
|
||||
to print all records, or with
|
||||
.Fl t
|
||||
to only print specific ones.
|
||||
.It Fl N Ar ndots
|
||||
Consider names with at least this many dots as absolute. That
|
||||
is, try to resolve them directly before consulting
|
||||
.Ic domain
|
||||
or
|
||||
.Ic search
|
||||
options from
|
||||
.Pa /etc/resolv.conf .
|
||||
.It Fl r
|
||||
Perform non-recursive query to the name server by clearing RD
|
||||
.Pq Dq recursion desired
|
||||
bit of the query.
|
||||
.It Fl R Ar number
|
||||
Retry this many times when a query does not receive an answer
|
||||
in time. The default is 1 retry. If
|
||||
.Ar number
|
||||
is negative or zero, 1 is used instead.
|
||||
.It Fl s
|
||||
Report SERVFAIL responses as they are, do not ignore them.
|
||||
.It Fl T
|
||||
Query name server over TCP. By default UDP is used, except for
|
||||
.Cm AXFR
|
||||
and
|
||||
.Cm IXFR
|
||||
queries, which require TCP.
|
||||
.Nm
|
||||
will also retry UDP queries in TCP mode if the UDP response was
|
||||
truncated (i.e. had TC bit set).
|
||||
.It Fl t Ar type
|
||||
Perform DNS query of type
|
||||
.Ar type ,
|
||||
which can be any standard query type name
|
||||
.Pq Cm A , CNAME , MX , TXT , No etc ,
|
||||
a wildcard query
|
||||
.Pq Cm ANY ,
|
||||
or
|
||||
.Cm TYPE Ns Ar N ,
|
||||
where
|
||||
.Ar N
|
||||
is a number from 1 to 65535. For
|
||||
.Cm IXFR Pq incremental zone transfer
|
||||
queries the starting serial number can be specified by appending
|
||||
an equal sign followed by the number
|
||||
.Pq e.g. Fl t Cm IXFR Ns =12345678 .
|
||||
.Pp
|
||||
The default is to query for
|
||||
.Cm A , AAAA , No and Cm MX
|
||||
records, unless
|
||||
.Fl C
|
||||
or
|
||||
.Fl l
|
||||
options are given (in which case
|
||||
.Cm SOA
|
||||
or
|
||||
.Cm AXFR
|
||||
queries are made) or
|
||||
.Ar name
|
||||
is a valid IP address
|
||||
(in which case reverse lookup using
|
||||
.Cm PTR
|
||||
query is performed).
|
||||
.It Fl v
|
||||
Produce verbose output.
|
||||
.It Fl w
|
||||
Wait forever (or for a very long time) for response from the
|
||||
name server.
|
||||
.It Fl W Ar wait
|
||||
Wait this many seconds for a reply from name server before timing
|
||||
out. If
|
||||
.Ar wait
|
||||
is negative or zero, value of 1 is used. The default is to wait
|
||||
10 seconds for TCP connections, and 5 seconds for UDP (both are
|
||||
subject to retries, see option
|
||||
.Fl R ) .
|
||||
.It Fl 4
|
||||
Only use IPv4 transport.
|
||||
.It Fl 6
|
||||
Only use IPv6 transport.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Pa /etc/resolv.conf
|
||||
.Sh SEE ALSO
|
||||
.Xr drill 1 ,
|
||||
.Xr resolv.conf 5
|
||||
.Sh COMPATIBILITY
|
||||
.Nm
|
||||
aims to be reasonably compatible with
|
||||
.Sq host
|
||||
utility from BIND9 distribution, both in supported options and
|
||||
in produced output. Here is a list of known notable differences:
|
||||
.Bl -bullet
|
||||
.It
|
||||
Debugging options
|
||||
.Pq Fl D No and Fl m
|
||||
are not supported.
|
||||
.It
|
||||
Query class
|
||||
.Cm CLASS0
|
||||
and type
|
||||
.Cm TYPE0
|
||||
are not supported.
|
||||
.It
|
||||
Backslashes in domain names are treated especially.
|
||||
.It
|
||||
The maximum of 255 retries (option
|
||||
.Fl R )
|
||||
are supported.
|
||||
.It
|
||||
Some resource records are formatted differently. For example,
|
||||
.Cm RRSIG
|
||||
and
|
||||
.Cm DNSKEY
|
||||
records are displayed without spaces in them.
|
||||
.It
|
||||
When parsing
|
||||
.Pa /etc/resolv.conf
|
||||
commands
|
||||
.Ic sortlist
|
||||
and
|
||||
.Ic options
|
||||
are ignored. When multiple
|
||||
.Ic search
|
||||
and/or
|
||||
.Ic domain
|
||||
commands are present,
|
||||
.Nm
|
||||
first uses the last
|
||||
.Ic domain
|
||||
command, and then all of
|
||||
.Ic search
|
||||
commands, while
|
||||
.Sq host
|
||||
from BIND9 uses whatever command was specified last.
|
||||
.It
|
||||
Multi-packet zone transfers are not supported; only the first
|
||||
response packet is printed.
|
||||
.It
|
||||
.Sq Pseudosection TSIG
|
||||
is missing from verbose packet output.
|
||||
.El
|
||||
.Sh AUTHORS
|
||||
.An Vitaly Magerya Aq magv@tx97.net
|
884
contrib/ldns-host/ldns-host.c
Normal file
884
contrib/ldns-host/ldns-host.c
Normal file
@ -0,0 +1,884 @@
|
||||
/*-
|
||||
* (c) Magerya Vitaly
|
||||
*
|
||||
* Copying and distribution of this file, with or without modification,
|
||||
* are permitted in any medium without royalty provided the copyright
|
||||
* notice and this notice are preserved. This file is offered as-is,
|
||||
* without any warranty.
|
||||
*/
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
/* General utilities.
|
||||
*/
|
||||
|
||||
static char *progname;
|
||||
|
||||
#define countof(array) (sizeof(array)/sizeof(*(array)))
|
||||
|
||||
static void
|
||||
die(int code, const char *fmt, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
fprintf(stderr, "%s: ", progname);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
static int
|
||||
ndots(const char *name) {
|
||||
int n;
|
||||
|
||||
for (n = 0; (name = strchr(name, '.')); n++, name++);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* General LDNS-specific utilities.
|
||||
*/
|
||||
|
||||
static ldns_status
|
||||
ldns_resolver_new_default(ldns_resolver **res) {
|
||||
if (ldns_resolver_new_frm_file(res, NULL) == LDNS_STATUS_OK ||
|
||||
(*res = ldns_resolver_new()) != NULL)
|
||||
return LDNS_STATUS_OK;
|
||||
return LDNS_STATUS_MEM_ERR;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
ldns_resolver_push_default_servers(ldns_resolver *res) {
|
||||
ldns_status status;
|
||||
ldns_rdf *addr;
|
||||
|
||||
if ((status = ldns_str2rdf_a(&addr, "127.0.0.1")) != LDNS_STATUS_OK ||
|
||||
(status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK)
|
||||
return ldns_rdf_deep_free(addr), status;
|
||||
ldns_rdf_deep_free(addr);
|
||||
if ((status = ldns_str2rdf_aaaa(&addr, "::1")) != LDNS_STATUS_OK ||
|
||||
(status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK)
|
||||
return ldns_rdf_deep_free(addr), status;
|
||||
ldns_rdf_deep_free(addr);
|
||||
return LDNS_STATUS_OK;
|
||||
}
|
||||
|
||||
static ldns_rdf *
|
||||
ldns_rdf_new_addr_frm_str(const char *str) {
|
||||
ldns_rdf *addr;
|
||||
|
||||
if ((addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, str)) == NULL)
|
||||
addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, str);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void
|
||||
ldns_resolver_remove_nameservers(ldns_resolver *res) {
|
||||
while (ldns_resolver_nameserver_count(res) > 0)
|
||||
ldns_rdf_deep_free(ldns_resolver_pop_nameserver(res));
|
||||
}
|
||||
|
||||
static ldns_rdf *
|
||||
ldns_rdf_reverse_a(ldns_rdf *addr, const char *base) {
|
||||
char *buf;
|
||||
int i, len;
|
||||
|
||||
len = strlen(base);
|
||||
buf = alloca(LDNS_IP4ADDRLEN*4 + len + 1);
|
||||
for (len = i = 0; i < LDNS_IP4ADDRLEN; i++)
|
||||
len += sprintf(&buf[len], "%d.",
|
||||
(int)ldns_rdf_data(addr)[LDNS_IP4ADDRLEN - i - 1]);
|
||||
sprintf(&buf[len], "%s", base);
|
||||
return ldns_dname_new_frm_str(buf);
|
||||
}
|
||||
|
||||
static ldns_rdf *
|
||||
ldns_rdf_reverse_aaaa(ldns_rdf *addr, const char *base) {
|
||||
char *buf;
|
||||
int i, len;
|
||||
|
||||
len = strlen(base);
|
||||
buf = alloca(LDNS_IP6ADDRLEN*4 + len + 1);
|
||||
for (i = 0; i < LDNS_IP6ADDRLEN; i++) {
|
||||
uint8_t byte = ldns_rdf_data(addr)[LDNS_IP6ADDRLEN - i - 1];
|
||||
sprintf(&buf[i*4], "%x.%x.", byte & 0x0F, byte >> 4);
|
||||
}
|
||||
sprintf(&buf[LDNS_IP6ADDRLEN*4], "%s", base);
|
||||
return ldns_dname_new_frm_str(buf);
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
ldns_pkt_push_rr_soa(ldns_pkt *pkt, ldns_pkt_section sec,
|
||||
const ldns_rdf *name, ldns_rr_class c, uint32_t serial) {
|
||||
ldns_rdf *rdf;
|
||||
ldns_rr *rr;
|
||||
uint32_t n;
|
||||
|
||||
if ((rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_SOA)) == NULL)
|
||||
return LDNS_STATUS_MEM_ERR;
|
||||
ldns_rr_set_class(rr, c);
|
||||
ldns_rr_set_owner(rr, ldns_rdf_clone(name));
|
||||
ldns_rr_set_ttl(rr, 0);
|
||||
|
||||
n = 0;
|
||||
if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 1, &n)) == NULL)
|
||||
goto memerr;
|
||||
ldns_rr_set_rdf(rr, rdf, 0);
|
||||
ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 1);
|
||||
|
||||
n = htonl(serial);
|
||||
if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT32, 4, &n)) == NULL)
|
||||
goto memerr;
|
||||
ldns_rr_set_rdf(rr, rdf, 2);
|
||||
|
||||
n = 0;
|
||||
if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_PERIOD, 4, &n)) == NULL)
|
||||
goto memerr;
|
||||
ldns_rr_set_rdf(rr, rdf, 3);
|
||||
ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 4);
|
||||
ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 5);
|
||||
ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 6);
|
||||
|
||||
if (ldns_rr_rdf(rr, 1) == NULL || ldns_rr_rdf(rr, 4) == NULL ||
|
||||
ldns_rr_rdf(rr, 5) == NULL || ldns_rr_rdf(rr, 6) == NULL ||
|
||||
!ldns_pkt_push_rr(pkt, sec, rr))
|
||||
goto memerr;
|
||||
return LDNS_STATUS_OK;
|
||||
|
||||
memerr:
|
||||
ldns_rr_free(rr);
|
||||
return LDNS_STATUS_MEM_ERR;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
ldns_resolver_send_to(ldns_pkt **answer, ldns_resolver *res,
|
||||
const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c,
|
||||
uint16_t flags, uint32_t ixfr_serial, int nameserver) {
|
||||
ldns_status status;
|
||||
ldns_pkt *qpkt;
|
||||
|
||||
int nscnt = ldns_resolver_nameserver_count(res);
|
||||
ldns_rdf **ns = ldns_resolver_nameservers(res);
|
||||
size_t *rtt = ldns_resolver_rtt(res);
|
||||
|
||||
ldns_resolver_set_nameservers(res, &ns[nameserver]);
|
||||
ldns_resolver_set_rtt(res, &rtt[nameserver]);
|
||||
ldns_resolver_set_nameserver_count(res, 1);
|
||||
|
||||
status = ldns_resolver_prepare_query_pkt(&qpkt, res, name, t, c, flags);
|
||||
if (status == LDNS_STATUS_OK && t == LDNS_RR_TYPE_IXFR)
|
||||
status = ldns_pkt_push_rr_soa(qpkt,
|
||||
LDNS_SECTION_AUTHORITY, name, c, ixfr_serial);
|
||||
if (status == LDNS_STATUS_OK)
|
||||
status = ldns_resolver_send_pkt(answer, res, qpkt);
|
||||
ldns_pkt_free(qpkt);
|
||||
|
||||
ldns_resolver_set_nameservers(res, ns);
|
||||
ldns_resolver_set_rtt(res, rtt);
|
||||
ldns_resolver_set_nameserver_count(res, nscnt);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
ldns_pkt_filter_answer(ldns_pkt *pkt, ldns_rr_type type) {
|
||||
int i, j, cnt;
|
||||
ldns_rr_list *rrlist;
|
||||
ldns_rr *rr;
|
||||
ldns_rr_type rrtype;
|
||||
|
||||
rrlist = ldns_pkt_answer(pkt);
|
||||
cnt = ldns_rr_list_rr_count(rrlist);
|
||||
for (i = j = 0; i < cnt; i++) {
|
||||
rr = ldns_rr_list_rr(rrlist, i);
|
||||
rrtype = ldns_rr_get_type(rr);
|
||||
if (type == LDNS_RR_TYPE_ANY ||
|
||||
type == rrtype ||
|
||||
(type == LDNS_RR_TYPE_AXFR &&
|
||||
(rrtype == LDNS_RR_TYPE_A ||
|
||||
rrtype == LDNS_RR_TYPE_AAAA ||
|
||||
rrtype == LDNS_RR_TYPE_NS ||
|
||||
rrtype == LDNS_RR_TYPE_PTR)))
|
||||
ldns_rr_list_set_rr(rrlist, rr, j++);
|
||||
}
|
||||
ldns_rr_list_set_rr_count(rrlist, j);
|
||||
}
|
||||
|
||||
/* Packet content printing.
|
||||
*/
|
||||
|
||||
static struct {
|
||||
ldns_rr_type type;
|
||||
const char *text;
|
||||
} rr_types[] = {
|
||||
{LDNS_RR_TYPE_A, "has address"},
|
||||
{LDNS_RR_TYPE_NS, "name server"},
|
||||
{LDNS_RR_TYPE_CNAME, "is an alias for"},
|
||||
{LDNS_RR_TYPE_WKS, "has well known services"},
|
||||
{LDNS_RR_TYPE_PTR, "domain name pointer"},
|
||||
{LDNS_RR_TYPE_HINFO, "host information"},
|
||||
{LDNS_RR_TYPE_MX, "mail is handled by"},
|
||||
{LDNS_RR_TYPE_TXT, "descriptive text"},
|
||||
{LDNS_RR_TYPE_X25, "x25 address"},
|
||||
{LDNS_RR_TYPE_ISDN, "ISDN address"},
|
||||
{LDNS_RR_TYPE_SIG, "has signature"},
|
||||
{LDNS_RR_TYPE_KEY, "has key"},
|
||||
{LDNS_RR_TYPE_AAAA, "has IPv6 address"},
|
||||
{LDNS_RR_TYPE_LOC, "location"},
|
||||
};
|
||||
|
||||
static void
|
||||
print_opcode(ldns_pkt_opcode opcode) {
|
||||
ldns_lookup_table *lt = ldns_lookup_by_id(ldns_opcodes, opcode);
|
||||
|
||||
if (lt && lt->name)
|
||||
printf("%s", lt->name);
|
||||
else
|
||||
printf("RESERVED%d", opcode);
|
||||
}
|
||||
|
||||
static void
|
||||
print_rcode(uint8_t rcode) {
|
||||
ldns_lookup_table *lt = ldns_lookup_by_id(ldns_rcodes, rcode);
|
||||
|
||||
if (lt && lt->name)
|
||||
printf("%s", lt->name);
|
||||
else
|
||||
printf("RESERVED%d", rcode);
|
||||
}
|
||||
|
||||
static int
|
||||
print_rr_type(ldns_rr_type type) {
|
||||
char *str;
|
||||
int n;
|
||||
|
||||
str = ldns_rr_type2str(type);
|
||||
n = printf("%s", str);
|
||||
free(str);
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
print_rr_class(ldns_rr_class cls) {
|
||||
char *str;
|
||||
int n;
|
||||
|
||||
str = ldns_rr_class2str(cls);
|
||||
n = printf("%s", str);
|
||||
free(str);
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
print_rdf(ldns_rdf *rdf) {
|
||||
char *str;
|
||||
int n;
|
||||
|
||||
str = ldns_rdf2str(rdf);
|
||||
n = printf("%s", str);
|
||||
free(str);
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
print_rdf_nodot(ldns_rdf *rdf) {
|
||||
char *str;
|
||||
int len, n;
|
||||
|
||||
str = ldns_rdf2str(rdf);
|
||||
len = strlen(str);
|
||||
n = printf("%.*s", str[len-1] == '.' ? len-1 : len, str);
|
||||
free(str);
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
print_padding(int fromcol, int tocol) {
|
||||
int col = fromcol, nextcol = fromcol + 8 - fromcol%8;
|
||||
|
||||
if (fromcol + 1 > tocol) tocol = fromcol + 1;
|
||||
for (; nextcol <= tocol; col = nextcol, nextcol += 8)
|
||||
printf("\t");
|
||||
for (; col < tocol; col++)
|
||||
printf(" ");
|
||||
return col - fromcol;
|
||||
}
|
||||
|
||||
static void
|
||||
print_rr_verbose(ldns_rr *rr) {
|
||||
bool isq = ldns_rr_is_question(rr);
|
||||
int rdcnt = ldns_rr_rd_count(rr);
|
||||
int i, n;
|
||||
|
||||
/* bind9-host does not count the initial ';' here */
|
||||
n = isq ? printf(";") : 0;
|
||||
n = print_rdf(ldns_rr_owner(rr));
|
||||
if (!isq) {
|
||||
n += print_padding(n, 24);
|
||||
n += printf("%d", ldns_rr_ttl(rr));
|
||||
}
|
||||
n += print_padding(n, 32);
|
||||
n += print_rr_class(ldns_rr_get_class(rr));
|
||||
n += print_padding(n, 40);
|
||||
n += print_rr_type(ldns_rr_get_type(rr));
|
||||
for (i = 0; i < rdcnt; i++) {
|
||||
if (i == 0) print_padding(n, 48);
|
||||
else printf(" ");
|
||||
print_rdf(ldns_rr_rdf(rr, i));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
print_pkt_section_verbose(const char *name, ldns_rr_list *rrlist) {
|
||||
int i, cnt = ldns_rr_list_rr_count(rrlist);
|
||||
|
||||
if (cnt == 0)
|
||||
return;
|
||||
printf(";; %s SECTION:\n", name);
|
||||
for (i = 0; i < cnt; i++)
|
||||
print_rr_verbose(ldns_rr_list_rr(rrlist, i));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
print_pkt_verbose(ldns_pkt *pkt) {
|
||||
int got_flags = 0;
|
||||
|
||||
printf(";; ->>HEADER<<- opcode: ");
|
||||
print_opcode(ldns_pkt_get_opcode(pkt));
|
||||
printf(", status: ");
|
||||
print_rcode(ldns_pkt_get_rcode(pkt));
|
||||
printf(", id: %u\n", ldns_pkt_id(pkt));
|
||||
printf(";; flags:");
|
||||
if (ldns_pkt_qr(pkt)) printf(" qr"), got_flags = 1;
|
||||
if (ldns_pkt_aa(pkt)) printf(" aa"), got_flags = 1;
|
||||
if (ldns_pkt_tc(pkt)) printf(" tc"), got_flags = 1;
|
||||
if (ldns_pkt_rd(pkt)) printf(" rd"), got_flags = 1;
|
||||
if (ldns_pkt_ra(pkt)) printf(" ra"), got_flags = 1;
|
||||
if (ldns_pkt_ad(pkt)) printf(" ad"), got_flags = 1;
|
||||
if (ldns_pkt_cd(pkt)) printf(" cd"), got_flags = 1;
|
||||
if (!got_flags) printf(" ");
|
||||
printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n",
|
||||
ldns_pkt_qdcount(pkt), ldns_pkt_ancount(pkt),
|
||||
ldns_pkt_nscount(pkt), ldns_pkt_arcount(pkt));
|
||||
if (ldns_pkt_edns(pkt))
|
||||
printf(";; EDNS: version: %u, udp=%u\n",
|
||||
ldns_pkt_edns_version(pkt), ldns_pkt_edns_udp_size(pkt));
|
||||
printf("\n");
|
||||
print_pkt_section_verbose("QUESTION", ldns_pkt_question(pkt));
|
||||
print_pkt_section_verbose("ANSWER", ldns_pkt_answer(pkt));
|
||||
print_pkt_section_verbose("AUTHORITY", ldns_pkt_authority(pkt));
|
||||
print_pkt_section_verbose("ADDITIONAL", ldns_pkt_additional(pkt));
|
||||
}
|
||||
|
||||
static void
|
||||
print_rr_short(ldns_rr *rr) {
|
||||
ldns_rr_type type = ldns_rr_get_type(rr);
|
||||
size_t i, rdcnt = ldns_rr_rd_count(rr);
|
||||
|
||||
print_rdf_nodot(ldns_rr_owner(rr));
|
||||
printf(" ");
|
||||
for (i = 0; i < countof(rr_types); i++) {
|
||||
if (rr_types[i].type == type) {
|
||||
printf("%s", rr_types[i].text);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
printf("has ");
|
||||
print_rr_type(type);
|
||||
printf(" record");
|
||||
|
||||
found:
|
||||
for (i = 0; i < rdcnt; i++) {
|
||||
printf(" ");
|
||||
print_rdf(ldns_rr_rdf(rr, i));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
print_pkt_short(ldns_pkt *pkt, bool print_rr_server) {
|
||||
ldns_rr_list *rrlist = ldns_pkt_answer(pkt);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
|
||||
if (print_rr_server) {
|
||||
printf("Nameserver ");
|
||||
print_rdf(ldns_pkt_answerfrom(pkt));
|
||||
printf(":\n\t");
|
||||
}
|
||||
print_rr_short(ldns_rr_list_rr(rrlist, i));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_received_line(ldns_resolver *res, ldns_pkt *pkt) {
|
||||
char *from = ldns_rdf2str(ldns_pkt_answerfrom(pkt));
|
||||
|
||||
printf("Received %zu bytes from %s#%d in %d ms\n",
|
||||
ldns_pkt_size(pkt), from, ldns_resolver_port(res),
|
||||
ldns_pkt_querytime(pkt));
|
||||
free(from);
|
||||
}
|
||||
|
||||
/* Main program.
|
||||
*
|
||||
* Note that no memory is freed below this line by intention.
|
||||
*/
|
||||
|
||||
#define DEFAULT_TCP_TIMEOUT 10
|
||||
#define DEFAULT_UDP_TIMEOUT 5
|
||||
|
||||
enum operation_mode { M_AXFR, M_DEFAULT_Q, M_SINGLE_Q, M_SOA };
|
||||
|
||||
static enum operation_mode o_mode = M_DEFAULT_Q;
|
||||
static bool o_ignore_servfail = true;
|
||||
static bool o_ip6_int = false;
|
||||
static bool o_print_pkt_server = false;
|
||||
static bool o_print_rr_server = false;
|
||||
static bool o_recursive = true;
|
||||
static bool o_tcp = false;
|
||||
static bool o_verbose = false;
|
||||
static char *o_name = NULL;
|
||||
static char *o_server = NULL;
|
||||
static int o_ipversion = LDNS_RESOLV_INETANY;
|
||||
static int o_ndots = 1;
|
||||
static int o_retries = 1;
|
||||
static ldns_rr_class o_rrclass = LDNS_RR_CLASS_IN;
|
||||
static ldns_rr_type o_rrtype = LDNS_RR_TYPE_A;
|
||||
static time_t o_timeout = 0;
|
||||
static uint32_t o_ixfr_serial = 0;
|
||||
|
||||
static void
|
||||
usage(void) {
|
||||
fputs(
|
||||
"Usage: host [-aCdilrsTvw46] [-c class] [-N ndots] [-R number]\n"
|
||||
" [-t type] [-W wait] name [server]\n"
|
||||
"\t-a same as -v -t ANY\n"
|
||||
"\t-C query SOA records from all authoritative name servers\n"
|
||||
"\t-c use this query class (IN, CH, HS, etc)\n"
|
||||
"\t-d produce verbose output, same as -v\n"
|
||||
"\t-i use IP6.INT for IPv6 reverse lookups\n"
|
||||
"\t-l list records in a zone via AXFR\n"
|
||||
"\t-N consider names with at least this many dots as absolute\n"
|
||||
"\t-R retry UDP queries this many times\n"
|
||||
"\t-r disable recursive query\n"
|
||||
"\t-s do not ignore SERVFAIL responses\n"
|
||||
"\t-T send query via TCP\n"
|
||||
"\t-t use this query type (A, AAAA, MX, etc)\n"
|
||||
"\t-v produce verbose output\n"
|
||||
"\t-w wait forever for a server reply\n"
|
||||
"\t-W wait this many seconds for a reply\n"
|
||||
"\t-4 use IPv4 only\n"
|
||||
"\t-6 use IPv6 only\n",
|
||||
stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_args(int argc, char *argv[]) {
|
||||
int ch;
|
||||
|
||||
progname = argv[0];
|
||||
while ((ch = getopt(argc, argv, "aCdilrsTvw46c:N:R:t:W:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
if (o_mode != M_AXFR)
|
||||
o_mode = M_SINGLE_Q;
|
||||
o_rrtype = LDNS_RR_TYPE_ANY;
|
||||
o_verbose = true;
|
||||
break;
|
||||
case 'C':
|
||||
o_mode = M_SOA;
|
||||
o_print_rr_server = true;
|
||||
o_rrclass = LDNS_RR_CLASS_IN;
|
||||
o_rrtype = LDNS_RR_TYPE_NS;
|
||||
break;
|
||||
case 'c':
|
||||
/* bind9-host sets o_mode to M_SINGLE_Q here */
|
||||
o_rrclass = ldns_get_rr_class_by_name(optarg);
|
||||
if (o_rrclass <= 0)
|
||||
die(2, "invalid class: %s\n", optarg);
|
||||
break;
|
||||
case 'd': o_verbose = true; break;
|
||||
case 'i': o_ip6_int = true; break;
|
||||
case 'l':
|
||||
o_mode = M_AXFR;
|
||||
o_rrtype = LDNS_RR_TYPE_AXFR;
|
||||
o_tcp = true;
|
||||
break;
|
||||
case 'N':
|
||||
o_ndots = atoi(optarg);
|
||||
if (o_ndots < 0) o_ndots = 0;
|
||||
break;
|
||||
case 'n':
|
||||
/* bind9-host accepts and ignores this option */
|
||||
break;
|
||||
case 'r': o_recursive = 0; break;
|
||||
case 'R':
|
||||
o_retries = atoi(optarg);
|
||||
if (o_retries <= 0) o_retries = 1;
|
||||
if (o_retries > 255) o_retries = 255;
|
||||
break;
|
||||
case 's': o_ignore_servfail = false; break;
|
||||
case 'T': o_tcp = true; break;
|
||||
case 't':
|
||||
if (o_mode != M_AXFR)
|
||||
o_mode = M_SINGLE_Q;
|
||||
if (strncasecmp(optarg, "ixfr=", 5) == 0) {
|
||||
o_rrtype = LDNS_RR_TYPE_IXFR;
|
||||
o_ixfr_serial = atol(optarg + 5);
|
||||
} else {
|
||||
o_rrtype = ldns_get_rr_type_by_name(optarg);
|
||||
if (o_rrtype <= 0)
|
||||
die(2, "invalid type: %s\n", optarg);
|
||||
}
|
||||
if (o_rrtype == LDNS_RR_TYPE_AXFR || o_rrtype == LDNS_RR_TYPE_IXFR)
|
||||
o_tcp = true;
|
||||
if (o_rrtype == LDNS_RR_TYPE_AXFR) {
|
||||
o_mode = M_AXFR;
|
||||
o_rrtype = LDNS_RR_TYPE_ANY;
|
||||
o_verbose = true;
|
||||
}
|
||||
break;
|
||||
case 'v': o_verbose = true; break;
|
||||
case 'w':
|
||||
o_timeout = (time_t)INT_MAX;
|
||||
break;
|
||||
case 'W':
|
||||
o_timeout = atol(optarg);
|
||||
if (o_timeout <= 0) o_timeout = 1;
|
||||
break;
|
||||
case '4': o_ipversion = LDNS_RESOLV_INET; break;
|
||||
case '6': o_ipversion = LDNS_RESOLV_INET6; break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
/* bind9-host ignores arguments after the 2-nd one */
|
||||
if (argc < 1)
|
||||
usage();
|
||||
o_name = argv[0];
|
||||
if (argc > 1) {
|
||||
o_server = argv[1];
|
||||
o_print_pkt_server = true;
|
||||
}
|
||||
}
|
||||
|
||||
static ldns_rdf*
|
||||
safe_str2rdf_dname(const char *name) {
|
||||
ldns_rdf *dname;
|
||||
ldns_status status;
|
||||
|
||||
if ((status = ldns_str2rdf_dname(&dname, name)) != LDNS_STATUS_OK) {
|
||||
die(1, "'%s' is not a legal name (%s)",
|
||||
name, ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
return dname;
|
||||
}
|
||||
|
||||
static ldns_rdf*
|
||||
safe_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) {
|
||||
ldns_rdf *result = ldns_dname_cat_clone(rd1, rd2);
|
||||
|
||||
if (!result)
|
||||
die(1, "not enought memory for a domain name");
|
||||
/* Why doesn't ldns_dname_cat_clone check this condition? */
|
||||
if (ldns_rdf_size(result) > LDNS_MAX_DOMAINLEN)
|
||||
die(1, "'%s' is not a legal name (%s)\n", ldns_rdf2str(result),
|
||||
ldns_get_errorstr_by_id(LDNS_STATUS_DOMAINNAME_OVERFLOW));
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
query(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt) {
|
||||
ldns_status status;
|
||||
ldns_pkt_rcode rcode;
|
||||
int i, cnt;
|
||||
|
||||
if (o_verbose) {
|
||||
printf("Trying \"");
|
||||
print_rdf_nodot(domain);
|
||||
printf("\"\n");
|
||||
}
|
||||
for (cnt = ldns_resolver_nameserver_count(res), i = 0; i < cnt; i++) {
|
||||
status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
|
||||
o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
*pkt = NULL;
|
||||
continue;
|
||||
}
|
||||
if (ldns_pkt_tc(*pkt) && !ldns_resolver_usevc(res)) {
|
||||
if (o_verbose)
|
||||
printf(";; Truncated, retrying in TCP mode.\n");
|
||||
ldns_resolver_set_usevc(res, true);
|
||||
status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
|
||||
o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i);
|
||||
ldns_resolver_set_usevc(res, false);
|
||||
if (status != LDNS_STATUS_OK)
|
||||
continue;
|
||||
}
|
||||
rcode = ldns_pkt_get_rcode(*pkt);
|
||||
if (o_ignore_servfail && rcode == LDNS_RCODE_SERVFAIL && cnt > 1)
|
||||
continue;
|
||||
return rcode == LDNS_RCODE_NOERROR;
|
||||
}
|
||||
if (*pkt == NULL) {
|
||||
printf(";; connection timed out; no servers could be reached\n");
|
||||
exit(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static ldns_rdf *
|
||||
search(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt, bool absolute) {
|
||||
ldns_rdf *dname, **searchlist;
|
||||
int i, n;
|
||||
|
||||
if (absolute && query(res, domain, pkt))
|
||||
return domain;
|
||||
|
||||
if ((dname = ldns_resolver_domain(res)) != NULL) {
|
||||
dname = safe_dname_cat_clone(domain, dname);
|
||||
if (query(res, dname, pkt))
|
||||
return dname;
|
||||
}
|
||||
|
||||
searchlist = ldns_resolver_searchlist(res);
|
||||
n = ldns_resolver_searchlist_count(res);
|
||||
for (i = 0; i < n; i++) {
|
||||
dname = safe_dname_cat_clone(domain, searchlist[i]);
|
||||
if (query(res, dname, pkt))
|
||||
return dname;
|
||||
}
|
||||
|
||||
if (!absolute && query(res, domain, pkt))
|
||||
return domain;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
report(ldns_resolver *res, ldns_rdf *domain, ldns_pkt *pkt) {
|
||||
ldns_pkt_rcode rcode;
|
||||
|
||||
if (o_print_pkt_server) {
|
||||
printf("Using domain server:\nName: %s\nAddress: ", o_server);
|
||||
print_rdf(ldns_pkt_answerfrom(pkt));
|
||||
printf("#%d\nAliases: \n\n", ldns_resolver_port(res));
|
||||
o_print_pkt_server = false;
|
||||
}
|
||||
rcode = ldns_pkt_get_rcode(pkt);
|
||||
if (rcode != LDNS_RCODE_NOERROR) {
|
||||
printf("Host ");
|
||||
print_rdf_nodot(domain);
|
||||
printf(" not found: %d(", rcode);
|
||||
print_rcode(rcode);
|
||||
printf(")\n");
|
||||
} else {
|
||||
if (o_verbose) {
|
||||
print_pkt_verbose(pkt);
|
||||
} else {
|
||||
print_pkt_short(pkt, o_print_rr_server);
|
||||
if (o_mode != M_DEFAULT_Q &&
|
||||
ldns_rr_list_rr_count(ldns_pkt_answer(pkt)) == 0) {
|
||||
print_rdf_nodot(domain);
|
||||
printf(" has no ");
|
||||
print_rr_type(o_rrtype);
|
||||
printf(" record\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (o_verbose)
|
||||
print_received_line(res, pkt);
|
||||
}
|
||||
|
||||
static bool
|
||||
doquery(ldns_resolver *res, ldns_rdf *domain) {
|
||||
ldns_pkt *pkt;
|
||||
bool q;
|
||||
|
||||
q = query(res, domain, &pkt);
|
||||
report(res, domain, pkt);
|
||||
return q;
|
||||
}
|
||||
|
||||
static bool
|
||||
doquery_filtered(ldns_resolver *res, ldns_rdf *domain) {
|
||||
ldns_pkt *pkt;
|
||||
bool q;
|
||||
|
||||
q = query(res, domain, &pkt);
|
||||
ldns_pkt_filter_answer(pkt, o_rrtype);
|
||||
report(res, domain, pkt);
|
||||
return q;
|
||||
}
|
||||
|
||||
static bool
|
||||
dosearch(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
|
||||
ldns_pkt *pkt;
|
||||
ldns_rdf *dname;
|
||||
|
||||
dname = search(res, domain, &pkt, absolute);
|
||||
report(res, dname != NULL ? dname : domain, pkt);
|
||||
return o_mode != M_DEFAULT_Q ? (dname != NULL) :
|
||||
(dname != NULL) &&
|
||||
(o_rrtype = LDNS_RR_TYPE_AAAA, doquery_filtered(res, dname)) &&
|
||||
(o_rrtype = LDNS_RR_TYPE_MX, doquery_filtered(res, dname));
|
||||
}
|
||||
|
||||
static bool
|
||||
doaxfr(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
|
||||
ldns_pkt *pkt;
|
||||
ldns_rdf *dname;
|
||||
ldns_rr_type rrtype;
|
||||
|
||||
rrtype = o_rrtype;
|
||||
o_rrtype = LDNS_RR_TYPE_AXFR;
|
||||
dname = search(res, domain, &pkt, absolute);
|
||||
ldns_pkt_filter_answer(pkt, rrtype);
|
||||
report(res, dname != NULL ? dname : domain, pkt);
|
||||
return dname != NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
dosoa(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
|
||||
ldns_rr_list *answer, **nsaddrs;
|
||||
ldns_rdf *dname, *addr;
|
||||
ldns_pkt *pkt;
|
||||
ldns_rr *rr;
|
||||
size_t i, j, n, cnt;
|
||||
|
||||
if ((dname = search(res, domain, &pkt, absolute)) == NULL)
|
||||
return false;
|
||||
|
||||
answer = ldns_pkt_answer(pkt);
|
||||
cnt = ldns_rr_list_rr_count(answer);
|
||||
nsaddrs = alloca(cnt*sizeof(*nsaddrs));
|
||||
for (n = 0, i = 0; i < cnt; i++)
|
||||
if ((addr = ldns_rr_ns_nsdname(ldns_rr_list_rr(answer, i))) != NULL)
|
||||
nsaddrs[n++] = ldns_get_rr_list_addr_by_name(res,
|
||||
addr, LDNS_RR_CLASS_IN, 0);
|
||||
|
||||
o_print_pkt_server = false;
|
||||
o_recursive = false;
|
||||
o_rrtype = LDNS_RR_TYPE_SOA;
|
||||
for (i = 0; i < n; i++) {
|
||||
cnt = ldns_rr_list_rr_count(nsaddrs[i]);
|
||||
for (j = 0; j < cnt; j++) {
|
||||
ldns_resolver_remove_nameservers(res);
|
||||
rr = ldns_rr_list_rr(nsaddrs[i], j);
|
||||
if ((ldns_resolver_ip6(res) == LDNS_RESOLV_INET &&
|
||||
ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) ||
|
||||
(ldns_resolver_ip6(res) == LDNS_RESOLV_INET6 &&
|
||||
ldns_rr_get_type(rr) == LDNS_RR_TYPE_A))
|
||||
continue;
|
||||
if (ldns_resolver_push_nameserver_rr(res, rr) == LDNS_STATUS_OK)
|
||||
/* bind9-host queries for domain, not dname here */
|
||||
doquery(res, dname);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
resolver_set_nameserver_hostname(ldns_resolver *res, const char *server) {
|
||||
struct addrinfo hints, *ailist, *ai;
|
||||
ldns_status status;
|
||||
ldns_rdf *rdf;
|
||||
int err;
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
switch (ldns_resolver_ip6(res)) {
|
||||
case LDNS_RESOLV_INET: hints.ai_family = PF_INET; break;
|
||||
case LDNS_RESOLV_INET6: hints.ai_family = PF_INET6; break;
|
||||
default: hints.ai_family = PF_UNSPEC; break;
|
||||
}
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
do err = getaddrinfo(server, NULL, &hints, &ailist);
|
||||
while (err == EAI_AGAIN);
|
||||
if (err != 0)
|
||||
die(1, "couldn't get address for '%s': %s", server, gai_strerror(err));
|
||||
for (ai = ailist; ai != NULL; ai = ai->ai_next) {
|
||||
if ((rdf = ldns_sockaddr_storage2rdf((void*)ai->ai_addr, NULL)) == NULL)
|
||||
die(1, "couldn't allocate an rdf: %s",
|
||||
ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
|
||||
status = ldns_resolver_push_nameserver(res, rdf);
|
||||
if (status != LDNS_STATUS_OK)
|
||||
die(1, "couldn't push a nameserver address: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
resolver_set_nameserver_str(ldns_resolver *res, const char *server) {
|
||||
ldns_rdf *addr;
|
||||
|
||||
ldns_resolver_remove_nameservers(res);
|
||||
addr = ldns_rdf_new_addr_frm_str(server);
|
||||
if (addr) {
|
||||
if (ldns_resolver_push_nameserver(res, addr) != LDNS_STATUS_OK)
|
||||
die(1, "couldn't push a nameserver address");
|
||||
} else
|
||||
resolver_set_nameserver_hostname(res, server);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
ldns_rdf *addr, *dname;
|
||||
ldns_resolver *res;
|
||||
ldns_status status;
|
||||
struct timeval restimeout;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
status = ldns_resolver_new_default(&res);
|
||||
if (status != LDNS_STATUS_OK)
|
||||
die(1, "error creating resolver: %s", ldns_get_errorstr_by_id(status));
|
||||
if (ldns_resolver_nameserver_count(res) == 0)
|
||||
ldns_resolver_push_default_servers(res);
|
||||
|
||||
ldns_resolver_set_usevc(res, o_tcp);
|
||||
restimeout.tv_sec = o_timeout > 0 ? o_timeout :
|
||||
o_tcp ? DEFAULT_TCP_TIMEOUT : DEFAULT_UDP_TIMEOUT;
|
||||
restimeout.tv_usec = 0;
|
||||
ldns_resolver_set_timeout(res, restimeout);
|
||||
ldns_resolver_set_retry(res, o_retries+1);
|
||||
ldns_resolver_set_ip6(res, o_ipversion);
|
||||
ldns_resolver_set_defnames(res, false);
|
||||
ldns_resolver_set_fallback(res, false);
|
||||
|
||||
if (o_server)
|
||||
resolver_set_nameserver_str(res, o_server);
|
||||
|
||||
if (ldns_str2rdf_a(&addr, o_name) == LDNS_STATUS_OK) {
|
||||
dname = ldns_rdf_reverse_a(addr, "in-addr.arpa");
|
||||
if (dname == NULL)
|
||||
die(1, "can't reverse '%s': %s", o_name,
|
||||
ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
|
||||
o_mode = M_SINGLE_Q;
|
||||
o_rrtype = LDNS_RR_TYPE_PTR;
|
||||
return !doquery(res, dname);
|
||||
} else if (ldns_str2rdf_aaaa(&addr, o_name) == LDNS_STATUS_OK) {
|
||||
dname = ldns_rdf_reverse_aaaa(addr, o_ip6_int ? "ip6.int" : "ip6.arpa");
|
||||
if (dname == NULL)
|
||||
die(1, "can't reverse '%s': %s", o_name,
|
||||
ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
|
||||
o_mode = M_SINGLE_Q;
|
||||
o_rrtype = LDNS_RR_TYPE_PTR;
|
||||
return !doquery(res, dname);
|
||||
}
|
||||
return !(o_mode == M_SOA ? dosoa : o_mode == M_AXFR ? doaxfr : dosearch)
|
||||
(res, safe_str2rdf_dname(o_name), ndots(o_name) >= o_ndots);
|
||||
}
|
@ -1,5 +1,29 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
.if ${MK_LDNS_UTILS} != "no"
|
||||
|
||||
LDNSDIR= ${.CURDIR}/../../contrib/ldns
|
||||
LDNSHOSTDIR= ${.CURDIR}/../../contrib/ldns-host
|
||||
|
||||
.PATH: ${LDNSHOSTDIR}
|
||||
|
||||
PROG= host
|
||||
SRCS= ldns-host.c
|
||||
MAN= host.1
|
||||
|
||||
host.1: ldns-host.1
|
||||
sed -e 's/ldns-//gI' <${.ALLSRC} >${.TARGET} || \
|
||||
(rm -rf ${.TARGET} ; false)
|
||||
|
||||
CFLAGS+= -I${LDNSDIR}
|
||||
DPADD+= ${LIBLDNS} ${LIBCRYPTO}
|
||||
LDADD+= -lldns -lcrypto
|
||||
USEPRIVATELIB= ldns
|
||||
|
||||
.else
|
||||
|
||||
BIND_DIR= ${.CURDIR}/../../contrib/bind9
|
||||
LIB_BIND_REL= ../../lib/bind
|
||||
LIB_BIND_DIR= ${.CURDIR}/${LIB_BIND_REL}
|
||||
@ -20,4 +44,6 @@ WARNS?= 0
|
||||
DPADD+= ${BIND_DPADD} ${CRYPTO_DPADD} ${PTHREAD_DPADD}
|
||||
LDADD+= ${BIND_LDADD} ${CRYPTO_LDADD} ${PTHREAD_LDADD}
|
||||
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
Loading…
Reference in New Issue
Block a user