`

MX解析代码

阅读更多
网上学来的代码。大部分是别人写的,自己改进了一下,添加了若干注释。
请注意在获取MX Domain Name那一步的时候,即:
		// 第10.3步:获取域名。
		//资源数据则根据类型字段的值有不同的格式. 对于A类型, 资源数据是IP地址. 对于MX查询, 资源数据是优先值和域名, 域名的格式与查询名字段格式相同
		memset(name,0,MAXDNAME); 
		if(dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0) 

这里有疑问啊,对于DNS解析的话,不是+2啊。

参照:http://hi.baidu.com/grdd/blog/item/df56ba51469a6710367abebe.html

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <arpa/nameser.h> 
#include <resolv.h> 
#include <errno.h> 

#include "dns.h" 

extern int res_query(); 
extern int res_search(); 
extern int errno; 
extern int h_errno; 

//getshort函数从指定地址读取16bit网络字节顺序的数据(big-endian), 并将其转换成little-endian的顺序返回.
static unsigned short getshort(unsigned char *c) 
{
	unsigned short u; //2字节
	u = c[0]; //将1字节装进来,低四位有值
	return (u << 8) + c[1]; //移动到高四位,然后加上一个字节的数
}

/*
 * 定义了一个联合体变量名为response, 用于存储DNS响应报文. HEADER是用于存储DNS首部的结构体
 * HEADER结构体中本文会用到的成员是dncount和ancout, 分别表示问题数和资源记录数
 * PACKETSZ定义在<arpa/nameser_compat.h>中, 这个宏表示一个报文的最大长度
 */
static union 
{
	HEADER hdr; //首部
	unsigned char buf[PACKETSZ]; //整个缓冲区
} response; 

static int responselen;  // 响应报文的长度
static unsigned char *responseend;  // 指向了响应报文最后一个字节之后的一字节,即response.buf+responselen
static unsigned char *responsepos;  // 指向了即将处理的字段
static int numanswers;  // 还未处理的回答数
static char name[MAXDNAME];  // 用来存储主机名, 长度是MAXDNAME个字节, MAXDNAME定义在<arpa/nameser.h>中, 表示域名的最大长度
static unsigned short pref;  // 用来存储MX记录的优先值.

void dns_init() 
{ 
	res_init();  // 【第一步】读取配置文件并修改环境变量:LOCALDOMAIN. 在调用其他地址解析函数前通常要先调用res_init. 如果执行成功, 函数返回0; 否则返回-1.
	memset(name,0,MAXDNAME); 
}

/* 
 * 功能:1.发起一个指定查询名(domain)和查询类型(type)的DNS查询;
 *       2.让指针指向第一个回答字段。
 *       3.获取资源记录数。
 * 返回:如果发生错误, 函数返回-1, 否则返回资源记录数。
 */
int dns_resolve(char *domain,int type) 
{ 
	int n; 
	int i; 
	errno=0; 
	if(NULL == domain) 
		return -1; 
	//【第二步】发起一条指定类型(C_IN)的DNS查询,这个查询是核心!!!后面都从这个结果中提取信息
	responselen = res_search(domain, C_IN, type, response.buf, sizeof(response)); 
	if(responselen <= 0) 
		return -1; 
	if(responselen >= sizeof(response)) 
		responselen = sizeof(response); 
	
	// 【第三步】以下就是将获取到的报文中我们想要的信息提取出来!
	responseend = response.buf + responselen;     // 第1步:获取报文结束字符后面那个位置
	responsepos = response.buf + sizeof(HEADER);  // 第2步:跳过12字节长的首部:HEADER是一个12字节长的首部,包括问题数和资源记录数
	n = ntohs(response.hdr.qdcount);              // 第3步:报文中的问题数(需要进行网络字节序转换)
	while(n-- > 0) //第4步:跳过所有的“查询问题”字段, 让responsepos指向第一个回答的首地址
	{
		//第4.1步:获得查询问题字段中“查询名”的长度
		i = dn_expand(response.buf, responseend, responsepos, name, MAXDNAME); 
		responsepos += i; //第4.2步:使得responsepos指向了“查询类型”字段的首地址
		i = responseend - responsepos;  //第4.3步:获取这个首地址到结束处的长度(因为指向最后一个字符的后面那个字节,所以不必+1)
		//QFIXEDSZ宏定义在<arpa/nameser_compat.h>中, 其值等于4. 它表示DNS查询报文中问题部分的定长字段的字节数, 即查询类型和查询类两个字段的总长度
		if(i < QFIXEDSZ)  // 第4.4步:验证剩余长度。如果这个长度比QFIXEDSZ还小,说明报文不正常
			return -1; 
		
		responsepos += QFIXEDSZ;  // 第4.5步:指向下一个“查询问题”字段
	}
	
	// 第5步:获取资源记录数并返回。
	numanswers = ntohs(response.hdr.ancount);  //将资源记录数的值赋给numanswers
	return numanswers; 
}

/*
 * 功能:从回答内容中提取1个得到的域名。并将指针移动。
 */
int dns_findmx(int wanttype) 
{
	unsigned short rrtype; 
	unsigned short rrdlen; 
	int i; 

	if(numanswers <=0) 
		return DNS_MSG_END; 
	
	numanswers--; 
	
	if(responsepos == responseend) 
		return -1; 
		
	//回答字段是以资源记录格式存储的. 第一项是域名. 因此用dn_expand函数将该字段还原为普通字符串格式. 并将返回的该字段长度赋值给i.
	// 第6步:获取回答字段的第一项:域名。
	i = dn_expand(response.buf, responseend, responsepos, name, MAXDNAME); 
	//printf("Domain:    %s\t", name);
	if(i < 0) 
		return -1; 

	responsepos += i;  // 第7步:指针跳过域名。
	i = responseend - responsepos;  // 第8步:获取剩下的字节数并判断。小于10说明非法。
	//资源记录中, 定长字段的总长度为10字节,即类型, 类, 生存时间和资源数据长度字段的总长度
	if(i < 10)
		return -1; 

	// 第8步:利用getshort函数分别获得“类型”和“资源数据长度”字段的值
	rrtype = getshort(responsepos); 
	rrdlen = getshort(responsepos + 8); 
	responsepos += 10;  // 第9步:使其指向资源数据的首地址
	
	if(rrtype == wanttype) // 第10步:如果这条资源记录的类型是函数参数所指定的类型, 则对其进行处理. MX记录中
	{
		// 第10.1步:判断资源数据长度是否合法。
		// 资源数据内第一项存储着16bit的优先值, 之后存储着1字节的主机名, 则资源数据长度至少要3字节。
		if(rrdlen < 3) 
			return -1; 
	
		// 第10.2步:从资源数据中获得优先值存储在pref中. 由于报文中的优先值是按照网络字节顺序存储的, 因此需要将其转换成little-endian顺序后存到pref中
		pref = getshort(responsepos);
		
		// 第10.3步:获取域名。
		//资源数据则根据类型字段的值有不同的格式. 对于A类型, 资源数据是IP地址. 对于MX查询, 资源数据是优先值和域名, 域名的格式与查询名字段格式相同
		memset(name,0,MAXDNAME); 
		if(dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0) 
			return -1; 
		//printf("MX domain: %s \n", name);
		responsepos += rrdlen; 
		return strlen(name); 
	} 
	
	//该资源记录的类型与参数指定类型不符, 则跳过该条记录, 将responsepos调整至下一条资源记录.
	responsepos += rrdlen; 
	return 0; 
} 

/*
 * dns_get_mxrr函数将pref的值(优先值)存储到p指向的地址中, 
 * 并将name中存储的主机名复制到dn指向的地址中, 
 * 复制的长度不超过len个字节. 
 * 如果len个字节不足以存储整个主机名, 则返回-1, 否则返回0.
 */
int dns_get_mxrr(unsigned short *p, unsigned char *dn,unsigned int len) 
{ 
	*p = pref; 
	strncpy(dn,name,len); 
	if(len < (strlen(name)+1)) 
		return -1; 
	return 0; 
}

int get_mx_name(char *addr, Mx_type *mx, int *num)
{
	char dname[MAXDNAME]; 
	int i; 
	unsigned short p; 
	
	dns_init(); 
	i = dns_resolve(addr, T_MX);
	if(i<0) 
	{ 
		//fprintf(stderr, "No MX\n"); 
		return -1; 
	} 
	
	*num = 0;
	while(dns_findmx(T_MX)!=DNS_MSG_END &&
			(!dns_get_mxrr(&p, dname, MAXDNAME)) )
	{ 
		strncpy(mx[*num].addr, dname, MAXDNAME);
		mx[*num].pref = p;
		(*num)++;
	}
	
	return 0;
}

//直接调用函数的用法——便于理解
int main(int argc, char *argv[]) 
{ 
	Mx_type mx[32] = {0};
	int i, num, ret;

	//printf("sizeof HEADER: %d; MAXDNAME: %d; \n", sizeof (HEADER), MAXDNAME);
	if(argc!=2) 
	{ 
		fprintf(stderr,"Usage: command <arg1>\n"); 
		exit(-1); 
	}
	
	ret = get_mx_name(argv[1], mx, &num);
	if (ret != 0) {
		printf("No mx\n");
		exit(-1);
	}
	
	printf("[Num] [Domain name]\t\t[Pref]\t[MX Domain name]\n"); 
	for(i=0; i<num; i++)
		printf("%-5d Dmain:%s\t\t%d\t%s\n", 
				i, argv[1], mx[i].pref, mx[i].addr);
	
	return 0; 
} 

0
1
分享到:
评论

相关推荐

    dns解析代码

    DNS解析代码主要涉及如何编程实现这个过程,通常使用TCP/IP协议栈中的UDP协议进行通信。在这个场景中,`www.pudn.com.txt`可能是记录了有关pudn.com域名解析数据的文本文件,而`SockClient.zip`和`SockSever.zip`...

    Flash MX游戏制作常用代码解析.doc

    ### Flash MX游戏制作常用代码解析 #### 一、获得随机数 在Flash游戏开发中,随机数的应用极为广泛,比如可以用来实现游戏元素的位置变化、难度级别调整等,以增加游戏的趣味性和挑战性。Flash提供了两种生成随机数...

    MX25U512存储器的演示代码

    **MX25U512存储器的演示代码** 这篇文档将深入探讨MX25U512存储器,这是一种常见的SPI(Serial Peripheral Interface)闪存芯片,它提供了512Kbit(64KB)的存储容量。MX25U512是微控制器系统中的理想选择,用于...

    DALSA MX4 Xtium-CL-MX4 SDK及driver

    本文将深入解析这款产品的SDK(软件开发工具包)和Driver(驱动程序),帮助读者理解其功能、应用场景以及如何有效利用这些资源进行开发。 首先,让我们了解DALSA MX4的核心特点。MX4是一款基于Camera Link接口的4...

    Director MX 2004多媒体课件源代码

    《Director MX 2004多媒体课件源代码解析与应用》 Director MX 2004是一款由Macromedia公司(现已被Adobe收购)推出的强大的多媒体创作软件,它为开发者提供了一个集成的环境,用于创建互动式多媒体应用程序,包括...

    flashMX做的百万富翁的源代码

    《基于Flash MX的“百万富翁”游戏源代码解析》 在数字娱乐领域,Flash MX是一款曾经广泛应用的动画和交互式内容开发工具,它以其强大的功能和易用性深受开发者喜爱。今天我们要探讨的是一个利用Flash MX制作的...

    DNS域名解析的VC代码,与大家分享

    本文将深入探讨DNS域名解析的过程,并通过一个简单的VC++代码示例来帮助初学者理解这一机制。 首先,DNS解析通常分为递归查询和迭代查询两种方式。在递归查询中,客户端向DNS服务器发起请求,服务器负责全程处理,...

    得到远程MX服务器DNS

    7. **代码实现**:在VC++7.0环境中,编写C++代码来执行上述操作,可能包括创建socket,设置查询参数,发送查询,接收并解析响应,关闭socket等步骤。 通过以上步骤,你可以实现一个程序,它可以查询任何给定域的MX...

    夏普MX M3608 4608 5608N 3658 4658 5658N中文维修手册

    - 对每种故障代码进行了详细的解析,包括问题的原因、可能的影响以及推荐的解决方案。 **卡纸代码清单:** - 列出了各种卡纸情况的代码及其处理方法。 #### 七、版本升级 **概要:** - 介绍了版本升级的重要性及...

    MH-MX8蓝牙音频.rar

    4. 示例代码或库:提供编程接口(API)的示例,帮助开发者快速理解如何与模块进行通信。 5. MH-MX18、MX28、MX38模块的单独说明书:针对不同型号的特点和应用进行详细解释。 6. 蓝牙音频功法:可能是一份关于如何优化...

    DNS域名解析应用

    Node.js的`dns`模块提供了丰富的API,如`dns.resolve`和`dns.resolve4`等,可以进行A记录(IPv4)查询、MX记录(邮件服务器)查询、NS记录(名称服务器)查询等。在这个项目中,很可能是使用`dns.resolve4`来获取...

    易语言源码易语言取MX服务器类模块源码.rar

    MX服务器类模块通常指的是邮件交换(MX)记录处理相关的代码,这部分源码可能包含了处理DNS查询、解析MX记录、连接邮件服务器等功能。在电子邮件系统中,MX记录用于指示接收电子邮件的服务器,通过这样的方式,邮件...

    使用 Dreamweaver MX

    《使用Dreamweaver MX:深度解析与应用技巧》 标题中的“使用Dreamweaver MX”指的是一款由Macromedia公司开发的专业网页设计与开发工具,后来被Adobe收购并更名为Adobe Dreamweaver。Dreamweaver MX是其历史版本之...

    这可能是最方便的C#调用三菱PLC MX方式

    5. **封装库**:为了提高代码的可重用性和可维护性,你可以将以上步骤封装成一个类库,提供简单的API接口,如ReadRegister和WriteRegister,供其他部分的代码调用。 6. **异步操作**:在C#中,利用async/await...

    NXP i.MX RT1052 LwIP实战:DNS功能解析域名

    在本文中,我们将深入探讨NXP i.MX RT1052处理器上的LwIP(Lightweight TCP/IP)实现,特别是其DNS(Domain Name System)功能。NXP i.MX RT1052是一款高性能、实时微控制器,适用于各种嵌入式应用,包括物联网设备...

    查询域名的MX记录是否正确源码

    通过查看这个文件,我们可以学习如何将DLL调用集成到VB项目中,以及如何处理查询结果,例如,解析返回的MX记录字符串,通常会包含优先级和邮件服务器的主机名。 为了更好地理解这个过程,我们需要了解DNS查询的工作...

    Flash MX 高级教程

    通过ActionScript,你可以解析XML文件,将其内容绑定到舞台上的元素,实现数据驱动的动态内容。 **网络通信** Flash MX 还允许使用ActionScript进行网络通信,如发送HTTP请求(通过XMLSocket或LoadVars对象),...

    夏普 MX-2018UC 2318UC 2618NC 3118NC 3618NC 彩色复印机维修手册

    ### 夏普彩色复印机维修手册知识点解析 #### 一、产品概要 - **产品性能**:夏普MX系列彩色复印机具有高效稳定的性能,适用于各种办公环境。 - **配置**:包括基本配置(如复印速度、分辨率等)以及选配功能(如...

    c语言网络解析程序源码

    通过阅读和学习这样的源码,我们可以了解到网络请求的基本流程,包括设置查询类型(A记录、MX记录等)、构建查询报文、发送和接收UDP数据包、解析返回的DNS应答等。 C语言网络解析程序还涉及到套接字编程。在C语言...

    DNS客户端源代码

    3. **解析响应**:DNS响应包含权威和辅助信息,源代码需要解析这些信息,提取出IP地址或其他记录数据。 4. **错误处理**:DNS查询可能遇到多种问题,如超时、重试、无效响应等。源代码会包含处理这些异常的逻辑。 ...

Global site tag (gtag.js) - Google Analytics