前文已经讲过,解析数据包主要通过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; }