在上一篇博客中简单对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. Android 自定义标题栏

    开发 Android APP 经常会用到自定义标题栏,而有多级页面的情况下还需要给自定义标题栏传递数据. 本文要点: 自定义标题填充不完整 自定义标题栏返回按钮的点击事件 一.代码 这里先介绍一下流程 ...

  2. HibernateTemplate 查询原生sql及ljava.lang.object cannot be cast to

    /** * 使用sql语句进行查询操作 * @param sql * @return */ public List queryWithSql(final String sql){ List list ...

  3. ExtJS:Grid数据导出至excel实例

    导出函数ExportExcel() var config={ store: alldataStore, title: '测试标题' }; var tab=tabPanel.getActiveTab() ...

  4. android查看源码的时候看不了

    原因:未关联android中jar包源码 解决方案:导入sdk---->>resource---->>api 这样就可以在代码中查看源码了.

  5. Netfilter的使用和实现

    本文主要内容:Netfilter的原理和实现浅析,以及示例模块. 内核版本:2.6.37 Author:zhangskd @ csdn blog 概述 Netfilter为多种网络协议(IPv4.IP ...

  6. ExtJS中xtype 概览

    基本组件: xtype Class 描述 button Ext.Button 按钮 splitbutton Ext.SplitButton 带下拉菜单的按钮 cycle Ext.CycleButton ...

  7. java并发之可见性与原子性:Syncronized和volatile

    转载:http://blog.csdn.net/guyuealian/article/details/52525724 在说明Java多线程内存可见性之前,先来简单了解一下Java内存模型.     ...

  8. openssh升级的坑爹之路

    安装Zlib http://zlib.net/zlib-1.2.8.tar.gz tar -zxvf zlib-1.2.8.tar.gz cd zlib-1.2.8 ./configure --sha ...

  9. AngualrJS之服务器端通信

    译自<AngularJS> 与服务器通信 目前,我们已经接触过下面要谈的主题的主要内容,这些内容包括你的Angular应用如何规划设计.不同的angularjs部件如何装配在一起并正常工作 ...

  10. MySQL快速生成本地测试数据

    利用数据的存储过程生成测试数据: 我们可以通过数据库的的 INSERT 语句直接在存储过程中向普通数据表中添加数据,但是 当我们添加到百万数据后,往普通表插入测试数据的性能就会明显降低.所以在这里建议 ...