X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=client%2Fadh-query.c;h=cc5dc122f2846f194aaee48244063b43b9e7b0d7;hb=10554ed5982b03b2a486c0f09d479f8806f04c6a;hp=fa8577977f7aacb5bf138daf64adb4a56f8ba768;hpb=d1cff511d87e902d96bcd39544635f81728de1ae;p=adns.git diff --git a/client/adh-query.c b/client/adh-query.c index fa85779..cc5dc12 100644 --- a/client/adh-query.c +++ b/client/adh-query.c @@ -26,32 +26,37 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -struct query_node { - struct query_node *next, *back; - struct perqueryflags_remember pqfr; - char *id; - adns_query qu; -}; +#include "adnshost.h" -static adns_state ads; -static struct { struct query_node *head, *tail; } outstanding; +adns_state ads; +struct outstanding_list outstanding; static unsigned long idcounter; -static void domain_do(const char *domain) { - struct query_node *qun; - char idbuf[20]; +void ensure_adns_init(void) { + int r; + + if (ads) return; - if (!ads) { - if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) sysfail("ignore SIGPIPE"); - r= adns_init(&ads, - adns_if_noautosys|adns_if_nosigpipe | - (ov_env ? 0 : adns_ifnoenv) | - ov_verbose, - 0); - if (r) sysfail("adns_init",r); - } + 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) { @@ -61,18 +66,215 @@ static void domain_do(const char *domain) { 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; +} - r= adns_submit(ads, domain, type, - (ov_search ? adns_qf_search : 0) | - (ov_tcp ? adns_qf_usevc : 0) | - (ov_pqfr.show_owner ? 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, +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); + qun->owner= xstrsave(arg); + 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); + qun->owner= xstrsave(domain); + 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); - DLIST_LINK_TAIL(outstanding,qun); + 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 const char *owner_show(struct query_node *qun, adns_answer *answer) { + return answer->owner ? answer->owner : qun->owner; +} + +static void print_owner_ttl(struct query_node *qun, adns_answer *answer) { + if (qun->pqfr.show_owner) print_withspace(owner_show(qun,answer)); + 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", owner_show(qun,answer)); + } 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", owner_show(qun,answer), typename); + } else { + statusstring= adns_strerror(st); + r= fprintf(stderr,"Error during DNS %s lookup for %s: %s\n", + typename, owner_show(qun,answer), 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 : owner_show(qun,answer); + 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); }