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