在前面的一篇文章中,简单了介绍了HTTP报文格式,详情参考http://www.firefoxbug.net/?cat=47。
这里大概介绍下基本的,常见的HTTP包头格式。
POST /report/getComment.jsp HTTP/1.1 Host: yeeg.com Connection: keep-alive Content-Length: 161 Origin: http://www.1g1g.com User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/535.7 content-type: application/x-www-form-urlencoded Accept: */* Referer: http://www.1g1g.com/player/loader.swf?uid=0.8106261373031884 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 Cookie: JSESSIONID=C3F105F72E3602D6292D3E4561E8E400
上面是一个POST包的包头,其中Content-Length字段里面的值就是POST包数据段的长度。可以用
wireshark抓取POST包,会发现,post包是把报文头和数据内容分开来发的,会被TCP分片,然后重组。
具体这里不详细讨论。
GET /enclosure/2010-09-10T02_51_05-07_00.mp3 HTTP/1.1 Host: 805665086.podomatic.com Connection: keep-alive User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/535.7 Accept: */* Referer: http://www.1g1g.com/player/loader.swf?uid=0.8106261373031884 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
上面是一个GET包,GET包请求的资源都是在URL里面的,所以数据段也就没有了,可以通过抓包分析。
HTTP/1.1 200 OK Date: Tue, 10 Jul 2012 09:12:52 GMT Server: Apache/2.2.14 (Ubuntu) Last-Modified: Thu, 23 Dec 2010 19:29:26 GMT ETag: "960fcf-4a6459-49818e3486374" Accept-Ranges: bytes Content-Length: 487 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: audio/mpeg
上面是一个http响应包,Content-Length指明了数据段的大小。
下面是我今天用C写了解析HTTP报文头的程序。注意:下面代码只主要用libcap实现实现了部分功能,具体
是解析GET包头,POST包头,还有HTTP相应包头,可能存在一些不足,希望大家多多交流。
/*
capture http packet by firefoxbug
*/
#include
#include
#include
#include
#include
#include
#include
#include //Provides declarations for icmp header
#include //Provides declarations for udp header
#include //Provides declarations for tcp header
#include //Provides declarations for ip header
#define BUFFSIZE 1500
typedef struct port{
unsigned int src_port;
unsigned int des_port;
}Port;
Port port;
int tcp=0;
FILE *logfile;
int size;
void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *buffer);
char *print_tcp_packet(const char *Buffer);
void get_line(char *data,char *buff,int length);
void print_http_req_packet(char *data);
void print_http_ans_packet(char *data);
int main(int argc,char *argv[])
{
pcap_if_t *alldevsp , *device;
pcap_t *handle; //Handle of the device that shall be sniffed
char errbuf[100] , *devname , devs[100][100];
int count = 1 , n;
//First get the list of available devices
printf("Finding available devices ... ");
if( pcap_findalldevs( &alldevsp , errbuf) )
{
printf("Error finding devices : %s" , errbuf);
exit(1);
}
printf("Done");
//Print the available devices
printf("\nAvailable Devices are :\n");
for(device = alldevsp ; device != NULL ; device = device->next)
{
printf("%d. %s - %s\n" , count , device->name , device->description);
if(device->name != NULL)
{
strcpy(devs[count] , device->name);
}
count++;
}
//Ask user which device to sniff
printf("Enter the number of the device you want to sniff : ");
scanf("%d" , &n);
devname = devs[n];
//Open the device for sniffing
printf("Opening device %s for sniffing ... " , devname);
handle = pcap_open_live(devname , 65536 , 1 , 0 , errbuf);
if (handle == NULL)
{
fprintf(stderr, "Couldn't open device %s : %s\n" , devname , errbuf);
exit(1);
}
printf("Done\n");
logfile=fopen("log.txt","w");
if(logfile==NULL)
{
printf("Unable to create file.");
}
//Put the device in sniff loop
pcap_loop(handle , -1 , process_packet , NULL);
return 0;
}
void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *buffer)
{
size = header->len;
// fprintf(logfile,"length of packet : %d \n",size);
//Get the IP Header part of this packet , excluding the ethernet header
struct iphdr *iph = (struct iphdr*)(buffer + sizeof(struct ethhdr));
switch (iph->protocol) //Check the Protocol and do accordingly...
{
case 6: //TCP Protocol
++tcp;
// printf("TCP : %d \n", tcp);
unsigned char *data = print_tcp_packet(buffer);
if (size <= 0)
break;
if (port.des_port == 80)
{
print_http_req_packet(data);
}
else if ( port.src_port == 80 )
{
print_http_ans_packet(data);
}
break;
}
}
char *print_tcp_packet(const char *Buffer)
{
//IP header
struct iphdr *iph = (struct iphdr *)( Buffer + sizeof(struct ethhdr) );
unsigned int iphdrlen = iph->ihl*4;
//TCP header
struct tcphdr *tcph=(struct tcphdr*)(Buffer + iphdrlen + sizeof(struct ethhdr));
port.src_port = ntohs(tcph->source);
port.des_port = ntohs(tcph->dest);
// mac_header + ip_header + tcp_header
int header_size = sizeof(struct ethhdr) + iphdrlen + tcph->doff*4;
size = size - header_size;
// fprintf(logfile,"length of header : %d \n",header_size );
return (char *)(Buffer + header_size);
}
void print_http_req_packet(char *data)
{
if( strncmp(data,"GET",3) == 0 || strncmp(data,"POST",4) == 0 )
{
fprintf(logfile,"\n/***********************length of data : %d**********************/ \n",size);
fprintf(logfile,"From %d To %d \n",port.src_port,port.des_port);
int i = 0;
for( ; i < size ; ++i)
{
fprintf(logfile,"%c",*(data + i));
}
fprintf(logfile,"/***************************** end *******************************/ \n\n");
}
return ;
}
void print_http_ans_packet(char *data)
{
if( strncmp(data,"HTTP",4) == 0 )
{
fprintf(logfile,"\n/***********************length of data : %d**********************/ \n",size);
fprintf(logfile,"From %d To %d \n",port.src_port,port.des_port);
char buff[BUFFSIZE] = {'\0'};
get_line(data,buff,size);
fprintf(logfile,"%s",buff);
unsigned int off = strlen(buff);
size = size - off;
while(strcmp(buff,"\r\n") != 0)
{
memset(buff,'\0',sizeof(buff));
get_line(data + off,buff,size);
fprintf(logfile,"%s",buff);
off = off + strlen(buff);
size = size - off;
}
fprintf(logfile,"/***************************** end *******************************/ \n\n");
}
}
void get_line(char *data,char *buff,int length)
{
int i = 0;
char ch;
for ( ; i < length;++i)
{
ch = *(data + i);
*(buff + i) = ch;
if(ch == '\n')
break;
}
}