⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 udp_dom.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
字号:
/*
 * Domain Name Server protocol
 *
 * This portion of the code needs some major work. I ported it (read STOLE IT)
 * from NCSA and lost about half the code somewhere in the process.
 *
 *  0.3 : Jun 16, 1997 - calling usr_yield (i.e. system_yield) while resolving
 *  0.2 : Apr 24, 1991 - use substring portions of domain
 *  0.1 : Mar 18, 1991 - improved the trailing domain list
 *  0.0 : Feb 19, 1991 - pirated by Erick Engelke
 * -1.0 :              - NCSA code
 */


#include <stdio.h>
#include <string.h>
#include <limits.h>

#include "copyrigh.h"
#include "wattcp.h"
#include "strings.h"
#include "misc.h"
#include "language.h"
#include "pcconfig.h"
#include "pc_cbrk.h"
#include "pcbsd.h"
#include "pctcp.h"
#include "udp_nds.h"
#include "udp_dom.h"

/* a hack to make gethostbyname() and resolve() cooperate --gv
 */
int called_from_resolve = 0;
int called_from_ghbn    = 0;

/* These next 'constants' are loaded from WATTCP.CFG file
 */
char  defaultdomain [MAX_HOSTLEN+1] = "your.domain.com";
char *def_domain = defaultdomain;
char *loc_domain;    /* current subname to be used by the domain system */

int (*_resolve_hook)(void);      /* user hook for terminating resolve() */
int   _resolve_exit;             /* user hook interrupted */
int   _resolve_timeout;          /* (reverse) lookup timeout */

DWORD def_nameservers [MAX_NAMESERVERS];
WORD  last_nameserver = 0;
UINT  dns_timeout     = 0;
int   dns_recurse     = 1;

static DWORD resolve_timeout;

static udp_Socket   *dom_sock;
static struct useek *question;
static const char   *no_serv = __LANG ("No nameserver defined!");

static void qinit (void)
{
  question->h.flags   = intel16 (DRD);
  question->h.qdcount = intel16 (1);
  question->h.ancount = 0;
  question->h.nscount = 0;
  question->h.arcount = 0;
}


/*
 * packdom()
 *   pack a regular text string into a packed domain name, suitable
 *   for the name server.
 *
 *   returns length
 */
static int packdom (char *dst, const char *src)
{
  char *p, *q, *savedst;
  int   i, dotflag, defflag;

  p = (char*) src;
  dotflag = defflag = 0;
  savedst = dst;

  do                          /* copy whole string */
  {
    *dst = 0;
    q = dst + 1;
    while (*p && *p != '.')
       *q++ = *p++;

    i = p - (char*)src;
    if (i > 0x3F)
       return (-1);
    *dst = i;
    *q = 0;

    if (*p)                   /* update pointers */
    {
      dotflag = 1;
      src = ++p;
      dst = q;
    }
    else if (!dotflag && !defflag && loc_domain)
    {
      p = loc_domain;         /* continue packing with default */
      defflag = 1;
      src = p;
      dst = q;
    }
  }
  while (*p);

  q++;
  return (q - savedst);       /* length of packed string */
}

/*
 * unpackdom()
 *  Unpack a compressed domain name that we have received from another
 *  host.  Handles pointers to continuation domain names -- buf is used
 *  as the base for the offset of any pointer which is present.
 *  returns the number of bytes at src which should be skipped over.
 *  Includes the NULL terminator in its length count.
 */
static int unpackdom (BYTE *dst, const BYTE *src, const BYTE *buf)
{
  int   retval  = 0;
  const BYTE *p = src;

  while (*src)
  {
    int i,j = *src;

    while ((j & 0xC0) == 0xC0)
    {
      if (!retval)
         retval = src - p + 2;
      src++;
      src = &buf[(j & 0x3F)*256 + *src];  /* pointer dereference */
      j = *src;
    }

    src++;
    for (i = 0; i < (j & 0x3F); i++)
        *dst++ = *src++;

    *dst++ = '.';
  }

  *(--dst) = 0;              /* add terminator */
  src++;                     /* account for terminator on src */

  if (!retval)
     retval = src - p;

  return (retval);
}


/*
 * send_dom()
 *   put together a domain lookup packet and send it.
 *   uses port 53.
 */
static int send_dom (const char *name, DWORD towho)
{
  WORD  ulen;
  BYTE *start = (BYTE*)&question->x;
  WORD  i     = packdom ((char*)start, name);
  BYTE *p     = &question->x[i];

  *p++ = 0;               /* high byte of qtype */
  *p++ = DTYPEA;          /* number is < 256, so we know high byte=0 */
  *p++ = 0;               /* high byte of qclass */
  *p++ = DIN;             /* qtype is < 256 */

  question->h.ident = Random (1, USHRT_MAX);

  if (!udp_open(dom_sock,997,towho,DOM_DST_PORT,NULL))
  {
    outsnl (_LANG("Nameserver ARP failed"));
    return (0);
  }
  ulen = sizeof (struct dhead) + (p - start);
  sock_write ((sock_type*)dom_sock, (BYTE*)question, ulen);
  return (ulen);
}

