4 #define ASCII_NULL '\0'
\r
5 #define MAXHOSTNAME 256
\r
8 // #pragma comment ( lib, "ws2_32.lib" )
\r
10 /* DNS Header Format
\r
12 * All DNS Message Formats have basically the same structure
\r
13 * (note that an RR (DNS Resource Record) is described in
\r
14 * the other structures that follow this header description):
\r
16 * +--------------------------------+
\r
17 * | DNS Header: <defined below> |
\r
18 * +--------------------------------+
\r
19 * | Question: type of query |
\r
20 * | QNAME: <see below> |
\r
21 * | QTYPE: 2-octet RR type |
\r
22 * | QCLASS: 2-octet RR class |
\r
23 * +--------------------------------+
\r
24 * | Answer: RR answer to query |
\r
25 * +--------------------------------+
\r
26 * | Authority: RR for name server |
\r
27 * +--------------------------------+
\r
28 * | Additional: RR(s) other info |
\r
29 * +--------------------------------+
\r
31 * QNAME is a variable length field where each portion of the
\r
32 * "dotted-notation" domain name is replaced by the number of
\r
33 * octets to follow. So, for example, the domain name
\r
34 * "www.sockets.com" is represented by:
\r
37 * octet 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
\r
38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\r
39 * |3|w|w|w|7|s|o|c|k|e|t|s|3|c|o|m|0|
\r
40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\r
42 * NOTE: The last section, "Additional," often contains records
\r
43 * for queries the server anticipates will be sent (to reduce
\r
44 * traffic). For example, a response to an MX query, would
\r
45 * usually have the A record in additional information.
\r
47 typedef struct dns_hdr
\r
49 USHORT dns_id; /* client query ID number */
\r
50 USHORT dns_flags; /* qualify contents <see below> */
\r
51 USHORT dns_q_count; /* number of questions */
\r
52 USHORT dns_rr_count; /* number of answer RRs */
\r
53 USHORT dns_auth_count; /* number of authority RRs */
\r
54 USHORT dns_add_count; /* number of additional RRs */
\r
55 } DNS_HDR, *PDNS_HDR, FAR *LPDNS_HDR;
\r
57 #define DNS_HDR_LEN 12
\r
59 /* DNS Flags field values
\r
61 * bits: 0 1-4 5 6 7 8 9-11 12-15
\r
62 * +----+--------+----+----+----+----+--------+-------+
\r
63 * | QR | opcode | AA | TC | RD | RA | <zero> | rcode |
\r
64 * +----+--------+----+----+----+----+--------+-------+
\r
66 * QR: 0 for query, and 1 for response
\r
67 * opcode: type of query (0: standard, and 1: inverse query)
\r
68 * AA: set if answer from domain authority
\r
69 * TC: set if message had to be truncated
\r
70 * RD: set if recursive query desired
\r
71 * RA: set if recursion is available from server
\r
72 * <zero>: reserved field
\r
73 * rcode: resulting error non-zero value from authoritative
\r
74 * server (0: no error, 3: name does not exist)
\r
76 #define DNS_FLAG_QR 0x8SpeedPostEmail
\r
77 #define DNS_FLAG_AA 0x0400
\r
78 #define DNS_FLAG_TC 0x0200
\r
79 #define DNS_FLAG_RD 0x0100
\r
80 #define DNS_FLAG_RA 0x0080
\r
81 #define DNS_RCODE_MASK 0xSpeedPostEmailF
\r
82 #define DNS_OPCODE_MASK 0x7800
\r
84 /* DNS Opcode (type of query) */
\r
85 char *DNS_Opcode[] =
\r
87 "Standard Query", /* 0: QUERY */
\r
88 "Inverse Query", /* 1: IQUERY */
\r
89 "Server Status Request", /* 2: STATUS */
\r
92 /* DNS Response Codes (error descriptions) */
\r
95 "No Error", /* 0: ok */
\r
96 "Format Error", /* 1: bad query */
\r
97 "Server Failure", /* 2: server is hosed */
\r
98 "Name Error", /* 3: name doesn't exist (authoritative) */
\r
99 "Not Implemented", /* 4: server doesn't support query */
\r
100 "Refused" /* 5: server refused request */
\r
103 /* DNS Generic Resource Record format (from RFC 1034 and 1035)
\r
105 * NOTE: The first field in the DNS RR Record header is always
\r
106 * the domain name in QNAME format (see earlier description)
\r
108 typedef struct dns_rr_hdr
\r
110 USHORT rr_type; /* RR type code (e.g. A, MX, NS, etc.) */
\r
111 USHORT rr_class; /* RR class code (IN for Internet) */
\r
112 ULONG rr_ttl; /* Time-to-live for resource */
\r
113 USHORT rr_rdlength; /* length of RDATA field (in octets) */
\r
114 USHORT rr_rdata; /* (fieldname used as a ptr) */
\r
115 } DNS_RR_HDR, *PDNS_RR_HDR, FAR *LPDNS_RR_HDR;
\r
117 #define DNS_RR_HDR_LEN 12
\r
119 /* DNS Resource Record RDATA Field Descriptions
\r
121 * The RDATA field contains resource record data associated
\r
122 * with the specified domain name
\r
124 * Type Value Description
\r
125 * -------------------------------------------------------------
\r
126 * A 1 IP Address (32-bit IP version 4)
\r
127 * NS 2 Name server QNAME (for referrals & recursive queries)
\r
128 * CNAME 5 Canonical name of an alias (in QNAME format)
\r
129 * SOA 6 Start of Zone Transfer (see definition below)
\r
130 * WKS 11 Well-known services (see definition below)
\r
131 * PTR 12 QNAME pointing to other nodes (e.g. in inverse lookups)
\r
132 * HINFO 13 Host Information (CPU string, then OS string)
\r
133 * MX 15 Mail server preference and QNAME (see below)
\r
135 char *DNS_RR_Type [] =
\r
138 "A", // 1: Host Address
\r
139 "NS", // 2: Authoritative Name Server
\r
140 "MD", // 3: <obsolete>
\r
141 "MF", // 4: <obsolete>
\r
142 "CNAME", // 5: The true, canonical name for an alias
\r
143 "SOA", // 6: Start-of-Zone of authority record
\r
144 "MB", // 7: Mailbox <experimental>
\r
145 "MG", // 8: Mailgroup <experimental>
\r
146 "MR", // 9: Mail Rename Domain Name <experimental>
\r
147 "NULL", // 10: NULL Resource Record <experimental>
\r
148 "WKS", // 11: Well-known service description
\r
149 "PTR", // 12: Domain Name Pointer
\r
150 "HINFO", // 13: Host Information
\r
151 "MINFO", // 14: Mailbox or Mail List information
\r
152 "MX", // 15: Mail Exchange (from RFC 974)
\r
153 "TXT" // 16: Text String
\r
156 #define DNS_RRTYPE_A 1
\r
157 #define DNS_RRTYPE_NS 2
\r
158 #define DNS_RRTYPE_CNAME 5
\r
159 #define DNS_RRTYPE_SOA 6
\r
160 #define DNS_RRTYPE_WKS 11
\r
161 #define DNS_RRTYPE_PTR 12
\r
162 #define DNS_RRTYPE_HINFO 13
\r
163 #define DNS_RRTYPE_MX 15
\r
165 /* DNS Resource Record Classes:
\r
167 * One almost always uses Internet RR Class (also note: the
\r
168 * class value 255 denotes a wildcard, all classes)
\r
170 char *DNS_RR_Class [] =
\r
173 "IN", // 1: Internet - used for most queries!
\r
174 "CS", // 2: CSNET <obsolete>
\r
175 "CH", // 3: CHAOS Net
\r
179 #define DNS_RRCLASS_IN 1
\r
180 #define DNS_RRCLASS_CS 2
\r
181 #define DNS_RRCLASS_CH 3
\r
182 #define DNS_RRCLASS_HS 4
\r
184 /* DNS SOA Resource Data Field
\r
186 * NOTE: First two fields not shown here. They are:
\r
187 * MNAME: QNAME of primary server for this zone
\r
188 * RNAME: QNAME of mailbox of admin for this zone
\r
190 typedef struct dns_rdata_soa
\r
192 ULONG soa_serial; /* data version for this zone */
\r
193 ULONG soa_refresh; /* time-to-live for data (in seconds) */
\r
194 ULONG soa_retry; /* time between retrieds (in seconds) */
\r
195 ULONG soa_expire; /* time until zone not auth (in seconds) */
\r
196 ULONG soa_minimum; /* default TTL for RRs (in seconds) */
\r
197 } DNS_RDATA_SOA, PDNS_RDATA_SOA, FAR *LPDNS_RDATA_SOA;
\r
199 #define DNS_SOA_LEN 20
\r
201 /* DNS WKS Resource Data Field (RFC 1035)
\r
203 * NOTE: The bitmap field is variable length, with as many
\r
204 * octets necessary to indicate the bit field for the port
\r
207 typedef struct dns_rdata_wks
\r
209 ULONG wks_addr; /* IPv4 address */
\r
210 UCHAR wks_protocol; /* Protocol (e.g. 6=TCP, 17=UDP) */
\r
211 UCHAR wks_bitmap; /* e.g. bit 26 = SMTP (port 25) */
\r
212 } DNS_RDATA_WKS, *PDNS_RDATA_WKS, FAR *LPDNS_RDATA_WKS;
\r
214 #define DNS_WKX_LEN 6
\r
216 /* DNS MX Resource Data Field
\r
218 typedef struct dns_rdata_mx
\r
220 USHORT mx_pref; /* Preference value */
\r
221 USHORT mx_xchange; /* QNAME (field used as ptr) */
\r
222 } DNS_RDATA_MX, *PDNS_RDATA_MX, FAR *LPDNS_RDATA_MX;
\r
224 #define DNS_MX_LEN 4
\r
226 /* Variables used for DNS Header construction & parsing */
\r
228 PDNS_RR_HDR pDNS_RR;
\r
229 PDNS_RDATA_SOA pDNS_SOA;
\r
230 PDNS_RDATA_WKS pDNS_WKS;
\r
231 PDNS_RDATA_MX pDNS_MX;
\r
233 /* For Parsing Names in a Reply */
\r
234 #define INDIR_MASK 0xc0
\r
236 /* Number of bytes of fixed size data in query structure */
\r
238 /* number of bytes of fixed size data in resource record */
\r
239 #define RRFIXEDSZ 10
\r
241 /* Processor Types */
\r
242 char *aszProcessor[] =
\r
253 void GetQName( char FAR *pszHostName, char FAR *pQName );
\r
254 void PrintQName( char FAR *pQName );
\r
255 int PutQName( char FAR *pszHostName, char FAR *pQName );
\r
257 USHORT _getshort(char *msgp)
\r
259 register UCHAR *p = (UCHAR *) msgp;
\r
263 return ((USHORT)(u | *p));
\r
266 ULONG _getlong(char *msgp)
\r
268 register UCHAR *p = (UCHAR *) msgp;
\r
272 u |= *p++; u <<= 8;
\r
273 u |= *p++; u <<= 8;
\r
279 * Expand compressed domain name 'comp_dn' to full domain name.
\r
280 * 'msg' is a pointer to the begining of the message,
\r
281 * 'eomorig' points to the first location after the message,
\r
282 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
\r
283 * Return size of compressed name or -1 if there was an error.
\r
285 int dn_expand(char *msg,char *eomorig,char *comp_dn,char *exp_dn,int length)
\r
287 register char *cp, *dn;
\r
290 int len = -1, checked = 0;
\r
294 eom = exp_dn + length - 1;
\r
296 * fetch next label in domain name
\r
298 while (n = *cp++) {
\r
300 * Check for indirection
\r
302 switch (n & INDIR_MASK) {
\r
304 if (dn != exp_dn) {
\r
313 if ((c = *cp++) == '.') {
\r
319 if (cp >= eomorig) /* out of range */
\r
326 len = cp - comp_dn + 1;
\r
327 cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
\r
328 if (cp < msg || cp >= eomorig) /* out of range */
\r
332 * Check for loops in the compressed name;
\r
333 * if we've looked at the whole message,
\r
334 * there must be a loop.
\r
336 if (checked >= eomorig - msg)
\r
341 return (-1); /* flag error */
\r
346 len = cp - comp_dn;
\r
351 * Skip over a compressed domain name. Return the size or -1.
\r
353 int dn_skipname(UCHAR *comp_dn, UCHAR *eom)
\r
355 register UCHAR *cp;
\r
359 while (cp < eom && (n = *cp++)) {
\r
361 * check for indirection
\r
363 switch (n & INDIR_MASK) {
\r
364 case 0: /* normal case, n == len */
\r
367 default: /* illegal type */
\r
369 case INDIR_MASK: /* indirection */
\r
374 return (cp - comp_dn);
\r
380 BOOL SetBlockingMode ( SOCKET hSocket, BOOL bNonblockingEnable )
\r
382 if ( hSocket == INVALID_SOCKET || hSocket == 0 )
\r
387 long cmd = FIONBIO;
\r
389 u_long* argp = NULL;
\r
390 if ( bNonblockingEnable )
\r
391 argp = (u_long*)&cmd;
\r
393 argp = (u_long*)&zero;
\r
394 int err = ioctlsocket ( hSocket, cmd, argp );
\r
407 OUT t_Ary_MXHostInfos &Ary_MXHostInfos
\r
411 SOCKADDR_IN stSockAddr; // socket address structures
\r
412 int nAddrLen = sizeof( SOCKADDR_IN );
\r
416 char achBufOut[ BUFSIZE ] = { 0 };
\r
417 char achBufIn[ BUFSIZE ] = { 0 };
\r
421 char *p, *np, name[128], *eom;
\r
422 int count, j, i, n;
\r
424 memset( &stSockAddr, ASCII_NULL, sizeof( stSockAddr ) );
\r
426 stSockAddr.sin_family = AF_INET;
\r
427 stSockAddr.sin_port = htons( 53);
\r
428 stSockAddr.sin_addr.s_addr = inet_addr( pszServer );
\r
429 if ( stSockAddr.sin_addr.s_addr == INADDR_NONE )
\r
431 pHostEnt = gethostbyname( pszServer );
\r
434 stSockAddr.sin_addr.s_addr = *((ULONG *)pHostEnt->h_addr_list[0]);
\r
443 /*------------------------------------------------------------
\r
444 * Get a DGRAM socket
\r
447 hSocket = socket( AF_INET, SOCK_DGRAM, 0 );
\r
449 if ( hSocket == INVALID_SOCKET )
\r
454 /*-----------------------------------------------------------
\r
458 pDNShdr = (PDNS_HDR)&( achBufOut[ 0 ] );
\r
459 pDNShdr->dns_id = htons( 0xDEAD );
\r
460 pDNShdr->dns_flags = htons( DNS_FLAG_RD ); // do recurse
\r
461 pDNShdr->dns_q_count = htons( 1 ); // one query
\r
462 pDNShdr->dns_rr_count = 0; // none in query
\r
463 pDNShdr->dns_auth_count = 0; // none in query
\r
464 pDNShdr->dns_add_count = 0; // none in query
\r
466 nQueryLen = PutQName( pszQuery, &(achBufOut[ DNS_HDR_LEN ] ) );
\r
467 nQueryLen += DNS_HDR_LEN;
\r
469 achBufOut[ nQueryLen++ ] = 0;
\r
470 achBufOut[ nQueryLen++ ] = 0;
\r
471 achBufOut[ nQueryLen ] = DNS_RRTYPE_MX;
\r
472 achBufOut[ nQueryLen + 1 ] = 0;
\r
473 achBufOut[ nQueryLen + 2 ] = DNS_RRCLASS_IN;
\r
474 achBufOut[ nQueryLen + 3 ] = 0;
\r
478 /*-----------------------------------------------------------
\r
479 * Send DNS Query to server
\r
482 nRC = sendto( hSocket,
\r
486 (LPSOCKADDR)&stSockAddr,
\r
487 sizeof( SOCKADDR_IN ) );
\r
489 if ( nRC == SOCKET_ERROR )
\r
492 closesocket( hSocket );
\r
500 // VERIFY ( SetBlockingMode ( hSocket, TRUE ) );
\r
502 // Óà select Ä£ÐÍʵÏÖÁ¬½Ó³¬Ê±
\r
503 struct timeval timeout;
\r
506 FD_SET(hSocket, &r);
\r
507 timeout.tv_sec = 5; //Á¬½Ó³¬Ê±Ãë
\r
508 timeout.tv_usec =0;
\r
509 int ret = select(0, &r, 0, 0, &timeout);
\r
510 if ( ret == SOCKET_ERROR )
\r
512 ::closesocket(hSocket);
\r
513 hSocket = SOCKET_ERROR;
\r
517 // µÃµ½¿É¶ÁµÄÊý¾Ý³¤¶È
\r
518 long cmd = FIONREAD;
\r
520 BOOL err = ioctlsocket ( hSocket, cmd, (u_long*)&argp );
\r
521 if ( err || argp < 1 )
\r
523 ::closesocket(hSocket);
\r
524 hSocket = SOCKET_ERROR;
\r
528 nRC = recvfrom( hSocket,
\r
532 (LPSOCKADDR)&stSockAddr,
\r
535 if ( nRC == SOCKET_ERROR )
\r
537 int nWSAErr = WSAGetLastError();
\r
539 if ( nWSAErr != WSAETIMEDOUT )
\r
542 closesocket( hSocket );
\r
548 closesocket( hSocket );
\r
554 pDNShdr = (PDNS_HDR)&( achBufIn[ 0 ] );
\r
555 p = (char *)&pDNShdr[0];
\r
559 // Parse the Question...
\r
560 for (i = 0; i< ntohs(pDNShdr->dns_q_count); i++)
\r
563 eom = (char *)pDNShdr+nRC;
\r
565 if ( (n = dn_expand((char *)pDNShdr, eom, p, name, 127)) < 0 )
\r
573 for (i = 0; i< ntohs(pDNShdr->dns_rr_count); i++)
\r
576 // The Question Name appears Again...
\r
577 if ((n = dn_expand((char *)pDNShdr, eom, p, name, 127)) < 0)
\r
584 j = _getshort(p);; //TYPE
\r
586 //printf("%s\tType:%d", name, j);
\r
588 j = _getshort(p); //CLASS
\r
590 // printf("\tClass:%d", j);
\r
592 j = _getlong(p); //TTL
\r
594 // printf("\tTTL:%d", j);
\r
596 j = _getshort(p); //RDLENGTH
\r
598 // printf("\tRDLENGTH:%d", j);
\r
600 j = _getshort(p); //N??
\r
603 // This should be an MX Name...
\r
604 if ( (n = dn_expand((char *)pDNShdr, eom, p, name, 127)) < 0 )
\r
609 t_MXHostInfo tMXHostInfo = {0};
\r
610 strncpy ( (char*)tMXHostInfo.szMXHost, name, sizeof(tMXHostInfo.szMXHost)/sizeof(tMXHostInfo.szMXHost[0]) );
\r
612 Ary_MXHostInfos.Add ( tMXHostInfo );
\r
613 TRACE ( _T("%s\t%d\r\n"), name, j );
\r
622 closesocket( hSocket );
\r
627 void GetQName( char FAR *pszHostName, char FAR *pQName )
\r
632 for ( i = 0; i < BUFSIZE; i++ )
\r
639 for ( k = 1; k <= j; k++ )
\r
641 *pszHostName++ = *( pQName + i + k );
\r
645 *pszHostName++ = ASCII_NULL;
\r
646 } /* end GetQName() */
\r
649 void PrintQName( char FAR *pQName )
\r
653 for ( i = 0; i < BUFSIZE; i++ )
\r
660 for ( k = 1; k <= j; k++ )
\r
662 //printf( "%c", *( pQName + i + k ) );
\r
665 } /* end PrintQName() */
\r
668 int PutQName( char FAR *pszHostName, char FAR *pQName )
\r
675 for ( i = 0; *( pszHostName + i ); i++ )
\r
677 char c = *( pszHostName + i ); /* get next character */
\r
682 /* dot encountered, fill in previous length */
\r
683 *( pQName + j ) = k;
\r
685 k = 0; /* reset segment length */
\r
686 j = i + 1; /* set index to next counter */
\r
690 *( pQName + i + 1 ) = c; /* assign to QName */
\r
691 k++; /* inc count of seg chars */
\r
695 *(pQName + j ) = k; /* count for final segment */
\r
696 *(pQName + i + 1 ) = 0; /* count for trailing NULL segment is 0 */
\r
698 return ( i + 1 ); /* return total length of QName */
\r
702 // ³¢ÊÔËùÓеÄDNSÀ´²éѯÓʾַþÎñÆ÷µØÖ·
\r
705 char *pszQuery, // Òª²éѯµÄÓòÃû
\r
706 OUT t_Ary_MXHostInfos &Ary_MXHostInfos // Êä³ö Mail Exchange Ö÷»úÃû
\r
709 CNetAdapterInfo m_NetAdapterInfo;
\r
710 m_NetAdapterInfo.Refresh ();
\r
711 int nNetAdapterCount = m_NetAdapterInfo.GetNetCardCount();
\r
712 for ( int i=0; i<nNetAdapterCount; i++ )
\r
714 COneNetAdapterInfo *pOneNetAdapterInfo = m_NetAdapterInfo.Get_OneNetAdapterInfo ( i );
\r
715 if ( pOneNetAdapterInfo )
\r
717 int nDNSCount = pOneNetAdapterInfo->Get_DNSCount ();
\r
718 for ( int j=0; j<nDNSCount; j++ )
\r
720 CString csDNS = pOneNetAdapterInfo->Get_DNSAddr ( j );
\r
721 if ( GetMX ( pszQuery, csDNS.GetBuffer(0), Ary_MXHostInfos ) )
\r