IP 数据包捕获和解析程序 (C++ & Java)
C++ 版本
#include <stdio.h>
#include <iostream.h>
#include <Winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, 'Ws2_32.lib')
#define BUFFER_SIZE 65535
#define IO_RCVALL _WSAIOW(IOC_VENDOR, 1)
typedef struct _IP_HEADER //定义IP头
{
union
{
BYTE Version; //版本(前4位)
BYTE HdrLen; //报头标长(后4位),IP头长度
};
BYTE ServiceType; //服务类型
WORD TotalLen; //数据报总长
WORD ID; //标识
union
{
WORD Flags; //标识(前3位)
WORD FragOff; //分段偏移(后13位)
};
BYTE TimeToLive; //生存周期
BYTE Protocol; //协议
WORD HdrChksum; //头校验和
DWORD SrcAddr; //源地址
DWORD DstAddr; //目地地址
BYTE Options; //选项
} IP_HEADER;
char * parseServiceType_getProcedence(BYTE b)
{
switch(b>>5) //获取服务类型字段中优先级子域
{
case 7:
return 'Network Control'; //网络控制
break;
case 6:
return 'Internet work Control'; //网络控制
break;
case 5:
return 'CRITIC/ECP';
break;
case 4:
return 'Flash Override'; //最优先信号
break;
case 3:
return 'Flsah';
break;
case 2:
return 'Immediate';
break;
case 1:
return 'Priority'; //协议
break;
case 0:
return 'Routine'; //路由
break;
default:
return 'Unknow';
break;
}
}
char * parseServiceType_getTOS(BYTE b)
{
b=(b>>1)&0x0f; //获取服务类型字段中的TOS子域
switch(b)
{
case 0:
return 'Normal service'; //正常运行
break;
case 1:
return 'Minimize monetary cost'; //成本
break;
case 2:
return 'Maximize reliability'; //可靠性
break;
case 4:
return 'Maximize throughput'; //吞吐量
break;
case 8:
return 'Minimize delay'; //延迟
break;
case 15:
return 'Maximize security'; //安全性
break;
default:
return 'Unknow';
}
}
char * getProtocol(BYTE Protocol) //获取协议字段共8位
{
switch(Protocol) //以下为协议号说明:
{
case 1:
return 'ICMP'; //Internet控制报文协议
case 2:
return 'IGMP'; //Internet组管理协议
case 4:
return 'IP in IP'; //移动IP数据封装和隧道
case 6:
return 'TCP'; //传输控制协议
case 8:
return 'EGP'; //外部网关协议
case 17:
return 'UDP'; //用户数据报文协议
case 41:
return 'IPv6';
case 46:
return 'RSVP'; //资源预留协议
case 89:
return 'OSPF'; //Open Shortest Path First 开发式最短路径优先
default:
return 'UNKNOW';
}
}
void ipparse(FILE* file,char* buffer)
{
IP_HEADER ip=(IP_HEADER)buffer; //通过指针把缓冲区的内容强制转化为IP_HEADER数据结构
fseek(file,0,SEEK_END);
fprintf(file, '版本号=%d\r\n',ip.Version>>4);
fprintf(file, '报头标长= %d (BYTE)\r\n',((ip.HdrLen & 0x0f)4));
fprintf(file, '服务器类型 = %s,%s\r\n',parseServiceType_getProcedence(ip.ServiceType),
parseServiceType_getTOS(ip.ServiceType));
fprintf(file, '总长度 = %d(BYTE)\r\n',ip.TotalLen);
fprintf(file, '标识 = %d\r\n',ip.ID);
fprintf(file, '标志位 DF=%d , MF=%d\r\n',((ip.Flags>>14)&0x01),((ip.Flags>>13)&0x01));
fprintf(file, '分段偏移值 = %d\r\n',(ip.FragOff&0x1fff));
fprintf(file, '生存期 = %d (hops)\r\n',ip.TimeToLive);
fprintf(file, '协议 = %s\r\n',getProtocol(ip.Protocol));
fprintf(file, '头校验和 = 0x%0x\r\n',ip.HdrChksum);
fprintf(file, '源IP地址 = %s\r\n',inet_ntoa((in_addr*)&ip.SrcAddr));
fprintf(file, '目的IP地址 = %s\r\n',inet_ntoa((in_addr)&ip.DstAddr));
fprintf(file, '---------------------------------------------\r\n');
}
int main()
{
FILE * file;
if((file=fopen('history.txt', 'wb+'))==NULL)
{
printf('fail to open file %s');
return -1;
}
WORD rv;
WSADATA WSAData; //定义了能够储存WSAStarup调用返回值的结构
rv=MAKEWORD(2,2); //Winsock2版本
WSAStartup(rv,&WSAData);
SOCKET sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP); //创建套接字,sock为套接字描述符
BOOL flag=true;
setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(CHAR*)&flag,sizeof(flag));//任意类型、任意状态套接口的设置选项值
char hostName[128];
gethostname(hostName,100); //获取主机名
hostent * pHostIP; //获取本地IP地址
pHostIP = gethostbyname(hostName);
sockaddr_in addr_in;
addr_in.sin_addr=*(in_addr *)pHostIP->h_addr_list[0];
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(6000); //将无符号短整型主机数据转换为网络字节顺序数据
bind(sock,(PSOCKADDR)&addr_in,sizeof(addr_in));
DWORD dwBufferLen[10]; //设置网卡为混杂模式
DWORD dwBufferInLen=1;
DWORD dwBytesReturned=0;
WSAIoctl(sock, IO_RCVALL,&dwBufferInLen,sizeof(dwBufferInLen),
&dwBufferLen,sizeof(dwBufferLen),&dwBytesReturned,NULL,NULL);
char buffer[BUFFER_SIZE]; //设置缓冲区
char i,a;
int n=0,c;
printf('数据包捕捉和解析程序正在启动\n');
for(a=1;a<=10;a++)
{
printf('…');
Sleep(300);
}
printf('\n\n确定要接收并解析本机的数据包吗? Y/N \n');
scanf('%c',&i);
printf('\n\n需要一次抓取几个数据包\n');
scanf('%d',&c);
system('cls');
while(true&&i=='Y'||i=='y')
{
if(n==-1){printf('\n\n需要一次抓取几个数据包\n');
scanf('%d',&c);n=0;}
int size=recv(sock,buffer,BUFFER_SIZE,0); //接收数据包
if (size>0)
{
printf('\n\n数据包捕获解析程序\n');
printf('---------------------------------------------\n');
ipparse(stdout,buffer);
ipparse(file,buffer);
n++;
if(n<c) {continue;}
else n=-1;
printf('是否要继续接收并解析本机的数据包? Y/N \n');
fflush(stdin);
scanf('%c',&i);
continue;
}
else
fclose(file);
return 0;
}
closesocket(sock);
}
Java 版本
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.jnetpcap.Pcap;
import org.jnetpcap.PcapIf;
import org.jnetpcap.packet.JPacket;
import org.jnetpcap.packet.JPacketHandler;
import org.jnetpcap.protocol.network.Ip4;
public class PacketCapture {
private static final int PACKET_COUNT = 10;
private static final int SNAPLEN = 65536;
private static final int TIMEOUT = 10;
private static final String FILENAME = 'history.txt';
public static void main(String[] args) {
Pcap pcap;
StringBuilder errbuf = new StringBuilder();
PcapIf device = null;
// Get available devices
PcapIf[] devices = new PcapIf[100];
int r = Pcap.findAllDevs(devices, errbuf);
if (r == Pcap.NOT_OK || devices.length == 0) {
System.err.printf('Can't read list of devices, error is %s', errbuf.toString());
return;
}
// Select device
System.out.println('Available devices:');
for (int i = 0; i < devices.length; i++) {
System.out.printf('%d. %s\n', i + 1, devices[i].getDescription());
}
System.out.println('Select device to capture packets:');
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
device = devices[choice - 1];
System.out.println('Selected device: ' + device.getDescription());
// Open device for capture
try {
pcap = Pcap.openLive(device.getName(), SNAPLEN, Pcap.MODE_PROMISCUOUS, TIMEOUT, errbuf);
} catch (SocketException e) {
System.err.println('Error opening device: ' + e.getMessage());
return;
}
// Set filter
String filter = 'ip';
PcapBpfProgram filterProgram = new PcapBpfProgram();
int optimize = 1;
int netmask = 0xFFFFFF00;
if (pcap.compile(filterProgram, filter, optimize, netmask) != Pcap.OK) {
System.err.println(pcap.getErr());
return;
}
if (pcap.setFilter(filterProgram) != Pcap.OK) {
System.err.println(pcap.getErr());
return;
}
// Create executor service for packet processing
ExecutorService executor = Executors.newSingleThreadExecutor();
// Create packet handler
JPacketHandler<String> packetHandler = new JPacketHandler<String>() {
private int count = 0;
private FileOutputStream fileOutputStream;
@Override
public void nextPacket(JPacket packet, String user) {
// Process packet
Ip4 ip = new Ip4();
if (packet.hasHeader(ip)) {
// Parse IP header
byte[] ipHeader = ip.getByteArray(0, ip.size());
IpHeader ipObj = parseIpHeader(ipHeader);
// Save to file
try {
fileOutputStream.write(ipHeader);
fileOutputStream.write(System.lineSeparator().getBytes());
} catch (IOException e) {
System.err.println('Error writing to file: ' + e.getMessage());
}
// Print to console
printIpHeader(ipObj);
count++;
if (count >= PACKET_COUNT) {
pcap.breakloop();
}
}
}
private IpHeader parseIpHeader(byte[] ipHeader) {
IpHeader ipObj = new IpHeader();
ipObj.version = (byte) ((ipHeader[0] & 0xFF) >>> 4);
ipObj.hdrLen = (byte) (ipHeader[0] & 0x0F);
ipObj.serviceType = ipHeader[1];
ipObj.totalLen = (short) ((ipHeader[2] << 8) | (ipHeader[3] & 0xFF));
ipObj.id = (short) ((ipHeader[4] << 8) | (ipHeader[5] & 0xFF));
ipObj.flags = (short) ((ipHeader[6] << 8) | (ipHeader[7] & 0xFF));
ipObj.fragOff = (short) ((ipHeader[7] << 8) | (ipHeader[8] & 0xFF));
ipObj.timeToLive = ipHeader[8];
ipObj.protocol = ipHeader[9];
ipObj.hdrChecksum = (short) ((ipHeader[10] << 8) | (ipHeader[11] & 0xFF));
ipObj.srcAddr = InetAddress.getByAddress(new byte[] { ipHeader[12], ipHeader[13], ipHeader[14], ipHeader[15] }).getHostAddress();
ipObj.dstAddr = InetAddress.getByAddress(new byte[] { ipHeader[16], ipHeader[17], ipHeader[18], ipHeader[19] }).getHostAddress();
return ipObj;
}
private void printIpHeader(IpHeader ipObj) {
System.out.println('版本号=' + ipObj.version);
System.out.println('报头标长=' + (ipObj.hdrLen * 4) + ' (BYTE)');
System.out.println('服务器类型=' + parseServiceType_getProcedence(ipObj.serviceType) + ',' + parseServiceType_getTOS(ipObj.serviceType));
System.out.println('总长度=' + ipObj.totalLen + ' (BYTE)');
System.out.println('标识=' + ipObj.id);
System.out.println('标志位 DF=' + ((ipObj.flags >>> 14) & 0x01) + ', MF=' + ((ipObj.flags >>> 13) & 0x01));
System.out.println('分段偏移值=' + (ipObj.fragOff & 0x1FFF));
System.out.println('生存期=' + ipObj.timeToLive + ' (hops)');
System.out.println('协议=' + getProtocol(ipObj.protocol));
System.out.println('头校验和=0x' + Integer.toHexString(ipObj.hdrChecksum));
System.out.println('源IP地址=' + ipObj.srcAddr);
System.out.println('目的IP地址=' + ipObj.dstAddr);
System.out.println('---------------------------------------------');
}
private String parseServiceType_getProcedence(byte b) {
switch (b >>> 5) {
case 7:
return 'Network Control';
case 6:
return 'Internet Work Control';
case 5:
return 'CRITIC/ECP';
case 4:
return 'Flash Override';
case 3:
return 'Flsah';
case 2:
return 'Immediate';
case 1:
return 'Priority';
case 0:
return 'Routine';
default:
return 'Unknown';
}
}
private String parseServiceType_getTOS(byte b) {
b = (byte) ((b >>> 1) & 0x0F);
switch (b) {
case 0:
return 'Normal service';
case 1:
return 'Minimize monetary cost';
case 2:
return 'Maximize reliability';
case 4:
return 'Maximize throughput';
case 8:
return 'Minimize delay';
case 15:
return 'Maximize security';
default:
return 'Unknown';
}
}
private String getProtocol(byte protocol) {
switch (protocol) {
case 1:
return 'ICMP';
case 2:
return 'IGMP';
case 4:
return 'IP in IP';
case 6:
return 'TCP';
case 8:
return 'EGP';
case 17:
return 'UDP';
case 41:
return 'IPv6';
case 46:
return 'RSVP';
case 89:
return 'OSPF';
default:
return 'Unknown';
}
}
};
// Create file output stream
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(FILENAME);
} catch (IOException e) {
System.err.println('Error creating file output stream: ' + e.getMessage());
return;
}
// Set file output stream for the handler
packetHandler.fileOutputStream = fileOutputStream;
// Start capture
try {
pcap.loop(PACKET_COUNT, packetHandler, '');
} catch (SocketTimeoutException e) {
System.err.println('Timeout reached');
}
// Close file output stream
try {
fileOutputStream.close();
} catch (IOException e) {
System.err.println('Error closing file output stream: ' + e.getMessage());
}
// Close pcap handler
pcap.close();
// Shutdown executor service
executor.shutdown();
// Close scanner
scanner.close();
}
private static class IpHeader {
public byte version;
public byte hdrLen;
public byte serviceType;
public short totalLen;
public short id;
public short flags;
public short fragOff;
public byte timeToLive;
public byte protocol;
public short hdrChecksum;
public String srcAddr;
public String dstAddr;
}
}
总结
本程序演示了如何使用 C++ 和 Java 捕获和解析 IP 数据包。 C++ 版本使用 Winsock 库,Java 版本使用 jNetPcap 库。两种版本都能够解析 IP 头信息,并将其保存到文件中。
注意:
- 为了运行 C++ 版本,需要安装 Winsock 库。
- 为了运行 Java 版本,需要安装 jNetPcap 库。
- 为了捕获数据包,需要将网卡设置为混杂模式。
- 为了解析数据包,需要了解 IP 头的结构。
相关资源:
建议:
- 可以使用其他库进行数据包捕获和解析,例如 libpcap、PCAP++ 等。
- 可以根据需要修改程序代码,例如添加其他数据包类型支持、添加数据包过滤功能等。
- 可以将程序代码封装为库,方便其他项目使用。
免责声明:
本程序仅供学习参考,请勿用于任何非法活动。
版权所有:
本程序代码版权归作者所有,转载请注明出处。
原文地址: https://www.cveoy.top/t/topic/d9Y4 著作权归作者所有。请勿转载和采集!