1 /* 2 * setup.c 3 * - configuration file parsing 4 * - management of global state 5 */ 6 /* 7 * This file is 8 * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> 9 * 10 * It is part of adns, which is 11 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk> 12 * Copyright (C) 1999-2000 Tony Finch <dot@dotat.at> 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2, or (at your option) 17 * any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software Foundation, 26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 */ 28 29 #ifdef ADNS_JGAA_WIN32 30 # include "adns_win32.h" 31 # include <iphlpapi.h> 32 #else 33 # include <stdlib.h> 34 # include <errno.h> 35 # include <limits.h> 36 # include <unistd.h> 37 # include <fcntl.h> 38 # include <netdb.h> 39 # include <sys/socket.h> 40 # include <netinet/in.h> 41 # include <arpa/inet.h> 42 #endif 43 44 #include "internal.h" 45 46 static void readconfig(adns_state ads, const char *filename, int warnmissing); 47 48 static void addserver(adns_state ads, struct in_addr addr) { 49 int i; 50 struct server *ss; 51 52 for (i=0; i<ads->nservers; i++) { 53 if (ads->servers[i].addr.s_addr == addr.s_addr) { 54 adns__debug(ads,-1,0,"duplicate nameserver %s ignored",inet_ntoa(addr)); 55 return; 56 } 57 } 58 59 if (ads->nservers>=MAXSERVERS) { 60 adns__diag(ads,-1,0,"too many nameservers, ignoring %s",inet_ntoa(addr)); 61 return; 62 } 63 64 ss= ads->servers+ads->nservers; 65 ss->addr= addr; 66 ads->nservers++; 67 } 68 69 static void freesearchlist(adns_state ads) { 70 if (ads->nsearchlist) free(*ads->searchlist); 71 free(ads->searchlist); 72 } 73 74 static void saveerr(adns_state ads, int en) { 75 if (!ads->configerrno) ads->configerrno= en; 76 } 77 78 static void configparseerr(adns_state ads, const char *fn, int lno, 79 const char *fmt, ...) { 80 va_list al; 81 82 saveerr(ads,EINVAL); 83 if (!ads->diagfile || (ads->iflags & adns_if_noerrprint)) return; 84 85 if (lno==-1) fprintf(ads->diagfile,"adns: %s: ",fn); 86 else fprintf(ads->diagfile,"adns: %s:%d: ",fn,lno); 87 va_start(al,fmt); 88 vfprintf(ads->diagfile,fmt,al); 89 va_end(al); 90 fputc('\n',ads->diagfile); 91 } 92 93 static int nextword(const char **bufp_io, const char **word_r, int *l_r) { 94 const char *p, *q; 95 96 p= *bufp_io; 97 while (ctype_whitespace(*p)) p++; 98 if (!*p) return 0; 99 100 q= p; 101 while (*q && !ctype_whitespace(*q)) q++; 102 103 *l_r= q-p; 104 *word_r= p; 105 *bufp_io= q; 106 107 return 1; 108 } 109 110 static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) { 111 struct in_addr ia; 112 113 if (!inet_aton(buf,&ia)) { 114 configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf); 115 return; 116 } 117 adns__debug(ads,-1,0,"using nameserver %s",inet_ntoa(ia)); 118 addserver(ads,ia); 119 } 120 121 static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) { 122 const char *bufp, *word; 123 char *newchars, **newptrs, **pp; 124 int count, tl, l; 125 126 if (!buf) return; 127 128 bufp= buf; 129 count= 0; 130 tl= 0; 131 while (nextword(&bufp,&word,&l)) { count++; tl += l+1; } 132 133 newptrs= malloc(sizeof(char*)*count); if (!newptrs) { saveerr(ads,errno); return; } 134 newchars= malloc(tl); if (!newchars) { saveerr(ads,errno); free(newptrs); return; } 135 136 bufp= buf; 137 pp= newptrs; 138 while (nextword(&bufp,&word,&l)) { 139 *pp++= newchars; 140 memcpy(newchars,word,l); 141 newchars += l; 142 *newchars++ = 0; 143 } 144 145 freesearchlist(ads); 146 ads->nsearchlist= count; 147 ads->searchlist= newptrs; 148 } 149 150 static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) { 151 const char *word; 152 char tbuf[200], *slash, *ep; 153 struct in_addr base, mask; 154 int l; 155 unsigned long initial, baselocal; 156 157 if (!buf) return; 158 159 ads->nsortlist= 0; 160 while (nextword(&buf,&word,&l)) { 161 if (ads->nsortlist >= MAXSORTLIST) { 162 adns__diag(ads,-1,0,"too many sortlist entries, ignoring %.*s onwards",l,word); 163 return; 164 } 165 166 if (l >= sizeof(tbuf)) { 167 configparseerr(ads,fn,lno,"sortlist entry `%.*s' too long",l,word); 168 continue; 169 } 170 171 memcpy(tbuf,word,l); tbuf[l]= 0; 172 slash= strchr(tbuf,'/'); 173 if (slash) *slash++= 0; 174 175 if (!inet_aton(tbuf,&base)) { 176 configparseerr(ads,fn,lno,"invalid address `%s' in sortlist",tbuf); 177 continue; 178 } 179 180 if (slash) { 181 if (strchr(slash,'.')) { 182 if (!inet_aton(slash,&mask)) { 183 configparseerr(ads,fn,lno,"invalid mask `%s' in sortlist",slash); 184 continue; 185 } 186 if (base.s_addr & ~mask.s_addr) { 187 configparseerr(ads,fn,lno, 188 "mask `%s' in sortlist overlaps address `%s'",slash,tbuf); 189 continue; 190 } 191 } else { 192 initial= strtoul(slash,&ep,10); 193 if (*ep || initial>32) { 194 configparseerr(ads,fn,lno,"mask length `%s' invalid",slash); 195 continue; 196 } 197 mask.s_addr= htonl((0x0ffffffffUL) << (32-initial)); 198 } 199 } else { 200 baselocal= ntohl(base.s_addr); 201 if (!(baselocal & 0x080000000UL)) /* class A */ 202 mask.s_addr= htonl(0x0ff000000UL); 203 else if ((baselocal & 0x0c0000000UL) == 0x080000000UL) 204 mask.s_addr= htonl(0x0ffff0000UL); /* class B */ 205 else if ((baselocal & 0x0f0000000UL) == 0x0e0000000UL) 206 mask.s_addr= htonl(0x0ff000000UL); /* class C */ 207 else { 208 configparseerr(ads,fn,lno, 209 "network address `%s' in sortlist is not in classed ranges," 210 " must specify mask explicitly", tbuf); 211 continue; 212 } 213 } 214 215 ads->sortlist[ads->nsortlist].base= base; 216 ads->sortlist[ads->nsortlist].mask= mask; 217 ads->nsortlist++; 218 } 219 } 220 221 static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) { 222 const char *word; 223 char *ep; 224 unsigned long v; 225 int l; 226 227 if (!buf) return; 228 229 while (nextword(&buf,&word,&l)) { 230 if (l==5 && !memcmp(word,"debug",5)) { 231 ads->iflags |= adns_if_debug; 232 continue; 233 } 234 if (l>=6 && !memcmp(word,"ndots:",6)) { 235 v= strtoul(word+6,&ep,10); 236 if (l==6 || ep != word+l || v > INT_MAX) { 237 configparseerr(ads,fn,lno,"option `%.*s' malformed or has bad value",l,word); 238 continue; 239 } 240 ads->searchndots= v; 241 continue; 242 } 243 if (l>=12 && !memcmp(word,"adns_checkc:",12)) { 244 if (!strcmp(word+12,"none")) { 245 ads->iflags &= ~adns_if_checkc_freq; 246 ads->iflags |= adns_if_checkc_entex; 247 } else if (!strcmp(word+12,"entex")) { 248 ads->iflags &= ~adns_if_checkc_freq; 249 ads->iflags |= adns_if_checkc_entex; 250 } else if (!strcmp(word+12,"freq")) { 251 ads->iflags |= adns_if_checkc_freq; 252 } else { 253 configparseerr(ads,fn,lno, "option adns_checkc has bad value `%s' " 254 "(must be none, entex or freq", word+12); 255 } 256 continue; 257 } 258 adns__diag(ads,-1,0,"%s:%d: unknown option `%.*s'", fn,lno, l,word); 259 } 260 } 261 262 static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) { 263 ads->nservers= 0; 264 } 265 266 static void ccf_include(adns_state ads, const char *fn, int lno, const char *buf) { 267 if (!*buf) { 268 configparseerr(ads,fn,lno,"`include' directive with no filename"); 269 return; 270 } 271 readconfig(ads,buf,1); 272 } 273 274 static const struct configcommandinfo { 275 const char *name; 276 void (*fn)(adns_state ads, const char *fn, int lno, const char *buf); 277 } configcommandinfos[]= { 278 { "nameserver", ccf_nameserver }, 279 { "domain", ccf_search }, 280 { "search", ccf_search }, 281 { "sortlist", ccf_sortlist }, 282 { "options", ccf_options }, 283 { "clearnameservers", ccf_clearnss }, 284 { "include", ccf_include }, 285 { 0 } 286 }; 287 288 typedef union { 289 FILE *file; 290 const char *text; 291 } getline_ctx; 292 293 static int gl_file(adns_state ads, getline_ctx *src_io, const char *filename, 294 int lno, char *buf, int buflen) { 295 FILE *file= src_io->file; 296 int c, i; 297 char *p; 298 299 p= buf; 300 buflen--; 301 i= 0; 302 303 for (;;) { /* loop over chars */ 304 if (i == buflen) { 305 adns__diag(ads,-1,0,"%s:%d: line too long, ignored",filename,lno); 306 goto x_badline; 307 } 308 c= getc(file); 309 if (!c) { 310 adns__diag(ads,-1,0,"%s:%d: line contains nul, ignored",filename,lno); 311 goto x_badline; 312 } else if (c == '\n') { 313 break; 314 } else if (c == EOF) { 315 if (ferror(file)) { 316 saveerr(ads,errno); 317 adns__diag(ads,-1,0,"%s:%d: read error: %s",filename,lno,strerror(errno)); 318 return -1; 319 } 320 if (!i) return -1; 321 break; 322 } else { 323 *p++= c; 324 i++; 325 } 326 } 327 328 *p++= 0; 329 return i; 330 331 x_badline: 332 saveerr(ads,EINVAL); 333 while ((c= getc(file)) != EOF && c != '\n'); 334 return -2; 335 } 336 337 static int gl_text(adns_state ads, getline_ctx *src_io, const char *filename, 338 int lno, char *buf, int buflen) { 339 const char *cp= src_io->text; 340 int l; 341 342 if (!cp || !*cp) return -1; 343 344 if (*cp == ';' || *cp == '\n') cp++; 345 l= strcspn(cp,";\n"); 346 src_io->text = cp+l; 347 348 if (l >= buflen) { 349 adns__diag(ads,-1,0,"%s:%d: line too long, ignored",filename,lno); 350 saveerr(ads,EINVAL); 351 return -2; 352 } 353 354 memcpy(buf,cp,l); 355 buf[l]= 0; 356 return l; 357 } 358 359 static void readconfiggeneric(adns_state ads, const char *filename, 360 int (*getline)(adns_state ads, getline_ctx*, 361 const char *filename, int lno, 362 char *buf, int buflen), 363 /* Returns >=0 for success, -1 for EOF or error 364 * (error will have been reported), or -2 for 365 * bad line was encountered, try again. 366 */ 367 getline_ctx gl_ctx) { 368 char linebuf[2000], *p, *q; 369 int lno, l, dirl; 370 const struct configcommandinfo *ccip; 371 372 for (lno=1; 373 (l= getline(ads,&gl_ctx, filename,lno, linebuf,sizeof(linebuf))) != -1; 374 lno++) { 375 if (l == -2) continue; 376 while (l>0 && ctype_whitespace(linebuf[l-1])) l--; 377 linebuf[l]= 0; 378 p= linebuf; 379 while (ctype_whitespace(*p)) p++; 380 if (*p == '#' || !*p) continue; 381 q= p; 382 while (*q && !ctype_whitespace(*q)) q++; 383 dirl= q-p; 384 for (ccip=configcommandinfos; 385 ccip->name && !((int)strlen(ccip->name)==dirl && !memcmp(ccip->name,p,q-p)); 386 ccip++); 387 if (!ccip->name) { 388 adns__diag(ads,-1,0,"%s:%d: unknown configuration directive `%.*s'", 389 filename,lno,q-p,p); 390 continue; 391 } 392 while (ctype_whitespace(*q)) q++; 393 ccip->fn(ads,filename,lno,q); 394 } 395 } 396 397 static const char *instrum_getenv(adns_state ads, const char *envvar) { 398 const char *value; 399 400 value= getenv(envvar); 401 if (!value) adns__debug(ads,-1,0,"environment variable %s not set",envvar); 402 else adns__debug(ads,-1,0,"environment variable %s set to `%s'",envvar,value); 403 return value; 404 } 405 406 static void readconfig(adns_state ads, const char *filename, int warnmissing) { 407 getline_ctx gl_ctx; 408 409 gl_ctx.file= fopen(filename,"r"); 410 if (!gl_ctx.file) { 411 if (errno == ENOENT) { 412 if (warnmissing) 413 adns__debug(ads,-1,0,"configuration file `%s' does not exist",filename); 414 return; 415 } 416 saveerr(ads,errno); 417 adns__diag(ads,-1,0,"cannot open configuration file `%s': %s", 418 filename,strerror(errno)); 419 return; 420 } 421 422 readconfiggeneric(ads,filename,gl_file,gl_ctx); 423 424 fclose(gl_ctx.file); 425 } 426 427 static void readconfigtext(adns_state ads, const char *text, const char *showname) { 428 getline_ctx gl_ctx; 429 430 gl_ctx.text= text; 431 readconfiggeneric(ads,showname,gl_text,gl_ctx); 432 } 433 434 static void readconfigenv(adns_state ads, const char *envvar) { 435 const char *filename; 436 437 if (ads->iflags & adns_if_noenv) { 438 adns__debug(ads,-1,0,"not checking environment variable `%s'",envvar); 439 return; 440 } 441 filename= instrum_getenv(ads,envvar); 442 if (filename) readconfig(ads,filename,1); 443 } 444 445 static void readconfigenvtext(adns_state ads, const char *envvar) { 446 const char *textdata; 447 448 if (ads->iflags & adns_if_noenv) { 449 adns__debug(ads,-1,0,"not checking environment variable `%s'",envvar); 450 return; 451 } 452 textdata= instrum_getenv(ads,envvar); 453 if (textdata) readconfigtext(ads,textdata,envvar); 454 } 455 456 457 int adns__setnonblock(adns_state ads, ADNS_SOCKET fd) { 458 #ifdef ADNS_JGAA_WIN32 459 unsigned long Val = 1; 460 return (ioctlsocket (fd, FIONBIO, &Val) == 0) ? 0 : -1; 461 #else 462 int r; 463 464 r= fcntl(fd,F_GETFL,0); if (r<0) return errno; 465 r |= O_NONBLOCK; 466 r= fcntl(fd,F_SETFL,r); if (r<0) return errno; 467 return 0; 468 #endif 469 } 470 471 static int init_begin(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { 472 adns_state ads; 473 474 #ifdef ADNS_JGAA_WIN32 475 WORD wVersionRequested = MAKEWORD( 2, 0 ); 476 WSADATA wsaData; 477 int err; 478 #endif 479 480 ads= malloc(sizeof(*ads)); if (!ads) return errno; 481 482 ads->iflags= flags; 483 ads->diagfile= diagfile; 484 ads->configerrno= 0; 485 LIST_INIT(ads->udpw); 486 LIST_INIT(ads->tcpw); 487 LIST_INIT(ads->childw); 488 LIST_INIT(ads->output); 489 ads->forallnext= 0; 490 ads->nextid= 0x311f; 491 ads->udpsocket= ads->tcpsocket= -1; 492 adns__vbuf_init(&ads->tcpsend); 493 adns__vbuf_init(&ads->tcprecv); 494 ads->tcprecv_skip= 0; 495 ads->nservers= ads->nsortlist= ads->nsearchlist= ads->tcpserver= 0; 496 ads->searchndots= 1; 497 ads->tcpstate= server_disconnected; 498 timerclear(&ads->tcptimeout); 499 ads->searchlist= 0; 500 501 #ifdef ADNS_JGAA_WIN32 502 err= WSAStartup( wVersionRequested, &wsaData ); 503 if ( err != 0 ) { 504 if (ads->diagfile && ads->iflags & adns_if_debug) 505 fprintf(ads->diagfile,"adns: WSAStartup() failed. \n"); 506 return -1;} 507 if (LOBYTE( wsaData.wVersion ) != 2 || 508 HIBYTE( wsaData.wVersion ) != 0 ) { 509 if (ads->diagfile && ads->iflags & adns_if_debug) 510 fprintf(ads->diagfile,"adns: Need Winsock 2.0 or better!\n"); 511 512 WSACleanup(); 513 return -1;} 514 515 /* The WinSock DLL is acceptable. Proceed. */ 516 #endif 517 518 *ads_r= ads; 519 520 return 0; 521 } 522 523 static int init_finish(adns_state ads) { 524 struct protoent *proto; 525 int r; 526 /* Don't add loopback on ReactOS it slows down queries to non existent server */ 527 #ifndef __REACTOS__ 528 struct in_addr ia; 529 if (!ads->nservers) { 530 if (ads->diagfile && ads->iflags & adns_if_debug) 531 fprintf(ads->diagfile,"adns: no nameservers, using localhost\n"); 532 ia.s_addr= htonl(INADDR_LOOPBACK); 533 addserver(ads,ia); 534 } 535 #endif 536 proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; } 537 ADNS_CLEAR_ERRNO; 538 ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto); 539 ADNS_CAPTURE_ERRNO; 540 if (ads->udpsocket<0) { r= errno; goto x_free; } 541 542 r= adns__setnonblock(ads,ads->udpsocket); 543 if (r) { r= errno; goto x_closeudp; } 544 return 0; 545 546 x_closeudp: 547 adns_socket_close(ads->udpsocket); 548 x_free: 549 free(ads); 550 #ifdef ADNS_JGAA_WIN32 551 WSACleanup(); 552 #endif /* WIN32 */ 553 return r; 554 } 555 556 static void init_abort(adns_state ads) { 557 if (ads->nsearchlist) { 558 free(ads->searchlist[0]); 559 free(ads->searchlist); 560 } 561 free(ads); 562 #ifdef ADNS_JGAA_WIN32 563 WSACleanup(); 564 #endif /* WIN32 */ 565 566 } 567 568 int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { 569 adns_state ads; 570 const char *res_options, *adns_res_options; 571 int r; 572 #ifdef ADNS_JGAA_WIN32 573 #define SECURE_PATH_LEN (MAX_PATH - 64) 574 char PathBuf[MAX_PATH]; 575 #endif 576 577 r= init_begin(&ads, flags, diagfile ? diagfile : stderr); 578 if (r) return r; 579 580 res_options= instrum_getenv(ads,"RES_OPTIONS"); 581 adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS"); 582 ccf_options(ads,"RES_OPTIONS",-1,res_options); 583 ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); 584 585 #ifdef ADNS_JGAA_WIN32 586 GetWindowsDirectory(PathBuf, SECURE_PATH_LEN); 587 strcat(PathBuf,"\\resolv.conf"); 588 readconfig(ads,PathBuf,1); 589 GetWindowsDirectory(PathBuf, SECURE_PATH_LEN); 590 strcat(PathBuf,"\\resolv-adns.conf"); 591 readconfig(ads,PathBuf,0); 592 GetWindowsDirectory(PathBuf, SECURE_PATH_LEN); 593 strcat(PathBuf,"\\System32\\Drivers\\etc\\resolv.conf"); 594 readconfig(ads,PathBuf,1); 595 GetWindowsDirectory(PathBuf, SECURE_PATH_LEN); 596 strcat(PathBuf,"\\System32\\Drivers\\etc\\resolv-adns.conf"); 597 readconfig(ads,PathBuf,0); 598 #else 599 readconfig(ads,"/etc/resolv.conf",1); 600 readconfig(ads,"/etc/resolv-adns.conf",0); 601 #endif 602 603 readconfigenv(ads,"RES_CONF"); 604 readconfigenv(ads,"ADNS_RES_CONF"); 605 606 readconfigenvtext(ads,"RES_CONF_TEXT"); 607 readconfigenvtext(ads,"ADNS_RES_CONF_TEXT"); 608 609 ccf_options(ads,"RES_OPTIONS",-1,res_options); 610 ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); 611 612 ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN")); 613 ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN")); 614 615 if (ads->configerrno && ads->configerrno != EINVAL) { 616 r= ads->configerrno; 617 init_abort(ads); 618 return r; 619 } 620 621 r= init_finish(ads); 622 if (r) return r; 623 624 adns__consistency(ads,0,cc_entex); 625 *ads_r= ads; 626 return 0; 627 } 628 629 int adns_init_strcfg(adns_state *ads_r, adns_initflags flags, 630 FILE *diagfile, const char *configtext) { 631 adns_state ads; 632 int r; 633 634 r= init_begin(&ads, flags, diagfile); if (r) return r; 635 636 readconfigtext(ads,configtext,"<supplied configuration text>"); 637 if (ads->configerrno) { 638 r= ads->configerrno; 639 init_abort(ads); 640 return r; 641 } 642 643 r= init_finish(ads); if (r) return r; 644 adns__consistency(ads,0,cc_entex); 645 *ads_r= ads; 646 return 0; 647 } 648 649 650 void adns_finish(adns_state ads) { 651 adns__consistency(ads,0,cc_entex); 652 for (;;) { 653 if (ads->udpw.head) adns_cancel(ads->udpw.head); 654 else if (ads->tcpw.head) adns_cancel(ads->tcpw.head); 655 else if (ads->childw.head) adns_cancel(ads->childw.head); 656 else if (ads->output.head) adns_cancel(ads->output.head); 657 else break; 658 } 659 adns_socket_close(ads->udpsocket); 660 if (ads->tcpsocket != -1) adns_socket_close(ads->tcpsocket); 661 adns__vbuf_free(&ads->tcpsend); 662 adns__vbuf_free(&ads->tcprecv); 663 freesearchlist(ads); 664 free(ads); 665 #ifdef ADNS_JGAA_WIN32 666 WSACleanup(); 667 #endif /* WIN32 */ 668 669 } 670 671 void adns_forallqueries_begin(adns_state ads) { 672 adns__consistency(ads,0,cc_entex); 673 ads->forallnext= 674 ads->udpw.head ? ads->udpw.head : 675 ads->tcpw.head ? ads->tcpw.head : 676 ads->childw.head ? ads->childw.head : 677 ads->output.head; 678 } 679 680 adns_query adns_forallqueries_next(adns_state ads, void **context_r) { 681 adns_query qu, nqu; 682 683 adns__consistency(ads,0,cc_entex); 684 nqu= ads->forallnext; 685 for (;;) { 686 qu= nqu; 687 if (!qu) return 0; 688 if (qu->next) { 689 nqu= qu->next; 690 } else if (qu == ads->udpw.tail) { 691 nqu= 692 ads->tcpw.head ? ads->tcpw.head : 693 ads->childw.head ? ads->childw.head : 694 ads->output.head; 695 } else if (qu == ads->tcpw.tail) { 696 nqu= 697 ads->childw.head ? ads->childw.head : 698 ads->output.head; 699 } else if (qu == ads->childw.tail) { 700 nqu= ads->output.head; 701 } else { 702 nqu= 0; 703 } 704 if (!qu->parent) break; 705 } 706 ads->forallnext= nqu; 707 if (context_r) *context_r= qu->ctx.ext; 708 return qu; 709 } 710 711 /* ReactOS addition */ 712 void adns_addserver(adns_state ads, struct in_addr addr) { 713 addserver(ads, addr); 714 } 715 void adns_ccf_search(adns_state ads, const char *fn, int lno, const char *buf) { 716 ccf_search(ads, fn, lno, buf); 717 } 718 int adns_numservers(adns_state ads) { 719 return ads->nservers; 720 } 721