在上一篇博客中简单对libpcap库基本函数及基本工作流程做了些简单说明,

今天我们先了解一下pcap_loop()及pcap_dispatch()函数的功能及作用:

(1)pcap_loop()循环进行数据包的抓取:

函数原型如下:

        typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h,
const u_char *bytes); int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
/*参数说明:
功能:循环捕获数据包,不会响应pcap_open_live()函数设置的超时时间
参数 pcap_t *p: p是嗅探器会话句柄
参数 cnt:cnt用于设置所捕获数据包的个数,负数的cnt表示pcap_loop永远循环抓包,直到出现错误。
参数callback:是个回调函数指针,它的原型如下:
typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h,
const u_char *bytes);
参数 user:用来给回调函数传递参数的,在callback函数当中只有第一个user指针是可以留给用户使用的,
如果你想给callback传递自己参数,那就只能通过pcap_loop的最后一个参数user来实现了*/ struct pcap_pkthdr {
struct timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
bpf_u_int32 len; /* length this packet (off wire) */
};
//ts——时间戳
//caplen——真正实际捕获的包的长度
//len——这个包的长度 /*因为在某些情况下你不能保证捕获的包是完整的,例如一个包长1480,但是你捕获到1000的时候,
可能因为某些原因就中止捕获了,所以caplen是记录实际捕获的包长,也就是1000,而len就是1480。*/

(2)pcap_dispatch()这个函数和pcap_loop()非常类似,只是在超过to_ms毫秒后就会返回(to_ms是pcap_open_live()的第4个参数)

下面是函数原型:

        int pcap_dispatch(pcap_t *p, int cnt,
pcap_handler callback, u_char *user);

说完两个函数的作用,下面我们开始自制我们自己的sniffer,改程序的功能是循环抓取以太网报文并获取其中的http报文,解析并显示其相应的url及长度

下面直接贴出代码:

 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <pcap.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h> #define DEVICE "enp0s3"
