DNS是全称是Domain Name Server,既域名服务器。域名系统(DNS)是一种用于TCP/IP应用程序的分布式数据库,它提供主机名字和IP地址之间的转换信息。通常,网络用户通过UDP协议和DNS服务器进行通信,而服务器在特定的53端口监听,并返回用户所需的相关信息。
其工作过程如下:1.DNS客户以特定标识向本地的DNS服务器发送解析请求:查询数据报。这个名字请求是从客户的某个随机选择的端口到服务器的绑定端口53。2.如果该DNS缓存有客户需要的数据,则以相应的ID号直接返回域名响应数据报给客户;若无则与其他的DNS联系获得数据,再返回给客户。3.如找不到则返回失败的异常信息。4.客户端会将收到的DNS响应数据报的ID和自己发送的查询数据报ID相比较,如果匹配则表明接收到的正是自己等待的数据报,如果不匹配则丢弃之。
我们来看DNS协议的相关数据结构。
DNS数据报:
typedef struct dns
{
unsigned short id;
//标识,通过它客户端可以将DNS的请求与应答相匹配;
unsigned short flags;
//标志:[QR | opcode | AA| TC| RD| RA | zero | rcode ]
unsigned short quests;
//问题数目;
unsigned short answers;
//资源记录数目;
unsigned short author;
//授权资源记录数目;
unsigned short addition;
//额外资源记录数目;
}DNS,*PDNS;
在16位的标志中:QR位判断是查询/响应报文,opcode区别查询类型,AA判断是否为授权回答,TC判断是否可截断,RD判断是否期望递归查询,RA判断是否为可用递归,zero必须为0,rcode为返回码字段。
DNS查询数据报:
typedef struct query
{
unsinged char *name;
//查询的域名,这是一个大小在0到63之间的字符串;
unsigned short type;
//查询类型,大约有20个不同的类型
unsigned short classes;
//查询类,通常是A类既查询IP地址。
}QUERY,*PQUERY;
DNS响应数据报:
typedef struct response
{
unsigned short name;
//查询的域名
unsigned short type;
//查询类型
unsigned short classes;
//类型码
unsigned int ttl;
//生存时间
unsigned short length;
//资源数据长度
unsigned int addr;
//资源数据
}RESPONSE,*PRESPONSE;
在DNS查询包可以看到一个重要的域叫做标识ID。用来鉴别每个DNS数据包的印记,从客户端设置。由服务器返回,它可以让客户匹配请求与响应。当DNS服务器发出查询包时,它会在包内设置标识ID,只有应答包中的ID值和IP地址都正确的时候才能为服务器所接受。这个ID每次自动增加1,所以可以先向要欺骗的DNS服务器发一个查询包并监听到该ID值,随后再发一个查询包,紧接着马上发送我们构造好的应答包,包内的标识ID为预测的值。这就是所谓的DNS欺骗。
我们可以调用函数 gethostbyname()来看DNS 是如何工作的。(Linux 平台 gcc 编译)#include <netdb.h>
struct hostent *gethostbyname(const char *name);
它传递一个保存机器名的字符串(例如 "whitehouse.gov") 给 gethostbyname(),然后从返回的数据结构 struct hostent 中获取信息。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
struct hostent *h;
if (argc != 2) { /* 检查命令行 */
fprintf(stderr,"usage: getip address\n");
exit(1);
}
if ((h=gethostbyname(argv[1])) == NULL) { /* 取得地址信息 */
herror("gethostbyname");
exit(1);
}
printf("Host name : %s\n", h->h_name);
printf("IP Address : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr)));
return 0;
}
这里是这个数据结构的详细资料:
struct hostent { char *h_name; //地址的正式名称。
char **h_aliases; //空字节-地址的预备名称的指针
int h_addrtype; //地址类型; 通常是AF_INET
int h_length; //地址的比特长度
char **h_addr_list; //零字节-主机网络地址指针。网络字节顺序
};
#define h_addr h_addr_list[0] //h_addr_list中的第一地址
在.NET Framework 类库中,Dns 类提供简单的域名解析功能
它是一个静态类,从 Internet 域名系统 (DNS) 检索关于特定主机的信息。
IPHostEntry 类为 Internet 主机地址信息提供容器类。作为 Helper 类和 Dns 类一起使用。IPHostEntry 类将一个域名系统 (DNS) 主机名与一组别名和一组匹配的 IP 地址关联。在 IPHostEntry 类的实例中返回来自 DNS 查询的主机信息。如果指定的主机在 DNS 数据库中有多个入口,则 IPHostEntry 包含多个 IP 地址和别名。构造函数示例:IPHostEntry hostInfo = Dns.GetHostByName("www.csdn.net");
IPAddress 类包含计算机在 IP 网络上的地址。
提供网际协议 (IP) 地址。
DnsPermission,用于允许使用 Dns。控制对网络上域名系统 (DNS) 服务器的访问权限认权限允许所有的本地和 Intranet 区域的应用程序访问 DNS 服务,并且 Internet 区域的应用程序没有 DNS 权限
如DnsPermission permission = new DnsPermission(PermissionState.Unrestricted);
如果 state 为 Unrestricted,则 DnsPermission 实例允许所有请求。如果 state 包含任何其他值,则 DnsPermission 实例禁止所有请求。
以下是一个实现IP地址批扫描的程序:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.IO;
namespace IPsacn
{
/// <summary>
/// Form1 的摘要说明。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
internal System.Windows.Forms.Button btnScan;
internal System.Windows.Forms.NumericUpDown Num5;
internal System.Windows.Forms.NumericUpDown Num4;
internal System.Windows.Forms.NumericUpDown Num3;
internal System.Windows.Forms.NumericUpDown Num2;
internal System.Windows.Forms.NumericUpDown Num1;
internal System.Windows.Forms.RichTextBox RichTextBox1;
internal System.Windows.Forms.ProgressBar ProgressBar1;
public static string IpAddressString;
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.btnScan = new System.Windows.Forms.Button();
this.Num5 = new System.Windows.Forms.NumericUpDown();
this.Num4 = new System.Windows.Forms.NumericUpDown();
this.Num3 = new System.Windows.Forms.NumericUpDown();
this.Num2 = new System.Windows.Forms.NumericUpDown();
this.Num1 = new System.Windows.Forms.NumericUpDown();
this.RichTextBox1 = new System.Windows.Forms.RichTextBox();
this.ProgressBar1 = new System.Windows.Forms.ProgressBar();
((System.ComponentModel.ISupportInitialize)(this.Num5)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.Num4)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.Num3)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.Num2)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.Num1)).BeginInit();
this.SuspendLayout();
//
// btnScan
//
this.btnScan.Location = new System.Drawing.Point(32, 40);
this.btnScan.Name = "btnScan";
this.btnScan.TabIndex = 11;
this.btnScan.Text = "Scan";
this.btnScan.Click += new System.EventHandler(this.btnScan_Click);
//
// Num5
//
this.Num5.Location = new System.Drawing.Point(144, 40);
this.Num5.Maximum = new System.Decimal(new int[] {
255,
0,
0,
0});
this.Num5.Name = "Num5";
this.Num5.Size = new System.Drawing.Size(48, 21);
this.Num5.TabIndex = 10;
this.Num5.Value = new System.Decimal(new int[] {
3,
0,
0,
0});
//
// Num4
//
this.Num4.Location = new System.Drawing.Point(144, 8);
this.Num4.Maximum = new System.Decimal(new int[] {
255,
0,
0,
0});
this.Num4.Name = "Num4";
this.Num4.Size = new System.Drawing.Size(48, 21);
this.Num4.TabIndex = 9;
this.Num4.Value = new System.Decimal(new int[] {
1,
0,
0,
0});
//
// Num3
//
this.Num3.Location = new System.Drawing.Point(96, 8);
this.Num3.Maximum = new System.Decimal(new int[] {
255,
0,
0,
0});
this.Num3.Name = "Num3";
this.Num3.Size = new System.Drawing.Size(48, 21);
this.Num3.TabIndex = 8;
//
// Num2
//
this.Num2.Location = new System.Drawing.Point(48, 8);
this.Num2.Maximum = new System.Decimal(new int[] {
255,
0,
0,
0});
this.Num2.Name = "Num2";
this.Num2.Size = new System.Drawing.Size(48, 21);
this.Num2.TabIndex = 7;
this.Num2.Value = new System.Decimal(new int[] {
168,
0,
0,
0});
//
// Num1
//
this.Num1.Location = new System.Drawing.Point(0, 8);
this.Num1.Maximum = new System.Decimal(new int[] {
255,
0,
0,
0});
this.Num1.Name = "Num1";
this.Num1.Size = new System.Drawing.Size(48, 21);
this.Num1.TabIndex = 6;
this.Num1.Value = new System.Decimal(new int[] {
192,
0,
0,
0});
//
// RichTextBox1
//
this.RichTextBox1.Location = new System.Drawing.Point(0, 80);
this.RichTextBox1.Name = "RichTextBox1";
this.RichTextBox1.Size = new System.Drawing.Size(392, 216);
this.RichTextBox1.TabIndex = 12;
this.RichTextBox1.Text = "";
//
// ProgressBar1
//
this.ProgressBar1.Location = new System.Drawing.Point(0, 304);
this.ProgressBar1.Name = "ProgressBar1";
this.ProgressBar1.Size = new System.Drawing.Size(392, 23);
this.ProgressBar1.TabIndex = 13;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(392, 325);
this.Controls.Add(this.ProgressBar1);
this.Controls.Add(this.RichTextBox1);
this.Controls.Add(this.btnScan);
this.Controls.Add(this.Num5);
this.Controls.Add(this.Num4);
this.Controls.Add(this.Num3);
this.Controls.Add(this.Num2);
this.Controls.Add(this.Num1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.Num5)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.Num4)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.Num3)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.Num2)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.Num1)).EndInit();
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void btnScan_Click(object sender, System.EventArgs e)
{
string aa=Num1.Text+"."+Num2.Text+"."+Num3.Text+".";
int i =Int32.Parse(Num4.Text); //转化为整型
int j=Int32.Parse(Num5.Text); //转化为整型
ProgressBar1.Minimum=i;
ProgressBar1.Maximum=j;
for(i=i;i<=j;i++)
{
string IpAddressString=aa+i.ToString();
IPAddress hostIPAddress=IPAddress.Parse(IpAddressString);//将 IP 地址字符串转换为 IPAddress 实例。
try
{
//Call the GetHostByAddress(IPAddress) method, passing an IPAddress object as an argument
// to obtain an IPHostEntry instance, containing address information for the specified host.
IPHostEntry hostInfo=Dns.GetHostByAddress(hostIPAddress);
string hostName=hostInfo.HostName.ToString();
RichTextBox1.AppendText(IpAddressString+"-->"+hostName);
RichTextBox1.AppendText("\nAliases :");
// Get the IP address list that resolves to the host names contained in
// the Alias property.
for(int index=0; index < hostInfo.Aliases.Length; index++)
{
RichTextBox1.AppendText(hostInfo.Aliases[index]);
}
RichTextBox1.AppendText("\nIP address list : ");
// Get the alias names of the addresses in the IP address list.
for(int index=0; index < hostInfo.AddressList.Length; index++)
{
RichTextBox1.AppendText(hostInfo.AddressList[index].ToString()+"\r");
}
}
catch(Exception ee){RichTextBox1.AppendText(IpAddressString+"-->"+ ee.Message +"\r");}
ProgressBar1.Value=i;
}
}
}
}
为简单起见程序只使用了单线程,故若扫描多个IP地址,易使程序陷入假死状态。