使用libpcap获取http报文
在上一篇博客中简单对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报文的更多相关文章
- Python编程系列---获取请求报文行中的URL的几种方法总结
在浏览器访问web服务器的时候,服务器收到的是一个请求报文,大概GET请求的格式大概如下: 先随便拿到一个请求报文,蓝色即为我们要获取的 GET /index.html HTTP/1.1 Hos ...
- 发送xml报文去第三方请求获取xml报文数据
import java.io.*; import java.net.HttpURLConnection; import java.net.MalformedURLException; import j ...
- Selenium自动化获取Http报文信息并判断当前API状态
public int loadingFinishedCount(WebDriver driver){ LogEntries logs = driver.manage().logs().get(&quo ...
- 使用JAVA获取JSON报文
基本JSON格式: { "name": "liming", "age": "13", "array" ...
- NetCore 中间件获取请求报文和返回报文
using System; using System.IO; namespace WebApi.Restful.Middlewares { public class MemoryWrappedHttp ...
- Servlet&JSP-HTTP报文头获取及应用
完整代码请参考:https://github.com/devway9/java-exercise/tree/master/servlet-jsp 目录 1 HttpServletRequest获取报文 ...
- Axis通过方法获取webService请求报文
MessageContext messageContext = _call.getMessageContext(); Message reqMsg = messageContext.getReques ...
- SNMP报文抓取与分析(一)
SNMP报文抓取与分析(一) 1.抓取SNMP报文 SNMP报文的形式大致如下图所示 我们这里使用netcat这个工具来抓取snmp的PDU(协议数据单元).(因为我们并不需要前面的IP和UDP首部) ...
- ISO8583报文解析
在此只写了一个8583报文的拆包,组包其实也差不多的. 不多说直接上文件, 具体思路过程,在解析类里面写的有. 其中包含了四个文件 8583resp.txt报文 ISO8583medata配置文件 B ...
随机推荐
- Android OnLowMemory和OnTrimMemory
1.OnLowMemory 是Android提供的API,在系统内存不足,所有后台程序(优先级为background的进程,不是指后台运行的进程)都被杀死时,系统会调用OnLowMemory. 系统提 ...
- FFMPEG结构体分析:AVFormatContext
注:写了一系列的结构体的分析的文章,在这里列一个列表: FFMPEG结构体分析:AVFrameFFMPEG结构体分析:AVFormatContextFFMPEG结构体分析:AVCodecContext ...
- android应用资源预编译,编译和打包全解析
我们知道,在一个APK文件中,除了有代码文件之外,还有很多资源文件.这些资源文件是通过Android资源打包工具aapt(Android Asset Package Tool)打包到APK文件里面的. ...
- IOS 与ANDROID框架及应用开发模式对比一
IOS 和ANDROID操作系统都是目前流行的移动操作系统,被移动终端和智能设备大量采用,两者都采用了先进的软件技术进行设计,为了方便应用开发两者都采用了先进的设计模式.两者在框架设计上都采用了什么技 ...
- Java中使用C3P0连接池
先看官网给的范例: import java.sql.*; import javax.naming.*; import javax.sql.DataSource; import com.mchange. ...
- 熊猫猪新系统测试之一:Windows 10 技术预览版
话说本猫不用windows很多年了呀!不过看到微软最新的Windows10还是手痒了,想安装体验一把.于是第一时间下载,并做成usb引导安装镜像,在08年的老台式机上安装尝鲜鸟.下载ISO和安装方法这 ...
- SpringBoot2.0之二 新建RESTfull风格项目
1.新建一个Maven项目(具体方法可以参照 SpringBoot之一) 2.先建一个User类 package com.somta.springboot.pojo; public class Use ...
- 什么才是java的基础知识?
近日里,很多人邀请我回答各种j2ee开发的初级问题,我无一都强调java初学者要先扎实自己的基础知识,那什么才是java的基础知识?又怎么样才算掌握了java的基础知识呢?这个问题还真值得仔细思考. ...
- 排序算法入门之堆排序(Java实现)
堆排序 在学习了二叉堆(优先队列)以后,我们来看看堆排序.堆排序总的运行时间为O(NlonN). 堆的概念 堆是以数组作为存储结构. 可以看出,它们满足以下规律: 设当前元素在数组中以R[i]表示,那 ...
- java 垃圾回收总结(1)
java 垃圾回收总结(1) 以前看过很多次关于垃圾回收相关的文章,都只是看过就忘记了,没有好好的整理一下,发现写文章可以强化自己的记忆. java与C,c++有很大的不同就是java语言开发者不 ...