static __inline int countpaths (const char *pathstring)
{
  int   count = 0;
  const char *p;

  for (p = pathstring; *p || *(p+1); p++)
  {
    if (*p == 0)
       count++;
  }
  return (++count);
}

static __inline const char *getpath (
                const char *pathstring,  /* the path list to search        */
                int         whichone)    /* which path to get, starts at 1 */
{
  const char *rc;

  if (whichone > countpaths(pathstring))
     return (NULL);

  whichone--;
  for (rc = pathstring; whichone; rc++)
  {
    if (*rc == 0)
       whichone--;
  }
  return (rc);
}


/*
 * ddextract()
 *   extract the ip number from a response message.
 *   returns the appropriate status code and if the ip number is available,
 *   copies it into mip
 */
static int ddextract (const struct useek *qp, DWORD *mip)
{
  WORD nans  = intel16 (qp->h.ancount);
  BYTE rcode = DRCODE & intel16(qp->h.flags);

  if (rcode > 0)
     return (int)rcode;

  if (nans > 0 &&                              /* at least one answer   */
      (intel16(qp->h.flags) & DQR))            /* response flag is set  */
  {
    BYTE  space[260];
    const BYTE *p = (const BYTE*) &qp->x;
    int   i = unpackdom (space, p, (const BYTE*)qp);

   /* spec defines name then QTYPE + QCLASS = 4 bytes
    */
    p += i + 4;

   /* at this point, there may be several answers.  We will take the first
    * one which has an IP number.  There may be other types of answers that
    * we want to support later.
    */
    while (nans-- > 0)                     /* look at each answer   */
    {
      struct rrpart *rrp;
      int    j;

      i   = unpackdom (space, p, (const BYTE*)qp);
      p  += i;                             /* account for string    */
      rrp = (struct rrpart*) p;            /* resource record here  */

      if (!*p && *(p+1) == DTYPEA &&       /* correct type and class */
          !*(p+2) && *(p+3) == DIN)
      {
        *mip = *(DWORD*)&rrp->rdata;       /* save IP #         */
        return (0);                        /* successful return */
      }
      j  = *(WORD*) &rrp->rdlength;
      p += 10 + intel16 (j);               /* length of rest of RR */
    }
  }
  return (-1);                             /* generic failed to parse */
}


/*
 * parse_domain()
 *   Look at the results to see if our DOMAIN request is ready.
 *   It may be a timeout, which requires another query.
 */
static DWORD parse_domain (void)
{
  DWORD ip = 0UL;

  sock_fastread ((sock_type*)dom_sock, (BYTE*)question, sizeof(*question));

 /* check to see if the necessary information was in the UDP response
  */
  switch (ddextract (question, &ip))
  {
    case  3: return (0);         /* name does not exist                */
    case  0: return intel (ip);  /* we found the IP number             */
    case -1: return (0);         /* strange return code from ddextract */
    default: return (0);         /* dunno                              */
  }
}


/*
 * lookup_domain()
 *   DOMAIN based name lookup
 *   query a domain name server to get an IP number
 *   Returns the machine number of the machine record for future reference.
 *   Events generated will have this number tagged with them.
 *   Returns various negative numbers on error conditions.
 *
 *   if add_dom is nonzero, add default domain
 */
static DWORD lookup_domain (const char *mname, int  add_dom,
                            DWORD nameserver,  BYTE *timedout)
{
  char  namebuff [512];
  int   sec;
  DWORD response;

  response  = 0;
  *timedout = 1;     /* assume we will timeout */

  if (!nameserver)   /* no nameserver, give up now */
  {
    outsnl (_LANG(no_serv));
    _resolve_exit = 1;
    return (0);
  }

  while (*mname && *mname <= ' ')   /* kill leading spaces */
     mname++;

  if (*mname == 0)
     return (0L);

  qinit();                     /* initialize some flag fields */
  strcpy (namebuff, mname);

  if (add_dom)
  {
    int dot = strlen (namebuff) - 1;
    if (namebuff[dot] != '.')    /* if no trailing dot */
    {
      if (loc_domain)            /* there is a search list */
      {
        strcat (namebuff, ".");
        strcat (namebuff, getpath(loc_domain,1));
      }
    }
    else
      namebuff [dot] = 0;        /* kill trailing dot */
  }

  /*
   * This is not terribly good, but it attempts to use a binary
   * exponentially increasing delays.
   */

  for (sec = 2; sec < dns_timeout-1 && !_resolve_exit; sec *= 2)
  {
    if (!send_dom(namebuff,nameserver))
    {
      _resolve_timeout = 1; /* Sort of..ARP failed */
      return (0);
    }

    ip_timer_init (dom_sock,sec);
    do
    {
      tcp_tick ((sock_type*)dom_sock);

      if (ip_timer_expired(dom_sock) || chk_timeout(resolve_timeout))
         break;

      kbhit();
      if (watcbroke || (_resolve_hook && (*_resolve_hook)() == 0))
      {
        _resolve_exit = 1;
        break;
      }
      if (dom_sock->usr_yield)    /* Added, 16-Jun-97 GV */
        (*dom_sock->usr_yield)();

      if (sock_dataready((sock_type*)dom_sock))
         *timedout = 0;
    }
    while (*timedout);

    if (!*timedout)           /* got an answer */
       break;      
  }

  if (*timedout)
       _resolve_timeout = 1;
  else response = parse_domain();

  sock_close ((sock_type*)dom_sock);
  return (response);
}

