首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

使用socket获取dns的mx的有关问题

2012-02-23 
使用socket获取dns的mx的问题怎样实现[解决办法]/*****************************************************

使用socket获取dns的mx的问题
怎样实现

[解决办法]
/******************************************************************
*本文首发于bbs.bluegem.org的linux区
*本人email:chenfei@sohu.com
*如转载本文,请保留首发地和本人联络方式,以方便交流,谢谢!
******************************************************************/
/* dns.c
*
* char *getmxbyname(char *domain) - gets the DNS MX records for host/domain char *domain
* it returns a colon delimited list of valid MXs.
*/


#include <msmtpd.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>

#include <sys/types.h> /* not always automatically included */
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <netdb.h>
#undef NOERROR /* in <sys/streams.h> on solaris 2.x */
#include <arpa/nameser.h>
#include <resolv.h>


/*
* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors ' ' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* Neither the name of the University nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS ' ' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

/*silly hackery */

#if defined(BIND_493)
typedef u_char qbuf_t;
#else
typedef char qbuf_t;
#endif

#if defined(BIND_493)
typedef char nbuf_t;
#else
typedef u_char nbuf_t;
#endif



/**/
/*
** GETMXBYNAME -- Fetch mx hosts for a domain
** ------------------------------------------
**
**Returns:
**Number of mx hosts found.
**
**Outputs:
**The contains the mx names.
*/

