1 /* 2 * adnstest.c 3 * - simple test program, not part of the library 4 */ 5 /* 6 * This file is 7 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk> 8 * 9 * It is part of adns, which is 10 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk> 11 * Copyright (C) 1999-2000 Tony Finch <dot@dotat.at> 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2, or (at your option) 16 * any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software Foundation, 25 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 26 */ 27 28 #ifdef ADNS_JGAA_WIN32 29 # include "adns_win32.h" 30 #else 31 # include <stdio.h> 32 # include <sys/time.h> 33 # include <unistd.h> 34 # include <assert.h> 35 # include <stdlib.h> 36 # include <string.h> 37 # include <errno.h> 38 #endif 39 40 #include "config.h" 41 #include "adns.h" 42 43 #ifdef ADNS_REGRESS_TEST 44 # include "hredirect.h" 45 #endif 46 47 struct myctx { 48 adns_query qu; 49 int doneyet, found; 50 const char *fdom; 51 }; 52 53 static struct myctx *mcs; 54 static adns_state ads; 55 static adns_rrtype *types_a; 56 57 static void quitnow(int rc) NONRETURNING; 58 static void quitnow(int rc) { 59 free(mcs); 60 free(types_a); 61 if (ads) adns_finish(ads); 62 63 exit(rc); 64 } 65 66 #ifndef HAVE_POLL 67 #undef poll 68 int poll(struct pollfd *ufds, int nfds, int timeout) { 69 fputs("poll(2) not supported on this system\n",stderr); 70 quitnow(5); 71 return -1; /* compiler food */ 72 } 73 #define adns_beforepoll(a,b,c,d,e) 0 74 #define adns_afterpoll(a,b,c,d) 0 75 #endif 76 77 static void failure_status(const char *what, adns_status st) NONRETURNING; 78 static void failure_status(const char *what, adns_status st) { 79 fprintf(stderr,"adns failure: %s: %s\n",what,adns_strerror(st)); 80 quitnow(2); 81 } 82 83 static void failure_errno(const char *what, int errnoval) NONRETURNING; 84 static void failure_errno(const char *what, int errnoval) { 85 fprintf(stderr,"adns failure: %s: errno=%d\n",what,errnoval); 86 quitnow(2); 87 } 88 89 static void usageerr(const char *why) NONRETURNING; 90 static void usageerr(const char *why) { 91 fprintf(stderr, 92 "bad usage: %s\n" 93 "usage: adnstest [-<initflagsnum>[,<owninitflags>]] [/<initstring>]\n" 94 " [ :<typenum>,... ]\n" 95 " [ [<queryflagsnum>[,<ownqueryflags>]/]<domain> ... ]\n" 96 "initflags: p use poll(2) instead of select(2)\n" 97 " s use adns_wait with specified query, instead of 0\n" 98 "queryflags: a print status abbrevs instead of strings\n" 99 "exit status: 0 ok (though some queries may have failed)\n" 100 " 1 used by test harness to indicate test failed\n" 101 " 2 unable to submit or init or some such\n" 102 " 3 unexpected failure\n" 103 " 4 usage error\n" 104 " 5 operation not supported on this system\n", 105 why); 106 quitnow(4); 107 } 108 109 static const adns_rrtype defaulttypes[]= { 110 adns_r_a, 111 adns_r_ns_raw, 112 adns_r_cname, 113 adns_r_soa_raw, 114 adns_r_ptr_raw, 115 adns_r_hinfo, 116 adns_r_mx_raw, 117 adns_r_txt, 118 adns_r_rp_raw, 119 120 adns_r_addr, 121 adns_r_ns, 122 adns_r_ptr, 123 adns_r_mx, 124 125 adns_r_soa, 126 adns_r_rp, 127 128 adns_r_none 129 }; 130 131 static void dumptype(adns_status ri, const char *rrtn, const char *fmtn) { 132 fprintf(stdout, "%s(%s)%s%s", 133 ri ? "?" : rrtn, ri ? "?" : fmtn ? fmtn : "-", 134 ri ? " " : "", ri ? adns_strerror(ri) : ""); 135 } 136 137 static void fdom_split(const char *fdom, const char **dom_r, int *qf_r, 138 char *ownflags, int ownflags_l) { 139 int qf; 140 char *ep; 141 142 qf= strtoul(fdom,&ep,0); 143 if (*ep == ',' && strchr(ep,'/')) { 144 ep++; 145 while (*ep != '/') { 146 if (--ownflags_l <= 0) { fputs("too many flags\n",stderr); quitnow(3); } 147 *ownflags++= *ep++; 148 } 149 } 150 if (*ep != '/') { *dom_r= fdom; *qf_r= 0; } 151 else { *dom_r= ep+1; *qf_r= qf; } 152 *ownflags= 0; 153 } 154 155 static int consistsof(const char *string, const char *accept) { 156 return strspn(string,accept) == strlen(string); 157 } 158 159 int main(int argc, char *const *argv) { 160 adns_query qu; 161 struct myctx *mc, *mcw; 162 void *mcr; 163 adns_answer *ans; 164 const char *initstring, *rrtn, *fmtn; 165 const char *const *fdomlist, *domain; 166 char *show, *cp; 167 int len, i, qc, qi, tc, ti, ch, qflags, initflagsnum; 168 adns_status ri; 169 int r; 170 const adns_rrtype *types; 171 struct timeval now; 172 char ownflags[10]; 173 char *ep; 174 const char *initflags, *owninitflags; 175 176 if (argv[0] && argv[1] && argv[1][0] == '-') { 177 initflags= argv[1]+1; 178 argv++; 179 } else { 180 initflags= ""; 181 } 182 if (argv[0] && argv[1] && argv[1][0] == '/') { 183 initstring= argv[1]+1; 184 argv++; 185 } else { 186 initstring= 0; 187 } 188 189 initflagsnum= strtoul(initflags,&ep,0); 190 if (*ep == ',') { 191 owninitflags= ep+1; 192 if (!consistsof(owninitflags,"ps")) usageerr("unknown owninitflag"); 193 } else if (!*ep) { 194 owninitflags= ""; 195 } else { 196 usageerr("bad <initflagsnum>[,<owninitflags>]"); 197 } 198 199 if (argv[0] && argv[1] && argv[1][0] == ':') { 200 for (cp= argv[1]+1, tc=1; (ch= *cp); cp++) 201 if (ch==',') tc++; 202 types_a= malloc(sizeof(*types_a)*(tc+1)); 203 if (!types_a) { perror("malloc types"); quitnow(3); } 204 for (cp= argv[1]+1, ti=0; ti<tc; ti++) { 205 types_a[ti]= strtoul(cp,&cp,10); 206 if ((ch= *cp)) { 207 if (ch != ',') usageerr("unexpected char (not comma) in or between types"); 208 cp++; 209 } 210 } 211 types_a[ti]= adns_r_none; 212 types= types_a; 213 argv++; 214 } else { 215 types_a= 0; 216 types= defaulttypes; 217 } 218 219 if (!(argv[0] && argv[1])) usageerr("no query domains supplied"); 220 fdomlist= (const char *const*)argv+1; 221 222 for (qc=0; fdomlist[qc]; qc++); 223 for (tc=0; types[tc] != adns_r_none; tc++); 224 mcs= malloc(tc ? sizeof(*mcs)*qc*tc : 1); 225 if (!mcs) { perror("malloc mcs"); quitnow(3); } 226 227 setvbuf(stdout,0,_IOLBF,0); 228 229 if (initstring) { 230 r= adns_init_strcfg(&ads, 231 (adns_if_debug|adns_if_noautosys|adns_if_checkc_freq) 232 ^initflagsnum, 233 stdout,initstring); 234 } else { 235 r= adns_init(&ads, 236 (adns_if_debug|adns_if_noautosys)^initflagsnum, 237 0); 238 } 239 if (r) failure_errno("init",r); 240 241 for (qi=0; qi<qc; qi++) { 242 fdom_split(fdomlist[qi],&domain,&qflags,ownflags,sizeof(ownflags)); 243 if (!consistsof(ownflags,"a")) usageerr("unknown ownqueryflag"); 244 for (ti=0; ti<tc; ti++) { 245 mc= &mcs[qi*tc+ti]; 246 mc->doneyet= 0; 247 mc->fdom= fdomlist[qi]; 248 249 fprintf(stdout,"%s flags %d type %d",domain,qflags,types[ti]); 250 r= adns_submit(ads,domain,types[ti],qflags,mc,&mc->qu); 251 if (r == ENOSYS) { 252 fprintf(stdout," not implemented\n"); 253 mc->qu= 0; 254 mc->doneyet= 1; 255 } else if (r) { 256 failure_errno("submit",r); 257 } else { 258 ri= adns_rr_info(types[ti], &rrtn,&fmtn,0, 0,0); 259 putc(' ',stdout); 260 dumptype(ri,rrtn,fmtn); 261 fprintf(stdout," submitted\n"); 262 } 263 } 264 } 265 266 for (;;) { 267 for (qi=0; qi<qc; qi++) { 268 for (ti=0; ti<tc; ti++) { 269 mc= &mcs[qi*tc+ti]; 270 mc->found= 0; 271 } 272 } 273 for (adns_forallqueries_begin(ads); 274 (qu= adns_forallqueries_next(ads,&mcr)); 275 ) { 276 mc= mcr; 277 assert(qu == mc->qu); 278 assert(!mc->doneyet); 279 mc->found= 1; 280 } 281 mcw= 0; 282 for (qi=0; qi<qc; qi++) { 283 for (ti=0; ti<tc; ti++) { 284 mc= &mcs[qi*tc+ti]; 285 if (mc->doneyet) continue; 286 assert(mc->found); 287 if (!mcw) mcw= mc; 288 } 289 } 290 if (!mcw) break; 291 292 if (strchr(owninitflags,'s')) { 293 qu= mcw->qu; 294 mc= mcw; 295 } else { 296 qu= 0; 297 mc= 0; 298 } 299 300 #ifdef HAVE_POLL 301 if (strchr(owninitflags,'p')) { 302 r= adns_wait_poll(ads,&qu,&ans,&mcr); 303 } else 304 #endif 305 { 306 r= adns_wait(ads,&qu,&ans,&mcr); 307 } 308 if (r) failure_errno("wait/check",r); 309 310 if (mc) assert(mcr==mc); 311 else mc= mcr; 312 assert(qu==mc->qu); 313 assert(!mc->doneyet); 314 315 fdom_split(mc->fdom,&domain,&qflags,ownflags,sizeof(ownflags)); 316 317 if (gettimeofday(&now,0)) { perror("gettimeofday"); quitnow(3); } 318 319 ri= adns_rr_info(ans->type, &rrtn,&fmtn,&len, 0,0); 320 fprintf(stdout, "%s flags %d type ",domain,qflags); 321 dumptype(ri,rrtn,fmtn); 322 fprintf(stdout, "%s%s: %s; nrrs=%d; cname=%s; owner=%s; ttl=%ld\n", 323 ownflags[0] ? " ownflags=" : "", ownflags, 324 strchr(ownflags,'a') 325 ? adns_errabbrev(ans->status) 326 : adns_strerror(ans->status), 327 ans->nrrs, 328 ans->cname ? ans->cname : "$", 329 ans->owner ? ans->owner : "$", 330 (long)ans->expires - (long)now.tv_sec); 331 if (ans->nrrs) { 332 assert(!ri); 333 for (i=0; i<ans->nrrs; i++) { 334 ri= adns_rr_info(ans->type, 0,0,0, ans->rrs.bytes + i*len, &show); 335 if (ri) failure_status("info",ri); 336 fprintf(stdout," %s\n",show); 337 free(show); 338 } 339 } 340 free(ans); 341 342 mc->doneyet= 1; 343 } 344 345 quitnow(0); 346 } 347