熟悉原始套接字编程.docx
- 文档编号:11553475
- 上传时间:2023-03-19
- 格式:DOCX
- 页数:31
- 大小:176.91KB
熟悉原始套接字编程.docx
《熟悉原始套接字编程.docx》由会员分享,可在线阅读,更多相关《熟悉原始套接字编程.docx(31页珍藏版)》请在冰豆网上搜索。
熟悉原始套接字编程
1.熟悉原始套接字编程
2.了解网络的结构
3.了解网络传输底层协议
本实验中,程序记录并显示了数据报从源端机器传送到目标机器的过程中所经过的路由器的IP地址,但是没有记录数据报到达每个路由器所需要的时间。
请完善本程序,打印出数据报到达每个路由器所需要的时间。
用类似的方法,写出模仿MS-Dos的Ping.exe程序。
在创建套接字的时候可以使用函数:
socket(intaf,inttype,intprotocol)。
其中type为SOCK_STREAM或SOCK_DAGRAM;protocol一般取0,表示默认TCP/IP协议。
Winsock2中除了现有的地址簇,套接字类型和协议标识外,还添加了一些地址簇,套接字类型和协议标识。
可以通过创建原始套接字来访问控制底层传输协议,比如ICMP协议,IGMP协议。
在本实验中,我们将使用ICMP协议来模拟tracert程序,也就是跟踪数据报在网络中传输时所经过的路由器。
图4-1.实验效果图
一.准备知识
1.路由器简介
什么是路由?
所谓路由就是指通过相互连接的网络把信息从源地点移动到目标地点的活动。
而路由器则是进行这种活动所必不可少的网络设备。
一般通过路由器连接不同的网络。
路由器工作在网络层,主要工作就是为经过路由器的每个数据帧寻找一条最佳传输路径。
事实上网络之间存在着许多许多的路由器,这些路由器都有自己的IP地址。
一台
主机的报文发送到另外一台主机,可能要经过一组路由器,而且很多时候,可能存在着很多组路由器可供选择,路由器通过一种特殊的算法,选择一条最优的通路。
2.IP数据报
IP(InternetProtocol)是一种具有不可靠,无连接交付机制的协议,是TCP/IP互联网设计中最基本的部分。
IP数据报分为首部和数据区,首部分为固定部分和可变部分。
数据区
首部
图4-2.IP数据报
如图4-3所示:
IP数据报的首部包含了IP的版本、首部长度、服务类型、协议、源地址和目的地址以及一些其他首部信息,而数据区则存放了要发送的具体内容。
32位
0
4
8
1631
版本
首部长度
服务类型
总长度
标识
标志
片偏移量
寿命
协议
首部校验和
源站IP地址
目的站IP地址
长度可变的任选字段
填充
数据……
图4-3.IP报文首部格式
IP数据报首部的固定部分中的各字段:
版本:
占4bit,指评协议的版本。
通信双方使用的IP协议的版本必须一致。
目前使用的IP协议版本为4。
以前的3个版本目前已不使用。
长度:
占4bit(IPv4),以32位为一个单位。
最小值是5,最大值是16。
也就是说IP首部最大只有60字节,而最小为20字节。
通常的IP报文首部不带选项,所以一般为20字节。
当IP分组的首部长度不是4字节的整数倍时,必须利用最后一个填充字段加以填充。
这样,数据部分永远在4字节的整数倍时开始,这样在实现起来会比较方便。
首部长度限制为60字节的缺点是有时(如采用源站选路时)不够用。
但这样做的用意是要用户尽量减少额外开销。
服务类型
:
占8bit,用来获得更好的服务。
服务类型字段的前三个比特表示优先级,它可使数据报具有8个优先级中的一个。
第4个比特是D比特,表示要求有更低的时延。
第5个比特是T比特,表示要求有更高的吞吐量。
第6个比特是R比特,表示要求有更高的可靠性,即在数据报传送的过程中,被结点交换机丢弃的概率要更小些。
第7个比特是C比特,是新增加的,表示要求选择费用更低廉的路由。
最后一个比特目前尚未使用。
总长度:
总长度指首部和数据之和的长度,单位为字节。
总长度字段为16bit.因此数据报的最大长度为65535字节。
这在当前是够用的。
当很长的数据报要分片进行传送时,“总长度”不是指未分片前的数据报长度,而是指分片后每片的首部长度与数据长度的总和。
标识:
标识字段是为了使分片后的各数据报片最后能准确地重装成为原来的数据报。
请注意:
这里的“标识”并没有顺序号的意思,因为IP是无连接服务,数据报不存在按序接收的问题。
标志:
占3bit。
目前只有前两个比特有意义。
标志字段中的最低位记为MF。
MF=l即表示后面还有分片的数据报。
MF=0表示这已是若干数据报片中的最后一个。
标志字段中间的一位记为DF。
只有当DF=0时才允许分片。
片偏移:
片偏移指出:
较长的分组在分片后,某个片在原分组中的相对位置。
也就是说,相对于用户数据字段的起点,该片从何处开始。
片偏移以8个字节为偏移单位。
寿命:
寿命字段记为TTL,其单位为秒。
寿命的建议值是32秒。
但也可设定为3。
4秒,或甚至255秒。
寿命又称为生存时间。
协议:
占8bit,协议字段指出此数据报携带的运输层数据是使用何种协议,以便目的主机的IP层知道应将此数据报上交给哪个进程。
常用的一些协议和相应的协议字段值(写在协议后面的括弧中)是:
UDP(17),TCP(6),ICMP
(1),GGP(3),EGP(8),IGMP
(2),IGP(9),OSPF(89),以及ISO的第4类运输协议TP4(29)。
这些协议的数据报都是通过封装在IP数据报内部发送的。
图4给出了TCP/IP的协议结构:
应用程序
ICMP
IGMP
UDP
TCP
RARP
IP
ARP
以太网驱动程序
图4-4.协议结构
首部检验和:
此字段只检验数据报的首部,不包括数据部分。
不检验数据部分是因为数据报每经过一个结点,结点处理机就要重新计算——下首部检验和(一些字段,如寿命、标志、片偏移等都可能发生变化)。
如将数据部分一起检验,计算的工作量就太大了。
为了简化运算,检验和不采用CRC检验码。
IP检验和的计算方法是:
将IP数据报首部看成为16bit字的序列c先将检验和字段置零。
将所有的16bit字相加后,将和的二进制反码写入检验和字段。
收到数据报后,将首部的16bit字的序列再相加——次,若首部未发生任何变化,则和必为全1。
否则即认为出差错,并将此数据报丢弃。
地址:
源站IP地址字段和目的站IP地址字段都各占4字节。
IP首部的可变部分
IP首部的可变部分就是一个选项字段。
选项字段用来支持排错、测量以及安全等措施,内容很丰富。
此字段的长度可变,从1个字节到40个字节不等,取决于所选择的项目。
某些选项项目只需要1个字节,它只包括1个字节的选项代码,图4-5画的是选项代码的格式。
还有些选项需要多个字节,但其第1个字节的格式仍为图4-5所示的那样。
图4-5一个字节的选项代码的格式
这些选项——个个拼接起来,中间不需要有分隔符,最后用全0的填充字段补齐成为4字节的整数倍。
选项代码共有三个字段。
第一个字段是复制字段,占1bit,它的作用是控制网络中的路由器在将数据报进行分片时所作的选择。
当复制字段为1时,必须将此选项字段复制到每一个数据报片。
而当复制字段为0时,就只复制到第1个数据报片上。
第二个字段是选项类别字段,占2bit.但目前只有两类可供选用。
当类别为0时,用作数据报或网络控制(主要是这类)。
当类别为2时,用作排错和测量,即Internet时间戳。
第三个字段是选项编号,占5bit,它指出选项是做什么用的。
属于选项类别0的有下列一些选项编号:
1.选项编号为0:
指出这是选项中的最后一个。
2.选项编号为1:
无操作,用于需要按每4个字节对齐之用。
和填充字段的功能是一样的。
以上两种都是只使用1个字节的选项代码。
下面的几种则要使用若干个字节。
1.选项编号为2:
为安全用的。
只用在美国国防系统来传送机密文件。
路由器在检测到这一安全选项时,就要使该数据报不要离开安全的环境。
在商业上尚无此应用。
2.选项编号为7:
为记录路由用的,其长度可变。
图4-6是记录路由的选项的格式。
0
8
16
24
任选代码
长度
指针
第1个IP地址
第2个IP地址
……
图4–6记录路由的选项的格式
这种数据报是用来监视和控制互连网中的路由器是如何转发数据报的。
源站发出一个空白的表,让数据报所经过的各路由填上其IP地址,以获得路由信息。
前3个字节是:
1.选项代码字段其中的3个字段分别填入0,0和7。
2.长度字段填入此选项的长度,包括这前3个字节。
3.指针字段指出下一个可填入IP地址的空白位置的偏移量。
在这之后,就是若干个4字节长的IP地址,让各个路由器填入。
当一个路由器收到包含有记录路由选项的数据报时,先检查指针所指的位置是否超过了表的长度。
如不超过,则填入自己的IP地址,并将指针值加4,然后转发出去。
但如表已填满,则不填入自己的IP地址,而仅仅转发此数据报。
一般的计算机在收到这样的数据报时,并不会理睬该数据报中所记录的路由。
因此,源站必须和有关目的站主机协商好,请目的主机在收到记录的路由信息后,将路由信息提取出来,并发回源站。
关于源站选路的两个选项。
1.选项编号为3:
不严格的源站选路,其长度是可变的。
2.选项编号为9:
严格的源站选路,其长度也是可变的。
源站选路本来是源站将数据报传送的路由事先规定好。
严格的源站选路不允许改变源站规定好的路由。
不严格的源站选路允许在数据报传送的过程中,将路由表中源站已规定要经过的一些路由器,改换成别的路由器。
源站选路选项的格式
与图4-6记录路由的相似。
前面也是3个固定的字节。
但选项代码字节中的3个字段应分别填入
1,0和3(不严格的源站选路)以及
l,0和9(严格的源站选路)。
此外,这3个字节后面的IP地址表不是空的,而是事先由源站写好的。
数据报按源站指定的路由传送。
当路由器收到此数据报后,若指针已超过表的范围,则转发此数据报,不写任何数据。
若指针的指示是正确的,则填入自己的IP地址(覆盖掉原来的IP地址),并按照表中指出的下一个地址转发出去。
这里要注意:
一个路由器有两个或两个以上的IP地址。
原来在这个选项路由表中写入的是路由器的入口IP地址,而路由器写的IP地址则是路由器的出口IP地址。
在数据报中加入源站选路选项,可以使网络的管理者了解沿网络中的某一条通路的通信状况是否正常。
一般的用户并不使用这一功能。
最后一个选项是Internet的时间戳。
3.选项编号为4:
作时间戳用,其长度是可变的。
格式和图4–6类似,但一开始除了原来的选项代码字段(填入0,2和4)、长度字段和指针字段这3个字节外,再加上溢出字段和标志字段(各为1个字节)。
标志字段区分几种情况:
1.只写入时间戳;
2.写入IP地址和时间戳;
3.IP地址由源站规定好,路由器只写入时间戳。
溢出字段写入一个数,此数值即数据报所经过的路由器的最大数目(考虑到太多的时问戳可能会写不下)。
时间戳记录了路由器收到数据报的日期和时间,占用4个字节。
时间的单位是毫秒,是从午夜算起的通用时间,也就是以前称作的格林尼治时间。
当网络中的主机的本地时间和时钟不一致时,记录的时间戳会有一些误差。
时间戳可用来统计数据报经路由器产生的时延和时延的变化。
这里给出不带选项的IP报文首部的数据结构:
//IP首部数据结构
structIPHEADER
{unsignedinth_len:
4;//首部长度
unsignedintversion:
4;//版本
unsignedchartos;//服务类型
unsignedshorttotal_len;//报文总长度
unsignedshortident;//标识
unsignedshortfrag_and_flags;//偏移量
unsignedcharttl;//寿命
unsignedcharproto;//协议
unsignedshortchecksum;//首部校验和
unsignedintsourceIP;//源站IP
unsignedintdestIP;//目的站IP
};
3.什么是ICMP
ICMP(InternetControlMessageProtocal)是为了让互联网中的路由器报告错误或提供有关意外情况的信息而设计的一个特殊报文机制。
它是IP协议的附属协议,是封装在IP数据报内部传送的,如图4-7所示:
IP数据报
ICMP报文
IP首部
图4-7.ICMP封装在IP数据报内部
ICMP的报文格式如图4–8所示:
ICMP类型(8位)
ICMP代码(8位)
ICMP校验和(16位)
ICMP报文具体内容(不同类型不同代码有不同内容)
图4-8.ICMP报文格式
尽管每个ICMP报文都有自己的格式,但它们开始的三个字段都是一样的:
一个8位的报文类型(type)用来标识报文,一个8位的代码(code)用来提供有关类型的进一步信息,一个16位的校验和(checksum)。
(ICMP采用和IP相同的校验和算法,但ICMP校验和只覆盖ICMP报文)
这里我们给出ICMP报文首部的数据结构:
//ICMP首部数据结构
structICMPHEADER
{
BYTEi_type;//类型
BYTEi_code;//代码
USHORTi_cksum;//首部校验和
USHORTi_id;//标识
USHORTi_seq;//序列号
ULONGtimestamp;//时间戳(选用)
};
表4-1表示了ICMP的报文类型及其含义:
Type
Code
类别
含义
0
0
查询
回送应答
3
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
差错
差错
差错
差错
差错
差错
差错
差错
差错
差错
差错
差错
差错
差错
差错
差错
网络不可抵达
主机不可抵达
协议不可抵达
端口不可抵达
需要重新分片但设置了不分片比特
源路由失败
目的网络未知
目的主机未知
源主机被隔离
目的网络被禁止
目的主机被禁止
对所请求的服务类型,网络不可达
对所请求的服务类型,主机不可达
由于过滤,通信被禁止
主机越权
优先级失效
4
0
差错
源端被关闭
5
0
1
2
3
差错
差错
差错
差错
对网络重定向
对主机重定向
对服务类型和网络重定向
对服务类型和主机重定向
8
0
查询
请求回显
9
0
查询
路由器通告
10
0
查询
陆由器请求
11
0
1
差错
差错
传输期间数据报超时
数据报组装期间超时
12
0
1
差错
差错
IP报头损坏
缺少必要的选项
13
0
查询
时间戳请求
14
0
查询
时间戳回复
15
0
查询
信息请求(已过时)
16
0
查询
信息回复(已过时)
17
0
查询
地址掩码请求
18
0
查询
地址掩码回复
表4-1ICMP报文类型
下面给出几种常用的ICMP报文格式
回显请求和应答报文格式:
通常用来判断目的主机是否可以通过网络访问到。
类型(8或0)
代码(0)
校验和
标识符
序号
可选项
时间戳请求与应答:
网络上的主机一般是独立的,每台机器都有自己的当前时间。
时间戳请求与应答用来查询目的主机系统当前的时间。
返回值是自午夜开始到现在的毫秒数,通过这个数值来协调时间的统一。
事实上因为延时,这个值是不准确的,通常采取多次测量求平均值的办法。
类型(13或14)
代码(0)
校验和
标识符
序号
发起时间戳
接收时间戳
传送时间戳
路由器通告:
当主机自举以后必须至少知道本地网络上的一个路由器的地址才能够向其它网络发送报文。
ICMP支持路由发现方案(RouterDiscovery),允许主机发现一个路由器地址。
类型(9)
代码(0)
校验和
地址号
地址大小
(1)
寿命
路由器地址1
优先级1
路由器地址2
优先级2
…
地址掩码请求与应答:
主机可以通过向路由器发送一个地址掩码请求,并且接收发回的地址掩码应答报文来获得本地网络所使用的子网掩码。
可以直接发送请求,但如果不知道路由器的地址,也可以采用广播的方式来发送报文。
类型(17或18)
代码(0)
校验和
标识符
序号
地址掩码
二.创建原始套接字
原始套接字(RawSocket)可以让我们对底层的传输协议加以控制。
我们可以用socket()或WSASocket()来创建。
在创建原始套接字的时候我们可以选用ICMP协议、UDP协议、IGMP协议、IP或原始IP。
它们的标志分别是IPPROTO_ICMP、IPPROTO_UDP、IPPROTO_IGMP、IPPROTO_IP和IPPROTO_RAW。
这里我们给出ICMP协议的原始套接字的创建例子:
//原始套接字的创建
SOCKETs;
s=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,
WSA_FLAG_OVERLAPPED);
//或者
s=socket(AF_INET,SOCK_RAW,IPROTO_ICMP);
if(s==INVALID_SOCKET)
{
//创建失败
}
需要注意的是由于原始套接字可以对底层的协议加以控制,所以在WindowsNT中必须以管理员身份(Administrator)或者拥有同等权限的用户身份登陆才可以创建原始套接字。
三.路由器跟踪的原理
记录数据报所经过的路由器可以有很多办法。
可以通过设置IP数据报首部的记录路由器选项来记录数据报发送过程中所经过的路由器,但是这样的方法有很大的局限性。
前面已经提到IP数据报首部的最大长度不超过60字节,去掉必要的首部格式,剩下的空间只能够存放最多9个路由器地址。
这本来是为ARPANET设计的,但是对现在的网络来讲9个地址空间已经远远不能满足要求。
我们必须采取别的方法。
IP数据首部中有一项为寿命(TTLtimetolive),它规定了数据报在网络中“存活”的时间。
每当数据报经过一个节点的时候,寿命就减1,当寿命为0的时候该报文就被丢弃。
同时向源主机发送一个超时的ICMP报文。
这是为了防止迷失的报文在网络上“游荡”而设计的。
我们可以通过向目的主机发送寿命递增的ICMP报文,让沿途的路由器顺次的发回超时报文,收集这些报文并且提取了地址以后就可以知道报文发送途中所经过的路由器的地址。
也可以向目的主机发送寿命递增的UDP报文,本实验中我们向目的主机发送ECHO请求的ICMP报文。
原理是同样的。
图4–9表示了这个算法:
…….
timeout
timeout
timeout
D
S
R2
R5
R3
R1
R4
图4-9算法示意图
S——源端主机D——目的主机Rn——途径的第n个路由器
当数据报到达目的主机以后,目的主机会发回一个ECHO回应,这时跟踪就完成了。
1.建MFC(exe)工程,名字为TraceRoute。
应用程序类型选择基于对话框,然后完成。
注意不要选“支持windowssocket”.
2.按图1添加和布置相应的控件。
给控件对应的ID和属性:
ID
类型
属性
IDC_STATIC
StaticText
标题:
“目的地址:
”
IDC_EDIT_ADDRESS
EditBox
IDC_STATIC
GroupBox
标题:
“跟踪结果:
”
IDC_BUTTON_TRACE
Button
标题:
“&Trace”
设置默认按钮
IDC_STATIC_SHOW
StaticText
设置staticedge
给控件添加相应的变量
ID
变量名
类型
IDC_EDIT_ADDRESS
m_strAddress
CString
IDC_STATIC_SHOW
m_strResult
CString
3.ClassView当中右键点击TraceRouteclasses,选择Newclass.在Newclass中Classtype选择GenericClass,Name填写CTracer,选择确定。
4.添加头文件和定义宏
//Tracer.h
#include"winsock2.h"
#include"ws2tcpip.h"
//必要的宏定义
#defineDEF_PACKET_SIZE32
#defineMAX_PACKET1024
#defineMAX_NOTES30
#defineICMP_MIN8
#defineICMP_ECHOREPLY0
#defineICMP_DESTUNREACH3
#defineICMP_SRCQUENCH4
#defineICMP_REDIRECT5
#defineICMP_ECHO8
#defineICMP_TIMEOUT11
#defineICMP_PARMERR12
5.为CTracer添加变量
//Tracer.h
private:
CDialog*m_pWnd;//指向主窗口的指针
char*icmpData;//指向发送报文内存空间的指针
char*icmpRcvBuf;//指向报文接收缓冲空间的指针
intm_nSeq;//报文序列号
SOCKETm_hSocket;//套接字句柄
SOCKADDR_INm_addrDest;//目的主机地址
SOCKADDR_INm_addrFrom;//存放路由地址
6.
为CTracer添加成员函数
1.构造函数:
在构造函数中完成成员变量的初始化,完成socket的初始化。
CTracer:
:
CTracer()
{
m_nSeq=1;
icmpData=NULL;
icmpRcvBuf=NULL;
m_hSocket=INVALID_SOCKET;
//初始化socket
WSADATAwsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData)!
=0)
{
AfxMessageBox("WSAStartup()出错!
");
}
}
2.析构函数:
在析构函数中关闭socket.
CTracer:
:
~CTracer()
{
//关闭Socket
if(m_hSocket!
=NULL)
closesocket(m_hSocket);
WSACleanup();
}
3.添加private函数CheckSum,返回型为USHORT。
用来计算校验和。
IP校验和的计算是把首部看成一个16
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 熟悉 原始 套接 编程