1132451Sroberto/* 2132451Sroberto * arlib.c (C)opyright 1993 Darren Reed. All rights reserved. 3132451Sroberto * This file may not be distributed without the author's permission in any 4132451Sroberto * shape or form. The author takes no responsibility for any damage or loss 5132451Sroberto * of property which results from the use of this software. 6132451Sroberto */ 7132451Sroberto#ifndef lint 8132451Srobertostatic char sccsid[] = "@(#)arlib.c 1.9 6/5/93 (C)opyright 1992 Darren \ 9132451SrobertoReed. ASYNC DNS"; 10132451Sroberto#endif 11132451Sroberto 12132451Sroberto#include <stdio.h> 13132451Sroberto#include <fcntl.h> 14132451Sroberto#include <signal.h> 15132451Sroberto#include <sys/types.h> 16132451Sroberto#include <sys/time.h> 17132451Sroberto#include <sys/socket.h> 18132451Sroberto#include <netinet/in.h> 19132451Sroberto#include "netdb.h" 20132451Sroberto#include "arpa/nameser.h" 21132451Sroberto#include <resolv.h> 22132451Sroberto#include "arlib.h" 23132451Sroberto#include "arplib.h" 24132451Sroberto 25132451Srobertoextern int errno, h_errno; 26132451Srobertostatic char ar_hostbuf[65], ar_domainname[65]; 27132451Srobertostatic char ar_dot[] = "."; 28132451Srobertostatic int ar_resfd = -1, ar_vc = 0; 29132451Srobertostatic struct reslist *ar_last, *ar_first; 30132451Sroberto 31132451Sroberto/* 32132451Sroberto * Statistics structure. 33132451Sroberto */ 34132451Srobertostatic struct resstats { 35132451Sroberto int re_errors; 36132451Sroberto int re_nu_look; 37132451Sroberto int re_na_look; 38132451Sroberto int re_replies; 39132451Sroberto int re_requests; 40132451Sroberto int re_resends; 41132451Sroberto int re_sent; 42132451Sroberto int re_timeouts; 43132451Sroberto} ar_reinfo; 44132451Sroberto 45132451Srobertostatic int do_query_name(/* struct resinfo *, char *, struct reslist * */); 46132451Srobertostatic int do_query_number(/* struct resinfo *, char *, struct reslist * */); 47132451Srobertostatic int ar_resend_query(/* struct reslist * */); 48132451Sroberto 49132451Sroberto/* 50132451Sroberto * ar_init 51132451Sroberto * 52132451Sroberto * Initializes the various ARLIB internal varilables and related DNS 53132451Sroberto * options for res_init(). 54132451Sroberto * 55132451Sroberto * Returns 0 or the socket opened for use with talking to name servers 56132451Sroberto * if 0 is passed or ARES_INITSOCK is set. 57132451Sroberto */ 58132451Srobertoint ar_init(op) 59132451Srobertoint op; 60132451Sroberto{ 61132451Sroberto int ret = 0; 62132451Sroberto 63132451Sroberto if (op & ARES_INITLIST) 64132451Sroberto { 65132451Sroberto bzero(&ar_reinfo, sizeof(ar_reinfo)); 66132451Sroberto ar_first = ar_last = NULL; 67132451Sroberto } 68132451Sroberto 69132451Sroberto if (op & ARES_CALLINIT && !(_res.options & RES_INIT)) 70132451Sroberto { 71132451Sroberto ret = res_init(); 72132451Sroberto (void)strcpy(ar_domainname, ar_dot); 73132451Sroberto (void)strncat(ar_domainname, _res.defdname, 74132451Sroberto sizeof(ar_domainname)-2); 75132451Sroberto } 76132451Sroberto 77132451Sroberto if (op & ARES_INITSOCK) 78132451Sroberto ret = ar_resfd = ar_open(); 79132451Sroberto 80132451Sroberto if (op & ARES_INITDEBG) 81132451Sroberto _res.options |= RES_DEBUG; 82132451Sroberto 83132451Sroberto if (op == 0) 84132451Sroberto ret = ar_resfd; 85132451Sroberto 86132451Sroberto return ret; 87132451Sroberto} 88132451Sroberto 89132451Sroberto 90132451Sroberto/* 91132451Sroberto * ar_open 92132451Sroberto * 93132451Sroberto * Open a socket to talk to a name server with. 94132451Sroberto * Check _res.options to see if we use a TCP or UDP socket. 95132451Sroberto */ 96132451Srobertoint ar_open() 97132451Sroberto{ 98132451Sroberto if (ar_resfd == -1) 99132451Sroberto { 100132451Sroberto if (_res.options & RES_USEVC) 101132451Sroberto { 102132451Sroberto struct sockaddr_in *sip; 103132451Sroberto int i; 104132451Sroberto 105132451Sroberto sip = _res.NS_ADDR_LIST; /* was _res.nsaddr_list */ 106132451Sroberto ar_vc = 1; 107132451Sroberto ar_resfd = socket(AF_INET, SOCK_STREAM, 0); 108132451Sroberto 109132451Sroberto /* 110132451Sroberto * Try each name server listed in sequence until we 111132451Sroberto * succeed or run out. 112132451Sroberto */ 113132451Sroberto while (connect(ar_resfd, (struct sockaddr *)sip++, 114132451Sroberto sizeof(struct sockaddr))) 115132451Sroberto { 116132451Sroberto (void)close(ar_resfd); 117132451Sroberto ar_resfd = -1; 118132451Sroberto if (i >= _res.nscount) 119132451Sroberto break; 120132451Sroberto ar_resfd = socket(AF_INET, SOCK_STREAM, 0); 121132451Sroberto } 122132451Sroberto } 123132451Sroberto else 124132451Sroberto ar_resfd = socket(AF_INET, SOCK_DGRAM, 0); 125132451Sroberto } 126132451Sroberto if (ar_resfd >= 0) 127132451Sroberto { /* Need one of these two here - and it MUST work!! */ 128132451Sroberto int flags; 129132451Sroberto 130132451Sroberto if ((flags = fcntl(ar_resfd, F_GETFL, 0)) != -1) 131132451Sroberto#ifdef O_NONBLOCK 132132451Sroberto if (fcntl(ar_resfd, F_SETFL, flags|O_NONBLOCK) == -1) 133132451Sroberto#else 134132451Sroberto# ifdef O_NDELAY 135132451Sroberto if (fcntl(ar_resfd, F_SETFL, flags|O_NDELAY) == -1) 136132451Sroberto# else 137132451Sroberto# ifdef FNDELAY 138132451Sroberto if (fcntl(ar_resfd, F_SETFL, flags|FNDELAY) == -1) 139132451Sroberto# endif 140132451Sroberto# endif 141132451Sroberto#endif 142132451Sroberto { 143132451Sroberto (void)close(ar_resfd); 144132451Sroberto ar_resfd = -1; 145132451Sroberto } 146132451Sroberto } 147132451Sroberto return ar_resfd; 148132451Sroberto} 149132451Sroberto 150132451Sroberto 151132451Sroberto/* 152132451Sroberto * ar_close 153132451Sroberto * 154132451Sroberto * Closes and flags the ARLIB socket as closed. 155132451Sroberto */ 156132451Srobertovoid ar_close() 157132451Sroberto{ 158132451Sroberto (void)close(ar_resfd); 159132451Sroberto ar_resfd = -1; 160132451Sroberto return; 161132451Sroberto} 162132451Sroberto 163132451Sroberto 164132451Sroberto/* 165132451Sroberto * ar_add_request 166132451Sroberto * 167132451Sroberto * Add a new DNS query to the end of the query list. 168132451Sroberto */ 169132451Srobertostatic int ar_add_request(new) 170132451Srobertostruct reslist *new; 171132451Sroberto{ 172132451Sroberto if (!new) 173132451Sroberto return -1; 174132451Sroberto if (!ar_first) 175132451Sroberto ar_first = ar_last = new; 176132451Sroberto else { 177132451Sroberto ar_last->re_next = new; 178132451Sroberto ar_last = new; 179132451Sroberto } 180132451Sroberto new->re_next = NULL; 181132451Sroberto ar_reinfo.re_requests++; 182132451Sroberto return 0; 183132451Sroberto} 184132451Sroberto 185132451Sroberto 186132451Sroberto/* 187132451Sroberto * ar_remrequest 188132451Sroberto * 189132451Sroberto * Remove a request from the list. This must also free any memory that has 190132451Sroberto * been allocated for temporary storage of DNS results. 191132451Sroberto * 192132451Sroberto * Returns -1 if there are anyy problems removing the requested structure 193132451Sroberto * or 0 if the remove is successful. 194132451Sroberto */ 195132451Srobertostatic int ar_remrequest(old) 196132451Srobertostruct reslist *old; 197132451Sroberto{ 198132451Sroberto register struct reslist *rptr, *r2ptr; 199132451Sroberto register char **s; 200132451Sroberto 201132451Sroberto if (!old) 202132451Sroberto return -1; 203132451Sroberto for (rptr = ar_first, r2ptr = NULL; rptr; rptr = rptr->re_next) 204132451Sroberto { 205132451Sroberto if (rptr == old) 206132451Sroberto break; 207132451Sroberto r2ptr = rptr; 208132451Sroberto } 209132451Sroberto 210132451Sroberto if (!rptr) 211132451Sroberto return -1; 212132451Sroberto if (rptr == ar_first) 213132451Sroberto ar_first = ar_first->re_next; 214132451Sroberto else if (rptr == ar_last) 215132451Sroberto { 216132451Sroberto if (ar_last = r2ptr) 217132451Sroberto ar_last->re_next = NULL; 218132451Sroberto } 219132451Sroberto else 220132451Sroberto r2ptr->re_next = rptr->re_next; 221132451Sroberto 222132451Sroberto if (!ar_first) 223132451Sroberto ar_last = ar_first; 224132451Sroberto 225132451Sroberto#ifdef ARLIB_DEBUG 226132451Sroberto ar_dump_hostent("ar_remrequest:", rptr->re_he); 227132451Sroberto#endif 228132451Sroberto 229132451Sroberto if (rptr->re_he.h_name) 230132451Sroberto (void)free(rptr->re_he.h_name); 231132451Sroberto if (s = rptr->re_he.h_aliases) 232132451Sroberto for (; *s; s++) 233132451Sroberto (void)free(*s); 234132451Sroberto if (rptr->re_rinfo.ri_ptr) 235132451Sroberto (void)free(rptr->re_rinfo.ri_ptr); 236132451Sroberto (void)free(rptr); 237132451Sroberto 238132451Sroberto return 0; 239132451Sroberto} 240132451Sroberto 241132451Sroberto 242132451Sroberto/* 243132451Sroberto * ar_make_request 244132451Sroberto * 245132451Sroberto * Create a DNS query recorded for the request being made and place it on the 246132451Sroberto * current list awaiting replies. Initialization of the record with set 247132451Sroberto * values should also be done. 248132451Sroberto */ 249132451Srobertostatic struct reslist *ar_make_request(resi) 250132451Srobertoregister struct resinfo *resi; 251132451Sroberto{ 252132451Sroberto register struct reslist *rptr; 253132451Sroberto register struct resinfo *rp; 254132451Sroberto 255132451Sroberto rptr = (struct reslist *)calloc(1, sizeof(struct reslist)); 256132451Sroberto rp = &rptr->re_rinfo; 257132451Sroberto 258132451Sroberto rptr->re_next = NULL; /* where NULL is non-zero ;) */ 259132451Sroberto rptr->re_sentat = time(NULL); 260132451Sroberto rptr->re_retries = _res.retry; 261132451Sroberto rptr->re_sends = 1; 262132451Sroberto rptr->re_resend = 1; 263132451Sroberto rptr->re_timeout = rptr->re_sentat + _res.retrans; 264132451Sroberto rptr->re_he.h_name = NULL; 265132451Sroberto rptr->re_he.h_addrtype = AF_INET; 266132451Sroberto rptr->re_he.h_aliases[0] = NULL; 267132451Sroberto rp->ri_ptr = resi->ri_ptr; 268132451Sroberto rp->ri_size = resi->ri_size; 269132451Sroberto 270132451Sroberto (void)ar_add_request(rptr); 271132451Sroberto 272132451Sroberto return rptr; 273132451Sroberto} 274132451Sroberto 275132451Sroberto 276132451Sroberto/* 277132451Sroberto * ar_timeout 278132451Sroberto * 279132451Sroberto * Remove queries from the list which have been there too long without 280132451Sroberto * being resolved. 281132451Sroberto */ 282132451Srobertolong ar_timeout(now, info, size) 283132451Srobertotime_t now; 284132451Srobertochar *info; 285132451Srobertoint size; 286132451Sroberto{ 287132451Sroberto register struct reslist *rptr, *r2ptr; 288132451Sroberto register long next = 0; 289132451Sroberto 290132451Sroberto for (rptr = ar_first, r2ptr = NULL; rptr; rptr = r2ptr) 291132451Sroberto { 292132451Sroberto r2ptr = rptr->re_next; 293132451Sroberto if (now >= rptr->re_timeout) 294132451Sroberto { 295132451Sroberto /* 296132451Sroberto * If the timeout for the query has been exceeded, 297132451Sroberto * then resend the query if we still have some 298132451Sroberto * 'retry credit' and reset the timeout. If we have 299132451Sroberto * used it all up, then remove the request. 300132451Sroberto */ 301132451Sroberto if (--rptr->re_retries <= 0) 302132451Sroberto { 303132451Sroberto ar_reinfo.re_timeouts++; 304132451Sroberto if (info && rptr->re_rinfo.ri_ptr) 305132451Sroberto bcopy(rptr->re_rinfo.ri_ptr, info, 306132451Sroberto MIN(rptr->re_rinfo.ri_size, 307132451Sroberto size)); 308132451Sroberto (void)ar_remrequest(rptr); 309132451Sroberto return now; 310132451Sroberto } 311132451Sroberto else 312132451Sroberto { 313132451Sroberto rptr->re_sends++; 314132451Sroberto rptr->re_sentat = now; 315132451Sroberto rptr->re_timeout = now + _res.retrans; 316132451Sroberto (void)ar_resend_query(rptr); 317132451Sroberto } 318132451Sroberto } 319132451Sroberto if (!next || rptr->re_timeout < next) 320132451Sroberto next = rptr->re_timeout; 321132451Sroberto } 322132451Sroberto return next; 323132451Sroberto} 324132451Sroberto 325132451Sroberto 326132451Sroberto/* 327132451Sroberto * ar_send_res_msg 328132451Sroberto * 329132451Sroberto * When sending queries to nameservers listed in the resolv.conf file, 330132451Sroberto * don't send a query to every one, but increase the number sent linearly 331132451Sroberto * to match the number of resends. This increase only occurs if there are 332132451Sroberto * multiple nameserver entries in the resolv.conf file. 333132451Sroberto * The return value is the number of messages successfully sent to 334132451Sroberto * nameservers or -1 if no successful sends. 335132451Sroberto */ 336132451Srobertostatic int ar_send_res_msg(msg, len, rcount) 337132451Srobertochar *msg; 338132451Srobertoint len, rcount; 339132451Sroberto{ 340132451Sroberto register int i; 341132451Sroberto int sent = 0; 342132451Sroberto 343132451Sroberto if (!msg) 344132451Sroberto return -1; 345132451Sroberto 346132451Sroberto rcount = (_res.nscount > rcount) ? rcount : _res.nscount; 347132451Sroberto if (_res.options & RES_PRIMARY) 348132451Sroberto rcount = 1; 349132451Sroberto 350132451Sroberto if (ar_vc) 351132451Sroberto { 352132451Sroberto ar_reinfo.re_sent++; 353132451Sroberto sent++; 354132451Sroberto if (write(ar_resfd, msg, len) == -1) 355132451Sroberto { 356132451Sroberto int errtmp = errno; 357132451Sroberto (void)close(ar_resfd); 358132451Sroberto errno = errtmp; 359132451Sroberto ar_resfd = -1; 360132451Sroberto } 361132451Sroberto } 362132451Sroberto else 363132451Sroberto for (i = 0; i < rcount; i++) 364132451Sroberto { 365132451Sroberto if (sendto(ar_resfd, msg, len, 0, 366132451Sroberto (struct sockaddr *)&(_res.NS_ADDR_LIST[i]), 367132451Sroberto sizeof(struct sockaddr_in)) == len) 368132451Sroberto { 369132451Sroberto ar_reinfo.re_sent++; 370132451Sroberto sent++; 371132451Sroberto } 372132451Sroberto } 373132451Sroberto return (sent) ? sent : -1; 374132451Sroberto} 375132451Sroberto 376132451Sroberto 377132451Sroberto/* 378132451Sroberto * ar_find_id 379132451Sroberto * 380132451Sroberto * find a dns query record by the id (id is determined by dn_mkquery) 381132451Sroberto */ 382132451Srobertostatic struct reslist *ar_find_id(id) 383132451Srobertoint id; 384132451Sroberto{ 385132451Sroberto register struct reslist *rptr; 386132451Sroberto 387132451Sroberto for (rptr = ar_first; rptr; rptr = rptr->re_next) 388132451Sroberto if (rptr->re_id == id) 389132451Sroberto return rptr; 390132451Sroberto return NULL; 391132451Sroberto} 392132451Sroberto 393132451Sroberto 394132451Sroberto/* 395132451Sroberto * ar_delete 396132451Sroberto * 397132451Sroberto * Delete a request from the waiting list if it has a data pointer which 398132451Sroberto * matches the one passed. 399132451Sroberto */ 400132451Srobertoint ar_delete(ptr, size) 401132451Srobertochar *ptr; 402132451Srobertoint size; 403132451Sroberto{ 404132451Sroberto register struct reslist *rptr; 405132451Sroberto register struct reslist *r2ptr; 406132451Sroberto int removed = 0; 407132451Sroberto 408132451Sroberto for (rptr = ar_first; rptr; rptr = r2ptr) 409132451Sroberto { 410132451Sroberto r2ptr = rptr->re_next; 411132451Sroberto if (rptr->re_rinfo.ri_ptr && ptr && size && 412132451Sroberto bcmp(rptr->re_rinfo.ri_ptr, ptr, size) == 0) 413132451Sroberto { 414132451Sroberto (void)ar_remrequest(rptr); 415132451Sroberto removed++; 416132451Sroberto } 417132451Sroberto } 418132451Sroberto return removed; 419132451Sroberto} 420132451Sroberto 421132451Sroberto 422132451Sroberto/* 423132451Sroberto * ar_query_name 424132451Sroberto * 425132451Sroberto * generate a query based on class, type and name. 426132451Sroberto */ 427132451Srobertostatic int ar_query_name(name, class, type, rptr) 428132451Srobertochar *name; 429132451Srobertoint class, type; 430132451Srobertostruct reslist *rptr; 431132451Sroberto{ 432132451Sroberto static char buf[MAXPACKET]; 433132451Sroberto int r,s,a; 434132451Sroberto HEADER *hptr; 435132451Sroberto 436132451Sroberto bzero(buf, sizeof(buf)); 437132451Sroberto r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, 438132451Sroberto buf, sizeof(buf)); 439132451Sroberto if (r <= 0) 440132451Sroberto { 441132451Sroberto h_errno = NO_RECOVERY; 442132451Sroberto return r; 443132451Sroberto } 444132451Sroberto hptr = (HEADER *)buf; 445132451Sroberto rptr->re_id = ntohs(hptr->id); 446132451Sroberto 447132451Sroberto s = ar_send_res_msg(buf, r, rptr->re_sends); 448132451Sroberto 449132451Sroberto if (s == -1) 450132451Sroberto { 451132451Sroberto h_errno = TRY_AGAIN; 452132451Sroberto return -1; 453132451Sroberto } 454132451Sroberto else 455132451Sroberto rptr->re_sent += s; 456132451Sroberto return 0; 457132451Sroberto} 458132451Sroberto 459132451Sroberto 460132451Sroberto/* 461132451Sroberto * ar_gethostbyname 462132451Sroberto * 463132451Sroberto * Replacement library function call to gethostbyname(). This one, however, 464132451Sroberto * doesn't return the record being looked up but just places the query in the 465132451Sroberto * queue to await answers. 466132451Sroberto */ 467132451Srobertoint ar_gethostbyname(name, info, size) 468132451Srobertochar *name; 469132451Srobertochar *info; 470132451Srobertoint size; 471132451Sroberto{ 472132451Sroberto char host[65]; 473132451Sroberto struct resinfo resi; 474132451Sroberto register struct resinfo *rp = &resi; 475132451Sroberto 476132451Sroberto if (size && info) 477132451Sroberto { 478132451Sroberto rp->ri_ptr = (char *)malloc(size); 479132451Sroberto bcopy(info, rp->ri_ptr, size); 480132451Sroberto rp->ri_size = size; 481132451Sroberto } 482132451Sroberto else 483132451Sroberto bzero((char *)rp, sizeof(resi)); 484132451Sroberto ar_reinfo.re_na_look++; 485132451Sroberto (void)strncpy(host, name, 64); 486132451Sroberto host[64] = '\0'; 487132451Sroberto 488132451Sroberto return (do_query_name(rp, host, NULL)); 489132451Sroberto} 490132451Sroberto 491132451Sroberto 492132451Srobertostatic int do_query_name(resi, name, rptr) 493132451Srobertostruct resinfo *resi; 494132451Srobertochar *name; 495132451Srobertoregister struct reslist *rptr; 496132451Sroberto{ 497132451Sroberto char hname[65]; 498132451Sroberto int len; 499132451Sroberto 500132451Sroberto len = strlen((char *)strncpy(hname, name, sizeof(hname)-1)); 501132451Sroberto 502132451Sroberto if (rptr && (hname[len-1] != '.')) 503132451Sroberto { 504132451Sroberto (void)strncat(hname, ar_dot, sizeof(hname)-len-1); 505132451Sroberto /* 506132451Sroberto * NOTE: The logical relationship between DNSRCH and DEFNAMES 507132451Sroberto * is implies. ie no DEFNAES, no DNSRCH. 508132451Sroberto */ 509132451Sroberto if (_res.options & (RES_DEFNAMES|RES_DNSRCH) == 510132451Sroberto (RES_DEFNAMES|RES_DNSRCH)) 511132451Sroberto { 512132451Sroberto if (_res.dnsrch[rptr->re_srch]) 513132451Sroberto (void)strncat(hname, _res.dnsrch[rptr->re_srch], 514132451Sroberto sizeof(hname) - ++len -1); 515132451Sroberto } 516132451Sroberto else if (_res.options & RES_DEFNAMES) 517132451Sroberto (void)strncat(hname, ar_domainname, sizeof(hname) - len -1); 518132451Sroberto } 519132451Sroberto 520132451Sroberto /* 521132451Sroberto * Store the name passed as the one to lookup and generate other host 522132451Sroberto * names to pass onto the nameserver(s) for lookups. 523132451Sroberto */ 524132451Sroberto if (!rptr) 525132451Sroberto { 526132451Sroberto rptr = ar_make_request(resi); 527132451Sroberto rptr->re_type = T_A; 528132451Sroberto (void)strncpy(rptr->re_name, name, sizeof(rptr->re_name)-1); 529132451Sroberto } 530132451Sroberto return (ar_query_name(hname, C_IN, T_A, rptr)); 531132451Sroberto} 532132451Sroberto 533132451Sroberto 534132451Sroberto/* 535132451Sroberto * ar_gethostbyaddr 536132451Sroberto * 537132451Sroberto * Generates a query for a given IP address. 538132451Sroberto */ 539132451Srobertoint ar_gethostbyaddr(addr, info, size) 540132451Srobertochar *addr; 541132451Srobertochar *info; 542132451Srobertoint size; 543132451Sroberto{ 544132451Sroberto struct resinfo resi; 545132451Sroberto register struct resinfo *rp = &resi; 546132451Sroberto 547132451Sroberto if (size && info) 548132451Sroberto { 549132451Sroberto rp->ri_ptr = (char *)malloc(size); 550132451Sroberto bcopy(info, rp->ri_ptr, size); 551132451Sroberto rp->ri_size = size; 552132451Sroberto } 553132451Sroberto else 554132451Sroberto bzero((char *)rp, sizeof(resi)); 555132451Sroberto ar_reinfo.re_nu_look++; 556132451Sroberto return (do_query_number(rp, addr, NULL)); 557132451Sroberto} 558132451Sroberto 559132451Sroberto 560132451Sroberto/* 561132451Sroberto * do_query_number 562132451Sroberto * 563132451Sroberto * Use this to do reverse IP# lookups. 564132451Sroberto */ 565132451Srobertostatic int do_query_number(resi, numb, rptr) 566132451Srobertostruct resinfo *resi; 567132451Srobertochar *numb; 568132451Srobertoregister struct reslist *rptr; 569132451Sroberto{ 570132451Sroberto register unsigned char *cp; 571132451Sroberto static char ipbuf[32]; 572132451Sroberto 573132451Sroberto /* 574132451Sroberto * Generate name in the "in-addr.arpa" domain. No addings bits to this 575132451Sroberto * name to get more names to query!. 576132451Sroberto */ 577132451Sroberto cp = (unsigned char *)numb; 578132451Sroberto (void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.", 579132451Sroberto (unsigned int)(cp[3]), (unsigned int)(cp[2]), 580132451Sroberto (unsigned int)(cp[1]), (unsigned int)(cp[0])); 581132451Sroberto 582132451Sroberto if (!rptr) 583132451Sroberto { 584132451Sroberto rptr = ar_make_request(resi); 585132451Sroberto rptr->re_type = T_PTR; 586132451Sroberto rptr->re_he.h_length = sizeof(struct in_addr); 587132451Sroberto bcopy(numb, (char *)&rptr->re_addr, rptr->re_he.h_length); 588132451Sroberto bcopy(numb, (char *)&rptr->re_he.h_addr_list[0].s_addr, 589132451Sroberto rptr->re_he.h_length); 590132451Sroberto } 591132451Sroberto return (ar_query_name(ipbuf, C_IN, T_PTR, rptr)); 592132451Sroberto} 593132451Sroberto 594132451Sroberto 595132451Sroberto/* 596132451Sroberto * ar_resent_query 597132451Sroberto * 598132451Sroberto * resends a query. 599132451Sroberto */ 600132451Srobertostatic int ar_resend_query(rptr) 601132451Srobertostruct reslist *rptr; 602132451Sroberto{ 603132451Sroberto if (!rptr->re_resend) 604132451Sroberto return -1; 605132451Sroberto 606132451Sroberto switch(rptr->re_type) 607132451Sroberto { 608132451Sroberto case T_PTR: 609132451Sroberto ar_reinfo.re_resends++; 610132451Sroberto return do_query_number(NULL, &rptr->re_addr, rptr); 611132451Sroberto case T_A: 612132451Sroberto ar_reinfo.re_resends++; 613132451Sroberto return do_query_name(NULL, rptr->re_name, rptr); 614132451Sroberto default: 615132451Sroberto break; 616132451Sroberto } 617132451Sroberto 618132451Sroberto return -1; 619132451Sroberto} 620132451Sroberto 621132451Sroberto 622132451Sroberto/* 623132451Sroberto * ar_procanswer 624132451Sroberto * 625132451Sroberto * process an answer received from a nameserver. 626132451Sroberto */ 627132451Srobertostatic int ar_procanswer(rptr, hptr, buf, eob) 628132451Srobertostruct reslist *rptr; 629132451Srobertochar *buf, *eob; 630132451SrobertoHEADER *hptr; 631132451Sroberto{ 632132451Sroberto char *cp, **alias, *s; 633132451Sroberto int class, type, dlen, len, ans = 0, n, i; 634132451Sroberto u_int32_t ttl, dr, *adr; 635132451Sroberto struct hent *hp; 636132451Sroberto 637132451Sroberto cp = buf + sizeof(HEADER); 638132451Sroberto adr = (u_int32_t *)rptr->re_he.h_addr_list; 639132451Sroberto 640132451Sroberto while (*adr) 641132451Sroberto adr++; 642132451Sroberto 643132451Sroberto alias = rptr->re_he.h_aliases; 644132451Sroberto while (*alias) 645132451Sroberto alias++; 646132451Sroberto 647132451Sroberto hp = &rptr->re_he; 648132451Sroberto 649132451Sroberto 650132451Sroberto /* 651132451Sroberto * Skip over the original question. 652132451Sroberto */ 653132451Sroberto while (hptr->qdcount-- > 0) 654132451Sroberto cp += dn_skipname(cp, eob) + QFIXEDSZ; 655132451Sroberto /* 656132451Sroberto * proccess each answer sent to us. blech. 657132451Sroberto */ 658132451Sroberto while (hptr->ancount-- > 0 && cp < eob) { 659132451Sroberto n = dn_expand(buf, eob, cp, ar_hostbuf, sizeof(ar_hostbuf)); 660132451Sroberto cp += n; 661132451Sroberto if (n <= 0) 662132451Sroberto return ans; 663132451Sroberto 664132451Sroberto ans++; 665132451Sroberto /* 666132451Sroberto * 'skip' past the general dns crap (ttl, class, etc) to get 667132451Sroberto * the pointer to the right spot. Some of thse are actually 668132451Sroberto * useful so its not a good idea to skip past in one big jump. 669132451Sroberto */ 670132451Sroberto type = (int)_getshort(cp); 671132451Sroberto cp += sizeof(short); 672132451Sroberto class = (int)_getshort(cp); 673132451Sroberto cp += sizeof(short); 674132451Sroberto ttl = (u_int32_t)_getlong(cp); 675132451Sroberto cp += sizeof(u_int32_t); 676132451Sroberto dlen = (int)_getshort(cp); 677132451Sroberto cp += sizeof(short); 678132451Sroberto rptr->re_type = type; 679132451Sroberto 680132451Sroberto switch(type) 681132451Sroberto { 682132451Sroberto case T_A : 683132451Sroberto rptr->re_he.h_length = dlen; 684132451Sroberto if (ans == 1) 685132451Sroberto rptr->re_he.h_addrtype=(class == C_IN) ? 686132451Sroberto AF_INET : AF_UNSPEC; 687132451Sroberto if (dlen != sizeof(dr)) 688132451Sroberto { 689132451Sroberto h_errno = TRY_AGAIN; 690132451Sroberto continue; 691132451Sroberto } 692132451Sroberto bcopy(cp, &dr, dlen); 693132451Sroberto *adr++ = dr; 694132451Sroberto *adr = 0; 695132451Sroberto cp += dlen; 696132451Sroberto len = strlen(ar_hostbuf); 697132451Sroberto if (!rptr->re_he.h_name) 698132451Sroberto { 699132451Sroberto rptr->re_he.h_name = (char *)malloc(len+1); 700132451Sroberto if (!rptr->re_he.h_name) 701132451Sroberto break; 702132451Sroberto (void)strcpy(rptr->re_he.h_name, ar_hostbuf); 703132451Sroberto } 704132451Sroberto break; 705132451Sroberto case T_PTR : 706132451Sroberto if ((n = dn_expand(buf, eob, cp, ar_hostbuf, 707132451Sroberto sizeof(ar_hostbuf) )) < 0) 708132451Sroberto { 709132451Sroberto cp += n; 710132451Sroberto continue; 711132451Sroberto } 712132451Sroberto cp += n; 713132451Sroberto len = strlen(ar_hostbuf)+1; 714132451Sroberto /* 715132451Sroberto * copy the returned hostname into the host name 716132451Sroberto * or alias field if there is a known hostname 717132451Sroberto * already. 718132451Sroberto */ 719132451Sroberto if (!rptr->re_he.h_name) 720132451Sroberto { 721132451Sroberto rptr->re_he.h_name = (char *)malloc(len); 722132451Sroberto if (!rptr->re_he.h_name) 723132451Sroberto break; 724132451Sroberto (void)strcpy(rptr->re_he.h_name, ar_hostbuf); 725132451Sroberto } 726132451Sroberto else 727132451Sroberto { 728132451Sroberto *alias = (char *)malloc(len); 729132451Sroberto if (!*alias) 730132451Sroberto return -1; 731132451Sroberto (void)strcpy(*alias++, ar_hostbuf); 732132451Sroberto *alias = NULL; 733132451Sroberto } 734132451Sroberto break; 735132451Sroberto case T_CNAME : 736132451Sroberto cp += dlen; 737132451Sroberto if (alias >= &(rptr->re_he.h_aliases[MAXALIASES-1])) 738132451Sroberto continue; 739132451Sroberto n = strlen(ar_hostbuf)+1; 740132451Sroberto *alias = (char *)malloc(n); 741132451Sroberto if (!*alias) 742132451Sroberto return -1; 743132451Sroberto (void)strcpy(*alias++, ar_hostbuf); 744132451Sroberto *alias = NULL; 745132451Sroberto break; 746132451Sroberto default : 747132451Sroberto break; 748132451Sroberto } 749132451Sroberto } 750132451Sroberto 751132451Sroberto return ans; 752132451Sroberto} 753132451Sroberto 754132451Sroberto 755132451Sroberto/* 756132451Sroberto * ar_answer 757132451Sroberto * 758132451Sroberto * Get an answer from a DNS server and process it. If a query is found to 759132451Sroberto * which no answer has been given to yet, copy its 'info' structure back 760132451Sroberto * to where "reip" points and return a pointer to the hostent structure. 761132451Sroberto */ 762132451Srobertostruct hostent *ar_answer(reip, size) 763132451Srobertochar *reip; 764132451Srobertoint size; 765132451Sroberto{ 766132451Sroberto static char ar_rcvbuf[sizeof(HEADER) + MAXPACKET]; 767132451Sroberto static struct hostent ar_host; 768132451Sroberto 769132451Sroberto register HEADER *hptr; 770132451Sroberto register struct reslist *rptr = NULL; 771132451Sroberto register struct hostent *hp; 772132451Sroberto register char **s; 773132451Sroberto unsigned long *adr; 774132451Sroberto int rc, i, n, a; 775132451Sroberto 776132451Sroberto rc = recv(ar_resfd, ar_rcvbuf, sizeof(ar_rcvbuf), 0); 777132451Sroberto if (rc <= 0) 778132451Sroberto goto getres_err; 779132451Sroberto 780132451Sroberto ar_reinfo.re_replies++; 781132451Sroberto hptr = (HEADER *)ar_rcvbuf; 782132451Sroberto /* 783132451Sroberto * convert things to be in the right order. 784132451Sroberto */ 785132451Sroberto hptr->id = ntohs(hptr->id); 786132451Sroberto hptr->ancount = ntohs(hptr->ancount); 787132451Sroberto hptr->arcount = ntohs(hptr->arcount); 788132451Sroberto hptr->nscount = ntohs(hptr->nscount); 789132451Sroberto hptr->qdcount = ntohs(hptr->qdcount); 790132451Sroberto /* 791132451Sroberto * response for an id which we have already received an answer for 792132451Sroberto * just ignore this response. 793132451Sroberto */ 794132451Sroberto rptr = ar_find_id(hptr->id); 795132451Sroberto if (!rptr) 796132451Sroberto goto getres_err; 797132451Sroberto 798132451Sroberto if ((hptr->rcode != NOERROR) || (hptr->ancount == 0)) 799132451Sroberto { 800132451Sroberto switch (hptr->rcode) 801132451Sroberto { 802132451Sroberto case NXDOMAIN: 803132451Sroberto h_errno = HOST_NOT_FOUND; 804132451Sroberto break; 805132451Sroberto case SERVFAIL: 806132451Sroberto h_errno = TRY_AGAIN; 807132451Sroberto break; 808132451Sroberto case NOERROR: 809132451Sroberto h_errno = NO_DATA; 810132451Sroberto break; 811132451Sroberto case FORMERR: 812132451Sroberto case NOTIMP: 813132451Sroberto case REFUSED: 814132451Sroberto default: 815132451Sroberto h_errno = NO_RECOVERY; 816132451Sroberto break; 817132451Sroberto } 818132451Sroberto ar_reinfo.re_errors++; 819132451Sroberto /* 820132451Sroberto ** If a bad error was returned, we stop here and dont send 821132451Sroberto ** send any more (no retries granted). 822132451Sroberto */ 823132451Sroberto if (h_errno != TRY_AGAIN) 824132451Sroberto { 825132451Sroberto rptr->re_resend = 0; 826132451Sroberto rptr->re_retries = 0; 827132451Sroberto } 828132451Sroberto goto getres_err; 829132451Sroberto } 830132451Sroberto 831132451Sroberto a = ar_procanswer(rptr, hptr, ar_rcvbuf, ar_rcvbuf+rc); 832132451Sroberto 833132451Sroberto if ((rptr->re_type == T_PTR) && (_res.options & RES_CHECKPTR)) 834132451Sroberto { 835132451Sroberto /* 836132451Sroberto * For reverse lookups on IP#'s, lookup the name that is given 837132451Sroberto * for the ip# and return with that as the official result. 838132451Sroberto * -avalon 839132451Sroberto */ 840132451Sroberto rptr->re_type = T_A; 841132451Sroberto /* 842132451Sroberto * Clean out the list of addresses already set, even though 843132451Sroberto * there should only be one :) 844132451Sroberto */ 845132451Sroberto adr = (unsigned long *)rptr->re_he.h_addr_list; 846132451Sroberto while (*adr) 847132451Sroberto *adr++ = 0L; 848132451Sroberto /* 849132451Sroberto * Lookup the name that we were given for the ip# 850132451Sroberto */ 851132451Sroberto ar_reinfo.re_na_look++; 852132451Sroberto (void)strncpy(rptr->re_name, rptr->re_he.h_name, 853132451Sroberto sizeof(rptr->re_name)-1); 854132451Sroberto rptr->re_he.h_name = NULL; 855132451Sroberto rptr->re_retries = _res.retry; 856132451Sroberto rptr->re_sends = 1; 857132451Sroberto rptr->re_resend = 1; 858132451Sroberto rptr->re_he.h_name = NULL; 859132451Sroberto ar_reinfo.re_na_look++; 860132451Sroberto (void)ar_query_name(rptr->re_name, C_IN, T_A, rptr); 861132451Sroberto return NULL; 862132451Sroberto } 863132451Sroberto 864132451Sroberto if (reip && rptr->re_rinfo.ri_ptr && size) 865132451Sroberto bcopy(rptr->re_rinfo.ri_ptr, reip, 866132451Sroberto MIN(rptr->re_rinfo.ri_size, size)); 867132451Sroberto /* 868132451Sroberto * Clean up structure from previous usage. 869132451Sroberto */ 870132451Sroberto hp = &ar_host; 871132451Sroberto#ifdef ARLIB_DEBUG 872132451Sroberto ar_dump_hostent("ar_answer: previous usage", hp); 873132451Sroberto#endif 874132451Sroberto 875132451Sroberto if (hp->h_name) 876132451Sroberto (void)free(hp->h_name); 877132451Sroberto if (s = hp->h_aliases) 878132451Sroberto { 879132451Sroberto while (*s) 880132451Sroberto (void)free(*s++); 881132451Sroberto (void)free(hp->h_aliases); 882132451Sroberto } 883132451Sroberto if (s = hp->h_addr_list) 884132451Sroberto { 885132451Sroberto /* 886132451Sroberto * Only free once since we allocated space for 887132451Sroberto * address in one big chunk. 888132451Sroberto */ 889132451Sroberto (void)free(*s); 890132451Sroberto (void)free(hp->h_addr_list); 891132451Sroberto } 892132451Sroberto bzero((char *)hp, sizeof(*hp)); 893132451Sroberto 894132451Sroberto /* 895132451Sroberto * Setup and copy details for the structure we return a pointer to. 896132451Sroberto */ 897132451Sroberto hp->h_addrtype = AF_INET; 898132451Sroberto hp->h_length = sizeof(struct in_addr); 899132451Sroberto if(rptr->re_he.h_name) 900132451Sroberto { 901132451Sroberto hp->h_name = (char *)malloc(strlen(rptr->re_he.h_name)+1); 902132451Sroberto if(!hp->h_name) 903132451Sroberto { 904132451Sroberto#ifdef ARLIB_DEBUG 905132451Sroberto fprintf(stderr, "no memory for hostname\n"); 906132451Sroberto#endif 907132451Sroberto h_errno = TRY_AGAIN; 908132451Sroberto goto getres_err; 909132451Sroberto } 910132451Sroberto (void)strcpy(hp->h_name, rptr->re_he.h_name); 911132451Sroberto } 912132451Sroberto#ifdef ARLIB_DEBUG 913132451Sroberto ar_dump_hostent("ar_answer: (snap) store name", hp); 914132451Sroberto#endif 915132451Sroberto 916132451Sroberto /* 917132451Sroberto * Count IP#'s. 918132451Sroberto */ 919132451Sroberto for (i = 0, n = 0; i < MAXADDRS; i++, n++) 920132451Sroberto if (!rptr->re_he.h_addr_list[i].s_addr) 921132451Sroberto break; 922132451Sroberto s = hp->h_addr_list = (char **)malloc((n + 1) * sizeof(char *)); 923132451Sroberto if (n) 924132451Sroberto { 925132451Sroberto *s = (char *)malloc(n * sizeof(struct in_addr)); 926132451Sroberto if(!*s) 927132451Sroberto { 928132451Sroberto#ifdef ARLIB_DEBUG 929132451Sroberto fprintf(stderr, "no memory for IP#'s (%d)\n", n); 930132451Sroberto#endif 931132451Sroberto h_errno = TRY_AGAIN; 932132451Sroberto goto getres_err; 933132451Sroberto } 934132451Sroberto bcopy((char *)&rptr->re_he.h_addr_list[0].s_addr, *s, 935132451Sroberto sizeof(struct in_addr)); 936132451Sroberto s++; 937132451Sroberto for (i = 1; i < n; i++, s++) 938132451Sroberto { 939132451Sroberto *s = hp->h_addr + i * sizeof(struct in_addr); 940132451Sroberto bcopy((char *)&rptr->re_he.h_addr_list[i].s_addr, *s, 941132451Sroberto sizeof(struct in_addr)); 942132451Sroberto } 943132451Sroberto } 944132451Sroberto *s = NULL; 945132451Sroberto#ifdef ARLIB_DEBUG 946132451Sroberto ar_dump_hostent("ar_answer: (snap) store IP#'s", hp); 947132451Sroberto#endif 948132451Sroberto 949132451Sroberto /* 950132451Sroberto * Count CNAMEs 951132451Sroberto */ 952132451Sroberto for (i = 0, n = 0; i < MAXADDRS; i++, n++) 953132451Sroberto if (!rptr->re_he.h_aliases[i]) 954132451Sroberto break; 955132451Sroberto s = hp->h_aliases = (char **)malloc((n + 1) * sizeof(char *)); 956132451Sroberto if (!s) 957132451Sroberto { 958132451Sroberto#ifdef ARLIB_DEBUG 959132451Sroberto fprintf(stderr, "no memory for aliases (%d)\n", n); 960132451Sroberto#endif 961132451Sroberto h_errno = TRY_AGAIN; 962132451Sroberto goto getres_err; 963132451Sroberto } 964132451Sroberto for (i = 0; i < n; i++) 965132451Sroberto { 966132451Sroberto *s++ = rptr->re_he.h_aliases[i]; 967132451Sroberto rptr->re_he.h_aliases[i] = NULL; 968132451Sroberto } 969132451Sroberto *s = NULL; 970132451Sroberto#ifdef ARLIB_DEBUG 971132451Sroberto ar_dump_hostent("ar_answer: (snap) store CNAMEs", hp); 972132451Sroberto ar_dump_hostent("ar_answer: new one", hp); 973132451Sroberto#endif 974132451Sroberto 975132451Sroberto if (a > 0) 976132451Sroberto (void)ar_remrequest(rptr); 977132451Sroberto else 978132451Sroberto if (!rptr->re_sent) 979132451Sroberto (void)ar_remrequest(rptr); 980132451Sroberto return hp; 981132451Sroberto 982132451Srobertogetres_err: 983132451Sroberto if (rptr) 984132451Sroberto { 985132451Sroberto if (reip && rptr->re_rinfo.ri_ptr && size) 986132451Sroberto bcopy(rptr->re_rinfo.ri_ptr, reip, 987132451Sroberto MIN(rptr->re_rinfo.ri_size, size)); 988132451Sroberto if ((h_errno != TRY_AGAIN) && 989132451Sroberto (_res.options & (RES_DNSRCH|RES_DEFNAMES) == 990132451Sroberto (RES_DNSRCH|RES_DEFNAMES) )) 991132451Sroberto if (_res.dnsrch[rptr->re_srch]) 992132451Sroberto { 993132451Sroberto rptr->re_retries = _res.retry; 994132451Sroberto rptr->re_sends = 1; 995132451Sroberto rptr->re_resend = 1; 996132451Sroberto (void)ar_resend_query(rptr); 997132451Sroberto rptr->re_srch++; 998132451Sroberto } 999132451Sroberto return NULL; 1000132451Sroberto } 1001132451Sroberto return NULL; 1002132451Sroberto} 1003132451Sroberto 1004132451Sroberto 1005132451Sroberto#ifdef ARLIB_DEBUG 1006132451Srobertovoid ar_dump_hostent(prefix, hp) 1007132451Srobertochar *prefix; 1008132451Srobertostruct hostent *hp; 1009132451Sroberto{ 1010132451Sroberto register char **s; 1011132451Sroberto 1012132451Sroberto fflush(stdout); 1013132451Sroberto 1014132451Sroberto fprintf(stderr, "%s\n", prefix); 1015132451Sroberto fprintf(stderr, " hp %p\n", hp); 1016132451Sroberto fprintf(stderr, " h_name %p '%s'\n", 1017132451Sroberto hp->h_name, hp->h_name); 1018132451Sroberto if (s = hp->h_aliases) 1019132451Sroberto { 1020132451Sroberto fprintf(stderr, " h_aliases %p\n", 1021132451Sroberto hp->h_aliases); 1022132451Sroberto while (*s) 1023132451Sroberto { 1024132451Sroberto fprintf(stderr, " element %p\n", *s); 1025132451Sroberto s++; 1026132451Sroberto } 1027132451Sroberto } 1028132451Sroberto if (s = hp->h_addr_list) 1029132451Sroberto { 1030132451Sroberto fprintf(stderr, " h_addr_list %p\n", 1031132451Sroberto hp->h_addr_list); 1032132451Sroberto while (*s) 1033132451Sroberto { 1034132451Sroberto fprintf(stderr, " element %p\n", *s); 1035132451Sroberto s++; 1036132451Sroberto } 1037132451Sroberto } 1038132451Sroberto 1039132451Sroberto fflush(stderr); 1040132451Sroberto} 1041132451Sroberto 1042132451Sroberto 1043132451Srobertovoid ar_dump_reslist(FILE* fp) 1044132451Sroberto{ 1045132451Sroberto register struct reslist *rptr; 1046132451Sroberto int c; 1047132451Sroberto 1048132451Sroberto c = 0; 1049132451Sroberto for (rptr = ar_first; rptr; rptr = rptr->re_next) 1050132451Sroberto { 1051132451Sroberto fprintf(fp, "%4d [%p] %4d [%p]: %s\n", rptr->re_id, rptr, 1052132451Sroberto *(rptr->re_rinfo.ri_ptr), rptr->re_rinfo.ri_ptr, 1053132451Sroberto rptr->re_name); 1054132451Sroberto } 1055132451Sroberto} 1056132451Sroberto#endif 1057