Exp6: DNS报文分析和基于UDP的Socket编程
[TOC]
题解请直接跳转task1,task2,task3
一、实验目的
- 学习DNS协议
- 学习使用Datagram Socket
二、实验任务
- 使用Wireshark分析DNS协议
- 使用DatagramSocket和DatagramPacket编写代码
三、实验过程
3.1 Wireshark补充
- 着色规则
数据包列表区中不同的协议使用了不同的颜色区分。协议颜色标识定位在菜单栏View —> Coloring Rules。如下所示:
Packet Details Pane(数据包详细信息)
在数据包列表中选择指定数据包,在数据包详细信息中会显示数据包的所有详细信息内容。数据包详细信息面板是最重要的,用来查看协议中的每一个字段。各行信息分别为:
1 | 1)Frame: 物理层的数据帧概况 |
3.1.1 Wireshake过滤器
- 捕获过滤器
捕获过滤器 是指wireshark⼀开始在抓包时,就确定要抓取哪些类型的包;对于不需要的,不进⾏
抓取。
- 显示过滤器
显示过滤器 是指wireshark对所有的包都进⾏抓取,当⽤户分析数据包的信息,便于筛选出需要的
数据包
捕获过滤器 是在⽤户开始任务之前就要使⽤的规则;⽽显示过滤器 是任务开始之后(⽆论是否已
完成)要使⽤的规则。
3.1.2 显示过滤器语法和实例
这⾥我们将主要介绍显示过滤器的常⽤语法和实例,捕获过滤器类似(可百度进⾏了解)。
- ⽐较操作符
1 | ==(eq) //等于,equal |
- 协议过滤
⽐较简单,直接在过滤框中直接输⼊协议名即可。 注意:协议名称需要输⼊⼩写。
1 | tcp、ip、dhcp、oicq、ftp、ssl等等 |
- 过滤IP地址
1 | ip.addr==192.168.1.104 //只显示源/⽬的IP为192.168.1.3的数据包 |
- 过滤端⼝
1 | tcp.port eq 80 //只显示源/⽬的端⼝为80的数据包 |
- 过滤协议参数
1 | tcp.flags.syn == 0x02 //显示包含syn标志位的数据包 |
tips:如图所示,在显示过滤器中输⼊规则时,会出现提示信息,可据此了解更多的协议过滤规则
- 逻辑运算符为 and/or/not
1 | 过滤多个条件组合时,使⽤and/or。 |
3.2 DNS协议
3.2.1 DNS协议简介
识别主机有两种⽅式:主机名、IP地址。前者便于记忆(如www.baidu.com),但路由器很难处理(主机名⻓度不定);后者定⻓、有层次结构,便于路由器处理,但难以记忆。折中的办法就是建⽴IP地址与主机名间的映射,这就是域名系统DNS做的⼯作。DNS通常由其他应⽤层协议使⽤(如HTTP、SMTP、FTP),将主机名解析为IP地址。
在本实验中,我们将仔细查看 DNS 报⽂的细节。
3.2.2 DNS报⽂
- 报⽂格式
DNS只有两种报⽂:查询报⽂、响应报⽂,两者有着相同格式,如下:
- 捕获的DNS报⽂
考虑访问百度⻚⾯的⼀个操作,在浏览器输⼊http://www.baidu.com/index.html并回⻋,⾸先需要将URL(存放对象的服务器主机名和对象的路径名)解析成IP地址,具体步骤为:
1 | 1)同⼀台⽤户主机上运⾏着DNS应⽤的客户机端(如浏览器) |
⽤Wireshark捕获的DNS报⽂如下图,第⼀⾏是DNS查询报⽂,第⼆⾏是DNS响应报⽂。
域名解析过程:
表示授权应答 域名解析总体可分为两大步骤:
第一个步骤是本机向本地域名服务器发出一个DNS请求报文,报文里携带需要查询的域名;第二个步骤是本地域名服务器向本机回应一个DNS响应报文,里面包含域名对应的IP地址或者别名等。
注意:第一个步骤从主机到本地域名服务器是递归查询;第二大步骤中采用的是迭代查询,其实是包含了很多小步骤的
递归查询:本机向本地域名服务器发出一次查询请求,就静待最终的结果。如果本地域名服务器无法解析,自己会以DNS客户机的身份向其它域名服务器查询,直到得到最终的IP地址告诉本机
迭代查询:本地域名服务器向根域名服务器查询,根域名服务器告诉它下一步到哪里去查询,然后它再去查,每次它都是以客户机的身份去各个服务器查询
task1:
内容: 根据Wireshark抓取的报⽂信息(例,下图所示示例),分别分析DNS查询报⽂和响应报⽂的组成结构,参考上⾯的报⽂格式指出报⽂的每个部分(如,头部区域等),请将实验结果附在实验报告中。
DNS 查询报文格式:
报文部分 | 字段名 |
---|---|
头部 | Transaction ID (事务ID) 这是DNS报文的ID标识,对于请求报文和其对应的应答报文,该字段的值是相同的。通过这个ID课题区分DNS 应答报文是对哪个请求进行相应的。 |
头部 | Flags (标志) 其中,Flags又有很多子字段,在下面详细介绍。 |
头部 | Questions(问题计数) |
头部 | Answer RRs(回答资源记录数) |
头部 | Authority RRs(权威名称能服务器计数) |
头部 | Additional RRs(附加资源记录数) |
问题部分 | Queries (查询问题区域) |
Flags 这个字段是一串二进制编码,用来标志该请求报文的一些属性和窗台。
1 | Flags: 0x0100 Standard query |
这个Flags字段里面一共有6个子字段:
- Response: 查询请求/响应的标志信息。 0代表查询请求,1代表响应请求,这里是0
- Opcode: 操作码。 0代表标准查询;1代表反响查询; 2代表服务器状态请求。
- Truncated: 表示是否被截断。 1代表响应已超过512字节并已经被截断,且只返回前面512个字节
- Recursion Desired: 期望递归。 该字段能在一个查询中设置,并在响应中返回。 该标志告诉名称服务器必须处理这个查询,这种方式被称为一个递归查询。如果该位为 0,且被请求的名称服务器没有一个授权回答,它将返回一个能解答该查询的其他名称服务器列表。这种方式被称为迭代查询。
- Z: 保留字段,在请求和响应报文中,值必须为0
- Non-authenticated data: Unacceptable:未经认证的数据;0 代表服务器已经进行了相关 DNSSEC 数字签名的验证 1 代表为服务器并未进行相关 DNSSEC 数字签名的验证
事实上,Flags字段还有其他几个子字段:
- Authoritative Answer 表示授权应答。 0代表 应答服务器不是该域名的权威解析服务器,1代表应答服务器是该域名的权威解析服务器。
- rcode返回码字段,表示响应的差错状态。不同的值代表了不同的错误。
Queries 查询问题区域:
该部分是用来显示 DNS 查询请求的问题,通常只有一个问题。该部分包含正在进行的查询信息,包含查询名(被查询主机名字)、查询类型、查询类。
比如说这是一个我查询 CSDN 时候捕捉到的DNS报文中的Queries部分:
1 | Queries //问题部分 |
注意,DNS响应报文中的 Type类型要和查询报文中的Type类型保持一致。
DNS 响应报文格式:
DNS响应报文的头部、查询问题区域结构基本和响应报文一致。并且一些查询主机的名字、查询类型等信息也需要保持一致。但是比起查询报文,响应报文多了一个资源记录部分:
资源记录部分是指 DNS 报文格式中的最后三个字段,包括Answers (回答问题区域)字段、Authoritative nameservers(权威名称服务器区域)字段、Additional records(附加信息区域)字段。这三个字段均采用一种称为资源记录的格式。
这里我分析的是访问百度新闻的 DNS 响应报文。
Answers 字段
1 | Answers |
Authoritative字段
1 | Authoritative nameservers |
在这里我们要了解一下 类型字段中 CNAME 类型和A类型的区别:
A类型即 Address,也是用来指定主机名(或域名)对应的IP地址记录。用户可以将该域名下的网站服务器指向到自己的web server上。
CNAME类型是 别名记录,也就是说,这种记录允许多个名字映射到另外一个域名。通常用于同时提供WWW和MAIL服务的计算机。例如,有一台计算机名为“host.mydomain.com”(A记录)。它同时提供WWW和MAIL服务,为了便于用户访问服务。可以为该计算机设置两个别名(CNAME):WWW和MAIL。这两个别名的全称就http://www.mydomain.com/
和mail.mydomain.com
。实际上他们都指向 host.mydomain.com
在 Authoritative 字段中的类型字段,这个报文中现实的是 SOA类型,这代表授权起始点 (SOA) 记录会提供有关域和相应托管区域的信息。此外,还有NS记录类型,会标识托管区域的名称服务器。NS 记录的值为名称服务器的域名。
3.3 基于UDP的Socket编程
3.3.1 什么是Socket
- 简单来说是⼀种地址和端⼝的结合描述协议。
- TCP/IP协议的相关API的总称、是⽹络API的集合实现,涵盖了TCP和UDP。
- UDP是⼀种⽤户报协议,⼜称为⽤户数据报⽂协议,是⼀个简单的⾯向数据报的传输层协议。
- 在本实验中,我们将重点学习基于UDP的Socket编程。
3.3.2 UDP核⼼API
- DatagramSocket
1 | ⽤于接收与发送UDP的类。 |
- DatagramPacket
⽤于报⽂处理。
将byte数组、⽬标地址、⽬标端⼝等数据包装成报⽂或者将报⽂拆卸成byte数组。
是UDP的发送实体,也是接收实体
1 | DatagramPacket(byte[] buf,int offset,int length、InetAddress address,int |
3.3.3 小试牛刀: UDP传输案例
UDP不分服务器端和客户端,这⾥为了更好地表示,采⽤了发送者和接收者的说法
task2:
内容:补充完整UDPSearcher类,并运⾏UDPProvider和UDPSearcher,请将实验结果附在实验报告中
首先, TCP是面向连接的,且为两个端系统之间的数据流动提供可靠的字节流通道。而UDP是无连接的,从一个端系统向另一个端系统发送独立的数据分组,不对交付提供任何保证。
这个小程序的功能就是接收我们的学号并返回学号的长度。我将利用多线程来分别启动 UDPProvider和UDPSearcher。
- 编写UDPProvider类
1 | package com.company; |
- 编写UDPSearcher
1 | package com.company; |
main函数
1 | package com.company; |
结果如下:
task3:
内容:改写UDPProvider和UDPSearcher以完成下述功能,请将实验结果附在实验报告中:
- ⼴播地址:255.255.255.255
- 现需完成如下场景的设计:
- UDPSearcher现将UDP包发送⾄⼴播地址的9091号端⼝(这表示该UDP包将会被⼴播⾄局域⽹下所有主机的对应端⼝)
- 如果有UDPProvider在监听,解析接受的UDP包,通过解析其中的data得到要回送的端⼝号,并将⾃⼰的⼀些信息写回,UDPSearcher接收到UDPProvider的消息后打印出来。
- 现提供发送消息的格式:
- UDPSearcher请使⽤如下buildWithPort构建消息,port在实验中指定为30000
- UDPProvider请使⽤如下parsePort解析收到的消息并得到要回写的端⼝号,然后⽤buildWithTag构建消息,tag可以是
String tag =UUID.randomUUID().toString();
,然后回送数据。
1 | public class MessageUtil { |
修改过的UDPProvider:
1 | package com.company; |
修改过的UDPSearcher:
1 | package com.company; |
结果如下: