dnsmx.cpp
上传用户:qdlutongda
上传日期:2007-01-14
资源大小:133k
文件大小:21k
源码类别:

Email客户端

开发平台:

Visual C++

  1. /*
  2.  *  The code I found by Bob Quinn was not complete - I hacked it to
  3.  *  completion just to see what the issues were with getting MX entries.
  4.  *
  5.  *  Part of the hacking involved extracting code from Unix BIND which 
  6.  *  does the low level packet parsing.  (The dn_ routines)
  7.  *
  8.  *  It needs to determine the DNS server's IP address - right now it is
  9.  *  hard coded into this program.  NSLOOKUP probably looks in the 
  10.  *  registry for that value.
  11.  *
  12.  * - David
  13.  */
  14. /*---------------------------------------------------------------------
  15.  *
  16.  * Program: DNS_QRY.EXE  Query DNS Server, and parse response
  17.  *
  18.  * filename: DNS_QRY.c
  19.  *
  20.  *  Copyright by Bob Quinn, 1997          http://www.sockets.com
  21.  *
  22.  * Description:
  23.  *  Not a test application, per se, but designed to allow custom
  24.  *  queries of DNS records by actually sending and receiving DNS
  25.  *  messages, rather than relying on the hostname resolution APIs
  26.  *  to do it for me.  The big advantage is that I can ask for any
  27.  *  DNS record types that I want.  The downside is that I have to
  28.  *  hard-code the DNS server myself, or peak at the implementation's
  29.  *  configuration (e.g. MSTCP) for the config'd server(s).
  30.  *
  31.  *  I started creating this in response to a Frequently Asked Question
  32.  *  on one of the WinSock mailing lists for a way to use WinSock to
  33.  *  retrieve an MX record.
  34.  *
  35.  *  NOTE: Eventually, I'd like to provide the same command-line
  36.  *   capabilities as available from BSD Unix NSLOOKUP utility.
  37.  *
  38.  * Editing History:
  39.  *  8/17/97  rcq  started work  -- STOPPED BEFORE GOT IT WORKING
  40.  *                 (serious byte order problems and buffer/format
  41.  *                 management problems in general, causing Format Err).
  42.  *  2/15/98  mjd  got query and reply working, working on decoding reply
  43.  *
  44.  *
  45.  *
  46.  ---------------------------------------------------------------------*/
  47. #include "stdafx.h"
  48. //#include "tools.h"
  49. #include <stdio.h>
  50. #define ASCII_NULL              ''
  51. #define MAXHOSTNAME             256
  52. #define BUFSIZE                 2048
  53. //#define BUFSIZE                 4096
  54. /* DNS Header Format
  55.  *
  56.  * All DNS Message Formats have basically the same structure
  57.  *   (note that an RR (DNS Resource Record) is described in
  58.  *   the other structures that follow this header description):
  59.  *
  60.  *        +--------------------------------+
  61.  *        | DNS Header: <defined below>    |
  62.  *        +--------------------------------+
  63.  *        | Question:   type of query      |
  64.  *        |   QNAME:    <see below>        |
  65.  *        |   QTYPE:    2-octet RR type    |
  66.  *        |   QCLASS:   2-octet RR class   |
  67.  *        +--------------------------------+
  68.  *        | Answer:     RR answer to query |
  69.  *        +--------------------------------+
  70.  *        | Authority:  RR for name server |
  71.  *        +--------------------------------+
  72.  *        | Additional: RR(s) other info   |
  73.  *        +--------------------------------+
  74.  *
  75.  *  QNAME is a variable length field where each portion of the
  76.  *   "dotted-notation" domain name is replaced by the number of
  77.  *   octets to follow.  So, for example, the domain name
  78.  *   "www.sockets.com" is represented by:
  79.  *
  80.  *         0                   1
  81.  *   octet 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
  82.  *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  83.  *        |3|w|w|w|7|s|o|c|k|e|t|s|3|c|o|m|0|
  84.  *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  85.  *
  86.  * NOTE: The last section, "Additional," often contains records
  87.  *  for queries the server anticipates will be sent (to reduce
  88.  *  traffic).  For example, a response to an MX query, would
  89.  *  usually have the A record in additional information.
  90.  */
  91. typedef struct dns_hdr
  92. {
  93.         u_short dns_id;          /* client query ID number */
  94.         u_short dns_flags;       /* qualify contents <see below> */
  95.         u_short dns_q_count;     /* number of questions */
  96.         u_short dns_rr_count;    /* number of answer RRs */
  97.         u_short dns_auth_count;  /* number of authority RRs */
  98.         u_short dns_add_count;   /* number of additional RRs */
  99. } DNS_HDR, *PDNS_HDR, FAR *LPDNS_HDR;
  100. #define DNS_HDR_LEN 12
  101. /* DNS Flags field values
  102.  *
  103.  *  bits:  0     1-4     5    6    7    8     9-11    12-15
  104.  *       +----+--------+----+----+----+----+--------+-------+
  105.  *       | QR | opcode | AA | TC | RD | RA | <zero> | rcode |
  106.  *       +----+--------+----+----+----+----+--------+-------+
  107.  *
  108.  *  QR:     0 for query, and 1 for response
  109.  *  opcode: type of query (0: standard, and 1: inverse query)
  110.  *  AA:     set if answer from domain authority
  111.  *  TC:     set if message had to be truncated
  112.  *  RD:     set if recursive query desired
  113.  *  RA:     set if recursion is available from server
  114.  *  <zero>: reserved field
  115.  *  rcode:  resulting error non-zero value from authoritative
  116.  *           server (0: no error, 3: name does not exist)
  117.  */
  118. #define DNS_FLAG_QR 0x8000
  119. #define DNS_FLAG_AA 0x0400
  120. #define DNS_FLAG_TC 0x0200
  121. #define DNS_FLAG_RD 0x0100
  122. #define DNS_FLAG_RA 0x0080
  123. #define DNS_RCODE_MASK  0x000F
  124. #define DNS_OPCODE_MASK 0x7800
  125. /* DNS Opcode (type of query) */
  126. char *DNS_Opcode[] =
  127. {
  128.         "Standard Query",         /* 0: QUERY  */
  129.         "Inverse Query",          /* 1: IQUERY */
  130.         "Server Status Request",  /* 2: STATUS */
  131. };
  132. /* DNS Response Codes (error descriptions) */
  133. char *DNS_RCode[] =
  134. {
  135.         "No Error",        /* 0: ok */
  136.         "Format Error",    /* 1: bad query */
  137.         "Server Failure",  /* 2: server is hosed */
  138.         "Name Error",      /* 3: name doesn't exist (authoritative) */
  139.         "Not Implemented", /* 4: server doesn't support query */
  140.         "Refused"          /* 5: server refused request */
  141. };
  142. /* DNS Generic Resource Record format (from RFC 1034 and 1035)
  143.  *
  144.  *  NOTE: The first field in the DNS RR Record header is always
  145.  *   the domain name in QNAME format (see earlier description)
  146.  */
  147. typedef struct dns_rr_hdr
  148. {
  149.         u_short rr_type;                /* RR type code (e.g. A, MX, NS, etc.) */
  150.         u_short rr_class;               /* RR class code (IN for Internet) */
  151.         u_long  rr_ttl;         /* Time-to-live for resource */
  152.         u_short rr_rdlength;    /* length of RDATA field (in octets) */
  153.         u_short rr_rdata;               /* (fieldname used as a ptr) */
  154. } DNS_RR_HDR, *PDNS_RR_HDR, FAR *LPDNS_RR_HDR;
  155. #define DNS_RR_HDR_LEN 12
  156. /* DNS Resource Record RDATA Field Descriptions
  157.  *
  158.  *  The RDATA field contains resource record data associated
  159.  *  with the specified domain name
  160.  *
  161.  *  Type Value Description
  162.  *  -------------------------------------------------------------
  163.  *   A     1   IP Address (32-bit IP version 4)
  164.  *   NS    2   Name server QNAME (for referrals & recursive queries)
  165.  *   CNAME 5   Canonical name of an alias (in QNAME format)
  166.  *   SOA   6   Start of Zone Transfer (see definition below)
  167.  *   WKS   11  Well-known services (see definition below)
  168.  *   PTR   12  QNAME pointing to other nodes (e.g. in inverse lookups)
  169.  *   HINFO 13  Host Information (CPU string, then OS string)
  170.  *   MX    15  Mail server preference and QNAME (see below)
  171.  */
  172. char *DNS_RR_Type [] =
  173. {
  174.         "<invalid>",
  175.         "A",     // 1:  Host Address
  176.         "NS",    // 2:  Authoritative Name Server
  177.         "MD",    // 3:  <obsolete>
  178.         "MF",    // 4:  <obsolete>
  179.         "CNAME", // 5:  The true, canonical name for an alias
  180.         "SOA",   // 6:  Start-of-Zone of authority record
  181.         "MB",    // 7:  Mailbox   <experimental>
  182.         "MG",    // 8:  Mailgroup <experimental>
  183.         "MR",    // 9:  Mail Rename Domain Name <experimental>
  184.         "NULL",  // 10: NULL Resource Record    <experimental>
  185.         "WKS",   // 11: Well-known service description
  186.         "PTR",   // 12: Domain Name Pointer
  187.         "HINFO", // 13: Host Information
  188.         "MINFO", // 14: Mailbox or Mail List information
  189.         "MX",    // 15: Mail Exchange (from RFC 974)
  190.         "TXT"    // 16: Text String
  191. };
  192. #define DNS_RRTYPE_A     1
  193. #define DNS_RRTYPE_NS    2
  194. #define DNS_RRTYPE_CNAME 5
  195. #define DNS_RRTYPE_SOA   6
  196. #define DNS_RRTYPE_WKS   11
  197. #define DNS_RRTYPE_PTR   12
  198. #define DNS_RRTYPE_HINFO 13
  199. #define DNS_RRTYPE_MX    15
  200. /* DNS Resource Record Classes:
  201.  *
  202.  * One almost always uses Internet RR Class (also note: the
  203.  *  class value 255 denotes a wildcard, all classes)
  204.  */
  205. char *DNS_RR_Class [] =
  206. {
  207.         "<invalid>",
  208.         "IN",    // 1: Internet - used for most queries!
  209.         "CS",    // 2: CSNET <obsolete>
  210.         "CH",    // 3: CHAOS Net
  211.         "HS"     // 4: Hesiod
  212. };
  213. #define DNS_RRCLASS_IN  1
  214. #define DNS_RRCLASS_CS  2
  215. #define DNS_RRCLASS_CH  3
  216. #define DNS_RRCLASS_HS  4
  217. /* DNS SOA Resource Data Field
  218.  *
  219.  *  NOTE: First two fields not shown here.  They are:
  220.  *    MNAME: QNAME of primary server for this zone
  221.  *    RNAME: QNAME of mailbox of admin for this zone
  222.  */
  223. typedef struct dns_rdata_soa
  224. {
  225.         u_long soa_serial;  /* data version for this zone */
  226.         u_long soa_refresh; /* time-to-live for data (in seconds) */
  227.         u_long soa_retry;   /* time between retrieds (in seconds) */
  228.         u_long soa_expire;  /* time until zone not auth (in seconds) */
  229.         u_long soa_minimum; /* default TTL for RRs (in seconds) */
  230. } DNS_RDATA_SOA, PDNS_RDATA_SOA, FAR *LPDNS_RDATA_SOA;
  231. #define DNS_SOA_LEN 20
  232. /* DNS WKS Resource Data Field (RFC 1035)
  233.  *
  234.  *  NOTE: The bitmap field is variable length, with as many
  235.  *   octets necessary to indicate the bit field for the port
  236.  *   number.
  237.  */
  238. typedef struct dns_rdata_wks
  239. {
  240.         u_long wks_addr;      /* IPv4 address */
  241.         u_char wks_protocol;  /* Protocol (e.g. 6=TCP, 17=UDP) */
  242.         u_char wks_bitmap;    /* e.g. bit 26 = SMTP (port 25) */
  243. } DNS_RDATA_WKS, *PDNS_RDATA_WKS, FAR *LPDNS_RDATA_WKS;
  244. #define DNS_WKX_LEN 6
  245. /* DNS MX Resource Data Field
  246.  */
  247. typedef struct dns_rdata_mx
  248. {
  249.         u_short mx_pref;     /* Preference value */
  250.         u_short mx_xchange;  /* QNAME (field used as ptr) */
  251. } DNS_RDATA_MX, *PDNS_RDATA_MX, FAR *LPDNS_RDATA_MX;
  252. #define DNS_MX_LEN 4
  253. /* Variables used for DNS Header construction & parsing */
  254. PDNS_HDR       pDNShdr;
  255. PDNS_RR_HDR    pDNS_RR;
  256. PDNS_RDATA_SOA pDNS_SOA;
  257. PDNS_RDATA_WKS pDNS_WKS;
  258. PDNS_RDATA_MX  pDNS_MX;
  259.     /* For Parsing Names in a Reply */
  260. #define INDIR_MASK 0xc0
  261. /* Number of bytes of fixed size data in query structure */
  262. #define QFIXEDSZ 4
  263. /* number of bytes of fixed size data in resource record */
  264. #define RRFIXEDSZ 10
  265. /* Processor Types */
  266. char *aszProcessor[] =
  267. {
  268.         "",
  269.         "",
  270.         "",
  271.         "Intel 386",
  272.         "Intel 486",
  273.         "Intel Pentium"
  274. };
  275. void GetQName( char FAR *pszHostName, char FAR *pQName );
  276. void PrintQName( char FAR *pQName );
  277. int  PutQName( char FAR *pszHostName, char FAR *pQName );
  278. u_short
  279. _getshort(char *msgp)
  280. {
  281. register u_char *p = (u_char *) msgp;
  282. register u_short u;
  283. u = *p++ << 8;
  284. return ((u_short)(u | *p));
  285. }
  286. u_long
  287. _getlong(char *msgp)
  288. {
  289. register u_char *p = (u_char *) msgp;
  290. register u_long u;
  291. u = *p++; u <<= 8;
  292. u |= *p++; u <<= 8;
  293. u |= *p++; u <<= 8;
  294. return (u | *p);
  295. }
  296. /*
  297.  * Expand compressed domain name 'comp_dn' to full domain name.
  298.  * 'msg' is a pointer to the begining of the message,
  299.  * 'eomorig' points to the first location after the message,
  300.  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
  301.  * Return size of compressed name or -1 if there was an error.
  302.  */
  303. int dn_expand(char *msg,char  *eomorig,char *comp_dn,char *exp_dn,int length)
  304. {
  305. register char *cp, *dn;
  306. register int n, c;
  307. char *eom;
  308. int len = -1, checked = 0;
  309. dn = exp_dn;
  310. cp = comp_dn;
  311. eom = exp_dn + length - 1;
  312. /*
  313.  * fetch next label in domain name
  314.  */
  315. while (n = *cp++) {
  316. /*
  317.  * Check for indirection
  318.  */
  319. switch (n & INDIR_MASK) {
  320. case 0:
  321. if (dn != exp_dn) {
  322. if (dn >= eom)
  323. return (-1);
  324. *dn++ = '.';
  325. }
  326. if (dn+n >= eom)
  327. return (-1);
  328. checked += n + 1;
  329. while (--n >= 0) {
  330. if ((c = *cp++) == '.') {
  331. if (dn+n+1 >= eom)
  332. return (-1);
  333. *dn++ = '\';
  334. }
  335. *dn++ = c;
  336. if (cp >= eomorig) /* out of range */
  337. return(-1);
  338. }
  339. break;
  340. case INDIR_MASK:
  341. if (len < 0)
  342. len = cp - comp_dn + 1;
  343. cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
  344. if (cp < msg || cp >= eomorig) /* out of range */
  345. return(-1);
  346. checked += 2;
  347. /*
  348.  * Check for loops in the compressed name;
  349.  * if we've looked at the whole message,
  350.  * there must be a loop.
  351.  */
  352. if (checked >= eomorig - msg)
  353. return (-1);
  354. break;
  355. default:
  356. return (-1); /* flag error */
  357. }
  358. }
  359. *dn = '';
  360. if (len < 0)
  361. len = cp - comp_dn;
  362. return (len);
  363. }
  364. /*
  365.  * Skip over a compressed domain name. Return the size or -1.
  366.  */
  367. dn_skipname(u_char *comp_dn,  u_char *eom)
  368. {
  369. register u_char *cp;
  370. register int n;
  371. cp = comp_dn;
  372. while (cp < eom && (n = *cp++)) {
  373. /*
  374.  * check for indirection
  375.  */
  376. switch (n & INDIR_MASK) {
  377. case 0: /* normal case, n == len */
  378. cp += n;
  379. continue;
  380. default: /* illegal type */
  381. return (-1);
  382. case INDIR_MASK: /* indirection */
  383. cp++;
  384. }
  385. break;
  386. }
  387. return (cp - comp_dn);
  388. }
  389. char* GetMX( char *pszQuery, char *pszServer, int minlevel )
  390. {
  391. WSADATA                 stWSAData;
  392.         WORD                            wWSAVersion     = 0x0202;
  393.         SOCKET                  hSocket;
  394.         SOCKADDR_IN             stSockAddr;                     // socket address structures
  395.         int                             nAddrLen = sizeof( SOCKADDR_IN );
  396.         HOSTENT                 *pHostEnt;
  397.         char                            achBufOut[ BUFSIZE ] = { 0 };
  398.         char                            achBufIn[ BUFSIZE ] = { 0 };
  399.         int                             nQueryLen = 0;
  400.         int                             nRC;
  401. char *p, *np, name[128], *eom;
  402. int count, j, i, n;
  403.         nRC = WSAStartup( wWSAVersion, &stWSAData );
  404.         if ( nRC )
  405.         {
  406.                 return NULL;
  407.         }
  408.         memset( &stSockAddr, ASCII_NULL, sizeof( stSockAddr ) );
  409.         stSockAddr.sin_family      = AF_INET;
  410.         stSockAddr.sin_port             = htons( 53);
  411.     stSockAddr.sin_addr.s_addr = inet_addr( pszServer );
  412.         if ( stSockAddr.sin_addr.s_addr == INADDR_NONE )
  413.         {
  414.                 pHostEnt = gethostbyname( pszServer );
  415.                 if ( pHostEnt )
  416.                 {
  417.                         stSockAddr.sin_addr.s_addr = *((u_long *)pHostEnt->h_addr_list[0]);
  418.                 }
  419.                 else
  420.                 {
  421.                         WSACleanup();
  422.                         return NULL;
  423.                 } // end if
  424.         } // end if
  425.         /*------------------------------------------------------------
  426.         *  Get a DGRAM socket
  427.         */
  428.         hSocket = socket( AF_INET, SOCK_DGRAM, 0 );
  429.         if ( hSocket == INVALID_SOCKET )
  430.         {
  431.                 WSACleanup();
  432.                 return NULL;
  433.         } // end if
  434.         /*-----------------------------------------------------------
  435.         * Format DNS Query
  436.         *
  437.         * <<8/17/97 hard-coded test case: MX Record>>
  438.         */
  439.         pDNShdr = (PDNS_HDR)&( achBufOut[ 0 ] );
  440.         pDNShdr->dns_id         = htons( 0xDEAD );
  441.         pDNShdr->dns_flags      = htons( DNS_FLAG_RD ); // do recurse
  442.         pDNShdr->dns_q_count    = htons( 1 );           // one query
  443.         pDNShdr->dns_rr_count   = 0;                  // none in query
  444.         pDNShdr->dns_auth_count = 0;                  // none in query
  445.         pDNShdr->dns_add_count  = 0;                  // none in query
  446.         nQueryLen = PutQName( pszQuery, &(achBufOut[ DNS_HDR_LEN ] ) );
  447.         nQueryLen += DNS_HDR_LEN;
  448.         achBufOut[ nQueryLen++ ]        = 0;
  449.         achBufOut[ nQueryLen++ ]        = 0;
  450.         /* BQ NOTE: I'm cheating on this one! (should be done cleaner)*/
  451.         achBufOut[ nQueryLen ]          = DNS_RRTYPE_MX;
  452.         achBufOut[ nQueryLen + 1 ]      = 0;
  453.         achBufOut[ nQueryLen + 2 ]      = DNS_RRCLASS_IN;
  454.         achBufOut[ nQueryLen + 3 ]      = 0;
  455.         nQueryLen += 4;
  456.         /*-----------------------------------------------------------
  457.         * Send DNS Query to server
  458.         */
  459.         nRC = sendto( hSocket,
  460.                       achBufOut,
  461.                       nQueryLen,
  462.                       0,
  463.                       (LPSOCKADDR)&stSockAddr,
  464.                       sizeof( SOCKADDR_IN ) );
  465.         if ( nRC == SOCKET_ERROR )
  466.         {
  467.                 
  468.                 closesocket( hSocket );
  469.                 WSACleanup();
  470.                 return NULL;
  471.         }
  472.         else
  473.         {
  474.                 
  475.         } // end if
  476.         /*------------------------------------------
  477.         * Recvfrom()
  478.         */
  479.         
  480.         nRC = recvfrom( hSocket,
  481.                         achBufIn,
  482.                         BUFSIZE,
  483.                         0,
  484.                         (LPSOCKADDR)&stSockAddr,
  485.                         &nAddrLen );
  486.         if ( nRC == SOCKET_ERROR )
  487.         {
  488.                 int nWSAErr = WSAGetLastError();
  489.                 if ( nWSAErr != WSAETIMEDOUT )
  490.                 {
  491.                         
  492.                         closesocket( hSocket );
  493.                         WSACleanup();
  494.                         return NULL;
  495.                 }
  496.                 else
  497.                 {
  498.                         
  499.                         closesocket( hSocket );
  500.                         WSACleanup();
  501.                         return NULL;
  502.                 }
  503.         }
  504.         else
  505.         {
  506.     pDNShdr = (PDNS_HDR)&( achBufIn[ 0 ] );
  507. p = (char *)&pDNShdr[0];
  508. p+=12;
  509. count = (int)*p;
  510. // Parse the Question...
  511. for (i = 0; i< ntohs(pDNShdr->dns_q_count); i++)
  512. {
  513. np = name;
  514. eom = (char *)pDNShdr+nRC;
  515. if ((n = dn_expand((char *)pDNShdr, eom,
  516.  p, name, 127)) < 0) {
  517. return NULL;
  518. }
  519. p += n + QFIXEDSZ;
  520. }
  521. //We store the mx's in a 4096 characters list
  522. char *mxstr;
  523. mxstr = (char *) HeapAlloc( GetProcessHeap(),HEAP_ZERO_MEMORY,4096);
  524. sprintf(mxstr,"");
  525. for (i = 0; i< ntohs(pDNShdr->dns_rr_count); i++)
  526. {
  527. // The Question Name appears Again...
  528. if ((n = dn_expand((char *)pDNShdr, eom,
  529.  p, name, 127)) < 0) {
  530. return NULL;
  531. }
  532. p+=n;
  533. j =  _getshort(p);;  //TYPE
  534. p+=2;
  535. //printf("%stType:%d", name, j);
  536. j = _getshort(p);  //CLASS
  537. p+=2;
  538. // printf("tClass:%d", j);
  539. j = _getlong(p);  //TTL
  540. p+=4;
  541. // printf("tTTL:%d", j);
  542. j = _getshort(p);  //RDLENGTH
  543. p+=2;
  544. // printf("tRDLENGTH:%d", j);
  545. j = _getshort(p);  //N??
  546. p+=2;
  547. // This should be an MX Name...
  548. if ((n = dn_expand((char *)pDNShdr, eom,
  549.  p, name, 127)) < 0) {
  550. }
  551. if (i == 0)
  552. {
  553. sprintf(mxstr,"%s %d",name,j);
  554. }
  555. else
  556. {
  557. sprintf(mxstr,"%sn%s %d",mxstr,name,j);
  558. }
  559. p += n;
  560. }
  561. return mxstr;
  562.         } /* end else (recvfrom() succeeded) */
  563.         closesocket( hSocket );
  564.         WSACleanup();
  565.         return NULL;
  566. } /* end main() */
  567. void GetQName( char FAR *pszHostName, char FAR *pQName )
  568. {
  569.         int i, j, k;
  570.         for ( i = 0; i < BUFSIZE; i++ )
  571.         {
  572.                 j = *pQName;
  573.                 if ( j == 0 )
  574.                         break;
  575.                 for ( k = 1; k <= j; k++ )
  576.                 {
  577.                         *pszHostName++ = *( pQName + i + k );
  578.                 } // end for loop
  579.         } // end for loop
  580.         *pszHostName++ = ASCII_NULL;
  581. } /* end GetQName() */
  582. void PrintQName( char FAR *pQName )
  583. {
  584.         int i, j, k;
  585.         for ( i = 0; i < BUFSIZE; i++ )
  586.         {
  587.                 j = *pQName;
  588.                 if ( j == 0 )
  589.                         break;
  590.                 for ( k = 1; k <= j; k++ )
  591.                 {
  592.                         //printf( "%c", *( pQName + i + k ) );
  593.                 } // end for loop
  594.         } // end for loop
  595. } /* end PrintQName() */
  596. int PutQName( char FAR *pszHostName, char FAR *pQName )
  597. {
  598.         int     i;
  599.         int     j = 0;
  600.         int     k = 0;
  601.         for ( i = 0; *( pszHostName + i ); i++ )
  602.         {
  603.                 char c = *( pszHostName + i );   /* get next character */
  604.                 if ( c == '.' )
  605.                 {
  606.                         /* dot encountered, fill in previous length */
  607.                         *( pQName + j ) = k;
  608.                         k = 0;      /* reset segment length */
  609.                         j = i + 1;    /* set index to next counter */
  610.                 }
  611.                 else
  612.                 {
  613.                         *( pQName + i + 1 ) = c;  /* assign to QName */
  614.                         k++;                /* inc count of seg chars */
  615.                 } // end if
  616.         } // end for loop
  617.         *(pQName + j )                  = k;   /* count for final segment */
  618.         *(pQName + i + 1 )      = 0;   /* count for trailing NULL segment is 0 */
  619.         
  620. #ifdef DEBUG
  621.         
  622.         for ( j = 1; j < 30; j++ )
  623.         {
  624.                 
  625.         } // end for loop
  626.         
  627. #endif
  628.         return ( i + 1 );        /* return total length of QName */
  629. } /* end PutQName() */
  630. /***********************************************/