用C++抓取网络数据包--嗅探器的设计原理

来源:互联网 发布:公务员工龄的算法 编辑:程序博客网 时间:2024/05/22 03:01
嗅探器作为一种网络通讯程序,也是通过对网卡的编程来实现网络通讯的,对网卡的编程也是使用通常的套接字(socket)方式来进行。但是,通常的套接字程序只能响应与自己硬件地址相匹配的或是以广播形式发出的数据帧,对于其他形式的数据帧比如已到达网络接口但却不是发给此地址的数据帧,网络接口在验证投递地址并非自身地址之后将不引起响应,也就是说应用程序无法收取到达的数据包。而网络嗅探器的目的恰恰在于从网卡接收所有经过它的数据包,这些数据包即可以是发给它的也可以是发往别处的。显然,要达到此目的就不能再让网卡按通常的正常模式工作,而必须将其设置为混杂模式。
具体到编程实现上,这种对网卡混杂模式的设置是通过原始套接字(raw socket)来实现的,这也有别于通常经常使用的数据流套接字和数据报套接字。在创建了原始套接字后,需要通过setsockopt()函数来设置IP头操作选项,然后再通过bind()函数将原始套接字绑定到本地网卡。为了让原始套接字能接受所有的数据,还需要通过ioctlsocket()来进行设置,而且还可以指定是否亲自处理IP头。至此,实际就可以开始对网络数据包进行嗅探了,对数据包的获取仍象流式套接字或数据报套接字那样通过recv()函数来完成。但是与其他两种套接字不同的是,原始套接字此时捕获到的数据包并不仅仅是单纯的数据信息,而是包含有 IP头、 TCP头等信息头的最原始的数据信息,这些信息保留了它在网络传输时的原貌。通过对这些在低层传输的原始信息的分析可以得到有关网络的一些信息。由于这些数据经过了网络层和传输层的打包,因此需要根据其附加的帧头对数据包进行分析。下面先给出结构.数据包的总体结构:
数据包
IP头 TCP头(或其他信息头) 数据

数据在从应用层到达传输层时,将添加TCP数据段头,或是UDP数据段头。其中UDP数据段头比较简单,由一个8字节的头和数据部分组成,具体格式如下:
16位 16位
源端口 目的端口
UDP长度 UDP校验和

而TCP数据头则比较复杂,以20个固定字节开始,在固定头后面还可以有一些长度不固定的可选项,下面给出TCP数据段头的格式组成:
16位 16位
源端口 目的端口
顺序号
确认号
TCP头长 (保留)7位 URG ACK PSH RST SYN FIN 窗口大小
校验和 紧急指针
可选项(0或更多的32位字)
数据(可选项)

对于此TCP数据段头的分析在编程实现中可通过数据结构_TCP来定义:
[cpp] view plain copy
  1. typedef struct _TCP{ WORD SrcPort; // 源端口  
  2. WORD DstPort; // 目的端口  
  3. DWORD SeqNum; // 顺序号  
  4. DWORD AckNum; // 确认号  
  5. BYTE DataOff; // TCP头长  
  6. BYTE Flags; // 标志(URG、ACK等)  
  7. WORD Window; // 窗口大小  
  8. WORD Chksum; // 校验和  
  9. WORD UrgPtr; // 紧急指针  
  10. } TCP;  
  11. typedef TCP *LPTCP;  
  12. typedef TCP UNALIGNED * ULPTCP;  



在网络层,还要给TCP数据包添加一个IP数据段头以组成IP数据报。IP数据头以大端点机次序传送,从左到右,版本字段的高位字节先传输(SPARC是大端点机;Pentium是小端点机)。如果是小端点机,就要在发送和接收时先行转换然后才能进行传输。IP数据段头格式如下:
16位 16位
版本 IHL 服务类型 总长
标识 标志 分段偏移
生命期 协议 头校验和
源地址
目的地址
选项(0或更多)

同样,在实际编程中也需要通过一个数据结构来表示此IP数据段头,下面给出此数据结构的定义:
[cpp] view plain copy
  1. typedef struct _IP{  
  2. unionBYTE Version; // 版本  
  3. BYTE HdrLen; // IHL  
  4. };  
  5. BYTE ServiceType; // 服务类型  
  6. WORD TotalLen; // 总长  
  7. WORD ID; // 标识  
  8. unionWORD Flags; // 标志  
  9. WORD FragOff; // 分段偏移  
  10. };  
  11. BYTE TimeToLive; // 生命期  
  12. BYTE Protocol; // 协议  
  13. WORD HdrChksum; // 头校验和  
  14. DWORD SrcAddr; // 源地址  
  15. DWORD DstAddr; // 目的地址  
  16. BYTE Options; // 选项  
  17. } IP;   
  18. typedef IP * LPIP;  
  19. typedef IP UNALIGNED * ULPIP;  



在明确了以上几个数据段头的组成结构后,就可以对捕获到的数据包进行分析了。
0 0
原创粉丝点击