编程要求:捕获本机网卡的IP包,对捕获的IP包进行解析。要求必须输出以下字段:版本号、总长度、标志位、片偏移、协议、源地址和目的地址。

TCP/IP协议定义了一个在因特网上传输的包,称为IP数据报(IP Datagram).这是一个与硬件无关的虚拟包,由首部和数据两部分组成.首部的前一部分是固定长度,共 20 字节,是所有IP数据报必须具有的.在首部的固定部分的后面是一些可选字段,其长度是可变的。下面我们看一下IP数据包的格式:

具体的说明:

各个字段说明

版本

IP协议版本号, IPv4此字段值为4, IPv6此字段值为6

首部长度

取值范围5(0101)~15(1111), 单位为4字节,包括固定部分和可选部分, 因此首部最长为60字节, 最短为20字节(不包括选项和填充部分);

服务类型

长度为8位(由于该字段一直弃而不用, 因此不用考虑)

服务类型(TO S)(8 bit)字段包括一个3 bit的优先权子字段(取值可以从000-111所有值),4 bit的TO S子字段和1 bit未用位但必须置0

总长度

该字段长度为16位, 以字节为单位, 总长度包含IP的头部和数据部分, IP数据报最大长度为65535字节, 但是注意最大不要超过MTU的长度

标识

16位长度, 唯一标识一个数据报,可以将之当成一个计数器, 每发送一个数据包, 则该值加1, 如果数据报分片,则每个分片的标识都一样, 各个分片共享一个标识号

标志

