home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / internet / tcpipsrc / DNS / c / resolve < prev   
Encoding:
Text File  |  1995-02-22  |  59.0 KB  |  2,380 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <errno.h>
  6.  
  7. #include "netdb.h"
  8. #include "resolve.h"
  9. #include "socket.h"
  10. #include "in.h"
  11. #include "inet.h"
  12. #include "nameser.h"
  13. #include "resolv.h"
  14. #include "global.h"
  15. #include "timer.h"
  16. #include "cmdparse.h"
  17. #include "netuser.h"
  18. #include "domain.h"
  19. #include "misc.h"
  20. #include "mbuf.h"
  21. #include "tcp.h"
  22. #include "session.h"
  23. #include "time.h"
  24. #include "event.h"
  25. #include "var.h"
  26.  
  27. extern varlist global_vars; /* Global variables chain in cmdparse */
  28.  
  29. #define shortsize 2
  30.  
  31. #include "if.h"             /* for struct ifconf */
  32.  
  33. #define TCPINBUFFLEN 1024
  34.  
  35. #define bad_config_format(cmd) \
  36. cwprintf(NULL, "resolv+: %s: \"%s\" command incorrectly formatted.\n", hostconf, cmd);
  37.  
  38. #define    MAXALIASES    35
  39. #define    MAXADDRS    35
  40. #define MAXTRIMDOMAINS  4
  41. #define MAXMXS        16
  42.  
  43.  
  44. #define SERVICE_NONE    0
  45. #define SERVICE_BIND    1
  46. #define SERVICE_HOSTS    2
  47. #define SERVICE_NIS    3
  48. #define SERVICE_MAX    3
  49.  
  50. #define CMD_ORDER    "order"
  51. #define CMD_TRIMDOMAIN    "trim"
  52. #define CMD_HMA        "multi"
  53. #define CMD_SPOOF    "nospoof"
  54. #define CMD_SPOOFALERT    "alert"
  55. #define CMD_REORDER    "reorder"
  56. #define CMD_ON        "on"
  57. #define CMD_OFF        "off"
  58. #define CMD_WARN    "warn"
  59. #define CMD_NOWARN    "warn off"
  60. #define CMD_CACHESIZE   "cachesize"
  61.  
  62. #define ORD_BIND    "bind"
  63. #define ORD_HOSTS    "hosts"
  64. #define ORD_NIS        "nis"
  65.  
  66. #define ENV_HOSTCONF    "RESOLV_HOST_CONF"
  67. #define ENV_SERVORDER    "RESOLV_SERV_ORDER"
  68. #define ENV_SPOOF    "RESOLV_SPOOF_CHECK"
  69. #define ENV_TRIM_OVERR    "RESOLV_OVERRIDE_TRIM_DOMAINS"
  70. #define ENV_TRIM_ADD    "RESOLV_ADD_TRIM_DOMAINS"
  71. #define ENV_HMA        "RESOLV_MULTI"
  72. #define ENV_REORDER    "RESOLV_REORDER"
  73. #define ENV_CACHESIZE   "RESOLV_CACHE_SIZE"
  74.  
  75. #define TOKEN_SEPARATORS " ,;:"
  76.  
  77. struct state _res = {
  78.   RES_TIMEOUT,                   /* retransmition time interval */
  79.   4,                             /* number of times to retransmit */
  80.   RES_DEFAULT,                /* options flags */
  81.   1,                             /* number of name servers */
  82. };
  83.  
  84. static int service_order[SERVICE_MAX + 1];
  85. static int service_done = 0;
  86.  
  87. static char *h_addr_ptrs[MAXADDRS + 1];
  88. static struct mx_data *mx_ptrs[MAXMXS+1];
  89. static struct mx_data mx_conts[MAXMXS];
  90.  
  91. static struct hostent host;
  92. static char *host_aliases[MAXALIASES];
  93. static char hostbuf[BUFSIZ+1];
  94. static struct in_addr host_addr;
  95. static FILE *hostf = NULL;
  96. static char hostaddr[MAXADDRS];
  97. static char *host_addrs[2];
  98. static int stayopen = 0;
  99. static int hosts_multiple_addrs = 0;
  100. static int spoof = 0;
  101. static int spoofalert = 0;
  102. static int reorder = 0;
  103. static char *trimdomain[MAXTRIMDOMAINS];
  104. static char trimdomainbuf[BUFSIZ];
  105. static int numtrimdomains = 0;
  106. static int trace=0;
  107. static struct tcb *tcpintcb;
  108. static int timeoutfact = 30;
  109.  
  110. static int single_query(int);
  111. int lookupnames = 0;
  112.  
  113. #if PACKETSZ > 1024
  114. #define    MAXPACKET    PACKETSZ
  115. #else
  116. #define    MAXPACKET    1024
  117. #endif
  118.  
  119. typedef union {
  120.   HEADER hdr;
  121.   u_char buf[MAXPACKET];
  122. }
  123. querybuf;
  124.  
  125. typedef union {
  126.   long al;
  127.   char ac;
  128. }
  129. align;
  130.  
  131. int h_errno;
  132.  
  133. static void print_host( struct hostent *host );
  134.  
  135. static int doresolve_host( int argc, char **argv )
  136. {
  137.   unsigned int addr;
  138.   struct hostent *hosts = NULL;
  139.   char name[300];
  140.  
  141.   strcpy( name, argv[1] );
  142.   if( ! ipaddr( name, &addr ) ) {
  143.     cwprintf(NULL, "%d.%d.%d.%d\n", (addr>>24), (addr>>16)&255, (addr>>8)&255, addr&255 );
  144.     hosts = gethostbyaddr(addr, 4, AF_INET);
  145.   }
  146.   else {
  147.     hosts = gethostbyname( name, 0 );
  148.   }
  149.   if( ! hosts ) {
  150.     cwprintf(NULL, "unknown host\n" );
  151.     return 1;
  152.   }
  153.   print_host( hosts );
  154.   if( ! hosts->h_addr_list[0] ) cwprintf(NULL, "no ip address associated with name\n" );
  155.   return 0;
  156. }
  157.  
  158.  
  159. static int doresolve_mx( int argc, char **argv )
  160. {
  161.   struct hostent *hosts = NULL;
  162.   char name[300];
  163.  
  164.   strcpy( name, argv[1] );
  165.   hosts = gethostbyname( name, 1 );
  166.   if( ! hosts )
  167.   {
  168.     cwprintf(NULL, "no mx record found\n" );
  169.     return 1;
  170.   }
  171.   print_host( hosts );
  172.   if( ! hosts->h_mx[0] )
  173.     cwprintf(NULL, "no MX records associated with name\n" );
  174.   return 0;
  175. }
  176.  
  177.  
  178. static int dotrace( int argc, char **argv )
  179. {
  180.   if( argc>1 )
  181.   {
  182.     trace = atoi(argv[1]);
  183.     if( trace ) _res.options |= RES_DEBUG;
  184.     else _res.options &= (~RES_DEBUG);
  185.   }
  186.   else
  187.     cwprintf(NULL, "trace level is %d\n", trace );
  188.   return 0;
  189. }
  190.  
  191.  
  192. static int dotimeout( int argc, char **argv )
  193. {
  194.   int tmp;
  195.  
  196.   if( argc>1 )
  197.   {
  198.     if( ! strcmp( argv[1], "none" ) )
  199.       tmp = -1;
  200.     else
  201.       tmp = atoi(argv[1]);
  202.     if( ! tmp )
  203.     {
  204.       cwprintf(NULL, "timeout cannot be 0 seconds (use 'none' for no timeout)\n" );
  205.       return 1;
  206.     }
  207.     timeoutfact = tmp;
  208.   }
  209.   else
  210.     cwprintf(NULL, "timeout is %d\n",  timeoutfact);
  211.   return 0;
  212. }
  213.  
  214.  
  215. static int docache( int argc, char **argv )
  216. {
  217.   cache_print();
  218.   return 0;
  219. }
  220.  
  221.  
  222. static int dosave( int argc, char **argv )
  223. {
  224.   cache_save();
  225.   return 0;
  226. }
  227.  
  228.  
  229. static int dopurge( int argc, char **argv )
  230. {
  231.   cache_purge();
  232.   return 0;
  233. }
  234.  
  235.  
  236. static int doload( int argc, char **argv )
  237. {
  238.   cache_restore();
  239.   return 0;
  240. }
  241.  
  242. static int donames(int argc, char **argv)
  243. {
  244.   if (argc>1)
  245.   {
  246.     if (!strncmp(argv[1], "on", strlen(argv[1])) ||
  247.         !strncmp(argv[1], "yes", strlen(argv[1])))
  248.       lookupnames = 1;
  249.     else if (!strncmp(argv[1], "off", strlen(argv[1])) ||
  250.              !strncmp(argv[1], "no", strlen(argv[1])))
  251.       lookupnames = 0;
  252.     else if (isdigit(*argv[1]))
  253.       lookupnames = atoi(argv[1])!=0;
  254.     else
  255.       return 1;
  256.   }
  257.   else
  258.     cwprintf(NULL, "Address to name lookups %s\r\n", (lookupnames)?"on":"off");
  259.   return 0;
  260. }
  261.  
  262. static struct cmds rescmds[] = {
  263.   "cache",      docache,        1,    "resolve cache",        NULLCHAR,
  264.   "host",         doresolve_host,    2,    "resolve host <host>",        NULLCHAR,
  265.   "mx",          doresolve_mx,        2,    "resolve mx <host>",        NULLCHAR,
  266.   "names",        donames,              1,      "names [y|n]",                  NULLCHAR,
  267.   "purge",      dopurge,        1,    "resolve purge",        NULLCHAR,
  268.   "restore",      doload,        1,    "resolve load",            NULLCHAR,
  269.   "save",      dosave,        1,    "resolve save",            NULLCHAR,
  270.   "timeout",      dotimeout,        1,    "resolve timeout [time|none]",    NULLCHAR,
  271.   "trace",        dotrace,        1,    "resolve trace [level]",    NULLCHAR,
  272.   NULLCHAR
  273. };
  274.  
  275.  
  276. int doresolve( int argc, char **argv )
  277. {
  278.   return subcmd( rescmds, argc, argv );
  279. }
  280.  
  281.  
  282. static void print_host( struct hostent *host )
  283. {
  284.   int i;
  285.   char **clist;
  286.   char *addr;
  287.   struct mx_data **mxs;
  288.  
  289.   cwprintf(NULL, "host name  : %s\n", host->h_name );
  290.   if( host->h_aliases && host->h_aliases[0] )
  291.   {
  292.     cwprintf(NULL, "alias(es)  : " );
  293.     for( clist=host->h_aliases; clist[1]; clist++ )
  294.       cwprintf(NULL, "%s, ", *clist );
  295.     cwprintf(NULL, "%s\n", *clist );
  296.   }
  297.   if( host->h_addr_list && host->h_addr_list[0] )
  298.   {
  299.     cwprintf(NULL, "address(es): " );
  300.     for( clist=host->h_addr_list; clist[0]; clist++ )
  301.     {
  302.       for( i=host->h_length-1,addr=clist[0]+host->h_length-1; i; i--,addr-- )
  303.         cwprintf(NULL, "%d.", *(unsigned char *)addr );
  304.       cwprintf(NULL, "%d", *(unsigned char *)addr );
  305.       if( clist[1] )
  306.         cwprintf(NULL, ", " );
  307.       else
  308.         cwprintf(NULL, "\n" );
  309.     }
  310.   }
  311.   if( host->h_mx[0] )
  312.   {
  313.     cwprintf(NULL, "mx host(s) : " );
  314.     for( mxs=host->h_mx; mxs[1]; mxs++ )
  315.       cwprintf(NULL, "%s, ", (*mxs)->host );
  316.     cwprintf(NULL, "%s\n", (*mxs)->host );
  317.   }
  318. }
  319.  
  320.  
  321.  
  322.  
  323. int _mxresolve( char *dest )
  324. {
  325.   struct hostent *he;
  326.   char hname[260];
  327.  
  328.   he = gethostbyname( dest, 1 );
  329.   if( he && he->h_mx[0] ) {
  330.     strcpy( hname, he->h_mx[0]->host );
  331.     dest = hname;
  332.   }
  333.   return resolve( dest );
  334. }
  335.  
  336.  
  337. int ipaddr( char *addr, unsigned int *iaddr )
  338. {
  339.   unsigned int b1, b2, b3, b4;
  340.  
  341.   if( sscanf( addr, "%d.%d.%d.%d", &b1, &b2, &b3, &b4 ) < 4 )
  342.     return -1;
  343.   if( b1>255 || b2>255 || b3>255 || b4>255 )
  344.     return -1;
  345.   *iaddr = (b1<<24) + (b2<<16) + (b3<<8) + b4;
  346.   return 0;
  347. }
  348.  
  349. unsigned long res_inet_addr( char *name )
  350. {
  351.   unsigned int addr;
  352.  
  353.   if (ipaddr( name, &addr ) )
  354.     return -1;
  355.   else
  356.     return addr;
  357. }
  358.  
  359. static void
  360. init_services(void)
  361. {
  362.   char *cp, *dp, buf[BUFSIZ];
  363.   register int cc = 0;
  364.   FILE *fd;
  365.   char *tdp = trimdomainbuf;
  366.   char *hostconf;
  367.   unsigned int cachesize = CACHE_SIZE;
  368.  
  369.   if(NULL==(hostconf=getenv(ENV_HOSTCONF)))
  370.   {
  371.     hostconf=_PATH_HOSTCONF;
  372.   }
  373.   if ((fd = (FILE *)fopen(hostconf, "r")) == NULL)
  374.   {
  375.     /* make some assumptions */
  376.     service_order[0] = SERVICE_BIND;
  377.     service_order[1] = SERVICE_NONE;
  378.   }
  379.   else
  380.   {
  381.     while (fgets(buf, BUFSIZ, fd) != NULL)
  382.     {
  383.       if ((cp = rindex(buf, '\n')) != NULL)
  384.         *cp = '\0';
  385.       if (buf[0] == '#')
  386.         continue;
  387.  
  388. #define checkbuf(b, cmd) (!strncasecmp(b, cmd, strlen(cmd)))
  389.  
  390.       if (checkbuf(buf, CMD_ORDER))
  391.       {
  392.         cp = strpbrk(buf, " \t");
  393.         if (!cp)
  394.         {
  395.           bad_config_format(CMD_ORDER);
  396.         }
  397.         else
  398.         {
  399.           do
  400.           {
  401.             while (*cp == ' ' || *cp == '\t')
  402.               cp++;
  403.             dp = strpbrk(cp, TOKEN_SEPARATORS);
  404.             if (dp) *dp = '\0';
  405.             if (checkbuf(cp, ORD_BIND))
  406.               service_order[cc++] = SERVICE_BIND;
  407.             else if (checkbuf(cp, ORD_HOSTS))
  408.               service_order[cc++] = SERVICE_HOSTS;
  409.             else if (checkbuf(cp, ORD_NIS))
  410.               service_order[cc++] = SERVICE_NIS;
  411.             else
  412.                 {
  413.               bad_config_format(CMD_ORDER);
  414.               cwprintf(NULL, "resolv+: \"%s\" is an invalid keyword\n", cp);
  415.               cwprintf(NULL, "resolv+: valid keywords are: %s, %s and %s\n",
  416.               ORD_BIND, ORD_HOSTS, ORD_NIS);
  417.             }
  418.  
  419.             if (dp) cp = ++dp;
  420.           }
  421.           while (dp != NULL);
  422.           if (cc == 0)
  423.           {
  424.             bad_config_format(CMD_ORDER);
  425.             cwprintf(NULL, "resolv+: search order not specified or unrecognized keyword, host resolution will fail.\n");
  426.           }
  427.         }
  428.  
  429.       }
  430.       else if (checkbuf(buf, CMD_HMA)) {
  431.         if ( cp = strpbrk(buf, " \t") )
  432.         {
  433.           while (*cp == ' ' || *cp == '\t') cp++;
  434.           if (checkbuf(cp, CMD_ON))
  435.             hosts_multiple_addrs = 1;
  436.         }
  437.         else
  438.             bad_config_format(CMD_HMA);
  439.  
  440.       }
  441.       else if (checkbuf(buf, CMD_SPOOF)) {
  442.         if ( cp = strpbrk(buf, " \t") )
  443.         {
  444.           while (*cp == ' ' || *cp == '\t') cp++;
  445.           if (checkbuf(cp, CMD_ON))
  446.             spoof = 1;
  447.         }
  448.         else
  449.             bad_config_format(CMD_SPOOF);
  450.  
  451.       }
  452.       else if (checkbuf(buf, CMD_SPOOFALERT)) {
  453.         if ( cp = strpbrk(buf, " \t") )
  454.         {
  455.           while (*cp == ' ' || *cp == '\t') cp++;
  456.           if (checkbuf(cp, CMD_ON))
  457.             spoofalert = 1;
  458.         }
  459.         else
  460.             bad_config_format(CMD_SPOOFALERT);
  461.  
  462.       }
  463.       else if (checkbuf(buf, CMD_REORDER)) {
  464.         if (cp = strpbrk(buf, " \t")) {
  465.           while (*cp == ' ' || *cp == '\t') cp++;
  466.           if (checkbuf(cp, CMD_ON))
  467.             reorder = 1;
  468.         }
  469.         else
  470.             bad_config_format(CMD_REORDER);
  471.  
  472.       }
  473.       else if (checkbuf(buf, CMD_TRIMDOMAIN)) {
  474.         if(numtrimdomains<MAXTRIMDOMAINS){
  475.           if ( cp = strpbrk(buf, " \t") )
  476.           {
  477.             while (*cp == ' ' || *cp == '\t') cp++;
  478.             if (cp)
  479.             {
  480.               (void) strcpy(tdp,cp);
  481.               trimdomain[numtrimdomains++]=tdp;
  482.               tdp += strlen(cp)+1;
  483.             }
  484.             else
  485.               bad_config_format(CMD_TRIMDOMAIN);
  486.           }
  487.           else
  488.               bad_config_format(CMD_TRIMDOMAIN);
  489.         }
  490.       }
  491.       else if (checkbuf(buf, CMD_CACHESIZE)) {
  492.         if (cp = strpbrk(buf, " \t")) {
  493.           while (*cp == ' ' || *cp == '\t') cp++;
  494.           cachesize = atoi(cp);
  495.         }
  496.         else
  497.             bad_config_format(CMD_CACHESIZE);
  498.       }
  499.     }
  500.  
  501.     service_order[cc] = SERVICE_NONE;
  502.   }
  503.   fclose(fd);
  504.   /* override service_order if environment variable */
  505.   if(NULL!=(cp=getenv(ENV_SERVORDER))){
  506.     cc=0;
  507.     if(NULL!=(cp=strtok(cp, TOKEN_SEPARATORS))){
  508.       do{
  509.         if(checkbuf(cp, ORD_BIND))
  510.           service_order[cc++] = SERVICE_BIND;
  511.         else if (checkbuf(cp, ORD_HOSTS))
  512.           service_order[cc++] = SERVICE_HOSTS;
  513.         else if (checkbuf(cp, ORD_NIS))
  514.           service_order[cc++] = SERVICE_NIS;
  515.       }
  516.       while(cp=strtok(NULL, TOKEN_SEPARATORS));
  517.       service_order[cc] = SERVICE_NONE;
  518.     }
  519.   }
  520.   /* override spoof if environment variable */
  521.   if(NULL!=(cp=getenv(ENV_SPOOF))){
  522.     if(checkbuf(cp, CMD_WARN)){
  523.       spoof=1;
  524.       spoofalert=1;
  525.     }
  526.     else if (checkbuf(cp, CMD_OFF)){
  527.       spoof=0;
  528.       spoofalert=0;
  529.     }
  530.     else if (checkbuf(cp, CMD_NOWARN)){
  531.       spoof=1;
  532.       spoofalert=0;
  533.     }
  534.     else {
  535.       spoof=1;
  536.     }
  537.   }
  538.  
  539.   /* override hma if environment variable */
  540.   if(NULL!=(cp=getenv(ENV_HMA))) {
  541.     if(checkbuf(cp, CMD_ON))
  542.       hosts_multiple_addrs=1;
  543.     else
  544.         hosts_multiple_addrs=0;
  545.   }
  546.   /* override reorder if environment variable */
  547.   if ((cp = getenv(ENV_REORDER)) != NULL) {
  548.     if (checkbuf(cp, CMD_ON))
  549.       reorder = 1;
  550.     else
  551.         reorder = 0;
  552.   }
  553.   /* add trimdomains from environment variable */
  554.   if(NULL!=(cp=getenv(ENV_TRIM_ADD))){
  555.     if(NULL!=(cp=strtok(cp, TOKEN_SEPARATORS))){
  556.       do{
  557.         if(numtrimdomains<MAXTRIMDOMAINS){
  558.           (void)strcpy(tdp, cp);
  559.           trimdomain[numtrimdomains++]=tdp;
  560.           tdp += strlen(cp)+1;
  561.         }
  562.       }
  563.       while(cp=strtok(NULL, TOKEN_SEPARATORS));
  564.     }
  565.   }
  566.  
  567.   /* override trimdomains from environment variable */
  568.   if(NULL!=(cp=getenv(ENV_TRIM_OVERR))){
  569.     numtrimdomains=0;
  570.     tdp=trimdomainbuf;
  571.     if(NULL!=(cp=strtok(cp, TOKEN_SEPARATORS))){
  572.       do{
  573.         if(numtrimdomains<MAXTRIMDOMAINS){
  574.           (void)strcpy(tdp, cp);
  575.           trimdomain[numtrimdomains++]=tdp;
  576.           tdp += strlen(cp)+1;
  577.         }
  578.       }
  579.       while(cp=strtok(NULL, TOKEN_SEPARATORS));
  580.     }
  581.   }
  582.  
  583.   /* override cache size if environment variable */
  584.   if ((cp = getenv(ENV_CACHESIZE)) != NULL) {
  585.     cachesize = atoi(cp);
  586.   }
  587.  
  588.   cache_init(cachesize);
  589.  
  590.   service_done = 1;
  591. }
  592.  
  593.  
  594. static char *gethostname( char *name, int len )
  595. {
  596.   extern char hostname[];
  597.  
  598.   strncpy( name, hostname, len );
  599.   return name;
  600. }
  601.  
  602.  
  603. _sethtent(int f)
  604. {
  605.   if (hostf == NULL)
  606.     hostf = fopen(HOSTDB, "r" );
  607.   else
  608.       rewind(hostf);
  609.   stayopen |= f;
  610. }
  611.  
  612. _endhtent(void)
  613. {
  614.   if (hostf && !stayopen) {
  615.     (void) fclose(hostf);
  616.     hostf = NULL;
  617.   }
  618. }
  619.  
  620. struct hostent *
  621. _gethtent(void)
  622. {
  623.   char *p;
  624.   register char *cp, **q;
  625.  
  626.   if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL)
  627.     return (NULL);
  628. again:
  629.   if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL)
  630.     return (NULL);
  631.  
  632.   { /* Little patch to ensure variables are translated in the hosts file */
  633.     char xbuf[BUFSIZ];
  634.     var_translate(global_vars, hostbuf, 0, xbuf, BUFSIZ);
  635.     strcpy(hostbuf, xbuf);
  636.   }
  637.   if (*p == '#')
  638.     goto again;
  639.   cp = strpbrk(p, "#\n");
  640.   if (cp == NULL)
  641.     goto again;
  642.   *cp = '\0';
  643.   cp = strpbrk(p, " \t");
  644.   if (cp == NULL)
  645.     goto again;
  646.   *cp++ = '\0';
  647.   /* THIS STUFF IS INTERNET SPECIFIC */
  648. #if BSD >= 43 || defined(h_addr)    /* new-style hostent structure */
  649.   host.h_addr_list = host_addrs;
  650. #endif
  651.   host.h_addr = hostaddr;
  652.   *((u_long *)host.h_addr) = res_inet_addr(p);
  653.   host.h_mx = mx_ptrs;
  654.   mx_ptrs[0] = NULL;
  655.   host.h_length = sizeof (u_long);
  656.   host.h_addrtype = AF_INET;
  657.   while (*cp == ' ' || *cp == '\t')
  658.     cp++;
  659.   host.h_name = cp;
  660.   q = host.h_aliases = host_aliases;
  661.   cp = strpbrk(cp, " \t");
  662.   if (cp != NULL)
  663.     *cp++ = '\0';
  664.   while (cp && *cp) {
  665.     if (*cp == ' ' || *cp == '\t') {
  666.       cp++;
  667.       continue;
  668.     }
  669.     if (q < &host_aliases[MAXALIASES - 1])
  670.       *q++ = cp;
  671.     cp = strpbrk(cp, " \t");
  672.     if (cp != NULL)
  673.       *cp++ = '\0';
  674.   }
  675.   *q = NULL;
  676.   return (&host);
  677. }
  678.  
  679.  
  680.  
  681. static u_long ntohl(u_long t)
  682. {
  683.   union {
  684.     u_long l;
  685.     u_char b[4];
  686.   }
  687.   tr;
  688.   tr.b[0] = t>>24;
  689.   tr.b[1] = t>>16;
  690.   tr.b[2] = t>>8;
  691.   tr.b[3] = t;
  692.   return tr.l;
  693. }
  694.  
  695. static u_short ntohs( u_short t )
  696. {
  697.   union {
  698.     u_short l;
  699.     u_char b[2];
  700.   }
  701.   tr;
  702.  
  703.   tr.b[0] = t>>8;
  704.   tr.b[1] = t;
  705.   return tr.l;
  706. }
  707.  
  708. static u_short htons( u_short t )
  709. {
  710.   union {
  711.     u_short l;
  712.     u_char b[4];
  713.   }
  714.   tr;
  715.  
  716.   tr.b[0] = t>>8;
  717.   tr.b[1] = t;
  718.   return tr.l;
  719. }
  720.  
  721.  
  722. void revcopy( char *s, char *d, int n )
  723. {
  724.   for( s+=n; n; n-- ) *(d++) = *(--s);
  725. }
  726.  
  727.  
  728. int _mx_sort(const void *o1, const void *o2)
  729. {
  730.   if (((struct mx_data *) o1)->preference < ((struct mx_data *) o2)->preference)
  731.     return -1;
  732.   else if (((struct mx_data *) o1)->preference == ((struct mx_data *) o2)->preference )
  733.     return 0;
  734.   else
  735.     return 1;
  736. }
  737.  
  738.  
  739. static struct hostent *
  740. getanswer(querybuf *answer, int anslen, int iquery, int mxquery, long *ansttl)
  741. {
  742.   register HEADER *hp;
  743.   register u_char *cp;
  744.   register int n;
  745.   u_char *eom;
  746.   char *bp, **ap;
  747.   int type, class, buflen, ancount, qdcount;
  748.   int haveanswer, getclass = C_ANY;
  749.   char **hap;
  750.   struct mx_data **mx, *nextmx;
  751.   int mxrecs=0;
  752.   long ttl;
  753.  
  754.   *ansttl = 0x7fffffff;
  755.   eom = answer->buf + anslen;
  756.   /*
  757.        * find first satisfactory answer
  758.        */
  759.   hp = &answer->hdr;
  760.   ancount = ntohs(hp->ancount);
  761.   qdcount = ntohs(hp->qdcount);
  762. #ifdef DEBUG
  763.   if (_res.options & RES_DEBUG)
  764.     cwprintf(NULL, "Got %d answers and %d questions\n", ancount, qdcount);
  765. #endif /* DEBUG */
  766.   bp = hostbuf;
  767.   buflen = sizeof(hostbuf);
  768.   cp = answer->buf + sizeof(HEADER);
  769.   if (qdcount) {
  770.     if (iquery || mxquery) {
  771.       if ((n = dn_expand((char *)answer->buf, eom,
  772.       cp, bp, buflen)) < 0) {
  773.         h_errno = NO_RECOVERY;
  774.         return ((struct hostent *) NULL);
  775.       }
  776.       cp += n + QFIXEDSZ;
  777.       host.h_name = bp;
  778.       n = strlen(bp) + 1;
  779.       bp += n;
  780.       buflen -= n;
  781.     }
  782.     else
  783.         cp += dn_skipname(cp, eom) + QFIXEDSZ;
  784.     while (--qdcount > 0)
  785.       cp += dn_skipname(cp, eom) + QFIXEDSZ;
  786.   }
  787.   else if (iquery) {
  788.     if (hp->aa)
  789.       h_errno = HOST_NOT_FOUND;
  790.     else
  791.         h_errno = TRY_AGAIN;
  792.     return ((struct hostent *) NULL);
  793.   }
  794.   ap = host_aliases;
  795.   *ap = NULL;
  796.   host.h_aliases = host_aliases;
  797.   hap = h_addr_ptrs;
  798.   *hap = NULL;
  799.   host.h_mx = mx_ptrs;
  800.   mx = mx_ptrs;
  801.   *mx = NULL;
  802.   nextmx = mx_conts;
  803. #if BSD >= 43 || defined(h_addr)    /* new-style hostent structure */
  804.   host.h_addr_list = h_addr_ptrs;
  805. #endif
  806.   haveanswer = 0;
  807.   while (--ancount >= 0 && cp < eom) {
  808.     if ((n = dn_expand((char *)answer->buf, eom, cp, bp, buflen)) < 0)
  809.       break;
  810.     cp += n;
  811.     type = _getshort(cp);
  812.     cp += sizeof(u_short);
  813.     class = _getshort(cp);
  814.     cp += sizeof(u_short);
  815.     if ((ttl = _getlong(cp)) < *ansttl)
  816.       *ansttl = ttl;
  817.     cp += sizeof(u_long);
  818.     n = _getshort(cp);
  819.     cp += sizeof(u_short);
  820.     if (type == T_CNAME) {
  821.       cp += n;
  822.       if (ap >= &host_aliases[MAXALIASES-1])
  823.         continue;
  824.       *ap++ = bp;
  825.       n = strlen(bp) + 1;
  826.       bp += n;
  827.       buflen -= n;
  828.       mxrecs++;
  829.       continue;
  830.     }
  831.     if (type == T_MX) {       /* MX record */
  832.       int i;
  833.       if( trace ) cwprintf(NULL, "MX record in answer\n" );
  834.       if ((i = dn_expand((char *)answer->buf, eom, cp+sizeof(u_short), bp, buflen)) < 0) {
  835.         cp += n;
  836.         continue;
  837.       }
  838.       *mx = nextmx++;
  839.       mxrecs++;
  840.       mx[1] = NULL;
  841.       (*mx)->preference = _getshort(cp);
  842.       (*mx)->host = bp;
  843.       mx++;
  844.       if( trace ) cwprintf(NULL, "MX host: %s\n", bp );
  845.       cp += n;
  846.       n = strlen(bp) + 1;
  847.       bp += n;
  848.       buflen -= n;
  849.       continue;
  850.     }
  851.     if (iquery && type == T_PTR) {
  852.       if ((n = dn_expand((char *)answer->buf, eom,
  853.       cp, bp, buflen)) < 0) {
  854.         cp += n;
  855.         continue;
  856.       }
  857.       cp += n;
  858.       host.h_name = bp;
  859.       return(&host);
  860.     }
  861.     if (iquery || type != T_A)  {
  862. #ifdef DEBUG
  863.       if (_res.options & RES_DEBUG)
  864.         printf("unexpected answer type %d, size %d\n",
  865.         type, n);
  866. #endif
  867.       cp += n;
  868.       continue;
  869.     }
  870.     if (haveanswer) {
  871.       if (n != host.h_length) {
  872.         cp += n;
  873.         continue;
  874.       }
  875.       if (class != getclass) {
  876.         cp += n;
  877.         continue;
  878.       }
  879.     }
  880.     else {
  881.       host.h_length = n;
  882.       getclass = class;
  883.       host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
  884.       if (!iquery) {
  885.         host.h_name = bp;
  886.         bp += strlen(bp) + 1;
  887.       }
  888.     }
  889.  
  890.     bp += sizeof(align) - ((u_long)bp % sizeof(align));
  891.  
  892.     if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
  893. #ifdef DEBUG
  894.       if (_res.options & RES_DEBUG)
  895.         printf("size (%d) too big\n", n);
  896. #endif
  897.       break;
  898.     }
  899.     revcopy((char *)cp, *hap++ = bp, n);
  900.     bp +=n;
  901.     cp += n;
  902.     haveanswer++;
  903.   }
  904.   if (haveanswer || (mxquery && mxrecs) ) {
  905.     *ap = NULL;
  906. #if BSD >= 43 || defined(h_addr)    /* new-style hostent structure */
  907.     *hap = NULL;
  908. #else
  909.     host.h_addr = h_addr_ptrs[0];
  910. #endif
  911.     if (mxrecs)
  912.       qsort(mx_conts, mxrecs, sizeof(struct mx_data), _mx_sort);
  913.     return(&host);
  914.   }
  915.   else
  916.   {
  917.     h_errno = TRY_AGAIN;
  918.     return ((struct hostent *) NULL);
  919.   }
  920. }
  921.  
  922.  
  923.  
  924. static void
  925. dotrimdomain(char *c)
  926. {
  927.   /* assume c points to the start of a host name; trim off any
  928.          domain name matching any of the trimdomains */
  929.   int d,l1,l2;
  930.  
  931.   for(d=0;d<numtrimdomains;d++){
  932.     l1=strlen(trimdomain[d]);
  933.     l2=strlen(c);
  934.     if(l2>l1 && !strcasecmp(c+l2-l1,trimdomain[d]))
  935.       *(c+(strlen(c)-l1))='\0';
  936.   }
  937. }
  938.  
  939. static struct hostent *
  940. trim_domains(struct hostent *h)
  941. {
  942.   if(numtrimdomains){
  943.     int i;
  944.     dotrimdomain(h->h_name);
  945.     for(i=0;h->h_aliases[i];i++)
  946.       dotrimdomain(h->h_aliases[i]);
  947.   }
  948.   return(h);
  949. }
  950.  
  951.  
  952. struct hostent *
  953. _gethtbyaddr(int addr, int len, int type)
  954. {
  955.   register struct hostent *p;
  956.   register char **cp;
  957.   int found=0;
  958.  
  959.   /* Reset the hosts file */
  960.   _sethtent(0);
  961.  
  962.   /* Loop over the entries from the hosts file */
  963.   while (p = _gethtent()) {
  964.  
  965.     /* Look for a matching address */
  966.     if ((p->h_length == len) && (p->h_addrtype == type))
  967.       for (cp = p->h_addr_list; *cp != 0; cp++)
  968.         if (memcmp(*cp, &addr, p->h_length) == 0)
  969.           found++;
  970.  
  971.     /* Found the address */
  972.     if (found) {
  973.       _endhtent();
  974.       return(p);
  975.     }
  976.   }
  977.  
  978.   /* Finish with the hosts file */
  979.   _endhtent();
  980.  
  981.   return((struct hostent *)NULL);
  982. }
  983.  
  984. struct hostent *gethostbyaddr(unsigned int addr, int len, int type)
  985. {
  986.   char name[128];
  987.   querybuf buf;
  988.   int n;
  989.   register int cc;
  990.   struct hostent *hp;
  991.   long ttl;
  992.  
  993.   /* See if the address is already cached */
  994.   if(!cache_req(&addr, CACHE_ADDR, len, &hp))
  995.     return hp;
  996.  
  997.   /* Initalise if necessary */
  998.   if ((_res.options & RES_INIT) == 0)
  999.     resolve_init();
  1000.   if (!service_done)
  1001.     init_services();
  1002.  
  1003.   /* Loop over the service order list, trying to find the target */
  1004.   for (cc = 0; service_order[cc] != SERVICE_NONE && cc <= SERVICE_MAX; cc++) {
  1005.     switch (service_order[cc]) {
  1006.       case SERVICE_BIND:
  1007.         if ((type != AF_INET) || (len != 4))
  1008.           break;
  1009.         sprintf(name, "%d.%d.%d.%d.IN-ADDR.ARPA", addr&255,
  1010.                 (addr>>8)&255, (addr>>16)&255, addr>>24);
  1011.         if ((n = res_query(name, C_IN, T_PTR, buf.buf, sizeof(buf))) < 0) {
  1012. #ifdef DEBUG
  1013.           if (_res.options & RES_DEBUG)
  1014.             cwprintf(NULL, "res_query failed\n");
  1015. #endif
  1016.           break;
  1017.         }
  1018.         hp = getanswer(&buf, n, 1, 0, &ttl);
  1019.         /*            if (h_addr_ptrs[1] && reorder)
  1020.                         reorder_addrs(hp); we do never reorder */
  1021.         if (hp) {
  1022.           hp = trim_domains(hp);
  1023.           hp->h_length = len;
  1024.           hp->h_addrtype = type;
  1025.           hp->h_addr_list[0] = hostbuf;
  1026.           bcopy(&addr, hostbuf, len);
  1027.           hp->h_addr_list[1] = 0;
  1028.           cache_it(&addr, CACHE_ADDR, len, hp, ttl);
  1029.           return hp;
  1030.         }
  1031.         break;
  1032.  
  1033.       case SERVICE_HOSTS:
  1034.         hp = _gethtbyaddr(addr, len, type);
  1035.         /*            if (h_addr_ptrs[1] && reorder)
  1036.                       reorder_addrs(hp); we do never reorder */
  1037.         if (hp) {
  1038.           cache_it(&addr, CACHE_ADDR, len, hp, CACHE_OBSOLETE);
  1039.           return hp;
  1040.         }
  1041.         h_errno = HOST_NOT_FOUND;
  1042.         break;
  1043.  
  1044. #ifdef NIS
  1045.       case SERVICE_NIS:
  1046.         hp = _getnishost(name, "hosts.byaddr");
  1047.         /*            if (h_addr_ptrs[1] && reorder)
  1048.                         reorder_addrs(hp); we do never reorder */
  1049.         if (hp) {
  1050.           cache_it(&addr, CACHE_ADDR, len, hp, CACHE_OBSOLETE);
  1051.           return hp;
  1052.         }
  1053.         h_errno = HOST_NOT_FOUND;
  1054.         break;
  1055. #endif
  1056.     }
  1057.   }
  1058.  
  1059.   /* Cache the fact that we can't find the address */
  1060.   cache_it(&addr, CACHE_ADDR, len, NULL, CACHE_OBSOLETE);
  1061.  
  1062.   return NULL;
  1063. }
  1064.  
  1065. /* if hosts_multiple_addrs set, then gethtbyname behaves as follows:
  1066.  *  - for hosts with multiple addresses, return all addresses, such that
  1067.  *  the first address is most likely to be one on the same net as the
  1068.  *  host we're running on, if one exists.
  1069.  *  - like the dns version of gethostsbyname, the alias field is empty
  1070.  *  unless the name being looked up is an alias itself, at which point the
  1071.  *  alias field contains that name, and the name field contains the primary
  1072.  *  name of the host. Unlike dns, however, this behavior will still take place
  1073.  *  even if the alias applies only to one of the interfaces.
  1074.  *  - determining a "local" address to put first is dependant on the netmask
  1075.  *  being such that the least significant network bit is more significant
  1076.  *  than any host bit. Only strange netmasks will violate this.
  1077.  *  - we assume addresses fit into u_longs. That's quite internet specific.
  1078.  *  - if the host we're running on is not in the host file, the address
  1079.  *  shuffling will not take place.
  1080.  *                     - John DiMarco <jdd@cdf.toronto.edu>
  1081.  */
  1082. struct hostent *
  1083. _gethtbyname(char *name)
  1084. {
  1085.   register struct hostent *p;
  1086.   register char **cp;
  1087.   char **hap, **lhap, *bp, *lbp;
  1088.   int htbuflen, locbuflen;
  1089.   int found=0, localfound=0;
  1090.   char localname[MAXHOSTNAMELEN];
  1091.  
  1092.   static char htbuf[BUFSIZ+1]; /* buffer for host addresses */
  1093.   static char locbuf[BUFSIZ+1]; /* buffer for local hosts's addresses */
  1094.   static char *ht_addr_ptrs[MAXADDRS+1];
  1095.   static char *loc_addr_ptrs[MAXADDRS+1];
  1096.   static struct hostent ht;
  1097.   static char *aliases[MAXALIASES];
  1098.   static char namebuf[MAXHOSTNAMELEN];
  1099.   static struct mx_data *dummymx[1];
  1100.  
  1101.   hap = ht_addr_ptrs;
  1102.   lhap = loc_addr_ptrs;
  1103.   *hap = NULL;
  1104.   *lhap = NULL;
  1105.   bp=htbuf;
  1106.   lbp=locbuf;
  1107.   htbuflen = sizeof(htbuf);
  1108.   locbuflen = sizeof(locbuf);
  1109.   ht.h_mx = dummymx;
  1110.   dummymx[0] = NULL;
  1111.  
  1112.   aliases[0]=NULL;
  1113.   aliases[1]=NULL;
  1114.   (void) strcpy(namebuf, name);
  1115.  
  1116.   (void)gethostname(localname, sizeof(localname));
  1117.  
  1118.   _sethtent(0);
  1119.   while (p = _gethtent()) {
  1120.     if (strcasecmp(p->h_name, name) == 0)
  1121.       found++;
  1122.     else
  1123.       for (cp = p->h_aliases; *cp != 0; cp++)
  1124.         if (strcasecmp(*cp, name) == 0){
  1125.           found++;
  1126.           aliases[0]=name;
  1127.           (void) strcpy(namebuf, p->h_name);
  1128.         }
  1129.     if (strcasecmp(p->h_name, localname) == 0)
  1130.       localfound++;
  1131.     else
  1132.         for (cp=p->h_aliases; *cp != 0; cp++)
  1133.       if (strcasecmp(*cp, localname) == 0)
  1134.         localfound++;
  1135.  
  1136.     if(found){
  1137.       int n;
  1138.  
  1139.       if(!hosts_multiple_addrs){
  1140.         /* original behaviour requested */
  1141.         _endhtent();
  1142.         return(p);
  1143.       }
  1144.       n = p->h_length;
  1145.  
  1146.       ht.h_addrtype = p->h_addrtype;
  1147.       ht.h_length = p->h_length;
  1148.  
  1149.       if(n<=htbuflen){
  1150.         /* add the found address to the list */
  1151.         bcopy(p->h_addr_list[0], bp, n);
  1152.         *hap++=bp;
  1153.         *hap=NULL;
  1154.         bp+=n;
  1155.         htbuflen-=n;
  1156.       }
  1157.       found=0;
  1158.     }
  1159.     if(localfound){
  1160.       int n = p->h_length;
  1161.       if(n<=locbuflen){
  1162.         /* add the found local address to the list */
  1163.         bcopy(p->h_addr_list[0], lbp, n);
  1164.         *lhap++=lbp;
  1165.         *lhap=NULL;
  1166.         lbp+=n;
  1167.         locbuflen-=n;
  1168.       }
  1169.       localfound=0;
  1170.     }
  1171.   }
  1172.   _endhtent();
  1173.  
  1174.   if(NULL==ht_addr_ptrs[0]){
  1175.     return((struct hostent *)NULL);
  1176.   }
  1177.  
  1178.   ht.h_aliases = aliases;
  1179.   ht.h_name = namebuf;
  1180.  
  1181.   /* shuffle addresses around to ensure one on same net as local host
  1182.          is first, if exists */
  1183.   {
  1184.     /* "best" address is assumed to be the one with the greatest
  1185.                number of leftmost bits matching any of the addresses of
  1186.                the local host. This assumes a netmask in which all net
  1187.                bits precede host bits. Usually but not always a fair
  1188.                assumption. */
  1189.  
  1190.     /* portability alert: assumption: iaddr fits in u_long.
  1191.                This is really internet specific. */
  1192.     int i,j, best=0;
  1193.     u_long bestval = (u_long)~0;
  1194.  
  1195.     for(i=0;loc_addr_ptrs[i];i++){
  1196.       for(j=0;ht_addr_ptrs[j];j++){
  1197.         u_long t, l, h;
  1198.         /* assert(sizeof(u_long)>=ht.h_length); */
  1199.         bcopy(loc_addr_ptrs[i], (char *)&t,
  1200.         ht.h_length);
  1201.         l=ntohl(t);
  1202.         bcopy(ht_addr_ptrs[j], (char *)&t,
  1203.         ht.h_length);
  1204.         t=l^h;
  1205.  
  1206.         if(t<bestval){
  1207.           best=j;
  1208.           bestval=t;
  1209.         }
  1210.       }
  1211.     }
  1212.     if(best){
  1213.       char *tmp;
  1214.  
  1215.       /* swap first and best address */
  1216.       tmp=ht_addr_ptrs[0];
  1217.       ht_addr_ptrs[0]=ht_addr_ptrs[best];
  1218.       ht_addr_ptrs[best]=tmp;
  1219.     }
  1220.   }
  1221.  
  1222.   ht.h_addr_list = ht_addr_ptrs;
  1223.   return (&ht);
  1224. }
  1225.  
  1226.  
  1227. struct hostent *gethostbyname(char *name, int mxquery)
  1228. {
  1229.   querybuf buf;
  1230.   register char *cp;
  1231.   register int cc;
  1232.   int n;
  1233.   struct hostent *hp;
  1234.   long ttl;
  1235.   extern struct hostent *_gethtbyname();
  1236.  
  1237.   if( !cache_req(name,mxquery?CACHE_MX:CACHE_NAME,strlen(name),&hp) ) return hp;
  1238.   if ((_res.options & RES_INIT) == 0)
  1239.     resolve_init();
  1240.   /*
  1241.        * disallow names consisting only of digits/dots, unless
  1242.        * they end in a dot.
  1243.        */
  1244.   if (isdigit(name[0]))
  1245.     for (cp = name;; ++cp) {
  1246.       if (!*cp) {
  1247.         if (*--cp == '.')
  1248.           break;
  1249.         /*
  1250.                          * All-numeric, no dot at the end.
  1251.                          * Fake up a hostent as if we'd actually
  1252.                          * done a lookup.  What if someone types
  1253.                          * 255.255.255.255?  The test below will
  1254.                          * succeed spuriously... ???
  1255.                          */
  1256.         if ((host_addr.s_addr = res_inet_addr(name)) == -1) {
  1257.           h_errno = HOST_NOT_FOUND;
  1258.           cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), NULL, CACHE_OBSOLETE );
  1259.           return((struct hostent *) NULL);
  1260.         }
  1261.         host.h_name = name;
  1262.         host.h_aliases = host_aliases;
  1263.         host_aliases[0] = NULL;
  1264.         host.h_addrtype = AF_INET;
  1265.         host.h_length = sizeof(u_long);
  1266.         h_addr_ptrs[0] = (char *)&host_addr;
  1267.         h_addr_ptrs[1] = (char *)0;
  1268. #if BSD >= 43 || defined(h_addr)    /* new-style hostent structure */
  1269.         host.h_addr_list = h_addr_ptrs;
  1270. #else
  1271.         host.h_addr = h_addr_ptrs[0];
  1272. #endif
  1273.         cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), &host, CACHE_OBSOLETE );
  1274.         return (&host);
  1275.       }
  1276.       if (!isdigit(*cp) && *cp != '.')
  1277.         break;
  1278.     }
  1279.  
  1280.   if (!service_done)
  1281.     init_services();
  1282.  
  1283.   for (cc = 0; service_order[cc] != SERVICE_NONE &&
  1284.          cc <= SERVICE_MAX; cc++) {
  1285.         switch (service_order[cc]) {
  1286.     case SERVICE_BIND:
  1287.       if ((n = res_search(name, C_IN, mxquery?T_MX:T_A,
  1288.       buf.buf, sizeof(buf))) < 0) {
  1289. #ifdef DEBUG
  1290.         if (_res.options & RES_DEBUG)
  1291.           cwprintf(NULL, "res_search failed\n");
  1292. #endif
  1293.         break;
  1294.       }
  1295.       hp = getanswer(&buf, n, 0, mxquery, &ttl);
  1296.       /*            if (h_addr_ptrs[1] && reorder)
  1297.                       reorder_addrs(hp); we do never reorder */
  1298.       if (hp) {
  1299.         hp = trim_domains(hp);
  1300.         cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), hp, ttl );
  1301.         return hp;
  1302.       }
  1303.       break;
  1304.  
  1305.     case SERVICE_HOSTS:
  1306.       if (mxquery) break;  /* MX records are not recorded in 'hosts' file */
  1307.  
  1308.       hp = _gethtbyname(name);
  1309.       /*            if (h_addr_ptrs[1] && reorder)
  1310.                       reorder_addrs(hp); we do never reorder */
  1311.       if (hp) {
  1312.         cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), hp, CACHE_OBSOLETE );
  1313.         return hp;
  1314.       }
  1315.       h_errno = HOST_NOT_FOUND;
  1316.       break;
  1317. #ifdef NIS
  1318.     case SERVICE_NIS:
  1319.       hp = _getnishost(name, "hosts.byname");
  1320.       /*            if (h_addr_ptrs[1] && reorder)
  1321.                       reorder_addrs(hp); we do never reorder */
  1322.       if (hp) {
  1323.         cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), hp, CACHE_OBSOLETE );
  1324.         return hp;
  1325.       }
  1326.       h_errno = HOST_NOT_FOUND;
  1327.       break;
  1328. #endif
  1329.     }
  1330.   }
  1331.   cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), NULL, CACHE_OBSOLETE );
  1332.   return ((struct hostent *) NULL);
  1333. }
  1334.  
  1335.  
  1336.  
  1337. /*
  1338.  * This array is designed for mapping upper and lower case letter
  1339.  * together for a case independent comparison.  The mappings are
  1340.  * based upon ascii character sequences.
  1341.  */
  1342. static u_char charmap[] = {
  1343.   '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
  1344.   '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
  1345.   '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
  1346.   '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
  1347.   '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
  1348.   '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
  1349.   '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
  1350.   '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
  1351.   '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
  1352.   '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
  1353.   '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
  1354.   '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
  1355.   '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
  1356.   '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
  1357.   '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
  1358.   '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
  1359.   '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
  1360.   '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
  1361.   '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
  1362.   '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
  1363.   '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
  1364.   '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
  1365.   '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
  1366.   '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
  1367.   '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
  1368.   '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
  1369.   '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
  1370.   '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
  1371.   '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
  1372.   '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
  1373.   '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
  1374.   '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
  1375. };
  1376.  
  1377. int
  1378. strcasecmp(char *s1, char *s2)
  1379. {
  1380.   register u_char    *cm = charmap,
  1381.   *us1 = (u_char *)s1,
  1382.   *us2 = (u_char *)s2;
  1383.  
  1384.   while (cm[*us1] == cm[*us2++])
  1385.     if (*us1++ == '\0')
  1386.       return(0);
  1387.   return(cm[*us1] - cm[*--us2]);
  1388. }
  1389.  
  1390. int
  1391. strncasecmp(char *s1, char *s2, register int n)
  1392. {
  1393.   register u_char    *cm = charmap,
  1394.   *us1 = (u_char *)s1,
  1395.   *us2 = (u_char *)s2;
  1396.  
  1397.   while (--n >= 0 && cm[*us1] == cm[*us2++])
  1398.     if (*us1++ == '\0')
  1399.       return(0);
  1400.   return(n < 0 ? 0 : cm[*us1] - cm[*--us2]);
  1401. }
  1402.  
  1403.  
  1404. char *hostalias(char *);
  1405.  
  1406. int
  1407. res_query(char *name, int class, int type, u_char *answer, int anslen)
  1408. /* size of answer buffer */
  1409. {
  1410.   char buf[MAXPACKET];
  1411.   HEADER *hp;
  1412.   int n;
  1413.  
  1414.   if ((_res.options & RES_INIT) == 0 && resolve_init() == -1)
  1415.     return (-1);
  1416. #ifdef DEBUG
  1417.   if (_res.options & RES_DEBUG)
  1418.     cwprintf(NULL, "res_query(%s, %d, %d)\n", name, class, type);
  1419. #endif
  1420.   n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
  1421.   buf, sizeof(buf));
  1422.  
  1423.   if (n <= 0) {
  1424. #ifdef DEBUG
  1425.     if (_res.options & RES_DEBUG)
  1426.       cwprintf(NULL, "res_query: mkquery failed\n");
  1427. #endif
  1428.     h_errno = NO_RECOVERY;
  1429.     return (n);
  1430.   }
  1431.   n = res_send(buf, n, answer, anslen);
  1432.   if (n < 0) {
  1433. #ifdef DEBUG
  1434.     if (_res.options & RES_DEBUG)
  1435.       cwprintf(NULL, "res_query: send error\n");
  1436. #endif
  1437.     h_errno = TRY_AGAIN;
  1438.     return(n);
  1439.   }
  1440.  
  1441.   hp = (HEADER *) answer;
  1442.   if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
  1443. #ifdef DEBUG
  1444.     if (_res.options & RES_DEBUG)
  1445.       cwprintf(NULL, "rcode = %d, ancount=%d\n", hp->rcode,
  1446.       ntohs(hp->ancount));
  1447. #endif
  1448.     switch (hp->rcode) {
  1449.     case NXDOMAIN:
  1450.       h_errno = HOST_NOT_FOUND;
  1451.       break;
  1452.     case SERVFAIL:
  1453.       h_errno = TRY_AGAIN;
  1454.       break;
  1455.     case NOERROR:
  1456.       h_errno = NO_DATA;
  1457.       break;
  1458.     case FORMERR:
  1459.     case NOTIMP:
  1460.     case REFUSED:
  1461.     default:
  1462.       h_errno = NO_RECOVERY;
  1463.       break;
  1464.     }
  1465.     return (-1);
  1466.   }
  1467.   return(n);
  1468. }
  1469.  
  1470.  
  1471. /*
  1472.  * Perform a call on res_query on the concatenation of name and domain,
  1473.  * removing a trailing dot from name if domain is NULL.
  1474.  */
  1475. int
  1476. res_querydomain(char *name, char *domain, int class, int type,
  1477. u_char *answer, int anslen)
  1478. /* size of answer */
  1479. {
  1480.   char nbuf[2*MAXDNAME+2];
  1481.   char *longname = nbuf;
  1482.   int n;
  1483.  
  1484. #ifdef DEBUG
  1485.   if (_res.options & RES_DEBUG)
  1486.     cwprintf(NULL, "res_querydomain(%s, %s, %d, %d)\n",
  1487.     name, domain?domain:"", class, type);
  1488. #endif
  1489.   if (domain == NULL) {
  1490.     /*
  1491.              * Check for trailing '.';
  1492.              * copy without '.' if present.
  1493.              */
  1494.     n = strlen(name) - 1;
  1495.     if (name[n] == '.' && n < sizeof(nbuf) - 1) {
  1496.       bcopy(name, nbuf, n);
  1497.       nbuf[n] = '\0';
  1498.     }
  1499.     else
  1500.       longname = name;
  1501.   }
  1502.   else
  1503.       (void)sprintf(nbuf, "%.*s.%.*s",
  1504.   MAXDNAME, name, MAXDNAME, domain);
  1505.  
  1506.   return (res_query(longname, class, type, answer, anslen));
  1507. }
  1508.  
  1509.  
  1510. int
  1511. res_search(char *name, int class, int type, u_char *answer, int anslen)
  1512. /* size of answer */
  1513. {
  1514.   register char *cp, **domain;
  1515.   int n, ret, got_nodata = 0;
  1516.   char *hostalias();
  1517.  
  1518.   if ((_res.options & RES_INIT) == 0 && resolve_init() == -1)
  1519.     return (-1);
  1520.  
  1521.   errno = 0;
  1522.   h_errno = HOST_NOT_FOUND;        /* default, if we never query */
  1523.   if( type == T_MX ) {
  1524.     ret = res_querydomain(name, (char *)NULL, class, type, answer, anslen);
  1525.     return ret;   /* do not use 'searches' for MX find */
  1526.   }
  1527.  
  1528.   for (cp = name, n = 0; *cp; cp++)
  1529.     if (*cp == '.')
  1530.       n++;
  1531.   if (n == 0 && (cp = hostalias(name)))
  1532.     return (res_query(cp, class, type, answer, anslen));
  1533.  
  1534.   /*
  1535.        * If it has two or more dots there is a good change it is
  1536.        * fully qualified so try it first.
  1537.        */
  1538.   if ((n >= 2) && (ret = res_querydomain(name, (char *)NULL, class,
  1539.   type, answer, anslen)) > 0)
  1540.     return (ret);
  1541.  
  1542.   /*
  1543.        * We do at least one level of search if
  1544.        *    - there is no dot and RES_DEFNAME is set, or
  1545.        *    - there is at least one dot, there is no trailing dot,
  1546.        *      and RES_DNSRCH is set.
  1547.        */
  1548.   if ((n == 0 && _res.options & RES_DEFNAMES) ||
  1549.       (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
  1550.     for (domain = _res.dnsrch; *domain; domain++) {
  1551.       ret = res_querydomain(name, *domain, class, type,
  1552.       answer, anslen);
  1553.       if (ret > 0)
  1554.         return (ret);
  1555.       /*
  1556.                * If no server present, give up.
  1557.                * If name isn't found in this domain,
  1558.                * keep trying higher domains in the search list
  1559.                * (if that's enabled).
  1560.                * On a NO_DATA error, keep trying, otherwise
  1561.                * a wildcard entry of another type could keep us
  1562.                * from finding this entry higher in the domain.
  1563.                * If we get some other error (negative answer or
  1564.                * server failure), then stop searching up,
  1565.                * but try the input name below in case it's fully-qualified.
  1566.                */
  1567.       if (errno == ECONNREFUSED) {
  1568.         h_errno = TRY_AGAIN;
  1569.         return (-1);
  1570.       }
  1571.       if (h_errno == NO_DATA)
  1572.         got_nodata++;
  1573.       if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
  1574.           (_res.options & RES_DNSRCH) == 0)
  1575.         break;
  1576.     }
  1577.   /*
  1578.        * If the search/default failed, try the name as fully-qualified,
  1579.        * but only if it contained at least one dot (even trailing).
  1580.        * This is purely a heuristic; we assume that any reasonable query
  1581.        * about a top-level domain (for servers, SOA, etc) will not use
  1582.        * res_search.
  1583.        */
  1584.   if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
  1585.   answer, anslen)) > 0)
  1586.     return (ret);
  1587.   if (got_nodata)
  1588.     h_errno = NO_DATA;
  1589.   return (-1);
  1590. }
  1591.  
  1592.  
  1593. char *
  1594. hostalias(register char *name)
  1595. {
  1596.   register char *C1, *C2;
  1597.   FILE *fp;
  1598.   char *file;
  1599.   char buf[BUFSIZ];
  1600.   static char abuf[MAXDNAME];
  1601.  
  1602.   file = getenv("HOSTALIASES");
  1603.   if (file == NULL || (fp = fopen(file, "r")) == NULL)
  1604.     return (NULL);
  1605.   buf[sizeof(buf) - 1] = '\0';
  1606.   while (fgets(buf, sizeof(buf), fp)) {
  1607.     for (C1 = buf; *C1 && !isspace(*C1); ++C1);
  1608.     if (!*C1)
  1609.       break;
  1610.     *C1 = '\0';
  1611.     if (!strcasecmp(buf, name)) {
  1612.       while (isspace(*++C1));
  1613.       if (!*C1)
  1614.         break;
  1615.       for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
  1616.       abuf[sizeof(abuf) - 1] = *C2 = '\0';
  1617.       (void)strncpy(abuf, C1, sizeof(abuf) - 1);
  1618.       fclose(fp);
  1619.       return (abuf);
  1620.     }
  1621.   }
  1622.   fclose(fp);
  1623.   return (NULL);
  1624. }
  1625.  
  1626.  
  1627.  
  1628. /*
  1629.  * Form all types of queries.
  1630.  * Returns the size of the result or -1.
  1631.  */
  1632. int
  1633. res_mkquery(int op, char *dname, int class, int type, char *data,
  1634. int datalen, struct rrec *newrr, char *buf, int buflen)
  1635. /* size of buffer */
  1636. {
  1637.   register HEADER *hp;
  1638.   register char *cp;
  1639.   register int n;
  1640.   char *dnptrs[10], **dpp, **lastdnptr;
  1641.  
  1642. #ifdef DEBUG
  1643.   if (_res.options & RES_DEBUG)
  1644.     cwprintf(NULL, "res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type);
  1645. #endif /* DEBUG */
  1646.   /*
  1647.        * Initialize header fields.
  1648.        */
  1649.   if ((buf == NULL) || (buflen < sizeof(HEADER)))
  1650.     return(-1);
  1651.   bzero(buf, sizeof(HEADER));
  1652.   hp = (HEADER *) buf;
  1653.   hp->id = htons(++_res.id);
  1654.   hp->opcode = op;
  1655.   hp->pr = (_res.options & RES_PRIMARY) != 0;
  1656.   hp->rd = (_res.options & RES_RECURSE) != 0;
  1657.   hp->rcode = NOERROR;
  1658.   cp = buf + sizeof(HEADER);
  1659.   buflen -= sizeof(HEADER);
  1660.   dpp = dnptrs;
  1661.   *dpp++ = buf;
  1662.   *dpp++ = NULL;
  1663.   lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
  1664.   /*
  1665.        * perform opcode specific processing
  1666.        */
  1667.   switch (op) {
  1668.   case QUERY:
  1669.     if ((buflen -= QFIXEDSZ) < 0)
  1670.       return(-1);
  1671.     if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
  1672.       return (-1);
  1673.     cp += n;
  1674.     buflen -= n;
  1675.     putshort(type, cp);
  1676.     cp += sizeof(u_short);
  1677.     putshort(class, cp);
  1678.     cp += sizeof(u_short);
  1679.     hp->qdcount = htons(1);
  1680.     if (op == QUERY || data == NULL)
  1681.       break;
  1682.     /*
  1683.              * Make an additional record for completion domain.
  1684.              */
  1685.     buflen -= RRFIXEDSZ;
  1686.     if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0)
  1687.       return (-1);
  1688.     cp += n;
  1689.     buflen -= n;
  1690.     putshort(T_NULL, cp);
  1691.     cp += sizeof(u_short);
  1692.     putshort(class, cp);
  1693.     cp += sizeof(u_short);
  1694.     putlong(0, cp);
  1695.     cp += sizeof(u_long);
  1696.     putshort(0, cp);
  1697.     cp += sizeof(u_short);
  1698.     hp->arcount = htons(1);
  1699.     break;
  1700.  
  1701.   case IQUERY:
  1702.     /*
  1703.              * Initialize answer section
  1704.              */
  1705.     if (buflen < 1 + RRFIXEDSZ + datalen)
  1706.       return (-1);
  1707.     *cp++ = '\0';    /* no domain name */
  1708.     putshort(type, cp);
  1709.     cp += sizeof(u_short);
  1710.     putshort(class, cp);
  1711.     cp += sizeof(u_short);
  1712.     putlong(0, cp);
  1713.     cp += sizeof(u_long);
  1714.     putshort(datalen, cp);
  1715.     cp += sizeof(u_short);
  1716.     if (datalen) {
  1717.       bcopy(data, cp, datalen);
  1718.       cp += datalen;
  1719.     }
  1720.     hp->ancount = htons(1);
  1721.     break;
  1722.  
  1723. #ifdef ALLOW_UPDATES
  1724.     /*
  1725.          * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
  1726.          * (Record to be modified is followed by its replacement in msg.)
  1727.          */
  1728.   case UPDATEM:
  1729.   case UPDATEMA:
  1730.  
  1731.   case UPDATED:
  1732.     /*
  1733.              * The res code for UPDATED and UPDATEDA is the same; user
  1734.              * calls them differently: specifies data for UPDATED; server
  1735.              * ignores data if specified for UPDATEDA.
  1736.              */
  1737.   case UPDATEDA:
  1738.     buflen -= RRFIXEDSZ + datalen;
  1739.     if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
  1740.       return (-1);
  1741.     cp += n;
  1742.     putshort(type, cp);
  1743.     cp += sizeof(u_short);
  1744.     putshort(class, cp);
  1745.     cp += sizeof(u_short);
  1746.     putlong(0, cp);
  1747.     cp += sizeof(u_long);
  1748.     putshort(datalen, cp);
  1749.     cp += sizeof(u_short);
  1750.     if (datalen) {
  1751.       bcopy(data, cp, datalen);
  1752.       cp += datalen;
  1753.     }
  1754.     if ( (op == UPDATED) || (op == UPDATEDA) ) {
  1755.       hp->ancount = htons(0);
  1756.       break;
  1757.     }
  1758.     /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
  1759.  
  1760.   case UPDATEA:    /* Add new resource record */
  1761.     buflen -= RRFIXEDSZ + datalen;
  1762.     if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
  1763.       return (-1);
  1764.     cp += n;
  1765.     putshort(newrr->r_type, cp);
  1766.     cp += sizeof(u_short);
  1767.     putshort(newrr->r_class, cp);
  1768.     cp += sizeof(u_short);
  1769.     putlong(0, cp);
  1770.     cp += sizeof(u_long);
  1771.     putshort(newrr->r_size, cp);
  1772.     cp += sizeof(u_short);
  1773.     if (newrr->r_size) {
  1774.       bcopy(newrr->r_data, cp, newrr->r_size);
  1775.       cp += newrr->r_size;
  1776.     }
  1777.     hp->ancount = htons(0);
  1778.     break;
  1779.  
  1780. #endif /* ALLOW_UPDATES */
  1781.   }
  1782.   return (cp - buf);
  1783. }
  1784.  
  1785.  
  1786.  
  1787.  
  1788. /*
  1789.  * Set up default settings.  If the configuration file exist, the values
  1790.  * there will have precedence.  Otherwise, the server address is set to
  1791.  * INADDR_ANY and the default domain name comes from the gethostname().
  1792.  *
  1793.  * The configuration file should only be used if you want to redefine your
  1794.  * domain or run without a server on your machine.
  1795.  *
  1796.  * Return 0 if completes successfully, -1 on error
  1797.  */
  1798. int
  1799. resolve_init(void)
  1800. {
  1801.   register FILE *fp;
  1802.   register char *cp, **pp;
  1803.   register int n;
  1804.   char buf[BUFSIZ];
  1805.   extern u_long res_inet_addr();
  1806.   extern char *index();
  1807.   extern char *strcpy(), *strncpy();
  1808.   extern char *getenv();
  1809.   int nserv = 0;    /* number of nameserver records read from file */
  1810.   int haveenv = 0;
  1811.   int havesearch = 0;
  1812.  
  1813.   _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
  1814.   _res.nsaddr.sin_family = AF_INET;
  1815.   _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
  1816.   _res.nscount = 1;
  1817.  
  1818.   /* Allow user to override the local domain definition */
  1819.   if ((cp = getenv("LOCALDOMAIN")) != NULL) {
  1820.     (void)strncpy(_res.defdname, cp, sizeof(_res.defdname));
  1821.     haveenv++;
  1822.   }
  1823.  
  1824.   if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
  1825.     /* read the config file */
  1826.     while (fgets(buf, sizeof(buf), fp) != NULL) {
  1827.       /* read default domain name */
  1828.  
  1829.       { /* Little patch to ensure variables are translated in the resconf file */
  1830.         char xbuf[BUFSIZ];
  1831.         var_translate(global_vars, buf, 0, xbuf, BUFSIZ);
  1832.         strcpy(buf, xbuf);
  1833.       }
  1834.  
  1835.       if (!strncmp(buf, "domain", sizeof("domain") - 1)) {
  1836.         if (haveenv)    /* skip if have from environ */
  1837.           continue;
  1838.         cp = buf + sizeof("domain") - 1;
  1839.         while (*cp == ' ' || *cp == '\t' || *cp == '.')
  1840.           cp++;
  1841.         if ((*cp == '\0') || (*cp == '\n'))
  1842.           continue;
  1843.         (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
  1844.         if ((cp = index(_res.defdname, '\n')) != NULL)
  1845.           *cp = '\0';
  1846.         havesearch = 0;
  1847.         continue;
  1848.       }
  1849.       /* debug */
  1850.       if( !strncmp(buf, "debug", sizeof("debug") - 1)) _res.options |= RES_DEBUG;
  1851.  
  1852.       /* set search list */
  1853.       if (!strncmp(buf, "search", sizeof("search") - 1)) {
  1854.         if (haveenv)    /* skip if have from environ */
  1855.           continue;
  1856.         cp = buf + sizeof("search") - 1;
  1857.         while (*cp == ' ' || *cp == '\t')
  1858.           cp++;
  1859.         if ((*cp == '\0') || (*cp == '\n'))
  1860.           continue;
  1861.         (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
  1862.         if ((cp = index(_res.defdname, '\n')) != NULL)
  1863.           *cp = '\0';
  1864.         /*
  1865.                      * Set search list to be blank-separated strings
  1866.                      * on rest of line.
  1867.                      */
  1868.         cp = _res.defdname;
  1869.         pp = _res.dnsrch;
  1870.         *pp++ = cp;
  1871.         for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
  1872.           if (*cp == ' ' || *cp == '\t') {
  1873.             *cp = 0;
  1874.             n = 1;
  1875.           }
  1876.           else if (n) {
  1877.             *pp++ = cp;
  1878.             n = 0;
  1879.           }
  1880.         }
  1881.         /* null terminate last domain if there are excess */
  1882.         while (*cp != '\0' && *cp != ' ' && *cp != '\t')
  1883.           cp++;
  1884.         *cp = '\0';
  1885.         *pp++ = 0;
  1886.         havesearch = 1;
  1887.         continue;
  1888.       }
  1889.       /* read nameservers to query */
  1890.       if (!strncmp(buf, "nameserver", sizeof("nameserver") - 1) &&
  1891.           nserv < MAXNS) {
  1892.         cp = buf + sizeof("nameserver") - 1;
  1893.         while (*cp == ' ' || *cp == '\t')
  1894.           cp++;
  1895.         if ((*cp == '\0') || (*cp == '\n'))
  1896.           continue;
  1897.         if ((_res.nsaddr_list[nserv].sin_addr.s_addr =
  1898.             res_inet_addr(cp)) == (unsigned)-1) {
  1899.           _res.nsaddr_list[nserv].sin_addr.s_addr
  1900.               = INADDR_ANY;
  1901.           continue;
  1902.         }
  1903.         _res.nsaddr_list[nserv].sin_family = AF_INET;
  1904.         _res.nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT);
  1905.         nserv++;
  1906.         continue;
  1907.       }
  1908.     }
  1909.     if (nserv > 1)
  1910.       _res.nscount = nserv;
  1911.     (void) fclose(fp);
  1912.   }
  1913.   if (_res.defdname[0] == 0) {
  1914.     if (gethostname(buf, sizeof(_res.defdname)) == 0 &&
  1915.         (cp = index(buf, '.')))
  1916.       (void)strcpy(_res.defdname, cp + 1);
  1917.   }
  1918.  
  1919.   /* find components of local domain that might be searched */
  1920.   if (havesearch == 0) {
  1921.     pp = _res.dnsrch;
  1922.     *pp++ = _res.defdname;
  1923.     for (cp = _res.defdname, n = 0; *cp; cp++)
  1924.       if (*cp == '.')
  1925.         n++;
  1926.     cp = _res.defdname;
  1927.     for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH;
  1928.             n--) {
  1929.           cp = index(cp, '.');
  1930.       *pp++ = ++cp;
  1931.     }
  1932.     *pp++ = 0;
  1933.   }
  1934.   _res.options |= RES_INIT;
  1935.   return (0);
  1936. }
  1937.  
  1938.  
  1939. static struct sockaddr no_addr;
  1940.  
  1941. static void rs_rec(struct tcb *, int16);
  1942. static void rs_cts(struct tcb *, int16);
  1943. static void rs_state(struct tcb *, char, char);
  1944. static void rs_init( void );
  1945. static void poll( int to );
  1946. static struct tcb *tcb;
  1947. static void sendit( void *, int );
  1948. static char tcpinbuff[TCPINBUFFLEN];
  1949. static int tcpinbuff_ptr = 0;
  1950.  
  1951. static int read( char *, int );
  1952.  
  1953. static enum {
  1954.   state_SYNC,
  1955.   state_ESTABLISHED,
  1956.   state_CLOSED,
  1957.   state_TIMEOUT
  1958. }
  1959. state;
  1960.  
  1961. static char *states[] = {
  1962.   "state_SYNC",
  1963.   "state_ESTABLISHED",
  1964.   "state_CLOSED",
  1965.   "state_TIMEOUT"
  1966. };
  1967.  
  1968.  
  1969. #ifndef FD_SET
  1970. #define    NFDBITS        32
  1971. #define    FD_SETSIZE    32
  1972. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  1973. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  1974. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  1975. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  1976. #endif
  1977.  
  1978. int
  1979. res_send(char *buf, int buflen, char *answer, int anslen)
  1980. {
  1981.   register int n;
  1982.   int s=-1;
  1983.   int try, v_circuit, resplen, ns;
  1984.   int gotsomewhere = 0;
  1985.   int connreset = 0;
  1986.   u_short id, len;
  1987.   char *cp;
  1988.   HEADER *hp = (HEADER *) buf;
  1989.   HEADER *anhp = (HEADER *) answer;
  1990.   int terrno = ETIMEDOUT;
  1991.   char junk[512];
  1992.   struct mbuf *bp;
  1993.  
  1994.   struct socket lsocket, fsocket;
  1995.  
  1996. #ifdef DEBUG
  1997.   if (_res.options & RES_DEBUG) {
  1998.     cwprintf(NULL, "res_send()\n");
  1999.     /*p_query(buf);*/
  2000.   }
  2001. #endif /* DEBUG */
  2002.   if (!(_res.options & RES_INIT))
  2003.     if (res_init() == -1) {
  2004.       return(-1);
  2005.     }
  2006.   v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
  2007.  
  2008.   /* Only allow one TCP query at a time */
  2009.   if (v_circuit && single_query(1))
  2010.     return (-1);
  2011.  
  2012.   id = hp->id;
  2013.   /*
  2014.        * Send request, RETRY times, or until successful
  2015.        */
  2016.   for (try = 0; try < _res.retry; try++) {
  2017.     for (ns = 0; ns < _res.nscount; ns++) {
  2018. #ifdef DEBUG
  2019.       if (_res.options & RES_DEBUG)
  2020.         cwprintf(NULL, "Querying server (# %d) address = %d.%d.%d.%d\n", ns+1,
  2021.                  (_res.nsaddr_list[ns].sin_addr.s_addr >> 24) & 0xff,
  2022.                  (_res.nsaddr_list[ns].sin_addr.s_addr >> 16) & 0xff,
  2023.                  (_res.nsaddr_list[ns].sin_addr.s_addr >> 8) & 0xff,
  2024.                  _res.nsaddr_list[ns].sin_addr.s_addr & 0xff);
  2025. #endif /* DEBUG */
  2026.       if (v_circuit) {
  2027.         int truncated = 0;
  2028.  
  2029.         /*
  2030.                      * Use virtual circuit;
  2031.                      * at most one attempt per server.
  2032.                      */
  2033.         try = _res.retry;
  2034.         if (s<0) {
  2035.           lsocket.address = ip_addr;
  2036.           lsocket.port = lport++;
  2037.           fsocket.address = _res.nsaddr_list[ns].sin_addr.s_addr;
  2038.           fsocket.port = ntohs(_res.nsaddr_list[ns].sin_port);
  2039.  
  2040.           state = state_SYNC;
  2041.           tcpintcb = tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,tcp_window,
  2042.           (void(*)())rs_rec, (void(*)())rs_cts, (void(*)())rs_state,0,NULL);
  2043.           rs_init();
  2044.           if (!tcb) {
  2045.             terrno = errno;
  2046. #ifdef DEBUG
  2047.             if (_res.options & RES_DEBUG)
  2048.               cwprintf(NULL, "socket (vc) failed\n");
  2049. #endif /* DEBUG */
  2050.             continue;
  2051.           }
  2052.           s = 1;
  2053.           poll(timeoutfact);
  2054.           while( state == state_SYNC ) poll(0);
  2055.           if( state != state_ESTABLISHED ) {
  2056. #ifdef DEBUG
  2057.             if (_res.options & RES_DEBUG)
  2058.               cwprintf(NULL, "connect failed, status=%s\n", states[state]);
  2059. #endif /* DEBUG */
  2060.             (void) close_tcp(tcb);
  2061.             s = -1;
  2062.             continue;
  2063.           }
  2064.         }
  2065.         /* Send length & message
  2066.                      */
  2067.         len = htons((u_short)buflen);
  2068.         sendit( &len, shortsize );
  2069.         sendit( buf, buflen );
  2070.         /* Receive length & response */
  2071.         cp = answer;
  2072.         len = shortsize;
  2073.         while (len != 0 &&
  2074.             (n = read( (char *)cp, (int)len)) > 0) {
  2075.           cp += n;
  2076.           len -= n;
  2077.         }
  2078.         if (n <= 0)
  2079.         {
  2080.           terrno = errno;
  2081. #ifdef DEBUG
  2082.           if (_res.options & RES_DEBUG)
  2083.             cwprintf(NULL, "read failed, status=%s\n", states[state]);
  2084. #endif /* DEBUG */
  2085.           (void) close_tcp(tcb);
  2086.           s = -1;
  2087.           /* A long running process might get its TCP
  2088.              connection reset if the remote server was
  2089.                restarted.  Requery the server instead of
  2090.              trying a new one.  When there is only one
  2091.                server, this means that a query might work
  2092.                instead of failing.  We only allow one reset
  2093.                per query to prevent looping. */
  2094.           if (terrno == ECONNRESET && !connreset)
  2095.           {
  2096.             connreset = 1;
  2097.             ns--;
  2098.           }
  2099.           continue;
  2100.         }
  2101.         cp = answer;
  2102.         if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
  2103. #ifdef DEBUG
  2104.           if (_res.options & RES_DEBUG)
  2105.             cwprintf(NULL, "response truncated\n");
  2106. #endif /* DEBUG */
  2107.           len = anslen;
  2108.           truncated = 1;
  2109.         }
  2110.         else
  2111.             len = resplen;
  2112.         while (len != 0 &&
  2113.             (n = read( (char *)cp, (int)len)) > 0) {
  2114.           cp += n;
  2115.           len -= n;
  2116.         }
  2117.         if (n <= 0) {
  2118.           terrno = errno;
  2119. #ifdef DEBUG
  2120.           if (_res.options & RES_DEBUG)
  2121.             cwprintf(NULL, "read failed\n");
  2122. #endif /* DEBUG */
  2123.           (void) close_tcp(tcb);
  2124.           s = -1;
  2125.           continue;
  2126.         }
  2127.         if (truncated)
  2128.         {
  2129.           /* Flush rest of answer
  2130.               so connection stays in synch. */
  2131.           anhp->tc = 1;
  2132.           len = resplen - anslen;
  2133.           while (len != 0) {
  2134.             n = (len > sizeof(junk) ?
  2135.             sizeof(junk) : len);
  2136.             if ((n = read(junk, n)) > 0)
  2137.               len -= n;
  2138.             else
  2139.               break;
  2140.           }
  2141.         }
  2142.       }
  2143.       else
  2144.       {
  2145.         /* Set up the socket descriptors */
  2146.         lsocket.address = ip_addr;
  2147.         lsocket.port = lport++;
  2148.         fsocket.address = _res.nsaddr_list[ns].sin_addr.s_addr;
  2149.         fsocket.port = ntohs(_res.nsaddr_list[ns].sin_port);
  2150.  
  2151.         /* Create the local socket to catch the response */
  2152.         if (open_udp(&lsocket,NULL) < 0) {
  2153.           terrno = errno;
  2154. #ifdef DEBUG
  2155.           if (_res.options & RES_DEBUG)
  2156.             cwprintf(NULL, "socket failed\n");
  2157. #endif /* DEBUG */
  2158.           continue;
  2159.         }
  2160.  
  2161.         /* Send length and message */
  2162.         bp = qdata(buf,(int16)buflen);
  2163.         if (send_udp(&lsocket,&fsocket,0,0,bp,0,0,0) == 0) {
  2164. #ifdef DEBUG
  2165.           if (_res.options & RES_DEBUG)
  2166.             cwprintf(NULL, "send failed\n");
  2167. #endif /* DEBUG */
  2168.           (void)del_udp(&lsocket);
  2169.           continue;
  2170.         }
  2171.  
  2172.         /* Wait until we get an answer or time out */
  2173.         state = state_ESTABLISHED;
  2174.         poll(timeoutfact);
  2175.         while( ( state == state_ESTABLISHED ) &&
  2176.                ( (resplen = recv_udp(&lsocket,&fsocket,&bp)) < 0 ) )
  2177.           poll(0);
  2178.  
  2179.         /* Give up on this server if we've timed out */
  2180.         if (state != state_ESTABLISHED) {
  2181. #ifdef DEBUG
  2182.           if (_res.options & RES_DEBUG)
  2183.             cwprintf(NULL, "lookup failed, status=%s\n", states[state]);
  2184. #endif /* DEBUG */
  2185.           (void)del_udp(&lsocket);
  2186.           continue;
  2187.         }
  2188.  
  2189.         /* Check the size of the answer */
  2190.         if (resplen > anslen) {
  2191. #ifdef DEBUG
  2192.           if (_res.options & RES_DEBUG)
  2193.             cwprintf(NULL, "response truncated\n");
  2194. #endif /* DEBUG */
  2195.           len = anslen;
  2196.         }
  2197.         else
  2198.           len = resplen;
  2199.  
  2200.         /* Read the answer, and throw away and excess data */
  2201.         pullup(&bp,(char *)answer,len);
  2202.         free_p(bp);
  2203.  
  2204.         /* Delete the local socket */
  2205.         del_udp(&lsocket);
  2206.       }
  2207. #ifdef DEBUG
  2208.       if (_res.options & RES_DEBUG) {
  2209.         cwprintf(NULL, "got answer:\n");
  2210.         /*p_query(answer);*/
  2211.       }
  2212. #endif /* DEBUG */
  2213.       /*
  2214.                * If using virtual circuits, we assume that the first server
  2215.                * is preferred * over the rest (i.e. it is on the local
  2216.                * machine) and only keep that one open.
  2217.                * If we have temporarily opened a virtual circuit,
  2218.                * or if we haven't been asked to keep a socket open,
  2219.                * close the socket.
  2220.                */
  2221.       if ((v_circuit &&
  2222.           ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
  2223.           (_res.options & RES_STAYOPEN) == 0) {
  2224.         (void) close_tcp(tcb);
  2225.         s = -1;
  2226.       }
  2227.       single_query(0);
  2228.       return (resplen);
  2229.     }
  2230.   }
  2231.   if (s >= 0) {
  2232.     (void) close_tcp(tcb);
  2233.     s = -1;
  2234.   }
  2235.   if (v_circuit == 0)
  2236.     if (gotsomewhere == 0)
  2237.       errno = ECONNREFUSED;    /* no nameservers found */
  2238.   else
  2239.       errno = ETIMEDOUT;    /* no answer obtained */
  2240.   else
  2241.       errno = terrno;
  2242.   single_query(0);
  2243.   return (-1);
  2244. }
  2245.  
  2246.  
  2247.  
  2248. static void rs_cts(struct tcb *tcb, int16 cnt)
  2249. {
  2250.   tcb = tcb;
  2251.   cnt = cnt;
  2252.   /* we actually don't use it */
  2253. }
  2254.  
  2255.  
  2256. static void rs_state(register struct tcb *tcb, char old, char new)
  2257. {
  2258.   if( trace>1 ) cwprintf(NULL, "resolve: state called, new state: %d\n", new );
  2259.   switch(new)
  2260.   {
  2261.   case SYN_SENT:
  2262.   case SYN_RECEIVED:
  2263.     state = state_SYNC;
  2264.     break;
  2265.   case ESTABLISHED:
  2266.     state = state_ESTABLISHED;
  2267.     break;
  2268.   case CLOSE_WAIT:
  2269.     close_tcp(tcb);                 /* shut things down */
  2270.     break;
  2271.   case CLOSED:
  2272.     /* if this close was not done by us ie. a RST */
  2273.     del_tcp(tcb);
  2274.     state = state_CLOSED;
  2275.     break;
  2276.   case LISTEN:
  2277.   case FINWAIT1:
  2278.   case FINWAIT2:
  2279.     break;
  2280.   }
  2281. }
  2282.  
  2283. static void rs_rec(struct tcb *tcb, int16 cnt)
  2284. {
  2285.   struct mbuf *bp;
  2286.  
  2287.   if( tcb != tcpintcb ) return;  /* to avoid receiving data from former queries */
  2288.   recv_tcp(tcb,&bp,cnt);  /* suck up chars from low level routine */
  2289.  
  2290.   tcpinbuff_ptr += pullup(&bp,&tcpinbuff[tcpinbuff_ptr],TCPINBUFFLEN-tcpinbuff_ptr);
  2291.   if( tcpinbuff_ptr >= TCPINBUFFLEN ) cwprintf(NULL, "resolve: tcp buffer overflow\n" );
  2292.   if( _res.options&RES_DEBUG ) cwprintf(NULL, "bytes in inqueue: %d\n", tcpinbuff_ptr );
  2293. }
  2294.  
  2295. static void rs_init(void)
  2296. {
  2297.   tcpinbuff_ptr = 0;
  2298. }
  2299.  
  2300. static void seterrno(void)
  2301. {
  2302.   switch( state )
  2303.   {
  2304.   case state_TIMEOUT:
  2305.     errno = ETIMEDOUT;
  2306.     break;
  2307.   case state_CLOSED :
  2308.     errno = ECONNREFUSED;
  2309.     break;
  2310.   default:
  2311.     errno = 0;
  2312.   }
  2313. }
  2314.  
  2315. static int read( char *buff, int len )
  2316. {
  2317.   while( state == state_ESTABLISHED && ! tcpinbuff_ptr ) poll(0);
  2318.   if( tcpinbuff_ptr ) {
  2319.     len = (len>tcpinbuff_ptr)?tcpinbuff_ptr:len;
  2320.     memcpy( buff, tcpinbuff, len );
  2321.     if( len<tcpinbuff_ptr ) memmove( tcpinbuff, &tcpinbuff[len], tcpinbuff_ptr - len );
  2322.     tcpinbuff_ptr -= len;
  2323.     if( _res.options & RES_DEBUG ) cwprintf(NULL, "read: %d bytes read\n", len );
  2324.     return len;
  2325.   }
  2326.   else {
  2327.     if( _res.options & RES_DEBUG ) cwprintf(NULL, "read: state changed to %s\n", states[state] );
  2328.     seterrno();
  2329.     return 0;
  2330.   }
  2331. }
  2332.  
  2333. static void poll( int to )
  2334. {
  2335.   static int timeout=-1;
  2336.   static time_t stime;
  2337.   time_t etime;
  2338.  
  2339.   if( to )
  2340.   {
  2341.     time( &stime );
  2342.     timeout = to;
  2343.   }
  2344.   event_process();
  2345.   if( timeout > 0 )
  2346.   {
  2347.     time( &etime );
  2348.     if( difftime( etime, stime ) >= timeout )
  2349.     {
  2350.       state = state_TIMEOUT;
  2351.       cwprintf(NULL, "resolve: time out\n" );
  2352.     }
  2353.   }
  2354. }
  2355.  
  2356. /* Send message back to server */
  2357. static void sendit( void *buff, int len)
  2358. {
  2359.   struct mbuf *bp;
  2360.  
  2361.   bp = qdata(buff,(int16)len);
  2362.   send_tcp(tcb,bp);
  2363. }
  2364.  
  2365. int single_query( int pg )
  2366. {
  2367.   static int in_progress=0;
  2368.  
  2369.   if( pg )
  2370.   {
  2371.     if( in_progress )
  2372.       return 1;
  2373.     in_progress = 1;
  2374.     return 0;
  2375.   }
  2376.   else
  2377.     in_progress = 0;
  2378.   return 0;
  2379. }
  2380.