#define URL_MAX_LEN 2048
#define MAX_HOST_LEN 1024
#define MAX_GET_LEN 2048 #define get_u_int8_t(X,O) (*(uint8_t *)(((uint8_t *)X) + O))
#define get_u_int16_t(X,O) (*(uint16_t *)(((uint8_t *)X) + O))
#define get_u_int32_t(X,O) (*(uint32_t *)(((uint8_t *)X) + O))
#define get_u_int64_t(X,O) (*(uint64_t *)(((uint8_t *)X) + O)) /*Display Ethernet Header*/
void show_ethhdr(struct ethhdr *eth)
{
printf("----------------eth---------------------\n");
printf("destination eth addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
eth->h_dest[], eth->h_dest[],
eth->h_dest[], eth->h_dest[],
eth->h_dest[], eth->h_dest[]);
printf("source eth addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
eth->h_source[], eth->h_source[],
eth->h_source[], eth->h_source[],
eth->h_source[], eth->h_source[]);
printf("protocol is: %04x\n", ntohs(eth->h_proto));
} /*Display IP Header*/
void show_iphdr(struct iphdr *ip)
{
struct in_addr addr; printf("----------------ip----------------------\n");
printf("version: %d\n", ip->version);
printf("head len: %d\n", ip->ihl * );
printf("total len: %d\n", ntohs(ip->tot_len));
printf("ttl: %d\n", ip->ttl);
printf("protocol: %d\n", ip->protocol);
printf("check: %x\n", ip->check);
addr.s_addr = ip->saddr;
printf("saddr: %s\n", inet_ntoa(addr));
addr.s_addr = ip->daddr;
printf("daddr: %s\n", inet_ntoa(addr));
} /*Display TCP Header*/
void show_tcphdr(struct tcphdr *tcp)
{
printf("----------------tcp---------------------\n");
printf("tcp len: %d\n", sizeof(struct tcphdr));
printf("tcp->doff: %d\n", tcp->doff * );
printf("source port: %d\n", ntohs(tcp->source));
printf("dest port: %d\n", ntohs(tcp->dest));
printf("sequence number: %d\n", ntohs(tcp->seq));
printf("ack sequence: %d\n", ntohs(tcp->ack_seq));
} int parse_http_head(const u_char *payload, int payload_len, char *url)
{
int line_len, offset;
int ustrlen;
int hstrlen; //"host: "
int hostlen;
int getlen;
char host[MAX_HOST_LEN];
char get[MAX_GET_LEN];
int a, b; /*filter get packet*/
if(memcmp(payload, "GET ", )) {
return ;
} for(a = , b = ; a < payload_len - ; a++) {
if (get_u_int16_t(payload, a) == ntohs(0x0d0a)) {
line_len = (u_int16_t)(((unsigned long) &payload[a]) - ((unsigned long)&payload[b])); if (line_len >= ( + )
&& memcmp(&payload[line_len - ], " HTTP/1.", ) == ) {
memcpy(get, payload + , line_len - ); //"GET HTTP/1.x" 13bit
getlen = line_len - ;
}
/*get url host of pcaket*/
if (line_len >
&& memcmp(&payload[b], "Host:", ) == ) {
if(*(payload + b + ) == ' ') {
hstrlen = b + ;
} else {
hstrlen = b + ;
}
hostlen = a - hstrlen;
memcpy(host, payload + hstrlen, (a - hstrlen));
}
b = a + ;
}
}
offset = ;
memcpy(url, "http://", offset);
memcpy(url + offset, host, hostlen);
offset += hostlen;
memcpy(url + offset, get, getlen); return strlen(url);
} void packet_http_handle(const u_char *tcp_payload, int payload_len)
{
int url_len;
char url[URL_MAX_LEN]; url_len = parse_http_head(tcp_payload, payload_len, url);
if (url_len <= ) {
return;
}
printf("----------------HTTP---------------------\n");
printf("url_len: %d\n", url_len);
printf("url: %s\n", url);
} int prase_packet(const u_char *buf, int caplen)
{
uint16_t e_type;
uint32_t offset;
int payload_len;
const u_char *tcp_payload; /* ether header */
struct ethhdr *eth = NULL;
eth = (struct ethhdr *)buf;
e_type = ntohs(eth->h_proto);
offset = sizeof(struct ethhdr);
show_ethhdr(eth); /*vlan 802.1q*/
while(e_type == ETH_P_8021Q) {
e_type = (buf[offset+] << ) + buf[offset+];
offset += ;
}
if (e_type != ETH_P_IP) {
return -;
} /* ip header */
struct iphdr *ip = (struct iphdr *)(buf + offset);
e_type = ntohs(ip->protocol);
offset += sizeof(struct iphdr);
show_iphdr(ip); if(ip->protocol != IPPROTO_TCP) {
return -;
} /*tcp header*/
struct tcphdr *tcp = (struct tcphdr *)(buf + offset);
offset += (tcp->doff << );
payload_len = caplen - offset;
tcp_payload = (buf + offset);
show_tcphdr(tcp); /*prase http header*/
packet_http_handle(tcp_payload, payload_len); return ;
} void get_packet(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet)
{
static int count = ;
printf("\n----------------------------------------\n");
printf("\t\tpacket %d\n", count);
printf("----------------------------------------\n");
printf("Packet id: %d\n", count);
printf("Packet length: %d\n", pkthdr->len);
printf("Number of bytes: %d\n", pkthdr->caplen);
printf("Recieved time: %s\n", ctime((const time_t *)&pkthdr->ts.tv_sec)); prase_packet(packet, pkthdr->len);
count++;
} int main()
{
char errBuf[PCAP_ERRBUF_SIZE]; /*error Buff*/
struct pcap_pkthdr packet; /*The header that pcap gives us*/
pcap_t *dev; /*network interface*/
bpf_u_int32 netp, maskp;
char *net, *mask;
struct in_addr addr;
int ret; /*look up device network addr and mask*/
if(pcap_lookupnet(DEVICE, &netp, &maskp, errBuf)) {
printf("get net failure\n");
exit();
}
addr.s_addr = netp;
net = inet_ntoa(addr);
printf("network: %s\n", net); addr.s_addr = maskp;
mask = inet_ntoa(addr);
printf("mask: %s\n", mask); /*open network device for packet capture*/
dev = pcap_open_live(DEVICE, , , , errBuf);
if(NULL == dev) {
printf("open %s failure\n", DEVICE);
exit();
} /*process packets from a live capture or savefile*/
pcap_loop(dev, , get_packet, NULL); /*close device*/
pcap_close(dev); return ;
}

下面是运行结果:

 ----------------------------------------
packet
----------------------------------------
Packet id:
Packet length:
Number of bytes:
Recieved time: Mon Aug :: ----------------eth---------------------
destination eth addr: ::0b:::2b
source eth addr: ::::e7:
protocol is:
----------------ip----------------------
version:
head len:
total len:
ttl:
protocol:
check: f793
saddr: 192.168.16.125
daddr: 119.84.70.22
----------------tcp---------------------
tcp len:
tcp->doff:
source port:
dest port:
sequence number:
ack sequence:
----------------HTTP---------------------
url_len:
url: http://cc.stream.qqmusic.qq.com/C200003a0iyj2fOc6y.m4a

使用libpcap获取http报文的更多相关文章

  1. Python编程系列---获取请求报文行中的URL的几种方法总结

    在浏览器访问web服务器的时候,服务器收到的是一个请求报文,大概GET请求的格式大概如下: 先随便拿到一个请求报文,蓝色即为我们要获取的 GET  /index.html  HTTP/1.1  Hos ...

  2. 发送xml报文去第三方请求获取xml报文数据

    import java.io.*; import java.net.HttpURLConnection; import java.net.MalformedURLException; import j ...

  3. Selenium自动化获取Http报文信息并判断当前API状态

    public int loadingFinishedCount(WebDriver driver){ LogEntries logs = driver.manage().logs().get(&quo ...

  4. 使用JAVA获取JSON报文

    基本JSON格式: { "name": "liming", "age": "13", "array" ...

  5. NetCore 中间件获取请求报文和返回报文

    using System; using System.IO; namespace WebApi.Restful.Middlewares { public class MemoryWrappedHttp ...

  6. Servlet&JSP-HTTP报文头获取及应用

    完整代码请参考:https://github.com/devway9/java-exercise/tree/master/servlet-jsp 目录 1 HttpServletRequest获取报文 ...

  7. Axis通过方法获取webService请求报文

    MessageContext messageContext = _call.getMessageContext(); Message reqMsg = messageContext.getReques ...

  8. SNMP报文抓取与分析(一)

    SNMP报文抓取与分析(一) 1.抓取SNMP报文 SNMP报文的形式大致如下图所示 我们这里使用netcat这个工具来抓取snmp的PDU(协议数据单元).(因为我们并不需要前面的IP和UDP首部) ...

  9. ISO8583报文解析

    在此只写了一个8583报文的拆包,组包其实也差不多的. 不多说直接上文件, 具体思路过程,在解析类里面写的有. 其中包含了四个文件 8583resp.txt报文 ISO8583medata配置文件 B ...

随机推荐

  1. centos6.5 rsync+inotify实现服务器之间文件实时同步

    1. rsync的优点与不足 与传统的cp.tar备份方式相比,rsync具有安全性高.备份迅速.支持增量备份等优点,通过rsync可以解决对实时性要求不高的数据备份需求,例如定期的备份文件服务器数据 ...

  2. 为神马精确Sprite的碰撞形状不通过简单的放大Sprite的尺寸来解决?

    原因是SoftBodyDrawNode的绘制代码中已经没有完整的,一体化的(incorporate)缩放,旋转或者甚至是精灵的位置(scale,rotation,or even the sprite' ...

  3. Java-ServletContextListener

    /** * Implementations of this interface receive notifications about * changes to the servlet context ...

  4. Java基本数据类型和长度

    转自:http://lysongfei.iteye.com/blog/602546 java数据类型     字节  表示范围 byte(字节型)     1  -128-127  short(短整型 ...

  5. AES涉及的有限域乘法及字节填充方法

     非常值得参考的是官方文档,它详细介绍了AES及其实验过程.博文AES加密算法的C++实现就是基于该文档的介绍及实现,是难得的一篇好文,故在本文最后会附上该文,以作备份. 还有很值得推荐的就是AES的 ...

  6. Auto Create Editable Copy Font(Unity3D开发之二十二)

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/48318879 ...

  7. ROS探索总结(十五)——amcl(导航与定位)

    在理解了move_base的基础上,我们开始机器人的定位与导航.gmaping包是用来生成地图的,需要使用实际的机器人获取激光或者深度数据,所以我们先在已有的地图上进行导航与定位的仿真. amcl是移 ...

  8. Spring对事务管理的支持的发展历程(基础篇)

    1.问题 Connection conn = DataSourceUtils.getConnection(); //开启事务 conn.setAutoCommit(false); try { Obje ...

  9. iOS Swift开发的一些坑

    0.人难招,特别是对于没钱的小团队,大多数的iOS开发者没有Swift经验,有经验的也并不是很深入 0.1.语言unwrap坑,虽然有自动修正提示,但感觉代码过程不流畅. 1.Realm的缺憾: 最近 ...

  10. 终端字形logo

    网上有很多的项目都有一个自己的字形logo,而我也在开发一个小的项目,也想要生成一个终端字形的logo,于是找到这款小工具,分享给大家:FIGlet “FIGlet is a program for ...