在上一篇博客中简单对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. Linux 打开句柄限制的调整

    Linux 打开句柄限制的调整 参考文章: Linux---进程句柄限制总结(http://blog.csdn.net/jhcsdb/article/details/32338953) !! 本文内容 ...

  2. android使用ViewPager实现欢迎引导页

    android使用ViewPager实现欢迎引导页 大多数APP第一次启动的时候,都会有一个引导界面,左右滑动,到最后一张,用户点击才再次进入主界面.当第二次启动的时候,则直接进入主界面. 这种效果一 ...

  3. 【翻译】提示18——如何决定ObjectContext的生命周期

    原文地址:http://blogs.msdn.com/b/alexj/archive/2009/05/07/tip-18-how-to-decide-on-a-lifetime-for-your-ob ...

  4. 《java第一季之入门篇》的想法

    学习java也有一段时间了,但是考虑到自己现在上课.复习.考试等耗费很多时间,感觉没有静下心来的时间去写一个长期的博客.计划今年7月1号开始写一套关于java的入门篇博客文章,入门篇计划这样--涵盖j ...

  5. OAF开发概念和案例总结(项目总结)

    留看: 网上关于OAF学习的资料比较少,最近有些时间,整理了下自己在项目上的经验总结和同学们一下共享一下 和学友一起讨论一下OAF开发,还有两个比较复杂的系列正在整理中..... 一.OAF EO定义 ...

  6. 【一天一道LeetCode】#15 3Sum

    一天一道LeetCode系列 (一)题目 Given an array S of n integers, are there elements a, b, c in S such that a + b ...

  7. linux下ruby使用tcl/tk编程环境设置

    正常情况下最新的ruby都是不带tcl/tk选项编译的,所以我们在运行tcl/tk代码时都会发生找不到tk库的错误.解决办法很简单只要以tcl/tk选项编译ruby即可. 这里以ubuntu 15.0 ...

  8. Order Management Suite - Pricing and Availability Form Library

    In this Document   Purpose   Scope   Details   A. Form / Functional Issues   "Add to Selection& ...

  9. Fullpage.js全屏滚动jQuery插件

    兼容性: 支持 IE8+ 及其他现代浏览器. 主要功能: 1.支持鼠标滚动: 2.支持前进后退键盘控制; 3.多个回调函数; 4.支持手机.移动设备; 5.支持窗口缩放自动调整; 6.可设置滚动宽度. ...

  10. 关于web页面JApplet打印小票

    版权所有 做这个的例子太少,我把我做的示例亮出来 一.先说说需要的版本 1.我用的浏览器只有ie: 火狐只支持52版本以下,并且是java7.java8.chrome不支持 2.applet客户端打印 ...