diff options
Diffstat (limited to 'adns-0.6/client')
-rw-r--r-- | adns-0.6/client/.cvsignore | 11 | ||||
-rw-r--r-- | adns-0.6/client/Makefile.in | 74 | ||||
-rw-r--r-- | adns-0.6/client/adh-main.c | 243 | ||||
-rw-r--r-- | adns-0.6/client/adh-opts.c | 337 | ||||
-rw-r--r-- | adns-0.6/client/adh-query.c | 274 | ||||
-rw-r--r-- | adns-0.6/client/adnshost.h | 118 | ||||
-rw-r--r-- | adns-0.6/client/adnslogres.c | 239 | ||||
-rw-r--r-- | adns-0.6/client/adnsresfilter.c | 454 | ||||
-rw-r--r-- | adns-0.6/client/adnstest.c | 337 | ||||
-rw-r--r-- | adns-0.6/client/fanftest.c | 85 | ||||
-rw-r--r-- | adns-0.6/client/x.gdb | 2 |
11 files changed, 2174 insertions, 0 deletions
diff --git a/adns-0.6/client/.cvsignore b/adns-0.6/client/.cvsignore new file mode 100644 index 0000000..45bcf1e --- /dev/null +++ b/adns-0.6/client/.cvsignore @@ -0,0 +1,11 @@ +Makefile +adnstest +adnstest_s +adnslogres +adnslogres_s +adnshost +adnshost_s +adnsresfilter +adnsresfilter_s +fanftest +fanftest_s diff --git a/adns-0.6/client/Makefile.in b/adns-0.6/client/Makefile.in new file mode 100644 index 0000000..a7b3aaa --- /dev/null +++ b/adns-0.6/client/Makefile.in @@ -0,0 +1,74 @@ +# client/Makefile - client program(s) Makefile +# +# This file is +# Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> +# +# It is part of adns, which is +# Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> +# Copyright (C) 1999 Tony Finch <dot@dotat.at> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +srcdir= @srcdir@ +VPATH= @srcdir@ + +PROGS_SYSDEP= @PROGS_HAVE_TSEARCH@ + +PROGRAMS= adnstest adnslogres adnshost $(PROGS_SYSDEP) +PROGRAMS_LOCAL= fanftest +PROGRAMS_ALL= $(PROGRAMS) $(PROGRAMS_LOCAL) + +TARG_INSTALL= $(PROGRAMS) +TARG_LOCAL= $(addsuffix _s, $(PROGRAMS_ALL)) +TARGETS= $(TARG_LOCAL) $(TARG_INSTALL) +include $(srcdir)/../settings.make + +DIRCFLAGS= -I$(srcdir)/../src + +TARG_OBJS= $(addsuffix .o, $(PROGRAMS_ALL)) +ADH_OBJS= adh-main.o adh-opts.o adh-query.o +ALL_OBJS= $(ADH_OBJS) $(TARG_OBJS) + +ADNSDIR= $(srcdir)/../src/ + +STATIC_LIB= $(ADNSDIR)/libadns.a +DYNAMIC_DEP= $(srcdir)/../dynamic/$(SHLIBFILE) +DYNAMIC_LINK= -L$(srcdir)/../dynamic -ladns + +all: $(TARGETS) + +install: $(TARG_INSTALL) + set -xe; for f in $(TARG_INSTALL); \ + do $(INSTALL_PROGRAM) $$f $(bin_dir)/$$f; done + +uninstall: + for f in $(TARGETS); do rm -f $(bin_dir)/$$f; done + +adnshost: $(ADH_OBJS) $(DYNAMIC_DEP) + $(CC) $(LDFLAGS) $(ADH_OBJS) $(DYNAMIC_LINK) -o $@ $(LDLIBS) + +adnshost_s: $(ADH_OBJS) $(STATIC_LIB) + $(CC) $(LDFLAGS) $(ADH_OBJS) $(STATIC_LIB) -o $@ $(LDLIBS) + +$(ADH_OBJS): adnshost.h +$(ALL_OBJS): $(ADNSDIR)/adns.h $(ADNSDIR)/config.h +adnsresfilter.o: $(ADNSDIR)/tvarith.h + +%: %.o $(DYNAMIC_DEP) + $(CC) $(LDFLAGS) $< $(DYNAMIC_LINK) -o $@ $(LDLIBS) + +%_s: %.o $(STATIC_LIB) + $(CC) $(LDFLAGS) $< $(STATIC_LIB) -o $@ $(LDLIBS) + diff --git a/adns-0.6/client/adh-main.c b/adns-0.6/client/adh-main.c new file mode 100644 index 0000000..81cff54 --- /dev/null +++ b/adns-0.6/client/adh-main.c @@ -0,0 +1,243 @@ +/* + * adh-main.c + * - useful general-purpose resolver client program + * main program and useful subroutines + */ +/* + * This file is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "adnshost.h" + +void sysfail(const char *what, int errnoval) { + fprintf(stderr,"adnshost failed: %s: %s\n",what,strerror(errnoval)); + exit(10); +} + +void usageerr(const char *fmt, ...) { + va_list al; + fputs("adnshost usage error: ",stderr); + va_start(al,fmt); + vfprintf(stderr,fmt,al); + va_end(al); + putc('\n',stderr); + exit(11); +} + +void outerr(void) { + sysfail("write to stdout",errno); +} + +void *xmalloc(size_t sz) { + void *p; + + p= malloc(sz); if (!p) sysfail("malloc",sz); + return p; +} + +char *xstrsave(const char *str) { + char *p; + + p= xmalloc(strlen(str)+1); + strcpy(p,str); + return p; +} + +void of_type(const struct optioninfo *oi, const char *arg) { + static const struct typename { + adns_rrtype type; + const char *desc; + } typenames[]= { + /* enhanced versions */ + { adns_r_ns, "ns" }, + { adns_r_soa, "soa" }, + { adns_r_ptr, "ptr" }, + { adns_r_mx, "mx" }, + { adns_r_rp, "rp" }, + { adns_r_addr, "addr" }, + + /* types with only one version */ + { adns_r_cname, "cname" }, + { adns_r_hinfo, "hinfo" }, + { adns_r_txt, "txt" }, + + /* raw versions */ + { adns_r_a, "a" }, + { adns_r_ns_raw, "ns-" }, + { adns_r_soa_raw, "soa-" }, + { adns_r_ptr_raw, "ptr-" }, + { adns_r_mx_raw, "mx-" }, + { adns_r_rp_raw, "rp-" }, + + { adns_r_none, 0 } + }; + + const struct typename *tnp; + + for (tnp=typenames; + tnp->type && strcmp(arg,tnp->desc); + tnp++); + if (!tnp->type) usageerr("unknown RR type %s",arg); + ov_type= tnp->type; +} + +int rcode; + +static void process_optarg(const char *arg, + const char *const **argv_p, + const char *value) { + const struct optioninfo *oip; + int invert; + + if (arg[0] == '-' || arg[0] == '+') { + if (arg[0] == '-' && arg[1] == '-') { + if (!strncmp(arg,"--no-",5)) { + invert= 1; + oip= opt_findl(arg+5); + } else { + invert= 0; + oip= opt_findl(arg+2); + } + if (oip->type == ot_funcarg) { + arg= argv_p ? *++(*argv_p) : value; + if (!arg) usageerr("option --%s requires a value argument",oip->lopt); + } else { + if (value) usageerr("option --%s does not take a value",oip->lopt); + arg= 0; + } + opt_do(oip,arg,invert); + } else if (arg[0] == '-' && arg[1] == 0) { + arg= argv_p ? *++(*argv_p) : value; + if (!arg) usageerr("option `-' must be followed by a domain"); + query_do(arg); + } else { /* arg[1] != '-', != '\0' */ + invert= (arg[0] == '+'); + ++arg; + while (*arg) { + oip= opt_finds(&arg); + if (oip->type == ot_funcarg) { + if (!*arg) { + arg= argv_p ? *++(*argv_p) : value; + if (!arg) usageerr("option -%s requires a value argument",oip->sopt); + } else { + if (value) usageerr("two values for option -%s given !",oip->sopt); + } + opt_do(oip,arg,invert); + arg= ""; + } else { + if (value) usageerr("option -%s does not take a value",oip->sopt); + opt_do(oip,0,invert); + } + } + } + } else { /* arg[0] != '-' */ + query_do(arg); + } +} + +static void read_stdin(void) { + static int used, avail; + static char *buf; + + int anydone, r; + char *newline, *space; + + anydone= 0; + while (!anydone || used) { + while (!(newline= memchr(buf,'\n',used))) { + if (used == avail) { + avail += 20; avail <<= 1; + buf= realloc(buf,avail); + if (!buf) sysfail("realloc stdin buffer",errno); + } + do { + r= read(0,buf+used,avail-used); + } while (r < 0 && errno == EINTR); + if (r == 0) { + if (used) { + /* fake up final newline */ + buf[used++]= '\n'; + r= 1; + } else { + ov_pipe= 0; + return; + } + } + if (r < 0) sysfail("read stdin",errno); + used += r; + } + *newline++= 0; + space= strchr(buf,' '); + if (space) *space++= 0; + process_optarg(buf,0,space); + used -= (newline-buf); + memmove(buf,newline,used); + anydone= 1; + } +} + +int main(int argc, const char *const *argv) { + struct timeval *tv, tvbuf; + adns_query qu; + void *qun_v; + adns_answer *answer; + int r, maxfd; + fd_set readfds, writefds, exceptfds; + const char *arg; + + while ((arg= *++argv)) process_optarg(arg,&argv,0); + + if (!ov_pipe && !ads) usageerr("no domains given, and -f/--pipe not used; try --help"); + + ensure_adns_init(); + + for (;;) { + for (;;) { + qu= ov_asynch ? 0 : outstanding.head ? outstanding.head->qu : 0; + r= adns_check(ads,&qu,&answer,&qun_v); + if (r == EAGAIN) break; + if (r == ESRCH) { if (!ov_pipe) goto x_quit; else break; } + assert(!r); + query_done(qun_v,answer); + } + maxfd= 0; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + if (ov_pipe) { + maxfd= 1; + FD_SET(0,&readfds); + } + tv= 0; + adns_beforeselect(ads, &maxfd, &readfds,&writefds,&exceptfds, &tv,&tvbuf,0); + r= select(maxfd, &readfds,&writefds,&exceptfds, tv); + if (r == -1) { + if (errno == EINTR) continue; + sysfail("select",errno); + } + adns_afterselect(ads, maxfd, &readfds,&writefds,&exceptfds, 0); + if (ov_pipe && FD_ISSET(0,&readfds)) read_stdin(); + } +x_quit: + if (fclose(stdout)) outerr(); + exit(rcode); +} diff --git a/adns-0.6/client/adh-opts.c b/adns-0.6/client/adh-opts.c new file mode 100644 index 0000000..46d5606 --- /dev/null +++ b/adns-0.6/client/adh-opts.c @@ -0,0 +1,337 @@ +/* + * adh-opts.c + * - useful general-purpose resolver client program + * option handling tables etc. + */ +/* + * This file is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "adnshost.h" + +int ov_env=1, ov_pipe=0, ov_asynch=0; +int ov_verbose= 0; +adns_rrtype ov_type= adns_r_none; +int ov_search=0, ov_qc_query=0, ov_qc_anshost=0, ov_qc_cname=1; +int ov_tcp=0, ov_cname=0, ov_format=fmt_default; +char *ov_id= 0; +struct perqueryflags_remember ov_pqfr = { 1,1,1, tm_none }; + +static const struct optioninfo global_options[]= { + { ot_desconly, "global binary options:" }, + { ot_flag, "Do not look at environment variables at all", + "e", "env", &ov_env, 0 }, + { ot_flag, "Read queries on stdin instead of using args", + "f", "pipe", &ov_pipe, 1 }, + { ot_flag, "Allow answers to be reordered", + "a", "asynch", &ov_asynch, 1 }, + + { ot_desconly, "answer/error output format and destination (see below):" }, + { ot_value, "Answers to stdout, errors as messages to stderr (default)", + "Fs", "fmt-simple", &ov_format, fmt_simple }, + { ot_value, "Answers and errors both to stdout in parseable format", + "Fi", "fmt-inline", &ov_format, fmt_inline }, + { ot_value, "Fully-parseable output format (default for --asynch)", + "Fa", "fmt-asynch", &ov_format, fmt_asynch }, + + { ot_desconly, "global verbosity level:" }, + { ot_value, "Do not print anything to stderr", + "Vq", "quiet", &ov_verbose, adns_if_noerrprint }, + { ot_value, "Report unexpected kinds of problem only (default)", + "Vn", "no-quiet", &ov_verbose, 0 }, + { ot_value, "Debugging mode", + "Vd", "debug", &ov_verbose, adns_if_debug }, + + { ot_desconly, "other global options:" }, + { ot_func, "Print usage information", + 0, "help", 0,0, of_help }, + + { ot_end } +}; + +static const struct optioninfo perquery_options[]= { + { ot_desconly, "per-query options:" }, + { ot_funcarg, "Query type (see below)", + "t", "type", 0,0, &of_type, "type" }, + { ot_funcarg, "Do reverse query (address -> name lookup)", + "i", "ptr", 0,0, &of_ptr, "addr" }, + + { ot_desconly, "per-query binary options:" }, + { ot_flag, "Use the search list", + "s", "search", &ov_search, 1 }, + { ot_flag, "Let query domains contain quote-requiring chars", + "Qq", "qc-query", &ov_qc_query, 1 }, + { ot_flag, "Let hostnames in answers contain ...", + "Qa", "qc-anshost", &ov_qc_anshost, 1 }, + { ot_flag, "Prevent CNAME target domains from containing ...", + "Qc", "qc-cname", &ov_qc_cname, 0 }, + { ot_flag, "Force use of a virtual circuit", + "u", "tcp", &ov_tcp, 1 }, + { ot_flag, "Do not display owner name in output", + "Do", "show-owner", &ov_pqfr.show_owner, 0 }, + { ot_flag, "Do not display RR type in output", + "Dt", "show-type", &ov_pqfr.show_type, 0 }, + { ot_flag, "Do not display CNAME target in output", + "Dc", "show-cname", &ov_pqfr.show_cname, 0 }, + + { ot_desconly, "per-query TTL mode (NB TTL is minimum across all info in reply):" }, + { ot_value, "Show the TTL as a TTL", + "Tt", "ttl-ttl", &ov_pqfr.ttl, tm_rel }, + { ot_value, "Show the TTL as a time_t when the data might expire", + "Ta", "ttl-abs", &ov_pqfr.ttl, tm_abs }, + { ot_value, "Do not show the TTL (default)", + "Tn", "no-ttl", &ov_pqfr.ttl, tm_none }, + + { ot_desconly, "per-query CNAME handling mode:" }, + { ot_value, "Call it an error if a CNAME is found", + "Cf", "cname-reject", &ov_cname, adns_qf_cname_forbid }, + { ot_value, "Allow references to CNAMEs in other RRs", + "Cl", "cname-loose", &ov_cname, adns_qf_cname_loose }, + { ot_value, "CNAME ok for query domain, but not in RRs (default)", + "Cs", "cname-ok", &ov_cname, 0 }, + + { ot_desconly, "asynchronous/pipe mode options:" }, + { ot_funcarg, "Set <id>, default is decimal sequence starting 0", + 0, "asynch-id", 0,0, &of_asynch_id, "id" }, + { ot_funcarg, "Cancel the query with id <id> (no error if not found)", + 0, "cancel-id", 0,0, &of_cancel_id, "id" }, + + { ot_end } +}; + +static void printusage(void) { + static const struct optioninfo *const all_optiontables[]= { + global_options, perquery_options, 0 + }; + + const struct optioninfo *const *oiap, *oip=0; + int maxsopt, maxlopt, l; + + maxsopt= maxlopt= 0; + + for (oiap=all_optiontables; *oiap; oiap++) { + for (oip=*oiap; oip->type != ot_end; oip++) { + if (oip->type == ot_funcarg) continue; + if (oip->sopt) { l= strlen(oip->sopt); if (l>maxsopt) maxsopt= l; } + if (oip->lopt) { + l= strlen(oip->lopt); + if (oip->type == ot_flag && !oip->value) l+= 3; + if (l>maxlopt) maxlopt= l; + } + } + } + + fputs("usage: adnshost [global-opts] [query-opts] query-domain\n" + " [[query-opts] query-domain ...]\n" + " adnshost [global-opts] [query-opts] -f|--pipe\n", + stdout); + + for (oiap=all_optiontables; *oiap; oiap++) { + putchar('\n'); + for (oip=*oiap; oip->type != ot_end; oip++) { + switch (oip->type) { + case ot_flag: + if (!oip->value) { + if (oip->sopt) { + printf(" +%-*s --no-%-*s %s\n", + maxsopt, oip->sopt, + maxlopt-2, oip->lopt, + oip->desc); + } else { + printf(" --no-%-*s %s\n", + maxlopt+maxsopt+1, oip->lopt, + oip->desc); + } + break; + } + case ot_value: case ot_func: /* fall through */ + if (oip->sopt) { + printf(" -%-*s --%-*s %s\n", + maxsopt, oip->sopt, + maxlopt+1, oip->lopt, + oip->desc); + } else { + printf(" --%-*s %s\n", + maxlopt+maxsopt+3, oip->lopt, + oip->desc); + } + break; + case ot_funcarg: + if (oip->sopt) { + l= (maxlopt + maxsopt - 9 - + (strlen(oip->sopt) + strlen(oip->lopt) + 2*strlen(oip->argdesc))); + printf(" -%s<%s> / --%s <%s>%*s%s\n", + oip->sopt, oip->argdesc, oip->lopt, oip->argdesc, + l>2 ? l : 2, "", + oip->desc); + } else { + l= (maxlopt + maxsopt + 1 - + (strlen(oip->lopt) + strlen(oip->argdesc))); + printf(" --%s <%s>%*s%s\n", + oip->lopt, oip->argdesc, + l>2 ? l : 2, "", + oip->desc); + } + break; + case ot_desconly: + printf("%s\n", oip->desc); + break; + default: + abort(); + } + } + } + + printf("\nEscaping domains which might start with `-':\n" + " - %-*s Next argument is a domain, but more options may follow\n", + maxlopt+maxsopt+3, "<domain>"); + + fputs("\n" + "Query domains should always be quoted according to master file format.\n" + "\n" + "For binary options, --FOO and --no-FOO are opposites, as are\n" + "-X and +X. In each case the default is the one not listed.\n" + "Per query options stay set a particular way until they are reset,\n" + "whether they appear on the command line or on stdin.\n" + "All global options must preceed the first query domain.\n" + "\n" + "With -f, the input should be lines with either an option, possibly\n" + "with a value argument (separated from the option by a space if it's a long\n" + "option), or a domain (possibly preceded by a hyphen and a space to\n" + "distinguish it from an option).\n" + "\n" + "Output format is master file format without class or TTL by default:\n" + " [<owner>] [<ttl>] [<type>] <data>\n" + "or if the <owner> domain refers to a CNAME and --show-cname is on\n" + " [<owner>] [<ttl>] CNAME <cname>\n" + " [<cname>] [<ttl>] <type> <data>\n" + "When a query fails you get an error message to stderr (with --fmt-simple).\n" + "Specify --fmt-inline for lines like this (broken here for readability):\n" + " ; failed <statustype> <statusnum> <statusabbrev> \\\n" + " [<owner>] [<ttl>] [<cname>] \"<status string>\"\n" + "If you use --fmt-asynch, which is the default for --asynch,\n" + "each answer (success or failure) is preceded by a line\n" + " <id> <nrrs> <statustype> <statusnum> <statusabbrev> \\\n" + " [<owner>] [<ttl>] [<cname>] \"<status string>\"\n" + "where <nrrs> is the number of RRs that follow and <cname> will be `$' or\n" + "the CNAME target; the CNAME indirection and error formats above are not used.\n" + "\n" + "Exit status:\n" + " 0 all went well\n" + " 1-6 at least one query failed with statustype:\n" + " 1 localfail )\n" + " 2 remotefail ) temporary errors\n" + " 3 tempfail __)_________________\n" + " 4 misconfig )\n" + " 5 misquery ) permanent errors\n" + " 6 permfail )\n" + " 10 system trouble\n" + " 11 usage problems\n" + "\n" + "Query types (see adns.h; default is addr):\n" + " ns soa ptr mx rp addr - enhanced versions\n" + " cname hinfo txt - types with only one version\n" + " a ns- soa- ptr- mx- rp- - _raw versions\n" + "Default is addr, or ptr for -i/--ptr queries\n", + stdout); + if (ferror(stdout)) sysfail("write usage message",errno); +} + +void of_help(const struct optioninfo *oi, const char *arg) { + printusage(); + if (fclose(stdout)) sysfail("finish writing output",errno); + exit(0); +} + +typedef int comparer_type(const char **optp, const struct optioninfo *entry); + +static int oc_long(const char **optp, const struct optioninfo *entry) { + return entry->lopt && !strcmp(*optp,entry->lopt); +} + +static int oc_short(const char **optp, const struct optioninfo *entry) { + const char *sopt; + int l; + + sopt= entry->sopt; + if (!sopt) return 0; + l= strlen(sopt); + if (memcmp(*optp,sopt,l)) return 0; + (*optp) += l; + return 1; +} + +static const struct optioninfo *find1(const char **optp, + const struct optioninfo *table, + comparer_type *comparer) { + for (;;) { + if (table->type == ot_end) return 0; + if (comparer(optp,table)) return table; + table++; + } +} + +static const struct optioninfo *find(const char **optp, + const char *prefix, + comparer_type *comparer) { + const struct optioninfo *oip; + const char *opt; + + opt= *optp; + oip= find1(optp,perquery_options,comparer); + if (oip) return oip; + oip= find1(optp,global_options,comparer); + if (!oip) usageerr("unknown option %s%s",prefix,opt); + if (ads) usageerr("global option %s%s specified after query domain(s)",prefix,opt); + return oip; +} + +const struct optioninfo *opt_findl(const char *opt) { return find(&opt,"--",oc_long); } +const struct optioninfo *opt_finds(const char **optp) { return find(optp,"-",oc_short); } + +static void noninvert(const struct optioninfo *oip) NONRETURNING; +static void noninvert(const struct optioninfo *oip) { + usageerr("option %s%s%s%s%s may not be inverted", + oip->sopt ? "-" : "", oip->sopt ? oip->sopt : "", + oip->lopt && oip->sopt ? " / " : "", + oip->lopt ? "--" : "", oip->lopt ? oip->lopt : ""); +} + +void opt_do(const struct optioninfo *oip, const char *arg, int invert) { + switch (oip->type) { + case ot_flag: + assert(!arg); + *oip->storep= !invert; + return; + case ot_value: + assert(!arg); + if (invert) noninvert(oip); + *oip->storep= oip->value; + return; + case ot_func: case ot_funcarg: + if (invert) noninvert(oip); + oip->func(oip,arg); + return; + default: + abort(); + } +} diff --git a/adns-0.6/client/adh-query.c b/adns-0.6/client/adh-query.c new file mode 100644 index 0000000..bae71f4 --- /dev/null +++ b/adns-0.6/client/adh-query.c @@ -0,0 +1,274 @@ +/* + * adh-query.c + * - useful general-purpose resolver client program + * make queries and print answers + */ +/* + * This file is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "adnshost.h" + +adns_state ads; +struct outstanding_list outstanding; + +static unsigned long idcounter; + +void ensure_adns_init(void) { + int r; + + if (ads) return; + + if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) sysfail("ignore SIGPIPE",errno); + r= adns_init(&ads, + adns_if_noautosys|adns_if_nosigpipe | + (ov_env ? 0 : adns_if_noenv) | + ov_verbose, + 0); + if (r) sysfail("adns_init",r); + + if (ov_format == fmt_default) + ov_format= ov_asynch ? fmt_asynch : fmt_simple; +} + +static void prep_query(struct query_node **qun_r, int *quflags_r) { + struct query_node *qun; + char idbuf[20]; + + if (ov_pipe && !ads) usageerr("-f/--pipe not consistent with domains on command line"); + ensure_adns_init(); + + qun= malloc(sizeof(*qun)); + qun->pqfr= ov_pqfr; + if (ov_id) { + qun->id= xstrsave(ov_id); + } else { + sprintf(idbuf,"%lu",idcounter++); + idcounter &= 0x0fffffffflu; + qun->id= xstrsave(idbuf); + } + + *quflags_r= + (ov_search ? adns_qf_search : 0) | + (ov_tcp ? adns_qf_usevc : 0) | + ((ov_pqfr.show_owner || ov_format == fmt_simple) ? adns_qf_owner : 0) | + (ov_qc_query ? adns_qf_quoteok_query : 0) | + (ov_qc_anshost ? adns_qf_quoteok_anshost : 0) | + (ov_qc_cname ? 0 : adns_qf_quoteok_cname) | + ov_cname, + + *qun_r= qun; +} + +void of_ptr(const struct optioninfo *oi, const char *arg) { + struct query_node *qun; + int quflags, r; + struct sockaddr_in sa; + + memset(&sa,0,sizeof(sa)); + sa.sin_family= AF_INET; + if (!inet_aton(arg,&sa.sin_addr)) usageerr("invalid IP address %s",arg); + + prep_query(&qun,&quflags); + r= adns_submit_reverse(ads, + (struct sockaddr*)&sa, + ov_type == adns_r_none ? adns_r_ptr : ov_type, + quflags, + qun, + &qun->qu); + if (r) sysfail("adns_submit_reverse",r); + + LIST_LINK_TAIL(outstanding,qun); +} + +void query_do(const char *domain) { + struct query_node *qun; + int quflags, r; + + prep_query(&qun,&quflags); + r= adns_submit(ads, domain, + ov_type == adns_r_none ? adns_r_addr : ov_type, + quflags, + qun, + &qun->qu); + if (r) sysfail("adns_submit",r); + + LIST_LINK_TAIL(outstanding,qun); +} + +static void dequeue_query(struct query_node *qun) { + LIST_UNLINK(outstanding,qun); + free(qun->id); + free(qun); +} + +static void print_withspace(const char *str) { + if (printf("%s ", str) == EOF) outerr(); +} + +static void print_ttl(struct query_node *qun, adns_answer *answer) { + unsigned long ttl; + time_t now; + + switch (qun->pqfr.ttl) { + case tm_none: + return; + case tm_rel: + if (time(&now) == (time_t)-1) sysfail("get current time",errno); + ttl= answer->expires < now ? 0 : answer->expires - now; + break; + case tm_abs: + ttl= answer->expires; + break; + default: + abort(); + } + if (printf("%lu ",ttl) == EOF) outerr(); +} + +static void print_owner_ttl(struct query_node *qun, adns_answer *answer) { + if (qun->pqfr.show_owner) print_withspace(answer->owner); + print_ttl(qun,answer); +} + +static void check_status(adns_status st) { + static const adns_status statuspoints[]= { + adns_s_ok, + adns_s_max_localfail, adns_s_max_remotefail, adns_s_max_tempfail, + adns_s_max_misconfig, adns_s_max_misquery + }; + + const adns_status *spp; + int minrcode; + + for (minrcode=0, spp=statuspoints; + spp < statuspoints + (sizeof(statuspoints)/sizeof(statuspoints[0])); + spp++) + if (st > *spp) minrcode++; + if (rcode < minrcode) rcode= minrcode; +} + +static void print_status(adns_status st, struct query_node *qun, adns_answer *answer) { + const char *statustypeabbrev, *statusabbrev, *statusstring; + + statustypeabbrev= adns_errtypeabbrev(st); + statusabbrev= adns_errabbrev(st); + statusstring= adns_strerror(st); + assert(!strchr(statusstring,'"')); + + if (printf("%s %d %s ", statustypeabbrev, st, statusabbrev) + == EOF) outerr(); + print_owner_ttl(qun,answer); + if (qun->pqfr.show_cname) + print_withspace(answer->cname ? answer->cname : "$"); + if (printf("\"%s\"\n", statusstring) == EOF) outerr(); +} + +static void print_dnsfail(adns_status st, struct query_node *qun, adns_answer *answer) { + int r; + const char *typename, *statusstring; + adns_status ist; + + if (ov_format == fmt_inline) { + if (fputs("; failed ",stdout) == EOF) outerr(); + print_status(st,qun,answer); + return; + } + assert(ov_format == fmt_simple); + if (st == adns_s_nxdomain) { + r= fprintf(stderr,"%s does not exist\n", answer->owner); + } else { + ist= adns_rr_info(answer->type, &typename, 0,0,0,0); + if (st == adns_s_nodata) { + r= fprintf(stderr,"%s has no %s record\n", answer->owner, typename); + } else { + statusstring= adns_strerror(st); + r= fprintf(stderr,"Error during DNS %s lookup for %s: %s\n", + typename, answer->owner, statusstring); + } + } + if (r == EOF) sysfail("write error message to stderr",errno); +} + +void query_done(struct query_node *qun, adns_answer *answer) { + adns_status st, ist; + int rrn, nrrs; + const char *rrp, *realowner, *typename; + char *datastr; + + st= answer->status; + nrrs= answer->nrrs; + if (ov_format == fmt_asynch) { + check_status(st); + if (printf("%s %d ", qun->id, nrrs) == EOF) outerr(); + print_status(st,qun,answer); + } else { + if (qun->pqfr.show_cname && answer->cname) { + print_owner_ttl(qun,answer); + if (qun->pqfr.show_type) print_withspace("CNAME"); + if (printf("%s\n", answer->cname) == EOF) outerr(); + } + if (st) { + check_status(st); + print_dnsfail(st,qun,answer); + } + } + if (qun->pqfr.show_owner) { + realowner= answer->cname ? answer->cname : answer->owner; + assert(realowner); + } else { + realowner= 0; + } + if (nrrs) { + for (rrn=0, rrp = answer->rrs.untyped; + rrn < nrrs; + rrn++, rrp += answer->rrsz) { + if (realowner) print_withspace(realowner); + print_ttl(qun,answer); + ist= adns_rr_info(answer->type, &typename, 0, 0, rrp, &datastr); + if (ist == adns_s_nomemory) sysfail("adns_rr_info failed",ENOMEM); + assert(!ist); + if (qun->pqfr.show_type) print_withspace(typename); + if (printf("%s\n",datastr) == EOF) outerr(); + free(datastr); + } + } + if (fflush(stdout)) outerr(); + free(answer); + dequeue_query(qun); +} + +void of_asynch_id(const struct optioninfo *oi, const char *arg) { + free(ov_id); + ov_id= xstrsave(arg); +} + +void of_cancel_id(const struct optioninfo *oi, const char *arg) { + struct query_node *qun; + + for (qun= outstanding.head; + qun && strcmp(qun->id,arg); + qun= qun->next); + if (!qun) return; + adns_cancel(qun->qu); + dequeue_query(qun); +} diff --git a/adns-0.6/client/adnshost.h b/adns-0.6/client/adnshost.h new file mode 100644 index 0000000..8b459b3 --- /dev/null +++ b/adns-0.6/client/adnshost.h @@ -0,0 +1,118 @@ +/* + * adnshost.h + * - useful general-purpose resolver client program, header file + */ +/* + * This file is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef ADNSHOST_H_INCLUDED +#define ADNSHOST_H_INCLUDED + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <stdarg.h> +#include <stdlib.h> +#include <assert.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "config.h" +#include "adns.h" +#include "dlist.h" + +/* declarations related to option processing */ + +struct optioninfo; +typedef void optfunc(const struct optioninfo *oi, const char *arg); + +struct optioninfo { + enum oi_type { + ot_end, ot_desconly, + ot_flag, ot_value, ot_func, ot_funcarg + } type; + const char *desc; + const char *sopt, *lopt; + int *storep, value; + optfunc *func; + const char *argdesc; +}; + +enum ttlmode { tm_none, tm_rel, tm_abs }; +enum outputformat { fmt_default, fmt_simple, fmt_inline, fmt_asynch }; + +struct perqueryflags_remember { + int show_owner, show_type, show_cname; + int ttl; +}; + +extern int ov_env, ov_pipe, ov_asynch; +extern int ov_verbose; +extern adns_rrtype ov_type; +extern int ov_search, ov_qc_query, ov_qc_anshost, ov_qc_cname; +extern int ov_tcp, ov_cname, ov_format; +extern char *ov_id; +extern struct perqueryflags_remember ov_pqfr; + +extern optfunc of_help, of_type, of_ptr, of_asynch_id, of_cancel_id; + +const struct optioninfo *opt_findl(const char *opt); +const struct optioninfo *opt_finds(const char **optp); +void opt_do(const struct optioninfo *oip, const char *arg, int invert); + +/* declarations related to query processing */ + +struct query_node { + struct query_node *next, *back; + struct perqueryflags_remember pqfr; + char *id; + adns_query qu; +}; + +extern adns_state ads; +extern struct outstanding_list { struct query_node *head, *tail; } outstanding; + +void ensure_adns_init(void); +void query_do(const char *domain); +void query_done(struct query_node *qun, adns_answer *answer); + +void of_asynch_id(const struct optioninfo *oi, const char *arg); +void of_cancel_id(const struct optioninfo *oi, const char *arg); + +/* declarations related to main program and useful utility functions */ + +void sysfail(const char *what, int errnoval) NONRETURNING; +void usageerr(const char *what, ...) NONRETURNPRINTFFORMAT(1,2); +void outerr(void) NONRETURNING; + +void *xmalloc(size_t sz); +char *xstrsave(const char *str); + +extern int rcode; + +#endif diff --git a/adns-0.6/client/adnslogres.c b/adns-0.6/client/adnslogres.c new file mode 100644 index 0000000..c732823 --- /dev/null +++ b/adns-0.6/client/adnslogres.c @@ -0,0 +1,239 @@ +/* + * adnslogres.c + * - a replacement for the Apache logresolve program using adns + */ +/* + * This file is + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * Copyright (C) 1999 Ian Jackson <ian@davenant.greenend.org.uk> + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * This version was originally supplied by Tony Finch, but has been + * modified by Ian Jackson as it was incorporated into adns. + */ + +static const char * const cvsid = + "$Id: adnslogres.c,v 1.1.1.1 2000-02-16 17:32:28 sdyoung Exp $"; + +#include <sys/types.h> +#include <sys/time.h> + +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> + +#include "adns.h" + +/* maximum number of concurrent DNS queries */ +#define MAXPENDING 1000 + +/* maximum length of a line */ +#define MAXLINE 1024 + +/* option flags */ +#define OPT_DEBUG 1 +#define OPT_POLL 2 + +static const char *progname; + +#define msg(fmt, args...) fprintf(stderr, "%s: " fmt "\n", progname, ##args) + +static void aargh(const char *cause) { + const char *why = strerror(errno); + if (!why) why = "Unknown error"; + msg("%s: %s (%d)", cause, why, errno); + exit(1); +} + +/* + * Parse the IP address and convert to a reverse domain name. + */ +static char *ipaddr2domain(char *start, char **addr, char **rest) { + static char buf[30]; /* "123.123.123.123.in-addr.arpa.\0" */ + char *ptrs[5]; + int i; + + ptrs[0]= start; +retry: + while (!isdigit(*ptrs[0])) + if (!*ptrs[0]++) { + strcpy(buf, "invalid."); + *addr= *rest= NULL; + return buf; + } + for (i= 1; i < 5; i++) { + ptrs[i]= ptrs[i-1]; + while (isdigit(*ptrs[i]++)); + if ((i == 4 && !isspace(ptrs[i][-1])) || + (i != 4 && ptrs[i][-1] != '.') || + (ptrs[i]-ptrs[i-1] > 4)) { + ptrs[0]= ptrs[i]-1; + goto retry; + } + } + sprintf(buf, "%.*s.%.*s.%.*s.%.*s.in-addr.arpa.", + ptrs[4]-ptrs[3]-1, ptrs[3], + ptrs[3]-ptrs[2]-1, ptrs[2], + ptrs[2]-ptrs[1]-1, ptrs[1], + ptrs[1]-ptrs[0]-1, ptrs[0]); + *addr= ptrs[0]; + *rest= ptrs[4]-1; + return buf; +} + +static void printline(FILE *outf, char *start, char *addr, char *rest, char *domain) { + if (domain) + fprintf(outf, "%.*s%s%s", addr - start, start, domain, rest); + else + fputs(start, outf); + if (ferror(outf)) aargh("write output"); +} + +typedef struct logline { + struct logline *next; + char *start, *addr, *rest; + adns_query query; +} logline; + +static logline *readline(FILE *inf, adns_state adns, int opts) { + static char buf[MAXLINE]; + char *str; + logline *line; + + if (fgets(buf, MAXLINE, inf)) { + str= malloc(sizeof(*line) + strlen(buf) + 1); + if (!str) aargh("malloc"); + line= (logline*)str; + line->next= NULL; + line->start= str+sizeof(logline); + strcpy(line->start, buf); + str= ipaddr2domain(line->start, &line->addr, &line->rest); + if (opts & OPT_DEBUG) + msg("submitting %.*s -> %s", line->rest-line->addr, line->addr, str); + if (adns_submit(adns, str, adns_r_ptr, + adns_qf_quoteok_cname|adns_qf_cname_loose, + NULL, &line->query)) + aargh("adns_submit"); + return line; + } + if (!feof(inf)) + aargh("fgets"); + return NULL; +} + +static void proclog(FILE *inf, FILE *outf, int opts) { + int eof, err, len; + adns_state adns; + adns_answer *answer; + logline *head, *tail, *line; + + errno= adns_init(&adns, (opts & OPT_DEBUG) ? adns_if_debug : 0, 0); + if (errno) aargh("adns_init"); + head= tail= readline(inf, adns, opts); + len= 1; eof= 0; + while (head) { + if (opts & OPT_DEBUG) + msg("%d in queue; checking %.*s", len, + head->rest-head->addr, head->addr); + if (eof || len > MAXPENDING) + if (opts & OPT_POLL) + err= adns_wait_poll(adns, &head->query, &answer, NULL); + else + err= adns_wait(adns, &head->query, &answer, NULL); + else + err= adns_check(adns, &head->query, &answer, NULL); + if (err != EAGAIN) { + printline(outf, head->start, head->addr, head->rest, + answer->status == adns_s_ok ? *answer->rrs.str : NULL); + line= head; head= head->next; + free(line); free(answer); + len--; + } + if (!eof) { + line= readline(inf, adns, opts); + if (!line) + eof= 1; + else { + if (!head) + head= line; + else + tail->next= line; + tail= line; + len++; + } + } + } + adns_finish(adns); +} + +static void usage(void) { + fprintf(stderr, "usage: %s [-d] [-p] [logfile]\n", progname); + exit(1); +} + +int main(int argc, char *argv[]) { + int c, opts; + FILE *inf; + + progname= strrchr(*argv, '/'); + if (progname) + progname++; + else + progname= *argv; + opts= 0; + + while ((c= getopt(argc, argv, "dp")) != -1) + switch (c) { + case 'd': + opts|= OPT_DEBUG; + break; + case 'p': + opts|= OPT_POLL; + break; + default: + usage(); + } + + argc-= optind; + argv+= optind; + + inf= NULL; + if (argc == 0) + inf= stdin; + else if (argc == 1) + inf= fopen(*argv, "r"); + else + usage(); + + if (!inf) + aargh("couldn't open input"); + + proclog(inf, stdout, opts); + + if (fclose(inf)) + aargh("fclose input"); + if (fclose(stdout)) + aargh("fclose output"); + + return 0; +} diff --git a/adns-0.6/client/adnsresfilter.c b/adns-0.6/client/adnsresfilter.c new file mode 100644 index 0000000..f265773 --- /dev/null +++ b/adns-0.6/client/adnsresfilter.c @@ -0,0 +1,454 @@ +/* + * adnsresfilter.c + * - filter which does resolving, not part of the library + */ +/* + * This file is + * Copyright (C) 1999 Ian Jackson <ian@davenant.greenend.org.uk> + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <search.h> +#include <assert.h> +#include <ctype.h> + +#include <sys/fcntl.h> + +#include "adns.h" +#include "config.h" +#include "dlist.h" +#include "tvarith.h" + +struct outqueuenode { + struct outqueuenode *next, *back; + void *buffer; + char *textp; + int textlen; + struct timeval printbefore; + struct treething *addr; +}; + +static int bracket, forever, address; +static unsigned long timeout=100; +static adns_rrtype rrt= adns_r_ptr; + +static int outblocked, inputeof; +static struct { struct outqueuenode *head, *tail; } outqueue; +static int peroutqueuenode, outqueuelen; + +static struct sockaddr_in sa; +static adns_state ads; + +static char addrtextbuf[14]; +static int cbyte, inbyte, inbuf; +static unsigned char bytes[4]; +static struct timeval printbefore; + +struct treething { + unsigned char bytes[4]; + adns_query qu; + adns_answer *ans; +}; + +static struct treething *newthing; +static void *treeroot; + +static int nonblock(int fd, int isnonblock) { + int r; + + r= fcntl(fd,F_GETFL); + if (r==-1) return -1; + r= fcntl(fd,F_SETFL, isnonblock ? r|O_NONBLOCK : r&~O_NONBLOCK); + if (r==-1) return -1; + return 0; +} + +static void quit(int exitstatus) NONRETURNING; +static void quit(int exitstatus) { + nonblock(0,0); + nonblock(1,0); + exit(exitstatus); +} + +static void sysfail(const char *what) NONRETURNING; +static void sysfail(const char *what) { + fprintf(stderr,"adnsresfilter: system call failed: %s: %s\n",what,strerror(errno)); + quit(2); +} + +static void *xmalloc(size_t sz) { + void *r; + r= malloc(sz); if (r) return r; + sysfail("malloc"); +} + +static void outputerr(void) NONRETURNING; +static void outputerr(void) { sysfail("write to stdout"); } + +static void usage(void) { + if (printf("usage: adnsresfilter [<options ...>]\n" + " adnsresfilter -h|--help\n" + "options: -t<milliseconds>|--timeout <milliseconds>\n" + " -w|--wait (always wait for queries to time out or fail)\n" + " -b|--brackets (require [...] around IP addresses)\n" + " -a|--address (always include [address] in output)\n" + " -u|--unchecked (do not forward map for checking)\n" + "Timeout is the maximum amount to delay any particular bit of output for.\n" + "Lookups will go on in the background. Default timeout = 100 (ms).\n") + == EOF) outputerr(); +} + +static void usageerr(const char *why) NONRETURNING; +static void usageerr(const char *why) { + fprintf(stderr,"adnsresfilter: bad usage: %s\n",why); + usage(); + quit(1); +} + +static void adnsfail(const char *what, int e) NONRETURNING; +static void adnsfail(const char *what, int e) { + fprintf(stderr,"adnsresfilter: adns call failed: %s: %s\n",what,strerror(e)); + quit(2); +} + +static void settimeout(const char *arg) { + char *ep; + timeout= strtoul(arg,&ep,0); + if (*ep) usageerr("invalid timeout"); +} + +static void parseargs(const char *const *argv) { + const char *arg; + int c; + + while ((arg= *++argv)) { + if (arg[0] != '-') usageerr("no non-option arguments are allowed"); + if (arg[1] == '-') { + if (!strcmp(arg,"--brackets")) { + bracket= 1; + } else if (!strcmp(arg,"--unchecked")) { + rrt= adns_r_ptr_raw; + } else if (!strcmp(arg,"--wait")) { + forever= 1; + } else if (!strcmp(arg,"--address")) { + address= 1; + } else if (!strcmp(arg,"--help")) { + usage(); quit(0); + } else if (!strcmp(arg,"--timeout")) { + if (!(arg= *++argv)) usageerr("--timeout needs a value"); + settimeout(arg); + forever= 0; + } else { + usageerr("unknown long option"); + } + } else { + while ((c= *++arg)) { + switch (c) { + case 'b': + bracket= 1; + break; + case 'u': + rrt= adns_r_ptr_raw; + break; + case 'w': + forever= 1; + break; + case 'a': + address= 1; + break; + case 'h': + usage(); + quit(0); + case 't': + if (*++arg) settimeout(arg); + else if ((arg= *++argv)) settimeout(arg); + else usageerr("-t needs a value"); + forever= 0; + arg= "\0"; + break; + default: + usageerr("unknown short option"); + } + } + } + } +} + +static void queueoutchar(int c) { + struct outqueuenode *entry; + + entry= outqueue.tail; + if (!entry || entry->addr || entry->textlen >= peroutqueuenode) { + peroutqueuenode= !peroutqueuenode || !entry || entry->addr ? 128 : + peroutqueuenode >= 1024 ? 4096 : peroutqueuenode<<2; + entry= xmalloc(sizeof(*entry)); + entry->buffer= xmalloc(peroutqueuenode); + entry->textp= entry->buffer; + entry->textlen= 0; + entry->addr= 0; + LIST_LINK_TAIL(outqueue,entry); + outqueuelen++; + } + entry->textp[entry->textlen++]= c; +} + +static void queueoutstr(const char *str, int len) { + while (len-- > 0) queueoutchar(*str++); +} + +static void writestdout(struct outqueuenode *entry) { + int r; + + while (entry->textlen) { + r= write(1, entry->textp, entry->textlen); + if (r < 0) { + if (errno == EINTR) continue; + if (errno == EAGAIN) { outblocked= 1; break; } + sysfail("write stdout"); + } + assert(r <= entry->textlen); + entry->textp += r; + entry->textlen -= r; + } + if (!entry->textlen) { + LIST_UNLINK(outqueue,entry); + free(entry->buffer); + free(entry); + outqueuelen--; + } +} + +static void replacetextwithname(struct outqueuenode *entry) { + char *name, *newbuf; + int namelen, newlen; + + name= entry->addr->ans->rrs.str[0]; + namelen= strlen(name); + if (!address) { + free(entry->buffer); + entry->buffer= 0; + entry->textp= name; + entry->textlen= namelen; + } else { + newlen= entry->textlen + namelen + (bracket ? 0 : 2); + newbuf= xmalloc(newlen + 1); + sprintf(newbuf, bracket ? "%s%.*s" : "%s[%.*s]", name, entry->textlen, entry->textp); + free(entry->buffer); + entry->buffer= entry->textp= newbuf; + entry->textlen= newlen; + } +} + +static void checkadnsqueries(void) { + adns_query qu; + adns_answer *ans; + void *context; + struct treething *foundthing; + int r; + + for (;;) { + qu= 0; context= 0; ans= 0; + r= adns_check(ads,&qu,&ans,&context); + if (r == ESRCH || r == EAGAIN) break; + assert(!r); + foundthing= context; + foundthing->ans= ans; + foundthing->qu= 0; + } +} + +static void restartbuf(void) { + if (inbuf>0) queueoutstr(addrtextbuf,inbuf); + inbuf= 0; +} + +static int comparer(const void *a, const void *b) { + return memcmp(a,b,4); +} + +static void procaddr(void) { + struct treething *foundthing; + void **searchfound; + struct outqueuenode *entry; + int r; + + if (!newthing) { + newthing= xmalloc(sizeof(struct treething)); + newthing->qu= 0; + newthing->ans= 0; + } + + memcpy(newthing->bytes,bytes,4); + searchfound= tsearch(newthing,&treeroot,comparer); + if (!searchfound) sysfail("tsearch"); + foundthing= *searchfound; + + if (foundthing == newthing) { + newthing= 0; + memcpy(&sa.sin_addr,bytes,4); + r= adns_submit_reverse(ads, (const struct sockaddr*)&sa, + rrt,0,foundthing,&foundthing->qu); + if (r) adnsfail("submit",r); + } + entry= xmalloc(sizeof(*entry)); + entry->buffer= xmalloc(inbuf); + entry->textp= entry->buffer; + memcpy(entry->textp,addrtextbuf,inbuf); + entry->textlen= inbuf; + entry->addr= foundthing; + entry->printbefore= printbefore; + LIST_LINK_TAIL(outqueue,entry); + outqueuelen++; + inbuf= 0; + cbyte= -1; +} + +static void startaddr(void) { + bytes[cbyte=0]= 0; + inbyte= 0; +} + +static void readstdin(void) { + char readbuf[512], *p; + int r, c, nbyte; + + while ((r= read(0,readbuf,sizeof(readbuf))) <= 0) { + if (r == 0) { inputeof= 1; return; } + if (r == EAGAIN) return; + if (r != EINTR) sysfail("read stdin"); + } + for (p=readbuf; r>0; r--,p++) { + c= *p; + if (cbyte==-1 && bracket && c=='[') { + addrtextbuf[inbuf++]= c; + startaddr(); + } else if (cbyte==-1 && !bracket && !isalnum(c)) { + queueoutchar(c); + startaddr(); + } else if (cbyte>=0 && inbyte<3 && c>='0' && c<='9' && + (nbyte= bytes[cbyte]*10 + (c-'0')) <= 255) { + bytes[cbyte]= nbyte; + addrtextbuf[inbuf++]= c; + inbyte++; + } else if (cbyte>=0 && cbyte<3 && inbyte>0 && c=='.') { + bytes[++cbyte]= 0; + addrtextbuf[inbuf++]= c; + inbyte= 0; + } else if (cbyte==3 && inbyte>0 && bracket && c==']') { + addrtextbuf[inbuf++]= c; + procaddr(); + } else if (cbyte==3 && inbyte>0 && !bracket && !isalnum(c)) { + procaddr(); + queueoutchar(c); + startaddr(); + } else { + restartbuf(); + queueoutchar(c); + cbyte= -1; + if (!bracket && !isalnum(c)) startaddr(); + } + } + if (cbyte==3 && inbyte>0 && !bracket) procaddr(); +} + +static void startup(void) { + int r; + + if (nonblock(0,1)) sysfail("set stdin to nonblocking mode"); + if (nonblock(1,1)) sysfail("set stdout to nonblocking mode"); + memset(&sa,0,sizeof(sa)); + sa.sin_family= AF_INET; + r= adns_init(&ads,0,0); if (r) adnsfail("init",r); + cbyte= -1; + inbyte= -1; + inbuf= 0; + if (!bracket) startaddr(); +} + +int main(int argc, const char *const *argv) { + int r, maxfd; + fd_set readfds, writefds, exceptfds; + struct outqueuenode *entry; + struct timeval *tv, tvbuf, now; + + parseargs(argv); + startup(); + + while (!inputeof || outqueue.head) { + maxfd= 2; + tv= 0; + FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); + if ((entry= outqueue.head) && !outblocked) { + if (!entry->addr) { + writestdout(entry); + continue; + } + if (entry->addr->ans) { + if (entry->addr->ans->nrrs) + replacetextwithname(entry); + entry->addr= 0; + continue; + } + r= gettimeofday(&now,0); if (r) sysfail("gettimeofday"); + if (forever) { + tv= 0; + } else if (!timercmp(&now,&entry->printbefore,<)) { + entry->addr= 0; + continue; + } else { + tvbuf.tv_sec= entry->printbefore.tv_sec - now.tv_sec - 1; + tvbuf.tv_usec= entry->printbefore.tv_usec - now.tv_usec + 1000000; + tvbuf.tv_sec += tvbuf.tv_usec / 1000000; + tvbuf.tv_usec %= 1000000; + tv= &tvbuf; + } + adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds, + &tv,&tvbuf,&now); + } + if (outblocked) FD_SET(1,&writefds); + if (!inputeof && outqueuelen<1024) FD_SET(0,&readfds); + + r= select(maxfd,&readfds,&writefds,&exceptfds,tv); + if (r < 0) { if (r == EINTR) continue; else sysfail("select"); } + + r= gettimeofday(&now,0); if (r) sysfail("gettimeofday"); + adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,&now); + checkadnsqueries(); + + if (FD_ISSET(0,&readfds)) { + if (!forever) { + printbefore= now; + timevaladd(&printbefore,timeout); + } + readstdin(); + } else if (FD_ISSET(1,&writefds)) { + outblocked= 0; + } + } + if (nonblock(0,0)) sysfail("un-nonblock stdin"); + if (nonblock(1,0)) sysfail("un-nonblock stdout"); + if (ferror(stdin) || fclose(stdin)) sysfail("read stdin"); + if (fclose(stdout)) sysfail("close stdout"); + exit(0); +} diff --git a/adns-0.6/client/adnstest.c b/adns-0.6/client/adnstest.c new file mode 100644 index 0000000..2460dbf --- /dev/null +++ b/adns-0.6/client/adnstest.c @@ -0,0 +1,337 @@ +/* + * adnstest.c + * - simple test program, not part of the library + */ +/* + * This file is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <sys/time.h> +#include <unistd.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "adns.h" + +#include "config.h" + +#ifndef OUTPUTSTREAM +# define OUTPUTSTREAM stdout +#endif + +struct myctx { + adns_query qu; + int doneyet, found; + const char *fdom; +}; + +static struct myctx *mcs; +static adns_state ads; +static adns_rrtype *types_a; + +static void quitnow(int rc) NONRETURNING; +static void quitnow(int rc) { + free(mcs); + free(types_a); + if (ads) adns_finish(ads); + + exit(rc); +} + +#ifndef HAVE_POLL +#undef poll +int poll(struct pollfd *ufds, int nfds, int timeout) { + fputs("poll(2) not supported on this system\n",stderr); + quitnow(5); +} +#define adns_beforepoll(a,b,c,d,e) 0 +#define adns_afterpoll(a,b,c,d) 0 +#endif + +static void failure_status(const char *what, adns_status st) NONRETURNING; +static void failure_status(const char *what, adns_status st) { + fprintf(stderr,"adns failure: %s: %s\n",what,adns_strerror(st)); + quitnow(2); +} + +static void failure_errno(const char *what, int errnoval) NONRETURNING; +static void failure_errno(const char *what, int errnoval) { + fprintf(stderr,"adns failure: %s: errno=%d\n",what,errnoval); + quitnow(2); +} + +static void usageerr(const char *why) NONRETURNING; +static void usageerr(const char *why) { + fprintf(stderr, + "bad usage: %s\n" + "usage: adnstest [-<initflagsnum>[,<owninitflags>]] [/<initstring>]\n" + " [ :<typenum>,... ]\n" + " [ [<queryflagsnum>[,<ownqueryflags>]/]<domain> ... ]\n" + "initflags: p use poll(2) instead of select(2)\n" + " s use adns_wait with specified query, instead of 0\n" + "queryflags: a print status abbrevs instead of strings\n" + "exit status: 0 ok (though some queries may have failed)\n" + " 1 used by test harness to indicate test failed\n" + " 2 unable to submit or init or some such\n" + " 3 unexpected failure\n" + " 4 usage error\n" + " 5 operation not supported on this system\n", + why); + quitnow(4); +} + +static const adns_rrtype defaulttypes[]= { + adns_r_a, + adns_r_ns_raw, + adns_r_cname, + adns_r_soa_raw, + adns_r_ptr_raw, + adns_r_hinfo, + adns_r_mx_raw, + adns_r_txt, + adns_r_rp_raw, + + adns_r_addr, + adns_r_ns, + adns_r_ptr, + adns_r_mx, + + adns_r_soa, + adns_r_rp, + + adns_r_none +}; + +static void dumptype(adns_status ri, const char *rrtn, const char *fmtn) { + fprintf(stdout, "%s(%s)%s%s", + ri ? "?" : rrtn, ri ? "?" : fmtn ? fmtn : "-", + ri ? " " : "", ri ? adns_strerror(ri) : ""); +} + +static void fdom_split(const char *fdom, const char **dom_r, int *qf_r, + char *ownflags, int ownflags_l) { + int qf; + char *ep; + + qf= strtoul(fdom,&ep,0); + if (*ep == ',' && strchr(ep,'/')) { + ep++; + while (*ep != '/') { + if (--ownflags_l <= 0) { fputs("too many flags\n",stderr); quitnow(3); } + *ownflags++= *ep++; + } + } + if (*ep != '/') { *dom_r= fdom; *qf_r= 0; } + else { *dom_r= ep+1; *qf_r= qf; } + *ownflags= 0; +} + +static int consistsof(const char *string, const char *accept) { + return strspn(string,accept) == strlen(string); +} + +int main(int argc, char *const *argv) { + adns_query qu; + struct myctx *mc, *mcw; + void *mcr; + adns_answer *ans; + const char *initstring, *rrtn, *fmtn; + const char *const *fdomlist, *domain; + char *show, *cp; + int len, i, qc, qi, tc, ti, ch, qflags, initflagsnum; + adns_status ri; + int r; + const adns_rrtype *types; + struct timeval now; + char ownflags[10]; + char *ep; + const char *initflags, *owninitflags; + + if (argv[0] && argv[1] && argv[1][0] == '-') { + initflags= argv[1]+1; + argv++; + } else { + initflags= ""; + } + if (argv[0] && argv[1] && argv[1][0] == '/') { + initstring= argv[1]+1; + argv++; + } else { + initstring= 0; + } + + initflagsnum= strtoul(initflags,&ep,0); + if (*ep == ',') { + owninitflags= ep+1; + if (!consistsof(owninitflags,"ps")) usageerr("unknown owninitflag"); + } else if (!*ep) { + owninitflags= ""; + } else { + usageerr("bad <initflagsnum>[,<owninitflags>]"); + } + + if (argv[0] && argv[1] && argv[1][0] == ':') { + for (cp= argv[1]+1, tc=1; (ch= *cp); cp++) + if (ch==',') tc++; + types_a= malloc(sizeof(*types_a)*(tc+1)); + if (!types_a) { perror("malloc types"); quitnow(3); } + for (cp= argv[1]+1, ti=0; ti<tc; ti++) { + types_a[ti]= strtoul(cp,&cp,10); + if ((ch= *cp)) { + if (ch != ',') usageerr("unexpected char (not comma) in or between types"); + cp++; + } + } + types_a[ti]= adns_r_none; + types= types_a; + argv++; + } else { + types_a= 0; + types= defaulttypes; + } + + if (!(argv[0] && argv[1])) usageerr("no query domains supplied"); + fdomlist= (const char *const*)argv+1; + + for (qc=0; fdomlist[qc]; qc++); + for (tc=0; types[tc] != adns_r_none; tc++); + mcs= malloc(tc ? sizeof(*mcs)*qc*tc : 1); + if (!mcs) { perror("malloc mcs"); quitnow(3); } + + if (initstring) { + r= adns_init_strcfg(&ads, + (adns_if_debug|adns_if_noautosys|adns_if_checkc_freq) + ^initflagsnum, + stdout,initstring); + } else { + r= adns_init(&ads, + (adns_if_debug|adns_if_noautosys)^initflagsnum, + 0); + } + if (r) failure_errno("init",r); + + for (qi=0; qi<qc; qi++) { + fdom_split(fdomlist[qi],&domain,&qflags,ownflags,sizeof(ownflags)); + if (!consistsof(ownflags,"a")) usageerr("unknown ownqueryflag"); + for (ti=0; ti<tc; ti++) { + mc= &mcs[qi*tc+ti]; + mc->doneyet= 0; + mc->fdom= fdomlist[qi]; + + fprintf(stdout,"%s flags %d type %d",domain,qflags,types[ti]); + r= adns_submit(ads,domain,types[ti],qflags,mc,&mc->qu); + if (r == ENOSYS) { + fprintf(stdout," not implemented\n"); + mc->qu= 0; + mc->doneyet= 1; + } else if (r) { + failure_errno("submit",r); + } else { + ri= adns_rr_info(types[ti], &rrtn,&fmtn,0, 0,0); + putc(' ',stdout); + dumptype(ri,rrtn,fmtn); + fprintf(stdout," submitted\n"); + } + } + } + + for (;;) { + for (qi=0; qi<qc; qi++) { + for (ti=0; ti<tc; ti++) { + mc= &mcs[qi*tc+ti]; + mc->found= 0; + } + } + for (adns_forallqueries_begin(ads); + (qu= adns_forallqueries_next(ads,&mcr)); + ) { + mc= mcr; + assert(qu == mc->qu); + assert(!mc->doneyet); + mc->found= 1; + } + mcw= 0; + for (qi=0; qi<qc; qi++) { + for (ti=0; ti<tc; ti++) { + mc= &mcs[qi*tc+ti]; + if (mc->doneyet) continue; + assert(mc->found); + if (!mcw) mcw= mc; + } + } + if (!mcw) break; + + if (strchr(owninitflags,'s')) { + qu= mcw->qu; + mc= mcw; + } else { + qu= 0; + mc= 0; + } + + if (strchr(owninitflags,'p')) { + r= adns_wait_poll(ads,&qu,&ans,&mcr); + } else { + r= adns_wait(ads,&qu,&ans,&mcr); + } + if (r) failure_errno("wait/check",r); + + if (mc) assert(mcr==mc); + else mc= mcr; + assert(qu==mc->qu); + assert(!mc->doneyet); + + fdom_split(mc->fdom,&domain,&qflags,ownflags,sizeof(ownflags)); + + if (gettimeofday(&now,0)) { perror("gettimeofday"); quitnow(3); } + + ri= adns_rr_info(ans->type, &rrtn,&fmtn,&len, 0,0); + fprintf(stdout, "%s flags %d type ",domain,qflags); + dumptype(ri,rrtn,fmtn); + fprintf(stdout, "%s%s: %s; nrrs=%d; cname=%s; owner=%s; ttl=%ld\n", + ownflags[0] ? " ownflags=" : "", ownflags, + strchr(ownflags,'a') + ? adns_errabbrev(ans->status) + : adns_strerror(ans->status), + ans->nrrs, + ans->cname ? ans->cname : "$", + ans->owner ? ans->owner : "$", + (long)ans->expires - (long)now.tv_sec); + if (ans->nrrs) { + assert(!ri); + for (i=0; i<ans->nrrs; i++) { + ri= adns_rr_info(ans->type, 0,0,0, ans->rrs.bytes + i*len, &show); + if (ri) failure_status("info",ri); + fprintf(stdout," %s\n",show); + free(show); + } + } + free(ans); + + mc->doneyet= 1; + } + + quitnow(0); +} diff --git a/adns-0.6/client/fanftest.c b/adns-0.6/client/fanftest.c new file mode 100644 index 0000000..2051f28 --- /dev/null +++ b/adns-0.6/client/fanftest.c @@ -0,0 +1,85 @@ +/* + * fanftest.c + * - a small test program from Tony Finch + */ +/* + * This file is + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * Copyright (C) 1999 Ian Jackson <ian@davenant.greenend.org.uk> + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> + * Copyright (C) 1999 Tony Finch <dot@dotat.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * This version was originally supplied by Tony Finch, but has been + * modified by Ian Jackson as it was incorporated into adns. + */ + +static const char * const cvsid = + "$Id: fanftest.c,v 1.1.1.1 2000-02-16 17:32:29 sdyoung Exp $"; + +#include <sys/types.h> +#include <sys/time.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +#include "adns.h" + +static const char *progname; + +static void aargh(const char *msg) { + fprintf(stderr, "%s: %s: %s (%d)\n", progname, msg, + strerror(errno) ? strerror(errno) : "Unknown error", errno); + exit(1); +} + +int main(int argc, char *argv[]) { + adns_state adns; + adns_query query; + adns_answer *answer; + + progname= strrchr(*argv, '/'); + if (progname) + progname++; + else + progname= *argv; + + if (argc != 2) { + fprintf(stderr, "usage: %s <domain>\n", progname); + exit(1); + } + + errno= adns_init(&adns, adns_if_debug, 0); + if (errno) aargh("adns_init"); + + errno= adns_submit(adns, argv[1], adns_r_ptr, + adns_qf_quoteok_cname|adns_qf_cname_loose, + NULL, &query); + if (errno) aargh("adns_submit"); + + errno= adns_wait(adns, &query, &answer, NULL); + if (errno) aargh("adns_init"); + + printf("%s\n", answer->status == adns_s_ok ? *answer->rrs.str : "dunno"); + + adns_finish(adns); + + return 0; +} diff --git a/adns-0.6/client/x.gdb b/adns-0.6/client/x.gdb new file mode 100644 index 0000000..2ee7597 --- /dev/null +++ b/adns-0.6/client/x.gdb @@ -0,0 +1,2 @@ +file adnsresfilter_s +set args <testinput -t2000 |