日期:2011-11-25  浏览次数:20463 次

一、前言
  foxmail新版中有一个《邮件特快专递》的功能。起先搞不懂如何用,后来知道要在 工具->系统选项 那边设置 本地DNS服务器的IP地址。
  觉得这个新功能蛮好用的。不需要通过SMTP代理,可以直接通过本地往邮箱所在的邮件交换器发送邮件。在暑假一开始想在VC++中实现这个功能。用IRIS截包后,发现程序后mx8.263.net发送邮箱,不知道这个是什么东西所以作罢。   后来才想到这个就是263.net的MX记录主机,原来特快专递的原理就是往这个主机上发送数据就行。
  运行nslookup程序:
  set type=mx
  263.net
  有了,有了,得到结果:
  Non-authoritative answer:
  263.net MX preference = 10, mail exchanger = mx06.263.net
  263.net MX preference = 10, mail exchanger = mx08.263.net
  263.net MX preference = 10, mail exchanger = mx09.263.net
  263.net MX preference = 10, mail exchanger = mx11.263.net
  263.net MX preference = 10, mail exchanger = mx12.263.net
  263.net MX preference = 40, mail exchanger = mx03.263.net
  263.net MX preference = 10, mail exchanger = mx01.263.net
  没有错了。就是这个了。后来因为不知道怎么实现nslookup的功能,就放弃了,学了半个多月的C#。后来偶然在网上查找到了一些相关的文档。几次实验。把我的开发过程拿过来分享,我第一次写教程性文档。所以不规范之处,请大家包涵。本文涉及的域名、邮箱及IP均为真实的。

二、DNS协议原理
  我认为,要想成为一个好的网络软件程序员,必须得读懂RFC文档。因为本文是面向大多广泛程序爱好者,所以我尽量从细节上写,如果高手的话,可以跳过此部分。
  DNS协议的相关RFC文档:
  RFC1034-《DOMAIN NAMES - CONCEPTS AND FACILITIES》
  RFC1035-《DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION》
  网上的计算机用形如 220.162.75.1 这样称为IP地址的数字串来标识一台计算机。而如果每次访问一台计算机都是通过输入这样的东东来访问,那不就太可怕了?以是出了DNS这样的好东东,用要指示其绑定的IP地址,当我们在浏览器内输入 http://zzsy.com 时,浏览器不知道网页该到哪里取,于是就向设定好的DNS服务器查询zzsy.com这个域名。DNS服务器会先寻找自己的记录库,如果没有发现就转向上一级DNS服务器进行查询(转发请求)。把找到后的IP告知你的浏览器。这里边浏览器查询的记录类型是A记录。RFC1035文档第11页中定义有16种记录类型,而常见的有A(地址)记录、CNAME(别名)记录、MX(邮件交换)记录。我们本篇要关心的是MX记录。
  查询的过程一般是:客户向DNS服务器的53端口发送UDP报文,DNS服务器收到后进行处理,并把结果记录仍以UDP报文的形式返回过来。
  此UDP报文的一般格式:

+---------------------+
| 报文头 |
+---------------------+
| 问题  | 向服务器提出的查询部分
+---------------------+
| 回答  | 服务器回复的资源记录
+---------------------+
| 授权 | 权威的资源记录
+---------------------+
| 格外的 | 格外的资源记录
+---------------------+

  除了报文头是固定的12字节外,其他每一部分的长度均为不定字节数。
  我们在这边关心的是报文头、问题、回答这三个部分。

  其中报文头的格式:


1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

  好家伙,是什么鬼画符!
  其中最上边是位的数字标识,0-15(注意,后边的10-15写成上下的形式了,一开始我楞没看懂)。
  接下来是:
  ID:占16位,2个字节。此报文的编号,由客户端指定。DNS回复时带上此标识,以指示处理的对应请应请求。
  QR:占1位,1/8字节。0代表查询,1代表DNS回复
  Opcode:占4位,1/2字节。指示查询种类:0:标准查询;1:反向查询;2:服务器状态查询;3-15:未使用。
  AA:占1位,1/8字节。是否权威回复。
  TC:占1位,1/8字节。因为一个UDP报文为512字节,所以该位指示是否截掉超过的部分。
  RD:占1位,1/8字节。此位在查询中指定,回复时相同。设置为1指示服务器进行递归查询。
  RA:占1位,1/8字节。由DNS回复返回指定,说明DNS服务器是否支持递归查询。
  Z:占3位,3/8字节。保留字段,必须设置为0。
  RCODE:占4位,1/2字节。由回复时指定的返回码:0:无差错;1:格式错;2:DNS出错;3:域名不存在;4:DNS不支持这类查询;5:DNS拒绝查询;6-15:保留字段。 
  QDCOUNT:占16位,2字节。一个无符号数指示查询记录的个数。
  ANCOUNT:占16位,2字节。一个无符号数指明回复记录的个数。
  NSCOUNT:占16位,2字节。一个无符号数指明权威记录的个数。
  ARCOUNT:占16位,2字节。一个无符号数指明格外记录的个数。

  其中每个查询的资源记录格式:


1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |