user-0 提问: C语言 liunx 下libpcap 解析 HTTP 拼包问题跪求

回复:
user: user-1
content: 1,创建一个buffer list,  这个buffer list的总体大小不超过4M， 2，抓包： 网络包都大于64byte; 如果小于64，当做坏包处理， 3，如果当前的list 是空，并且整个包长小于 140 （tcp + http head ... 知道出现content length）    		并且pkt_data+34 是“HTTP” , 或者进一步判断是 HTTP/1.1 200 OK 			如果是，说明这个包是http的response的开头。 			寻找当前的content length ,并求出content length的大小。 				如果没有找到content length，也没有找到 Transfer-Encoding ： 那这种包，我还没有见过。 				如果找到content length ，那判断pkt_data 的剩余长度 + 4 （\r\n\r\n），是不是 恰好是content length, 				如果是-恰好说明是： 这个包已经是一个完整的http 包了，没有分包，即没有出现 数据被分包的问题。 				如果不是-- 说明数据被分包了，请把下列属性当成一个 list 的一个节点。 					src_ip，dst_ip，src_port，dst_port，seq ,next_seq, ack, current_buffer,cur_buf_len. 					请把这个member ,增加到 list里面。 		 		如果当前的list 非空， 		那对比当前的 这些属性 是否和list的某个成员的属性一致: src_ip，dst_ip，src_port，dst_port，seq ,next_seq, ack 		注意ack ,seq的大小端问题： BigLittleSwap32。 		如果属性匹配那把这个buffer 增加到 旧的buffer后面，再次call : Check_http_content_is_end 		 		如果分包的话，一般情况下包的长度的序列如下：X,X,X,X,...Y ,并且X>Y, 		如果中间出现某些 包的PDU_Packet_length 和 X的包长不相等 --- 至少我没有见过， 那我就报错了。		 		如果不相等，去判断Check_http_content_is_end（）了。 		 		如果没有content-length ,na zhoad transfer-Encoding: 看是否是chunked. 		 		如果最后一个包的tcp的flag: 是0x18 (PSH,ACK)， 这更能说明是这是一个http 分包的最后一个包了。

user: user-2
content: HTTP不是有Content-Length吗？

