上周接收完成离职同事的活: 对网络中用户访问的内容进行监控(某些非法关键字)。 需要用到HTTP协议对网页进行解析。
由于以前同事写的代码过于杂乱,并且在实际环境中,出现以下问题:段错误, chunked传输方式的网页无法监测。
项目经理让我进行重新架构。我简单学习了一下http协议(RFC2616)。
对于完整的http的解析, 考虑的东西还是很多的,但是针对于我们的需要, 解析的内容不需要面面俱到,只是需要几个需求:
1. 请求的方法是GET方式
2.响应的http的Content-Type是文本格式,如txt/html,txt/plain
3.响应解析支持固定size的网页(报文有Content-Length信息)和 trunked模式发送数据的网页(报文中Transfer-Encoding:trunked)
实现简单描述:
1.使用libpcap库,监听网卡的80端口
libpcap使用方法,可以参考http://yuba.stanford.edu/~casado/pcap/
2. 当监听到有网络数据时
1)如果远端端口是80,是http 请求。 用环形缓冲区存储request 数据包,直到有一个完整的http 头(包含请求行和头信息,以CRLFCRLF结尾), 解析这个完整http头
2)如果远端端口不是80, 是http响应。同样方式缓存http数据包,直到有一个完整http响应头(包含状态行和头信息,以CRLFCRLF结尾),解析这个头,如果是GET方式并且是文本内容,就存储payload数据
简单代码摘取:
// IP header
payload_len -= sizeof(struct ether_header);
if (payload_len < sizeof(struct iphdr))
{
fprintf(stderr, "error ip header\n");
return;
}
// TCP header
payload_len -= sizeof(struct iphdr);
if (payload_len < sizeof(struct tcphdr))
{
fprintf(stderr, "error tcp header\n");
return;
}
tcpptr = (struct tcphdr*)(packet + sizeof(struct ether_header) +
sizeof(struct iphdr));
// payload
payload_len -= tcpptr->doff * 4;
if (payload_len <= 0)
{
// No payload, just return
// fprintf(stderr," No payload!\n");
return;
}
src_port = ntohs(tcpptr->source);
dest_port = ntohs(tcpptr->dest);
seq = ntohl(tcpptr->seq);
ack_seq = ntohl(tcpptr->ack_seq);
payload = (char*)packet + header->len - payload_len;
if (dest_port == 80)
{
// TODO:Parse request
gp_parse_http_request(net_filter,
seq + payload_len,
payload,
payload_len,
http_request_callback);
}
else
{
// TODO:Parse response
gp_parese_http_response(net_filter,
payload,
payload_len,
ack_seq,
http_response_callback,
on_http_dump_data);
}