《第13章原始套接字》由会员分享,可在线阅读,更多相关《第13章原始套接字(35页珍藏版)》请在金锄头文库上搜索。
1、第第1313章章 原始套接字原始套接字通常情况下程序设计人员接触的网络知识限于如下两类:通常情况下程序设计人员接触的网络知识限于如下两类:流式套接字(流式套接字(SOCK_STREAM),它是一种面向连接的套),它是一种面向连接的套接字,对应于接字,对应于TCP应用程序。应用程序。数据报套接字(数据报套接字(SOCK_DGRAM),它是一种无连接的套接),它是一种无连接的套接字,对应于的字,对应于的UDP应用程序。应用程序。除了以上两种基本的套接字外还有一类原始套接字,它除了以上两种基本的套接字外还有一类原始套接字,它是一种对原始网络报文进行处理的套接字。是一种对原始网络报文进行处理的套接字。
2、13.1 13.1 概述概述前面几章介绍了基础的套接字知识,流式套接字前面几章介绍了基础的套接字知识,流式套接字(SOCK_STREAM)和数据报套接字()和数据报套接字(SOCK_DGRAM)涵盖了一)涵盖了一般应用层次的般应用层次的TCP/IP应用。应用。13.2 13.2 原始套接字的创建原始套接字的创建原始套接字的创建使用与通用的套接字创建的方法是一原始套接字的创建使用与通用的套接字创建的方法是一致的,只是在套接字类型的选项上使用的是另一个致的,只是在套接字类型的选项上使用的是另一个SOCK_RAW。在使用。在使用socket函数进行函数创建完毕的时候,函数进行函数创建完毕的时候,还要
3、进行套接字数据中格式类型的指定,设置从套接字中可还要进行套接字数据中格式类型的指定,设置从套接字中可以接收到的网络数据格式。以接收到的网络数据格式。13.2.1 SOCK_RAW13.2.1 SOCK_RAW选项选项创建原始套接字使用函数创建原始套接字使用函数socket,第二个参数设置为,第二个参数设置为SOCK_RAW,函数,函数socket()可以创建一个原始套接字。下可以创建一个原始套接字。下面的代码,创建一个面的代码,创建一个AF_INET协议族中的原始套接字,协议协议族中的原始套接字,协议类型为类型为protocol。int rawsock = socket(AF_INET, SO
4、CK_RAW, protocol);13.2.2 IP_HDRINCL13.2.2 IP_HDRINCL套接字选项套接字选项使用套接字选项使用套接字选项IP_HDRINCL设置套接字,在之后进行设置套接字,在之后进行的接收和发送的时候,接收到的数据包含的接收和发送的时候,接收到的数据包含IP数据的,包含数据的,包含IP的头部。用户之后需要对的头部。用户之后需要对IP层相关的数据段进行处理,例如层相关的数据段进行处理,例如IP头部数据的设置和分析,校验和的计算等。设置方法如下:头部数据的设置和分析,校验和的计算等。设置方法如下:int set = 1;if(setsockopt(rawsock,
5、 IPPROTO_IP, IP_HDRINCL, &set, sizeof(set)0)13.2.3 13.2.3 不需要不需要bind()bind()函数函数原始套接字不需要使用原始套接字不需要使用bind()函数,因为进行发送和接函数,因为进行发送和接收数据的时候可以指定要发送和接收的目的地址的收数据的时候可以指定要发送和接收的目的地址的IP。例如。例如使用函数使用函数sendto()和函数和函数recvfrom()来发送和接收数据,来发送和接收数据,sendto()和和recvfrom()函数分别需要指定函数分别需要指定IP地址。地址。sendto (rawsock, data, dat
6、asize, 0, (struct sockaddr *) &to, sizeof (to);recvfrom(rawsock, data,size , 0,(struct sockaddr)&from, &len) ;当系统对当系统对socket进行了绑定的时候,发送和接收的函进行了绑定的时候,发送和接收的函数可以使用数可以使用send()和和recv()及及read()和和write()等不需要指定等不需要指定目的地址的函数。目的地址的函数。13.3 13.3 原始套接字发送报文原始套接字发送报文原始套接字发送报文有如下的原则:原始套接字发送报文有如下的原则:通常情况下可以使用通常情况下可
7、以使用sendto()函数并指定发送目的地址函数并指定发送目的地址发送数据,当已经发送数据,当已经bind()了目标地址的时候可以使用了目标地址的时候可以使用write()或者或者send()发送数据。发送数据。如果使用如果使用setsockopt()设置了选项设置了选项IP_RINCL,则发送,则发送的数据缓冲区指向的数据缓冲区指向IP头部第一个字节的头部,用户发送的数头部第一个字节的头部,用户发送的数据包含据包含IP头部之后的所有数据,需要用户自己填写头部之后的所有数据,需要用户自己填写IP头部和头部和计算校验和及所包含数据的处理和计算。计算校验和及所包含数据的处理和计算。如果没有设置如果
8、没有设置IP_RINCL,则发送缓冲区指向,则发送缓冲区指向IP头部后头部后面数据区域的第一个字节,不需要用户填写面数据区域的第一个字节,不需要用户填写IP头部,头部,IP头部头部的填写工作有内核进行,内核还进行校验和的计算。的填写工作有内核进行,内核还进行校验和的计算。13.4 13.4 原始套接字接收报文原始套接字接收报文接收报文还有自己的一些特点,主要有如下几个:接收报文还有自己的一些特点,主要有如下几个:对于对于ICMP的协议,绝大部分数据可以通过原始套接字的协议,绝大部分数据可以通过原始套接字获得,例如回显请求、响应,时间戳请求等。获得,例如回显请求、响应,时间戳请求等。接收的接收的
9、UDP和和TCP协议的数据不会传给任何原始套接协议的数据不会传给任何原始套接字接口,这些协议的数据需要通过数据链路层获得。字接口,这些协议的数据需要通过数据链路层获得。如果如果IP以分片形式到达,则所有分片都已经接收到并重以分片形式到达,则所有分片都已经接收到并重组后才传给原始套接字。组后才传给原始套接字。内核不能识别的协议、格式等传给原始套接字,因此,内核不能识别的协议、格式等传给原始套接字,因此,可以使用原始套接字定义用户自己的协议格式。可以使用原始套接字定义用户自己的协议格式。13.5 13.5 原始套接字报文处理时的结构原始套接字报文处理时的结构本节介绍进行报文处理时常用的数据结构,包
10、含本节介绍进行报文处理时常用的数据结构,包含IP头部、头部、ICMP头部、头部、UDP头部、头部、TCP头部。使用这些数据格式对原头部。使用这些数据格式对原始套接字进行处理,可以从底层获取高层的网络数据。始套接字进行处理,可以从底层获取高层的网络数据。13.5.1 IP13.5.1 IP头部的结构头部的结构13.5.2 ICMP13.5.2 ICMP头部结构头部结构ICMP的头部结构比较复杂,主要包含消息类型的头部结构比较复杂,主要包含消息类型icmp_type,消息代码,消息代码icmp_code、校验和、校验和icmp_cksum等,等,不同的不同的ICMP类型其他部分有不同的实现。类型其
11、他部分有不同的实现。1ICMP的头部结构的头部结构2不同类型的不同类型的ICMP请求请求13.5.3 UDP13.5.3 UDP头部结构头部结构13.5.4 TCP13.5.4 TCP头部结构头部结构TCP的头部结构主要包含发送端的源端口、接收端的目的头部结构主要包含发送端的源端口、接收端的目的端口、数据的序列号、上一个数据的确认号、滑动窗口大的端口、数据的序列号、上一个数据的确认号、滑动窗口大小、数据的校验和、紧急数据的偏移指针以及一些控制位等小、数据的校验和、紧急数据的偏移指针以及一些控制位等信息。信息。13.5.4 TCP13.5.4 TCP头部结构头部结构13.6 ping13.6 p
12、ing的例子的例子ping命令向目的主机发送命令向目的主机发送ICMP ECHO_REQUEST请请求并接收目的主机返回的响应报文,用来检验本地主机和远求并接收目的主机返回的响应报文,用来检验本地主机和远程的主机是否连接。程的主机是否连接。13.6.1 13.6.1 协议格式协议格式图图13-13中已经对中已经对ICMP协议的报文格式进行了说明。协议的报文格式进行了说明。ping的客户端方式的类型为的客户端方式的类型为8,代码值为,代码值为0,表示,表示ICMP的回的回显请求。类型为显请求。类型为0,代码为,代码为0时,是时,是ICMP回显应答。校验和回显应答。校验和为为16位的位的crc16
13、的算法。的算法。13.6.2 13.6.2 校验和函数校验和函数TCP/IP协议栈使用的校验算法是比较经典的,对协议栈使用的校验算法是比较经典的,对16位位的数据进行累加计算,并返回计算结果。需要注意的是对奇的数据进行累加计算,并返回计算结果。需要注意的是对奇数个字节数据的计算,是将最后的有效数据作为最高位的字数个字节数据的计算,是将最后的有效数据作为最高位的字节,低字节填充了节,低字节填充了0。13.6.3 13.6.3 设置设置ICMPICMP发送报文的头部发送报文的头部对于回显请求的对于回显请求的ICMP报文,报文,13.5节的节的ICMP结构可以简结构可以简化为如下的形式:化为如下的形
14、式:struct icmpu_int8_t icmp_type; u_int8_t icmp_code; u_int16_t icmp_cksum; union struct ih_idseq u_int16_t icd_id; u_int16_t icd_seq; ih_idseq; icmp_hun;#defineicmp_idicmp_hun.ih_idseq.icd_id#defineicmp_seqicmp_hun.ih_idseq.icd_seq union u_int8_t id_data1; icmp_dun;#defineicmp_dataicmp_dun.id_data;1
15、3.6.4 13.6.4 剥离剥离ICMPICMP接受报文的头部接受报文的头部函数函数icmp_unpack()用于剥离用于剥离IP头部,分析头部,分析ICMP头部头部的值。判断是否为正确的的值。判断是否为正确的ICMP报文,并打印结果。报文,并打印结果。参数参数buf为剥去了以太网部分数据的为剥去了以太网部分数据的IP数据报文,数据报文,len为为数据长度。可以利用数据长度。可以利用IP头部的参数快速的跳到头部的参数快速的跳到ICMP报文部报文部分,分,IP结构的结构的ip_hl标识标识IP头部的长度,由于头部的长度,由于ip_hl标识的是标识的是4字节单位,所以需要乘以字节单位,所以需要乘
16、以4来获得来获得ICMP段的地址。段的地址。获得获得ICMP数据段后,判断其类型是否为数据段后,判断其类型是否为ICMP_ECHOREPLY,并核实其标识是否为本进程的,并核实其标识是否为本进程的PID。由于需要判断数据报文的往返时间,在本程序中需要先查找由于需要判断数据报文的往返时间,在本程序中需要先查找这个包发送时的时间,与当前时间进行计算后,可以得出本这个包发送时的时间,与当前时间进行计算后,可以得出本地主机与目标主机之间网络地主机与目标主机之间网络ICMP回显报文的差值。回显报文的差值。13.6.5 13.6.5 计算时间差计算时间差由于需要评估网络状况,在发送数据报文的时候保存发由于
17、需要评估网络状况,在发送数据报文的时候保存发送时间,接收到报文后,计算两个时刻之间的差值,生成了送时间,接收到报文后,计算两个时刻之间的差值,生成了ICMP源主机和目标主机之间的网络状况的时间评估。源主机和目标主机之间的网络状况的时间评估。/*计算时间差计算时间差time_sub参数:参数:end,接收到的时间接收到的时间begin,开始发送的时间,开始发送的时间返回值:返回值:使用的时间使用的时间13.6.6 13.6.6 发送报文发送报文发送报文函数是一个线程,每隔发送报文函数是一个线程,每隔1秒钟向目的主机发送秒钟向目的主机发送一个一个ICMP回显请求报文,它在整个程序处于激活状态回显请
18、求报文,它在整个程序处于激活状态(alive为为1)时一直发送报文。)时一直发送报文。(1)获得当前的时间值,按照序列号)获得当前的时间值,按照序列号packet_send将将ICMP报文打包到缓冲区报文打包到缓冲区send_buff中后,发送到目的地址。中后,发送到目的地址。发送成功后,记录发送报文的状态:发送成功后,记录发送报文的状态:(2)每次发送成功后序号值会增加)每次发送成功后序号值会增加1,即,即packet_send+。(3)在线程开始进入主循环)在线程开始进入主循环while(alive)之前,将整个之前,将整个程序的开始发送时间记录下来,用于在程序退出的时候进行程序的开始发送
19、时间记录下来,用于在程序退出的时候进行全局统计,即全局统计,即gettimeofday(&tv_begin, NULL),将时间保,将时间保存在变量存在变量tv_begin中。中。13.6.7 13.6.7 接收报文接收报文与发送函数一样,接收报文也用一个线程实现,使用与发送函数一样,接收报文也用一个线程实现,使用select()轮询等待报文到来。当接收到一个报文后使用函数轮询等待报文到来。当接收到一个报文后使用函数icmp_unpack()来解包和查找报文之前发送时的记录,获取发送时间,计来解包和查找报文之前发送时的记录,获取发送时间,计算收发差值并打印信息。算收发差值并打印信息。(1)接收
20、成功后将合法的报文记录重置为没有使用,)接收成功后将合法的报文记录重置为没有使用,flag为为0。(2)接收报文数量增加)接收报文数量增加1。(3)为了防止丢包,)为了防止丢包,select()的轮询时间设置的比较短。的轮询时间设置的比较短。13.6.8 13.6.8 主函数过程主函数过程ping程序的实现使用了两个线程,一个线程程序的实现使用了两个线程,一个线程icmp_send()用于发送请求,一个线程用于发送请求,一个线程icmp_recv()用于接收远程主机用于接收远程主机的响应。当变量的响应。当变量alive为为0时,两个线程退出。时,两个线程退出。1ping数据的数据结构数据的数据
21、结构2信号信号SIGINT处理函数处理函数3查找数组中的标示函数查找数组中的标示函数icmp_findpacket()4统计数据结果函数统计数据结果函数icmp_statistics()13.6.9 13.6.9 主函数主函数main()main()建立两个线程建立两个线程icmp_send()和和icmp_recv()进行接收和进行接收和发送,然后主程序等待两个线程结束。发送,然后主程序等待两个线程结束。1主函数初始化主函数初始化2进行数据报文发送之前的准备工作进行数据报文发送之前的准备工作3发送数据并接收回应发送数据并接收回应13.6.10 13.6.10 编译测试编译测试将所有的代码保存
22、到文件将所有的代码保存到文件ping.c中,使用如下命令方式中,使用如下命令方式进行编译,生成可执行文件进行编译,生成可执行文件ping:Debain#gcc o ping ping.c -lpthread运行程序运行程序ping,对本机地址进行测试,在出现,对本机地址进行测试,在出现4个响应个响应后按后按CTRL+C键,结果如下:键,结果如下:Debian#./ping 127.0.0.1PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.64 byte from 127.0.0.1: icmp_seq=0 ttl=64 rtt=0 ms64 by
23、te from 127.0.0.1: icmp_seq=1 ttl=64 rtt=0 ms64 byte from 127.0.0.1: icmp_seq=2 ttl=64 rtt=0 ms64 byte from 127.0.0.1: icmp_seq=3 ttl=64 rtt=0 ms- 127.0.0.1 ping statistics -4 packets transmitted, 4 received, 0% packet loss, time 3642 ms13.7 13.7 洪水攻击洪水攻击洪水攻击指的是利用计算机网络技术向目标机发送大量洪水攻击指的是利用计算机网络技术向目标机发
24、送大量的无用数据报文,使得目标主机忙于处理无用的数据报文而的无用数据报文,使得目标主机忙于处理无用的数据报文而无法提供正常的服务的网络行为。无法提供正常的服务的网络行为。洪水攻击(洪水攻击(FLOOD ATTACK),顾名思义,是用大量的),顾名思义,是用大量的请求来淹没目标机。洪水攻击主要利用了网络协议的安全机请求来淹没目标机。洪水攻击主要利用了网络协议的安全机制或者直接用十分简单的拼资源的方法来对目标机造成影响。制或者直接用十分简单的拼资源的方法来对目标机造成影响。攻击的手段主要是使用畸形的报文来让目标机进行处理攻击的手段主要是使用畸形的报文来让目标机进行处理或者等待,一般都是在原始套接字
25、层进行程序设计。洪水攻或者等待,一般都是在原始套接字层进行程序设计。洪水攻击主要分为击主要分为ICMP、UDP和和SYN攻击攻击3种类型。种类型。13.8 ICMP13.8 ICMP洪水攻击洪水攻击本实例的本实例的ICMP代码是简单的直接方法,建立多个线程代码是简单的直接方法,建立多个线程向同一个主机发送向同一个主机发送ICMP请求,而本地的请求,而本地的IP地址是伪装的。地址是伪装的。由于程序仅发送响应,不接收响应,容易造成目标主机的宕由于程序仅发送响应,不接收响应,容易造成目标主机的宕机。机。13.8.1 ICMP13.8.1 ICMP洪水攻击的原理洪水攻击的原理ICMP Flood是一种
26、在是一种在ping基础上形成的,但是用基础上形成的,但是用ping程序很少能造成目标机的问题。这里边最大的问题是提高处程序很少能造成目标机的问题。这里边最大的问题是提高处理的速度。理的速度。ICMP洪水攻击主要有洪水攻击主要有3种方式。种方式。直接洪水攻击:直接洪水攻击:伪装伪装IP攻击:攻击:反射攻击:反射攻击:13.8.1 ICMP13.8.1 ICMP洪水攻击的原理洪水攻击的原理13.8.2 ICMP13.8.2 ICMP洪水攻击的例子洪水攻击的例子上面对上面对ICMP洪水攻击的基本原理进行了介绍,本小节洪水攻击的基本原理进行了介绍,本小节为一个为一个ICMP的样例代码,以下逐步介绍。的
27、样例代码,以下逐步介绍。1随机函数随机函数myrandom2多线程函数多线程函数DoS_fun()3ICMP头部打包含数头部打包含数DoS_icmp()4线程函数线程函数DoS_fun6主函数主函数13.9 UDP13.9 UDP洪水攻击洪水攻击本程序建立了一个固定的结构,将本程序建立了一个固定的结构,将IP头部和头部和UDP头部均头部均包含在内,设置完毕数据后,可以直接发送向目标机。包含在内,设置完毕数据后,可以直接发送向目标机。13.10 SYN13.10 SYN洪水攻击洪水攻击SYN洪水攻击也称为拒绝服务攻击,它利用了洪水攻击也称为拒绝服务攻击,它利用了TCP的的3次握手,利用大量的的次
28、握手,利用大量的的TCP连接请求造成目标机的资源耗尽连接请求造成目标机的资源耗尽而不能提供正常的服务或者服务质量下降。而不能提供正常的服务或者服务质量下降。13.10.1 SYN13.10.1 SYN洪水攻击的原理洪水攻击的原理一般情况下的一般情况下的TCP连接函数连接函数connect(),经历了,经历了3次握次握手,如果从手,如果从IP层协议来看,客户端先发送层协议来看,客户端先发送SYN请求,服务器请求,服务器对客户端的对客户端的SYN进行响应,而客户端对服务器的响应再次进进行响应,而客户端对服务器的响应再次进行确认后才建立了一个行确认后才建立了一个TCP的连接。在服务器发送响应后,的连
29、接。在服务器发送响应后,要等待一段时间才能获得客户端的确认,即第二次和第三次要等待一段时间才能获得客户端的确认,即第二次和第三次握手之间有一个超时时间,握手之间有一个超时时间,SYN攻击就利用了这个时机。攻击就利用了这个时机。13.10.2 SYN13.10.2 SYN洪水攻击的例子洪水攻击的例子上面对上面对TCP的的SYN进行攻击的原理进行了简单的介绍,进行攻击的原理进行了简单的介绍,下面分析一下下面分析一下SYN攻击的核心代码攻击的核心代码DoS_syn函数。函数。(1)先建立一个结构)先建立一个结构dosseg(2)填写)填写IP头部数据部分头部数据部分(3)填写完)填写完IP头部后需要
30、填写头部后需要填写TCP的头部数据的头部数据(4)最后填写发送目的地址并发送出去。)最后填写发送目的地址并发送出去。(5)头文件、一些函数定义和一些宏如下:)头文件、一些函数定义和一些宏如下:(6)以下是主函数部分,先声明一些变量)以下是主函数部分,先声明一些变量(7)获取)获取ICMP的类型:的类型:(8)判断输入的目的)判断输入的目的IP地址和目的端口:地址和目的端口:(9)设置原始套接字,并设置选项为)设置原始套接字,并设置选项为IP选项:选项:(10)建立多个线程进行协同处理,然后等待用户发送)建立多个线程进行协同处理,然后等待用户发送的的SIGINT信号,所线程退出后结束程序。信号,
31、所线程退出后结束程序。13.11 13.11 小结小结与通常的与通常的TCP和和UDP相对应,还存在一种原始套接字的相对应,还存在一种原始套接字的概念,主要用于对底层协议的控制和自定义协议的编写。原概念,主要用于对底层协议的控制和自定义协议的编写。原始套接字进行创建的时候使用始套接字进行创建的时候使用socket函数,第二个参数使用函数,第二个参数使用SOCK_RAW。介绍了一个。介绍了一个ping的例子,使用了的例子,使用了ICMP协议的协议的类型类型8,代码,代码0,设置,设置ICMP头部。本章中对头部。本章中对IP层头部、层头部、TCP头头部、部、UDP头部、头部、ICMP头部进行了简单
32、的介绍,并在实际的头部进行了简单的介绍,并在实际的程序中进行了使用。程序中进行了使用。最后介绍了网络安全中经常碰到的洪水攻击,主要介绍最后介绍了网络安全中经常碰到的洪水攻击,主要介绍了了ICMP、UDP和和TCP的的SYN攻击。洪水攻击是指对目标机攻击。洪水攻击是指对目标机发送大量的数据造成目标机运行缓慢或者不能正常响应。洪发送大量的数据造成目标机运行缓慢或者不能正常响应。洪水攻击采用的手段有直接攻击、伪装水攻击采用的手段有直接攻击、伪装IP头部、反射攻击和拒头部、反射攻击和拒绝服务的绝服务的SYN攻击。反射攻击是使用了一组服务器的攻击。反射攻击是使用了一组服务器的ICMP回回显进行的。而显进行的。而SYN攻击则利用了攻击则利用了TCP的三次握手中的第二次的三次握手中的第二次握手和第三次握手之间的超时时间,使得目标机的资源耗尽握手和第三次握手之间的超时时间,使得目标机的资源耗尽而不能正常响应服务。而不能正常响应服务。