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++ 等。
  • 可以根据需要修改程序代码,例如添加其他数据包类型支持、添加数据包过滤功能等。
  • 可以将程序代码封装为库,方便其他项目使用。

免责声明:

本程序仅供学习参考,请勿用于任何非法活动。

版权所有:

本程序代码版权归作者所有,转载请注明出处。

IP 数据包捕获和解析程序 (C++ & Java)

原文地址: https://www.cveoy.top/t/topic/d9Y4 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录