/*
 * nextdomain - given domain and count = 0,1,2,..., return next larger
 * domain or NULL when no more are available
 */
static const char *nextdomain (const char *domain, int count)
{
  const char *p = domain;
  int   i;

  for (i = 0; i < count; i++)
  {
    if ((p = strchr(p,'.')) == NULL)
       return (NULL);
    p++;
  }
  return (p);
}


/*
 * resolve()
 *   convert domain name -> address resolution.
 *   returns 0 if name is unresolvable right now
 *   return value is host-order
 */
DWORD resolve (const char *name)
{
  DWORD        ip_address = 0L;
  int          count, len;
  char         namebuf [MAX_HOSTLEN];
  BYTE         timeout [MAX_NAMESERVERS];
  WORD         oldhndlcbrk;
  struct useek qp;       /* temp buffer */
  udp_Socket   ds;       /* DNS socket  */

  if (!name || *name == 0)
     return (0);

  len = strlen (name);
  if (len >= sizeof(namebuf)-1)
     return (0);

  memcpy (namebuf, name, len+1); /* make a copy of 'name'      */
  rip (namebuf);                 /* strip off '\r' and/or '\n' */

  if (isaddr(namebuf))
     return aton (namebuf);

#if defined(USE_BSD_FUNC)
  if (!called_from_ghbn)         /* This hack avoids reentrancy */
  {                              /* from gethostbyname()        */
    struct hostent *h;

    called_from_resolve = 1;     /* ditto hack ! (vice versa)   */
    h = gethostbyname (namebuf);
    called_from_resolve = 0;
    if (h)                       /* IP from host file or cache  */
    {
      /*
       * NOTE: gethostbyname() returns network order
       *       We assume IPv4 (32-bit)
       */
      DWORD ip = *(DWORD*)h->h_addr_list[0];
      return intel (ip);
    }

    /* not found in /etc/hosts file, ask the DNS server(s)
     */
  }
#endif

  if (last_nameserver == 0)    /* no nameserver, give up now */
  {
    outsnl (_LANG(no_serv));
    return (0);
  }

  if (my_ip_addr == 0)         /* not configured, give up now */
  {
    outsnl (_LANG("Cannot resolve without IP"));
    return (0);
  }

  if (dns_timeout == 0)
      dns_timeout = (UINT)sock_delay << 2;
  resolve_timeout = set_timeout (1000 * dns_timeout);

  count = 0;
  memset (&timeout, 0, sizeof(timeout));

  question    = &qp;
  dom_sock    = &ds;
  oldhndlcbrk = wathndlcbrk;
  wathndlcbrk = 1;        /* enable special interrupt mode */
  watcbroke   = 0;

  _resolve_exit = _resolve_timeout = 0;

  do
  {
    int i;

    if (strchr(namebuf,'.'))
    {
      loc_domain = NULL;
      count = -1;
    }
    else if (dns_recurse == 0 && count == 0)
    {
      loc_domain = NULL;
      count = -1;
    }
    else
    {
      loc_domain = (char*) nextdomain (def_domain, count);
      if (!loc_domain)
         count = -1;     /* use default name */
    }

    for (i = 0; i < last_nameserver; i++)
    {
      if (!timeout[i])
      {
        ip_address = lookup_domain (namebuf, count != -1,
                                    def_nameservers[i], timeout+i);
        if (ip_address)
           break;           /* got name, bail out of for loop */
        if (_resolve_exit)
           break;           /* an error occured, return to caller */
      }

      /*
       * Should we really try the other nameservers if the first
       * says the host doesn't exist? Maybe a trusting mechanism
       * is needed
       */
    }
    if (count == -1)
       break;
    count++;
  }
  while (!ip_address && !_resolve_exit);

  watcbroke   = 0;        /* always clean up */
  wathndlcbrk = oldhndlcbrk;

  return (ip_address);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -