我编写了一个简单的源文件,可以使用 C 中的 libpcap 库读取 pcap 文件。我可以逐个解析数据包并分析它们。我希望能够推断出我解析的 TCP 数据包是否是 TCP 重传。在网上广泛搜索后,我得出结论,为此,我需要跟踪流量行为,这意味着还要分析以前收到的数据包。
我真正想要实现的是,在基本层面上,tcp.analysis.retransmission
过滤器在wireshark中所做的事情。
这是一个读取 pcap 文件并分析通过 IPv4 发送的 TCP 数据包的 MRE。该函数find_retransmissions
是分析数据包的地方。
#include <pcap.h>
#include <stdio.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <net/ethernet.h>
#include <string.h>
void process_packet(u_char *,const struct pcap_pkthdr * , const u_char *);
void find_retransmissions(const u_char * , int );
int main()
{
pcap_t *handle;
char errbuff[PCAP_ERRBUF_SIZE];
handle = pcap_open_offline("smallFlows.pcap", errbuff);
pcap_loop(handle, -1, process_packet, NULL);
}
void process_packet(u_char *args,
const struct pcap_pkthdr * header,
const u_char *buffer)
{
int size = header->len;
struct ethhdr *eth = (struct ethhdr *)buffer;
if(eth->h_proto == 8) //Check if IPv4
{
struct iphdr *iph = (struct iphdr*)(buffer +sizeof(struct ethhdr));
if(iph->protocol == 6) //Check if TCP
{
find_retransmissions(buffer,size);
}
}
}
void find_retransmissions(const u_char * Buffer, int Size)
{
static struct iphdr previous_packets[20000];
static struct tcphdr previous_tcp[20000];
static int index = 0;
static int retransmissions = 0;
int retransmission = 0;
struct sockaddr_in source,dest;
unsigned short iphdrlen;
// IP header
struct iphdr *iph = (struct iphdr *)(Buffer + sizeof(struct ethhdr));
previous_packets[index] = *iph;
iphdrlen =iph->ihl*4;
memset(&source, 0, sizeof(source));
source.sin_addr.s_addr = iph->saddr;
memset(&dest, 0, sizeof(dest));
dest.sin_addr.s_addr = iph->daddr;
// TCP header
struct tcphdr *tcph=(struct tcphdr*)(Buffer
+ iphdrlen
+ sizeof(struct ethhdr));
previous_tcp[index]=*tcph;
index++;
int header_size = sizeof(struct ethhdr) + iphdrlen + tcph->doff*4;
unsigned int segmentlength;
segmentlength = Size - header_size;
/* First check if a same TCP packet has been received */
for(int i=0;i<index-1;i++)
{
// Check if packet has been resent
unsigned short temphdrlen;
temphdrlen = previous_packets[i].ihl*4;
// First check IP header
if ((previous_packets[i].saddr == iph->saddr) // Same source IP address
&& (previous_packets[i].daddr == iph->daddr) // Same destination Ip address
&& (previous_packets[i].protocol == iph->protocol) //Same protocol
&& (temphdrlen == iphdrlen)) // Same header length
{
// Then check TCP header
if((previous_tcp[i].source == tcph->source) // Same source port
&& (previous_tcp[i].dest == tcph->dest) // Same destination port
&& (previous_tcp[i].th_seq == tcph->th_seq) // Same sequence number
&& (previous_tcp[i].th_ack==tcph->th_ack) // Same acknowledge number
&& (previous_tcp[i].th_win == tcph->th_win) // Same window
&& (previous_tcp[i].th_flags == tcph->th_flags) // Same flags
&& (tcph->syn==1 || tcph->fin==1 ||segmentlength>0)) // Check if SYN or FIN are
{ // set or if tcp.segment 0
// At this point the packets are almost identical
// Now Check previous communication to check for retransmission
for(int z=index-1;z>=0;z--)
{
// Find packets going to the reverse direction
if ((previous_packets[z].daddr == iph->saddr) // Swapped IP source addresses
&& (previous_packets[z].saddr ==iph->daddr) // Same for IP dest addreses
&& (previous_packets[z].protocol == iph->protocol)) // Same protocol
{
if((previous_tcp[z].dest==tcph->source) // Swapped ports
&& (previous_tcp[z].source==tcph->dest)
&& (previous_tcp[z].th_seq-1 != tcph->th_ack) // Not Keepalive
&& (tcph->syn==1 // Either SYN is set
|| tcph->fin==1 // Either FIN is set
|| (segmentlength>0)) // Either segmentlength >0
&& (previous_tcp[z].th_seq>tcph->th_seq) // Next sequence number is
// bigger than the expected
&& (previous_tcp[z].ack != 1)) // Last seen ACK is set
{
retransmission = 1;
retransmissions++;
break;
}
}
}
}
}
}
if (retransmission == 1)
{
printf("Retransmission: True\n");
printf("\n\n******************IPv4 TCP Packet*************************\n");
printf(" |-IP Version : %d\n",(unsigned int)iph->version);
printf(" |-Source IP : %s\n" , inet_ntoa(source.sin_addr) );
printf(" |-Destination IP : %s\n" , inet_ntoa(dest.sin_addr) );
printf(" |-Source Port : %u\n", ntohs(tcph->source));
printf(" |-Destination Port : %u\n", ntohs(tcph->dest));
printf(" |-Protocol : %d\n",(unsigned int)iph->protocol);
printf(" |-IP Header Length : %d DWORDS or %d Bytes\n",
(unsigned int)iph->ihl,((unsigned int)(iph->ihl))*4);
printf(" |-Payload Length : %d Bytes\n",Size - header_size);
}
printf("Total Retransmissions: %d\n",retransmissions);
}
这种方法基于有关重传的 wireshark wiki段落。我确实点击了谷歌必须提供的关于如何进行这种分析的每一页,但这是我唯一能找到的东西。我得到的结果有些正确,一些重传没有被注意到,我得到了很多 DUP-ACK 数据包,一些正常的流量也通过了(用wireshark检查)。我使用在这里找到的 smallFlows.pcap 文件,我相信我应该得到的结果应该与tcp.analysis.retransmission && not tcp.analysis.spurious_retransmission
wireshark 中的过滤器相同。这相当于88
此 pcap 的重新传输。运行此代码会产生 45,我不明白为什么。
对不起,如果声明凌乱,我尽力清理它们。