在上一篇博客中简单对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开发性能分析

    1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结.我一总结的都说到了很多优化注意事项,但是看过这些文章后大多数存在一个问题就是只 ...

  2. Java-ServletOutputStream

    /** * Provides an output stream for sending binary data to the * client. A <code>ServletOutput ...

  3. PS 滤镜——极坐标变换到平面坐标

    %%% 极坐标到平面坐标 clc; clear all; close all; addpath('E:\PhotoShop Algortihm\Image Processing\PS Algorith ...

  4. 解决Cell重用内容混乱的几种简单方法,有些方法会增加内存

    重用实现分析 查看UITableView头文件,会找到NSMutableArray*  visiableCells,和NSMutableDictnery* reusableTableCells两个结构 ...

  5. linux下利用ruby做系统备份与还原

    啥都不说了,都在代码里 :) #!/usr/bin/ruby BAK_PATH = "/media/backup.tar.xz" def to_backup exclude_fil ...

  6. 八、Join 连接查询

    文档目录 开发中...

  7. CALayer简介

    一.什么是CALayer * 在iOS系统中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮.一个文本标签.一个文本输入框.一个图标等等,这些都是UIView. * 其实UIView之所以 ...

  8. 移动端 slide拖拽

    <html> <head> <meta charset="UTF-8"> <meta name="viewport" ...

  9. 用js来实现那些数据结构14(树02-AVL树)

    在使用二叉搜索树的时候会出现 一个问题,就是树的一条分支会有很多层,而其他的分支却只有几层,就像下面这样: 如果数据量够大,那么我们在某条边上进行增删改查的操作时,就会消耗大量的时间.我们花费精力去构 ...

  10. 听《津津乐道》ThinkPad专题节目有感

    自2011年使用Mac以来,就没怎么想过要再换一个windows使用,可是前几天听了<津津乐道>播客节目,主播朱峰讲了ThinkPad的使用经历,这个倒是让我回想起第一次见到IBM电脑时的 ...