user: user-0
content: #include <stdio.h> #include <pcap.h> #include <string.h>   /*ip*/ struct ip_address {     u_char byte1;     u_char byte2;     u_char byte3;     u_char byte4; };  struct ipadd { 	struct ip_address src_ip; 	struct ip_address dst_ip; };  /*udp和tcp的端口*/ struct ip_port {   u_int16_t src_port;	/*源端口*/   u_int16_t dst_port;	/*目的端口*/ };  struct tcp_header { 	u_int16_t src_port; 	u_int16_t dst_port; 	u_int32_t num1; 	u_int32_t num2; 	u_int8_t tcp_hlen_f; /*tcp首部长度和选项*/ 	u_int8_t tcp_hlen; 	u_int16_t windows; 	u_int16_t checksum; 	u_int16_t urgent_pointer; };  struct udp_header { 	u_int16_t src_port; 	u_int16_t dst_port; 	u_int16_t len; 	u_int16_t Checksum; };  /*ip数据头*/ struct ip_header   {   u_int8_t ip_hlen_v;  /*ip版本和首部长度*/   u_int8_t ip_tos;     u_int16_t ip_length;  /*ip总长度*/   u_int16_t ip_id;     u_int16_t  ip_off;     u_int8_t ip_ttl;     u_int8_t ip_protocol;     u_int16_t ip_checksum;     struct ipadd ip;	/*ip地址*/ };  u_int8_t get_tcpLen(u_int8_t tcp_hlen_f) { 	tcp_hlen_f >>= 4; 	tcp_hlen_f <<= 2; 	return tcp_hlen_f; }  u_int8_t get_ipLen(u_int8_t ip_hlen_v) { 	ip_hlen_v <<=4; 	ip_hlen_v >>= 2; 	return ip_hlen_v; }  /*获取对应http信息*/ void get_http(const u_char * packet_data, char * head_str, char *tail_str, u_int16_t datelen, u_int8_t p)/*head_str：需要查找的字段头，tail_str：结束。len：数据报文长度*/ { 	char * data = NULL; 	data = (char *)(packet_data + 14 + p); /*用户忽略数据帧、ip头和tcp头*/ 	char * d = NULL; 	d = strstr(data,head_str); 	datelen -= p; 	if (d != NULL) 	{ 		char * m = NULL; 		m = strstr(d,tail_str); 		int l = m - d; 		char buf[l+1]; 		buf[l]='\0'; 		strncpy(buf,d,l); 		printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n"); 		printf("%s\n",buf); 		 		char da[datelen + 1]; 		da[datelen]='\0'; 		strncpy(da,data,datelen); 		printf("pake len:%d-  - - %d\n",datelen,strlen(da)); 		printf("%s\n",da); 	} 	else 	{                 char da[datelen + 1];                 da[datelen]='\0';                 strncpy(da,data,datelen);                 printf("pake len:%d-  - - %d\n",datelen,strlen(da));                 printf("%s\n",da); 	 	}  }  void tcp_udp(char * typ, const u_char * pack_tcp_udp, struct ipadd ip, u_int16_t datelen, u_int8_t p) { 	struct ip_port * ip_port = (struct ip_port *)(pack_tcp_udp + 14 + p); 	u_int16_t src_port = ntohs(ip_port->src_port); 	u_int16_t dst_port = ntohs(ip_port->dst_port); 	/* 	printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \n"); 	printf("%s\t%d.%d.%d.%d : %d -> %d.%d.%d.%d : %d\n", 		typ, 		ip.src_ip.byte1, 		ip.src_ip.byte2, 		ip.src_ip.byte3, 		ip.src_ip.byte4, 		src_port, 		ip.dst_ip.byte1, 		ip.dst_ip.byte2, 		ip.dst_ip.byte3, 		ip.dst_ip.byte4, 		dst_port); 	*/ 	if (strcmp(typ, "Tcp") == 0) 	{ 		u_int8_t tcplen; 		struct tcp_header * tcp_header = (struct tcp_header*)(pack_tcp_udp + 14 + p); 		tcplen = get_tcpLen(tcp_header->tcp_hlen_f); 		//printf("%d\n",tcplen); 		if(src_port == 80 || dst_port == 80) 		{ 			//get_http(pack_tcp_udp, "GET ", "HTTP/1.1\r\n", datelen, p + tcplen); 			get_http(pack_tcp_udp, "POST ", "HTTP/1.1\r\n", datelen, p + tcplen); 		}  	}else 	{ 		 		 	} }  void packet_out(u_char * argument,const struct pcap_pkthdr * packet_header,                    const u_char * packet_content) { 	struct ip_header * ip_header; 	u_int8_t iplen; 	char *typ; 	 	ip_header = (struct ip_header*)(packet_content+14); 	iplen = get_ipLen(ip_header -> ip_hlen_v); 	 	switch(ip_header -> ip_protocol)   	{ 		case 6: 			typ = "Tcp"; 			break; 		case 17:   			typ = "Udp"; 			break;  		default: 			return;  	} 	 	tcp_udp(typ, packet_content, ip_header->ip, ntohs(ip_header->ip_length), iplen); 	 	//pcap_dump(argument,packet_header,packet_content);  }  void ReadPcap(char * fname) { 	pcap_t *fp; 	char ebuf[PCAP_ERRBUF_SIZE]; 	fp = pcap_open_offline(fname, ebuf);  	pcap_loop(fp, 0, packet_out, NULL); 	 }   int main(int argc, char **argv) /*-i 指定网口 -w 输出报文文件 port 指定端口 tcp 或 udp 过滤 -r 读包文件名*/ { 	pcap_t *handle;     char err[PCAP_ERRBUF_SIZE], *dev, *out; 	char pd[20] = "";      out = "output.pcap"; 	dev = pcap_lookupdev(err);  	int i;         for (i = 1; i < argc; i++  )         {         	if (strcmp(argv[i], "-i") == 0 )                 {                 	dev = argv[++i];                 }                 else if (strcmp(argv[i], "-w") == 0)                 {                         out = argv[++i];                 } 		else if(strcmp(argv[i], "udp") == 0 			|| strcmp(argv[i], "tcp") == 0) 		{ 			char pdtcp[20]; 			strcpy(pdtcp, argv[i]); 			strcat(pdtcp, " "); 			strcat(pdtcp, pd); 			strcpy(pd, pdtcp); 		} 		else if (strcmp(argv[i], "port") == 0 ) 		{ 			strcat(pd, argv[i]); 			strcat(pd, " "); 			strcat(pd, argv[++i]); 			strcat(pd, " "); 		} else if (strcmp(argv[i], "-r") == 0) 		{ 			ReadPcap(argv[++i]); 			return 0; 			 		} 		 	}          if(dev)     {             printf("dev:%s\n",dev); 	printf("output file: %s\n", out); 	printf("pd: %s\n", pd); 	printf("ing......\n");     }     else     {         printf("error :%s\n",err); 		return 0;     }      bpf_u_int32 mask;     bpf_u_int32 net; 	struct bpf_program filter;  	pcap_lookupnet(dev, &net, &mask, err);  	handle = pcap_open_live(dev, BUFSIZ, 1, 0, err);  	pcap_compile(handle, &filter, pd, 0, net); 	pcap_setfilter(handle, &filter);  	pcap_dumper_t* out_pcap; 	out_pcap  = pcap_dump_open(handle, out); 	 	while(1) 	{ 		pcap_loop(handle,30,packet_out,(u_char *)out_pcap);         pcap_dump_flush(out_pcap); 	} 	pcap_close(handle); 	pcap_dump_close(out_pcap); 	 	return 0; }