前文已經講過,解析數據包主要通過analyze_frame()這個函數實現的,實際上並非這個函數完成了所有的功能,其實從名字就可以看出,它只是完成了對“幀”的解析,也就是鏈路層數據的解析,還有analyze_arp()、analyze_ip()、analyze_ip6()、analyze_icmp()……等來完成其他協議層的解析工作。
爲什麼會這樣定義?熟悉協議棧工作流程的都知道,數據是由應用層把數據加上應用層協議頭後給傳輸層,傳輸層在最外面加上它的頭部後給網絡層,網絡層在外面加上它的頭部後再給鏈路層……所以當數據包被捕獲到之後最外面的就是鏈路層的協議頭,因此首先要解析的就是鏈路層協議,這也就是爲什麼首先要調用analyze_frame()這個函數了,然後再一層一層把它“剝開”,最終獲得裏面的數據。
每一層的上層可能有多種協議在工作,比如IP上層就有TCP和UDP等之分,所以在解析數據包的時候需要根據不同的特徵來判斷上層協議到底是什麼,然後再來調用相關的函數對其進行解析,下面將列出一些主要的判斷特徵:
1、 鏈路層--網絡層
網絡層可能會有arp、ipv4、ipv6這三種不同的情況,在鏈路層定義了一個type字段,專門用於指示網絡層數據包是什麼類型。
type == 0x0806 表示這是一個arp包
type == 0x0800 表示這是一個ipv4包
type == 0x86dd 表示這是一個ipv6包
2、 網絡層(IP層)--傳輸層
IP層之上可能會有tcp、udp、icmp等
IPv4協議定義了proto字段來指示傳輸層協議是什麼。還記得上一章的Protocol.h文件中的這段定義不?proto什麼值對應什麼協議很明白了吧?
#definePROTO_ICMP 1
#define PROTO_TCP 6
#define PROTO_UDP 17
IPv6使用nh字段來標明傳輸層協議,如下:
nh== 0x3a 表示上層是icmpv6
nh== 0x06 表示上層是tcp
nh== 0x11 表示上層是udp
3、 傳輸層之上就是應用層了,這裏我們的應用層只支持http協議,判斷方法很簡單,就是看目的或源端口是不是80。
餘下的工作就是一個字段一個字段地獲取數據包的值了。函數的整體調用關係如下圖:
需要特別說明的一點是,網絡中的字節順序跟主機中的字節順序是完全不一樣的,所以特別是要獲得數字的值的時候,一定要先調用ntohs()函數(network to host short)或ntohl()函數(network to host long)將數據包的網絡字節順轉換爲主機字節序,這樣在做一些判斷的時候纔是準確的。
下一章:千呼萬喚始出來,不抱琵琶也露面——將解析數據寫到GUI上
解析函數的代碼如下:
/*pkt爲網絡中捕獲的包,data爲要存爲本機上的數據*/
/*分析鏈路層*/
int analyze_frame(const u_char * pkt,struct datapkt * data,struct pktcount *npacket)
{
int i;
struct ethhdr *ethh = (struct ethhdr*)pkt;
data->ethh = (struct ethhdr*)malloc(sizeof(struct ethhdr));
if(NULL == data->ethh)
return -1;
for(i=0;i<6;i++)
{
data->ethh->dest[i] = ethh->dest[i];
data->ethh->src[i] = ethh->src[i];
}
npacket->n_sum++;
/*由於網絡字節順序原因,需要對齊*/
data->ethh->type = ntohs(ethh->type);
//處理ARP還是IP包?
switch(data->ethh->type)
{
case 0x0806:
return analyze_arp((u_char*)pkt+14,data,npacket); //mac 頭大小爲14
break;
case 0x0800:
return analyze_ip((u_char*)pkt+14,data,npacket);
break;
case 0x86dd:
return analyze_ip6((u_char*)pkt+14,data,npacket);
return -1;
break;
default:
npacket->n_other++;
return -1;
break;
}
return 1;
}
/*分析網絡層:ARP*/
int analyze_arp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
{
int i;
struct arphdr *arph = (struct arphdr*)pkt;
data->arph = (struct arphdr*)malloc(sizeof(struct arphdr));
if(NULL == data->arph )
return -1;
//複製IP及MAC
for(i=0;i<6;i++)
{
if(i<4)
{
data->arph->ar_destip[i] = arph->ar_destip[i];
data->arph->ar_srcip[i] = arph->ar_srcip[i];
}
data->arph->ar_destmac[i] = arph->ar_destmac[i];
data->arph->ar_srcmac[i]= arph->ar_srcmac[i];
}
data->arph->ar_hln = arph->ar_hln;
data->arph->ar_hrd = ntohs(arph->ar_hrd);
data->arph->ar_op = ntohs(arph->ar_op);
data->arph->ar_pln = arph->ar_pln;
data->arph->ar_pro = ntohs(arph->ar_pro);
strcpy(data->pktType,"ARP");
npacket->n_arp++;
return 1;
}
/*分析網絡層:IP*/
int analyze_ip(const u_char* pkt,datapkt *data,struct pktcount *npacket)
{
int i;
struct iphdr *iph = (struct iphdr*)pkt;
data->iph = (struct iphdr*)malloc(sizeof(struct iphdr));
if(NULL == data->iph)
return -1;
data->iph->check = iph->check;
npacket->n_ip++;
/*for(i = 0;i<4;i++)
{
data->iph->daddr[i] = iph->daddr[i];
data->iph->saddr[i] = iph->saddr[i];
}*/
data->iph->saddr = iph->saddr;
data->iph->daddr = iph->daddr;
data->iph->frag_off = iph->frag_off;
data->iph->id = iph->id;
data->iph->proto = iph->proto;
data->iph->tlen = ntohs(iph->tlen);
data->iph->tos = iph->tos;
data->iph->ttl = iph->ttl;
data->iph->ihl = iph->ihl;
data->iph->version = iph->version;
//data->iph->ver_ihl= iph->ver_ihl;
data->iph->op_pad = iph->op_pad;
int iplen = iph->ihl*4; //ip頭長度
switch(iph->proto)
{
case PROTO_ICMP:
return analyze_icmp((u_char*)iph+iplen,data,npacket);
break;
case PROTO_TCP:
return analyze_tcp((u_char*)iph+iplen,data,npacket);
break;
case PROTO_UDP:
return analyze_udp((u_char*)iph+iplen,data,npacket);
break;
default :
return-1;
break;
}
return 1;
}
/*分析網絡層:IPV6*/
int analyze_ip6(const u_char* pkt,datapkt *data,struct pktcount *npacket)
{
int i;
struct iphdr6 *iph6 = (struct iphdr6*)pkt;
data->iph6 = (struct iphdr6*)malloc(sizeof(struct iphdr6));
if(NULL == data->iph6)
return -1;
npacket->n_ip6++;
data->iph6->version = iph6->version;
data->iph6->flowtype = iph6->flowtype;
data->iph6->flowid = iph6->flowid;
data->iph6->plen = ntohs(iph6->plen);
data->iph6->nh = iph6->nh;
data->iph6->hlim =iph6->hlim;
for(i=0;i<16;i++)
{
data->iph6->saddr[i] = iph6->saddr[i];
data->iph6->daddr[i] = iph6->daddr[i];
}
switch(iph6->nh)
{
case 0x3a:
return analyze_icmp6((u_char*)iph6+40,data,npacket);
break;
case 0x06:
return analyze_tcp((u_char*)iph6+40,data,npacket);
break;
case 0x11:
return analyze_udp((u_char*)iph6+40,data,npacket);
break;
default :
return-1;
break;
}
//npacket->n_ip6++;
//strcpy(data->pktType,"IPV6");
return 1;
}
/*分析傳輸層:ICMP*/
int analyze_icmp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
{
struct icmphdr* icmph = (struct icmphdr*)pkt;
data->icmph = (struct icmphdr*)malloc(sizeof(struct icmphdr));
if(NULL == data->icmph)
return -1;
data->icmph->chksum = icmph->chksum;
data->icmph->code = icmph->code;
data->icmph->seq =icmph->seq;
data->icmph->type = icmph->type;
strcpy(data->pktType,"ICMP");
npacket->n_icmp++;
return 1;
}
/*分析傳輸層:ICMPv6*/
int analyze_icmp6(const u_char* pkt,datapkt *data,struct pktcount *npacket)
{
int i;
struct icmphdr6* icmph6 = (struct icmphdr6*)pkt;
data->icmph6 = (struct icmphdr6*)malloc(sizeof(struct icmphdr6));
if(NULL == data->icmph6)
return -1;
data->icmph6->chksum = icmph6->chksum;
data->icmph6->code = icmph6->code;
data->icmph6->seq =icmph6->seq;
data->icmph6->type = icmph6->type;
data->icmph6->op_len = icmph6->op_len;
data->icmph6->op_type = icmph6->op_type;
for(i=0;i<6;i++)
{
data->icmph6->op_ethaddr[i] = icmph6->op_ethaddr[i];
}
strcpy(data->pktType,"ICMPv6");
npacket->n_icmp6++;
return 1;
}
/*分析傳輸層:TCP*/
int analyze_tcp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
{
struct tcphdr *tcph = (struct tcphdr*)pkt;
data->tcph = (struct tcphdr*)malloc(sizeof(struct tcphdr));
if(NULL == data->tcph)
return -1;
data->tcph->ack_seq = tcph->ack_seq;
data->tcph->check = tcph->check;
data->tcph->doff = tcph->doff;
data->tcph->res1 = tcph->res1;
data->tcph->cwr = tcph->cwr;
data->tcph->ece = tcph->ece;
data->tcph->urg = tcph->urg;
data->tcph->ack = tcph->ack;
data->tcph->psh = tcph->psh;
data->tcph->rst = tcph->rst;
data->tcph->syn = tcph->syn;
data->tcph->fin = tcph->fin;
//data->tcph->doff_flag = tcph->doff_flag;
data->tcph->dport = ntohs(tcph->dport);
data->tcph->seq = tcph->seq;
data->tcph->sport = ntohs(tcph->sport);
data->tcph->urg_ptr = tcph->urg_ptr;
data->tcph->window= tcph->window;
data->tcph->opt = tcph->opt;
/////////////////////*不要忘記http分支*/////////////////////////
if(ntohs(tcph->dport) == 80 || ntohs(tcph->sport)==80)
{
npacket->n_http++;
strcpy(data->pktType,"HTTP");
}
else{
npacket->n_tcp++;
strcpy(data->pktType,"TCP");
}
return 1;
}
/*分析傳輸層:UDP*/
int analyze_udp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
{
struct udphdr* udph = (struct udphdr*)pkt;
data->udph = (struct udphdr*)malloc(sizeof(struct udphdr));
if(NULL == data->udph )
return -1;
data->udph->check = udph->check;
data->udph->dport = ntohs(udph->dport);
data->udph->len = ntohs(udph->len);
data->udph->sport = ntohs(udph->sport);
strcpy(data->pktType,"UDP");
npacket->n_udp++;
return 1;
}