3位标志中第一位不使用, 第二位为DF(Don`t Fragment不分片), 如果该位为1, 并且传输的数据报超过最大传输单元(MTU), 则该数据报会被丢弃, 并发送一个ICMP差错报文; 第三位MF(More Fragment更多分片),表示是否有更多的分片, 如果该位为1, 则说明后续还有分片, 最后一片MF为0

片偏移

用以指出该分段的第一个数据字节在原始数据报中的偏移位置(以8字节为单位),IP分片后每一个分组都具有自己的首部, 而且标志位相同, 但是片偏移值不同, 通过片偏移值接收端可以重新组装IP包

生存时间(TTL)

表示数据报最多可经过的路由器的数量. 取值0~255,每经过一个路由器, TTL值减1,为0时被丢弃, 并发送ICMP报文通知源主机, TTL可以避免数据报在路由器之间不断循环(Tranceroute程序的实现原理)

协议类型

指明IP层上承载的是哪个高级协议, 在分用的过程中, 协议栈知道该交给上层的哪个协议处理, 如1为ICMP, 2为IGMP, 6为TCP, 17为UDP等.

头部校验和

保证数据报头部的数据完整性,但校验不包括数据部分。这样做的目的有二:一是所有将数据封装在IP数据包中的高层协议均含有覆盖整个数据的校验和,因此IP数据报没有必要再对其所承载的数据部分进行校验。二是每经过一个路由器,IP数据报的头部要发生改变(如TTL),而数据部分不变,这样只对发生改变的头部进行校验,显然不会浪费太多的时间。为了减少计算时间,一般不用CRC校验码,而是采用更简单的网际校验和(Internet Checksum)。

选项与填充

增加首部的可变部分是为了增加IP数据报的功能, 如支持排错, 测量以及安全等, 选项长度从1到40字节不等, 取决于所选择的项目(选项为4字节整数倍,否则用0填充); 但这样就增加了每一个路由器处理数据的开销, 实际上这些选项很少被使用, 很多路由器都并不考虑IP首部的选项字段;

到这里,搞清楚IP数据包的结构体设置之后,剩下的就是基本的socket编程的模式,只不过需要设置几个选项罢了。

详细见代码,有具体的注释:

#define _CRT_SECURE_NO_WARNINGS#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <string.h>
#include <mstcpip.h>
#pragma comment(lib,"Ws2_32.lib")using namespace std;//IP首部
typedef struct tIPPackHead
{BYTE ver_hlen;      //IP协议版本和IP首部长度。高4位为版本,低4位为首部的长度(单位为4bytes)BYTE byTOS;       //服务类型WORD wPacketLen; //IP包总长度。包括首部,单位为byte。[Big endian]WORD wSequence;    //标识,一般每个IP包的序号递增。[Big endian]union{WORD Flags; //标志WORD FragOf;//分段偏移};BYTE byTTL;         //生存时间 BYTE byProtocolType; //协议类型,见PROTOCOL_TYPE定义WORD wHeadCheckSum;    //IP首部校验和[Big endian]DWORD dwIPSrc;         //源地址DWORD dwIPDes;         //目的地址BYTE Options;          //选项
} IP_HEAD;int cnt;int DecodeIP(char *buf, int len)
{int n = len;if (n >= sizeof(IP_HEAD)){IP_HEAD iphead;iphead = *(IP_HEAD*)buf;cout << "第 "<<cnt++<<" 个IP数据包信息:" << endl;cout << "协议版本:" <<(iphead.ver_hlen >> 4) << endl;cout << "首部长度:" << ((iphead.ver_hlen & 0x0F) << 2) << endl;//单位为4字节cout << "服务类型:Priority: " << (iphead.byTOS >> 5) << ",Service: " << ((iphead.byTOS >> 1) & 0x0f) << endl;cout << "IP包总长度:" << ntohs(iphead.wPacketLen) << endl; //网络字节序转为主机字节序cout << "标识:" << ntohs(iphead.wSequence) << endl;cout << "标志位:" << "DF=" << ((iphead.Flags >> 14) & 0x01) << ",MF=" << ((iphead.Flags >> 13) & 0x01) << endl;cout << "片偏移:" << (iphead.FragOf & 0x1fff) << endl;cout << "生存周期:" << (int)iphead.byTTL << endl;cout << "协议类型:" << int(iphead.byProtocolType) << endl;cout << "首部校验和:" << ntohs(iphead.wHeadCheckSum) << endl;cout << "源地址:" << inet_ntoa(*(in_addr*)&iphead.dwIPSrc) << endl;cout << "目的地址:" << inet_ntoa(*(in_addr*)&iphead.dwIPDes) << endl;cout << "==============================================================" << endl << endl;}return 0;
}
void AutoWSACleanup()
{::WSACleanup();
}
int main()
{int n;WSADATA wd;n = WSAStartup(MAKEWORD(2, 2), &wd);if (n){cout << "WSAStartup函数错误!" << endl;return -1;}atexit(AutoWSACleanup);//创建SOCKETSOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);if (sock == INVALID_SOCKET){cout << WSAGetLastError();return 0;}//获取本机地址char  name[128];if (-1 == gethostname(name, sizeof(name))){closesocket(sock);cout << WSAGetLastError();return 0;}struct hostent * pHostent;pHostent = gethostbyname(name);//绑定本地地址到SOCKET句柄sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr = *(in_addr*)pHostent->h_addr_list[0]; //IPaddr.sin_port = 8888; //端口,IP层端口可随意填if (SOCKET_ERROR == bind(sock, (sockaddr *)&addr, sizeof(addr))){closesocket(sock);cout << WSAGetLastError();return 0;}//设置该SOCKET为接收所有流经绑定的IP的网卡的所有数据,包括接收和发送的数据包u_long sioarg = 1;DWORD wt = 0;if (SOCKET_ERROR == WSAIoctl(sock, SIO_RCVALL, &sioarg, sizeof(sioarg), NULL, 0, &wt, NULL, NULL)){closesocket(sock);cout << WSAGetLastError();return 0;}//我们只需要接收数据,因此设置为阻塞IO,使用最简单的IO模型u_long bioarg = 0;if (SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &bioarg)){closesocket(sock);cout << WSAGetLastError();return 0;}//开始接收数据//因为前面已经设置为阻塞IO,recv在接收到数据前不会返回。cnt = 1;char buf[65535];int len = 0;do{len = recv(sock, buf, sizeof(buf), 0);if (len > 0){DecodeIP(buf, len);}} while (len > 0);closesocket(sock);return 0;
}

最后,由于本程序是需要特权用户权限的,所以我们找到debug下的exe程序,右键以管理员权限运行即可。

结果截图:

C++ 捕获本机网卡的IP包并对其解析的实现相关推荐

  1. 使用Sniffer截获流经本机网卡的IP数据包

    Win2K下的Sniffer工具源代码 详细信息 < 局域网 > Win2K下的Sniffer源代码. [代码性质] VC完整应用程序代码 [代码作者] zw [文件大小] 130K [更 ...

  2. 以原始套接字的方式 截获流经本机网卡的IP数据包

    从事网络安全的技术人员和相当一部分准黑客(指那些使用现成的黑客软件进行攻击而不是根据需要去自己编写代码的人)都一定不会对网络嗅探器(sniffer)感到陌生,网络嗅探器无论是在网络安全还是在黑客攻击方 ...

  3. Teardrop攻击——发送虚假IP包信息

    Teardrop攻击--发送虚假IP包信息 一.原始套接字概述 二.Teardrop攻击原理阐述 三.编写Teardrop程序(伪造一个虚假地址的IP包) 四.参考链接 一.原始套接字概述 原始套接字 ...

  4. 多个ip对应的是同一个mac_Python3+Scapy安装使用 + 查询本机对应网卡,IP,MAC代码...

    安装 直接使用pip安装 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple scapy 一些扩展功能,可选: pip install -i ...

  5. 查看docker与宿主机网卡的对应关系,tcpdump在容器外网络抓包

    通过iflink找到网卡对应关系 1. 在宿主机上执行命令ip link $ ip link ...... 13: veth56ecf40@if12: <BROADCAST,MULTICAST, ...

  6. QQWRY应用:ASP.NET捕获客户机IP和物理地址

    应用场景:像QQ那样动态捕获客户机IP以及地址 (1)主要实现类: using System; using System.IO; using System.Collections; using Sys ...

  7. 信息安全技术—实验四:Ip包监视程序实现

    一.实验目的及要求 学生在熟悉网络数据通信原理以及TCP/IP协议结构原理的基础上,运用套接字编程实现的网络封包监视技术,有效地探测在网络上传输的数据包信息,通过对这些信息的分析利用是有助于网络安全维 ...

  8. ip 包流量分析程序_【干货】西门子S7300六大流量异常场景检测

    前言 互联与共享成为工业控制系统新的发展方向,工控系统与企业办公网和互联网逐渐相连,工业控制网络环境越来越开放. 工业控制系统需从设备安全和信息数据安全两方面保障系统稳定运行: 从 ICS 自身结构看 ...

  9. Neutron 理解(5):Neutron 是如何向 Nova 虚机分配固定IP地址的

    Neutron 理解 (1): Neutron 所实现的虚拟化网络 Neutron 理解 (2): 使用 Open vSwitch + VLAN 组网 Neutron 理解 (3): Open vSw ...

最新文章

  1. 怎么设置tomcat管理员的用户名和密码
  2. GitHub Universe 2021|MS Reactor 邀你共聚年度盛会
  3. 分组分页连接查询子查询9202-0422
  4. 【C语言】创建一个函数,并调用比较三个数的大小
  5. Flutter 动态饼状图 让你的APP中无聊的统计图动起来 挻舒适的感觉瞬间提升一个档次 -深夜创作
  6. cocos2dx阴影层的实现
  7. H5 下载文件到本地
  8. ISTP概况及网络版检索方法
  9. unity 画球面_Unity实现球面行走
  10. linux中获取日志5分钟以内的内容
  11. 【微信小程序】全局数据共享
  12. 直流电机,传递函数,模糊控制pid算法,matlab代码
  13. 【三十天精通 Vue 3】 专栏内容介绍
  14. python 魔兽世界升级脚本_How to use Python to automatically modify WoW toc file version
  15. 模块的included()
  16. 16、Python小案例
  17. RT-thread之RTC时间的获取
  18. svn使用问题:SVNlicense到期问题设置SVN提交代码时必须填写日志
  19. 高科路由器有虚拟服务器设置吗,高科路由器怎么设置无线中继
  20. python爬去淘宝客订单_如何采集阿里妈妈后台的淘客订单

热门文章

  1. 分子对接教程 | (8) PyMOL可视化对接结果
  2. 利用python做微信聊天记录词云分析——记录美好回忆
  3. LabVIEW控制Arduino采集光敏电阻数值(基础篇—14)
  4. ThinkPad X270 升级固态硬盘(M2 2242 NVMe)
  5. 5、ByteBuffer(基础使用)
  6. vue range 双向滚动 取中间值
  7. TortoiseGit - git小乌龟可视化管理Gitee和本地代码仓库
  8. 主成分分析法PCA(一):算法原理
  9. 在Ubuntu中运行.exe程序
  10. 关于安阳工学院ACM实验室纳新问题解答