char *getmxbyname(char *domain) /*find mxs for this domain*/
{
//int verbose = 0;
//int debug = 0;

/* #define HFIXEDSZ sizeof(HEADER) actually 12 */
#define MAXPACKET 8192/* max size of packet */
//#define MAXMXHOSTS 20/* max num of mx records we want to see */
enum { MAXMXHOSTS = 20 };
//char _arr[MAXBUF][MAXBUF];
enum { MAXMXBUFSIZ = (MAXMXHOSTS * (MAXBUF+1)) };

typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf;

static char hostbuf[MAXMXBUFSIZ];

char *MxHosts[MAXMXHOSTS];
querybuf answer;/* answer buffer from nameserver */
HEADER *hp;/* answer buffer header */
int ancount, qdcount;/* answer count and query count */
u_char *msg, *eom, *cp;/* answer buffer positions */
int type, class, dlen;/* record type, class and length */
u_short pref;/* mx preference value */
u_short prefer[MAXMXHOSTS];/* saved preferences of mx records */


char *bp;/* hostbuf pointer */
int nmx;/* number of mx hosts found */
register int i;
register int j;
register int n;

char *str;/* final answer string buffer. */
str = xmalloc(MAXBUF);

/*
* Query the nameserver to retrieve mx records for the given domain.
*/
errno = 0;/* reset before querying nameserver */
h_errno = 0;

n = res_search(domain, C_IN, T_MX, (u_char *)&answer, sizeof(answer));
if (n < 0)
{
if (_res.options & RES_DEBUG)
debug( "sres_search failed\n ");
return(0);
}

errno = 0;/* reset after we got an answer */

if (n < HFIXEDSZ)
{
h_errno = NO_RECOVERY;
return(0);
}

/* avoid problems after truncation in tcp packets */
if (n > sizeof(answer))
n = sizeof(answer);

/*
* Valid answer received. Skip the query record.
*/
hp = (HEADER *)&answer;
qdcount = ntohs((u_short)hp-> qdcount);
ancount = ntohs((u_short)hp-> ancount);

msg = (u_char *)&answer;
eom = (u_char *)&answer + n;
cp = (u_char *)&answer + HFIXEDSZ;

while (qdcount-- > 0 && cp < eom)
{
n = dn_skipname(cp, eom);
if (n < 0)
return(0);
cp += n;
cp += QFIXEDSZ;
}

/*
* Loop through the answer buffer and extract mx records.
*/
nmx = 0;
bp = hostbuf;

while (ancount-- > 0 && cp < eom && nmx < MAXMXHOSTS)
{
//if (verbose > = 4 || debug)
//(void) p_rr((qbuf_t *)cp, (qbuf_t *)msg, stdout);

n = dn_expand(msg, eom, cp, (nbuf_t *)bp, MAXBUF);
if (n < 0)
break;
cp += n;

type = _getshort(cp);
cp += INT16SZ;

class = _getshort(cp);
cp += INT16SZ;

/* ttl = _getlong(cp); */
cp += INT32SZ;

dlen = _getshort(cp);
cp += INT16SZ;

if (type != T_MX || class != C_IN)
{
cp += dlen;
continue;
}

pref = _getshort(cp);
cp += INT16SZ;

n = dn_expand(msg, eom, cp, (nbuf_t *)bp, MAXBUF);
if (n < 0)
break;
cp += n;

prefer[nmx] = pref;
MxHosts[nmx] = bp;
nmx++;

//n = strlength(bp) + 1;
n = strlen(bp) + 1;
bp += n;
}

/*
* Sort all records by preference.
*/
for (i = 0; i < nmx; i++)
{
for (j = i + 1; j < nmx; j++)
{
if (prefer[i] > prefer[j])
{
register u_short tmppref;
register char *tmphost;

tmppref = prefer[i];
prefer[i] = prefer[j];
prefer[j] = tmppref;

tmphost = MxHosts[i];
MxHosts[i] = MxHosts[j];
MxHosts[j] = tmphost;
}
}
}

for (i = 0; i < nmx; i++){
strcat(str, MxHosts[i]);
strcat(str, ": ");
}

return(str);
[解决办法]
void CGetDNS::mx_query(char* host, SOCKADDR_IN dns_addr){
int length=0,result,i,timeout=20,err;
char *query,message[256],*name,*answer;
unsigned char errors;
unsigned short int qdcount,ancount,nscount,arcount,anstype;
SOCKET sock;
BOOL alias;

while(1){
length++;
query=(char*)malloc(length);
result=res_mkquery(0,host,1,15,0,0,0,query,length);


if (result!=-1) break;
free(query);
}
sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
setsockopt(sock,SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
err=connect(sock,(SOCKADDR*)&dns_addr,16);
if (err){
//sprintf(message, "Socket error, connection failed ");
//AfxMessageBox(message);
return;
}
send(sock,((char*)(&result))+1,1,0);
send(sock,((char*)(&result))+0,1,0);
send(sock,query,result,0);
already_read=-2;
length=GetShortInt(sock);
query_rep=(unsigned char*)malloc(length);
GetShortInt(sock);//id
GetByte(sock);//type
errors=GetByte(sock);
if (process_errors(errors,message,host)){
//AfxMessageBox(message);
return;
}
qdcount=GetShortInt(sock);
ancount=GetShortInt(sock);
nscount=GetShortInt(sock);
arcount=GetShortInt(sock);
if (ancount==0){
//sprintf(message, "%s is a valid domain name, but not a valid mail address ",host);
//AfxMessageBox(message);
closesocket(sock);
return;
}
name=(char*)malloc(256);
answer=(char*)malloc(256);
for(i=0;i <qdcount;i++){
GetLabel(sock,name,already_read);
GetTypeAndClass(sock);
}
for(i=0;i <ancount;i++){
char pref[6];
GetLabel(sock,name,already_read);
anstype=GetTypeAndClass(sock);
GetAnswer(sock,anstype,answer);
sprintf(pref, "%u ",answer[0]*256+answer[1]);
//-- Ensure we dont go over our structure array
if( iStructCounter <= 20 ) {
strcpy( DNS_RESULT[iStructCounter].szMailDomain , name);
strcpy( DNS_RESULT[iStructCounter].szMailExchange , answer+2);
strcpy( DNS_RESULT[iStructCounter].szMailPreference , pref);
iStructCounter++;
}
}
alias=TRUE;
closesocket(sock);
free(query_rep);
}

void CGetDNS::Query(HWND hwnd, char* host, char* dns){
//char message[256];
SOCKADDR_IN dns_addr, host_addr;

dns_addr.sin_port=htons(53);
dns_addr.sin_family=AF_INET;
dns_addr.sin_addr.S_un.S_addr=inet_addr(dns);
if (dns_addr.sin_addr.S_un.S_addr==INADDR_NONE){
struct hostent* hostgot=gethostbyname(dns);
if (hostgot==NULL){
/*
sprintf(message, "Could not resolve %s ",dns);
MessageBox(hwnd,message, "Error ",MB_OK|MB_ICONERROR);
*/
return;
}
dns_addr.sin_addr.S_un.S_un_b.s_b1=hostgot-> h_addr_list[0][0];
dns_addr.sin_addr.S_un.S_un_b.s_b2=hostgot-> h_addr_list[0][1];
dns_addr.sin_addr.S_un.S_un_b.s_b3=hostgot-> h_addr_list[0][2];
dns_addr.sin_addr.S_un.S_un_b.s_b4=hostgot-> h_addr_list[0][3];
}
memset(dns_addr.sin_zero,0,8);
host_addr.sin_addr.S_un.S_addr=inet_addr(host);

//-- Perform MX_DNS
mx_query(host,dns_addr);

//-- Loop thru structure of returned results
/*
for( int n = 0; n <= iStructCounter -1; n++ ) {
CString szOutput;
szOutput.Format( "[%s] %s ", DNS_RESULT[n].szMailPreference, DNS_RESULT[n].szMailExchange);
AfxMessageBox(szOutput);
}
*/
}

//-- Pass reference to lowest MX preference
void CGetDNS::GetBestPreference(CString *szMailExchange)
{
int iPos = 0;


int iPreference = 100;
if( iStructCounter > 0 ) {
for( int n = 0; n <= iStructCounter -1; n++ ) {
if( iPreference > = atoi(DNS_RESULT[n].szMailPreference) ) {
iPreference = atoi(DNS_RESULT[n].szMailPreference);
iPos = n;
}
}
*szMailExchange = DNS_RESULT[iPos].szMailExchange;
}else{
szMailExchange-> Empty();
}
}

//http://www.codeguru.com/cgi-bin/bbs/wt/showpost.pl?Board=vc&Number=329921&page=&view=&sb=
//An example of usage is:
CGetDNS oDNS;
CString szDNSResult, szDomain;
oDNS.Query( m_hWnd, szDomain.GetBuffer(szDomain.GetLength()+1),
m_szDNSServer.GetBuffer(m_szDNSServer.GetLength()+1) );
oDNS.GetBestPreference( &szDNSResult );
szDomain.ReleaseBuffer();
m_szDNSServer.ReleaseBuffer();
if( !szDNSResult.IsEmpty() )
{
AfxMessageBox(szDNSResult)
}

热点排行