manio的libpcap使用总结

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

要包含文件pcap.h

1.获取设备名
使用
char * pcap_lookupdev ( char * errbuf );
来获取设备名,例如返回"eth0",errbuf是出错信息字符串,一旦函数出错,其中将会包括出错信息
errbuf一般定义为
char errbuf[PCAP_ERRBUF_SIZE];

2.获取设备描述符
就像对文件操作时要取得文件描述符一样,在这里要取得网卡的描述符
pcap_t * pcap_open_live ( char * device, int snaplen, int promisc,
                          int to_ms, char * errbuf );
pcap_t就是网卡描述符的类型,
device是设备名,如eth0
snaplen是要抓获的最大的包的字节数
promisc如果为非0的话,则将网卡设为混杂模式
to_ms是超时时间,如果为0则永不超时
errbuf与上同

如果pcap_open_live返回NULL,则表明函数执行出错,errbuf的值将会被设置

3.循环处理包
int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)

pcap_loop会一直读取包,直到读完cnt个数据包
当cnt为负时,pcap_loop会永远循环运行
对于每一个包,pcap_loop会一直尝试读取,直到pcap_open_live中设置的to_ms时间达到时仍未成功读取包.
callback是一个回调函数,当抓取到一个包时,就会调用这个callback函数

callback的protype是
typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);
u_char(第一个参数)是从pcap_loop传入的值,即pcap_loop中的user.
const struct pcap_pkthdr是一个结构体,成员如下
              ts     a  struct timeval containing the time when the packet was
                     captured
              struct timeval {
                  time_t      tv_sec;     /* seconds */
                  suseconds_t tv_usec;    /* microseconds */
                };
       timeval中给出距1970年1月1日0时0分0秒的时间


              caplen a bpf_u_int32 giving the number of bytes  of  the  packet
                     that are available from the capture
       给出包的大小,以byte为单位

              len    a  bpf_u_int32  giving the length of the packet, in bytes
                     (which might be more than the number of  bytes  available
                     from  the  capture, if the length of the packet is larger
                     than the maximum number of bytes to capture)
       这个值可能比caplen大,因为包的实际大小有可能比程序中所设置的抓包的最大长度大.
const u_char *,指向包中最开始caplen比特大小数据.不过这些数据可能不是整个包的数据,因为有可能在pcap_open_live中设置的snaplen可能小于包的大小,所以就有可能得不到整个包,如果一定要得到整个包,可以将snaplen设置为65535

返回值:
pcap_loop返回-1,表明运行时出错
pcap_loop返回0,表明已经读取了cnt个包
pcap_loop返回-1,表明循环被pcap_breakloop()中止

4.关闭设备
void pcap_close(pcap_t *p)
关闭设备并释放资源

5.获取下一个包
const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)
这个函数其实是调用pcap_dispatch()(令参数cnt为1),返回指向包中数据的指针.在这个函数中,pcap_pkthdr结构没有提供.
当函数产生错误或者没有抓到包时,函数返回NULL,

6.编译过滤器
int pcap_compile(pcap_t *p, struct bpf_program *fp
                 char *str, int optimize, bpf_u_int32 netmask)
编译过滤字符串str,
netmask是要被过滤的子网掩码,这个参数只在检查IPV4广播地址时使用
optimize表明是否被优化

7.使用过滤器
int pcap_setfilter(pcap_t *p, struct bpf_program *fp)

//fedora core 6,gcc
//compile:gcc thisfile.c -o xthisfile -lpcap
#include <stdio.h>
#include 
<stdlib.h>
#include 
<pcap.h>
#include 
<errno.h>
#include 
<sys/socket.h>
#include 
<netinet/in.h>
#include 
<arpa/inet.h>
#include 
<netinet/if_ether.h> /* includes net/ethernet.h */


struct my_ip {
    u_int8_t    ip_vhl;        
/* header length, version */
#define IP_V(ip)    (((ip)->ip_vhl & 0xf0) >> 4)
#define IP_HL(ip)    ((ip)->ip_vhl & 0x0f)
    u_int8_t    ip_tos;        
/* type of service */
    u_int16_t    ip_len;        
/* total length */
    u_int16_t    ip_id;        
/* identification */
    u_int16_t    ip_off;        
/* fragment offset field */
#define    IP_DF 0x4000            /* dont fragment flag */
#define    IP_MF 0x2000            /* more fragments flag */
#define    IP_OFFMASK 0x1fff        /* mask for fragmenting bits */
    u_int8_t    ip_ttl;        
/* time to live */
    u_int8_t    ip_p;        
/* protocol */
    u_int16_t    ip_sum;        
/* checksum */
    
struct    in_addr ip_src,ip_dst;    /* source and dest address */
};


////////////////////////////////////////
//回调函数,用于对抓获的包做相应处理
void pkt_callback(u_char *arg1, const struct pcap_pkthdr *phdr,const u_char *packet)
{
    
struct in_addr ipaddr;//ipv4地址
    struct my_ip *ipptr; //ip数据报头指针
    struct tcphdr *tcpptr;//tcp数据报头指针
    struct ether_header *eptr;//以太网报头指针
    char *chtmp;
    
static int ipcnt=0,arpcnt=0;
    
if( packet == NULL ){
        printf(
"Didn't get any packet! ");
        exit(
1);
    }
    printf(
"*************************** ");
    printf(
"capure time:%s",ctime((const time_t*)&(phdr->ts.tv_sec)));
    printf(
"the length of packet captured:%ld; the total length:%ld ",
            phdr
->caplen,phdr->len);
    
//得到以太网帧结构的数据
    eptr = (struct ether_header*)packet;

    
if( ntohs(eptr->ether_type) == ETHERTYPE_IP ){
        printf(
"IP ");
    
        
//decode ip header
        printf("decoding ip header now ");
        
//将指针指向ip数据报报头
        ipptr = (struct my_ip* )(packet + sizeof(struct ether_header));
        printf(
"the total length of the IP packet:%d ",IP_HL(ipptr));
        printf(
"the version:%d ",IP_V(ipptr));
        printf(
"ttl:%d ",ipptr->ip_ttl);
        
        
++ipcnt;
    }
else if ( ntohs(eptr->ether_type) == ETHERTYPE_ARP){
        printf(
"ARP ");
        
++arpcnt;
    }
else{
        printf(
"Packet is not IP or ARP.(%x) ",ntohs(eptr->ether_type));
    }
        
    
//print number of packet
    printf("ip packet number:%d ",ipcnt);
    printf(
"arp packet number:%d ",arpcnt);

}

int main(int argc,char **argv)
{
    
char * dev; //设备名
    pcap_t * pt; //网卡设备描述符
    struct in_addr ipv4addr;//ipv4地址
    bpf_u_int32 netp;
    bpf_u_int32 maskp;
    u_char 
*packet;
    
struct pcap_pkthdr pdr; //包结构体,其中包括了包长度、指向包数据的指针
    char errbuf[PCAP_ERRBUF_SIZE];//存放错误信息
    struct ether_header *ethhd;//指向以太网头部的指针
    struct bpf_program *fp;//用于HOLD滤包程序
    
    
//查找网卡
    if( (dev = pcap_lookupdev(errbuf)) == NULL ){
        printf(
"lookupdev:%s ",errbuf);
        exit(
1);
    }
    
//打开设备,得到描述符
    if( (pt = pcap_open_live(dev, 10000100, errbuf)) == NULL){
        printf(
"pcap_open_live:%s ",errbuf);
        exit(
1);
    }
    
//得到网络IP及掩码
    if( pcap_lookupnet(dev, &netp, &maskp, errbuf) == -1 ){
        printf(
"pcap_lookupnet:%s ",errbuf);
        exit(
1);
    }

    
//打印网络环境信息
    ipv4addr.s_addr = netp;
    printf(
"================================ ");
    printf(
"device name:%s ",dev);
    printf(
"net:%s ",inet_ntoa(ipv4addr));
    ipv4addr.s_addr 
= maskp;
    printf(
"mask:%s ",inet_ntoa(ipv4addr));    
    printf(
"================================ ");

    
/////////////////////////////////////
    //开始包的相关处理

    
if( (pcap_loop(pt, -1, pkt_callback,NULL)) == -1 ){
        perror(
"pcap_loop");
        exit(
1);
    }    

    pcap_close(pt);
    printf(
"end of program ");
}

libpcap抓包延时问题分析 按照上面的描述就会有个问题,如果抓取的网络包不是连续的,就会是的pcap_loop进入阻塞模式,如果这个时候有网络数据包过来,触发处理包的回调函数会有约一分钟的延时,对于实时系统或者类似Wireshark、Tcpdump等工具那就能立即反应的系统来说很不实用,因此上述方式并不实用与这种场景。因此,如果没有数据包到达,pcap_loop函数就会一直等待。在默认情况下,pcap_loop函数的超时时间是1秒,也就是说,如果1秒内没有数据包到达,pcap_loop函数就会返回,然后再次等待。函数之前是不可用的。 阅读详情

相关推荐

PACP学习笔记三:PCAP方法说明

描述 用于创建数据包捕获句柄()以查看网络上的数据包。 source 是一个字符串,指定要打开的网络设备;在具有 2.2 或更高版本内核的 Linux 系统上,可以使用“any”或 NULL 的源参数来捕获来自所有接口的数据包。 返回的句柄必须先用 激活,然后才能用它捕获数据包;捕获的选项,例如混杂模式,可以在激活之前在句柄上设置。 成功时返回 pcap_t *,失败时返回 NULL。如果返回 NULL,则 errbuf 会填充适当的错误消息。假设 errbuf 至少能够保存 PCAP_ERRBUF_S

山鬼谣的专栏 8631

Linux中pcap_loop()函数

【代码】Linux中pcap_loop()函数。pcap_loop()函数是在Linux系统下用于数据包捕获的函数。它属于libpcap库,这个库提供了一种与系统无关的方式来捕获网络数据包。pcap_loop()函数允许用户指定一个回调函数,当捕获到满足条件的数据包时,就会调用这个回调函数来处理数据包,从而实现对网络流量的实时监控和分析。

luotuo28的博客 1333

pcap详解

pcap格式及API详解

7928

Pcap_loop函数

函数名称:int pcap_loop(pcap_t * p,int cnt, pcap_handler callback, uchar * user); 函数功能:捕获数据包,不会响应pcap_open_live()函数设置的超时时间 参数说明:p 是由pcap_open_live()返回的所打的网卡的指针;cnt用于设置所捕获数据包的个数;pcap_handler 是与void packet

那些年....的专栏 1万+

libpcap pcap_loop捕获包数据

pcap_loop, pcap_dispatch - process packets from a live capture or savefile 处理抓取的数据包 函数原型 #include <pcap/pcap.h> 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_hand

zhuzitop的博客 2279

libpcap库学习

下面开始正式讲解如何使用libpcap: 首先要使用libpcap,我们必须包含pcap.h头文件,可以在/usr/local/include/pcap/pcap.h找到,其中包含了每个类型定义的详细说明。 1.获取网络接口 首先我们需要获取监听的网络接口: 我们可以手动指定或让libpcap自动选择,先介绍如何让libpcap自动选择:char *pcap_lookupdev(char * errbuf)上面这个函数返回第一个合适的网络接口的字符串指针,如果出错,则errbuf存放出错信息字符串,e.

Kolane的博客 1436

pcap_loop

函数名称:int pcap_loop(pcap_t * p,int cnt, pcap_handler callback, uchar * user);  函数功能:捕获数据包,不会响应pcap_open_live()函数设置的超时时间  参数说明:p 是由pcap_open_live()返回的所打的网卡的指针;cnt用于设置所捕获数据包的个数;pcap_handler 是与void packet

lizhifeng2009的专栏 1320

pcap_loop()函数是阻塞调用吗

【代码】pcap_loop()函数是阻塞调用吗。当pcap_loop()函数开始执行时,它会一直等待符合条件的网络数据包到来。如果设置的cnt(要捕获的数据包数量)为一个正数,它会阻塞直到捕获到指定数量的数据包;如果cnt为-1,它会一直阻塞,持续捕获数据包,直到出现错误或者被手动停止(比如通过在另一个线程中发送信号来停止它)。

luotuo28的博客 700

pcap_loop 及callback

<br />对于最常用的 pcap_loop:<br />pcap_loop原型是pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user)<br />其中第一个参数是winpcap的句柄,第二个是指定捕获的数据包个数,如果为-1则无限循环捕获。第四个参数user是留给用户使用的。<br />第三个是回调函数其原型如下:<br />pcap_callback(u_char* argument,const struct pcap_pkthdr

brucetiancai的专栏 1564

WINPCAP抓包并用回调函数处理包

#include "pcap.h" void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); int main() { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t *

wjeson的专栏 6623

[总结] 浅谈渐进式优化LinuxPcap抓包历程(部分附代码)

最近一直在做pcap抓包,需求很简单就是指定一个或多个bpf语句抓计算机上所有网卡。不考虑性能开销和资源开销的话,实现方式很多。优化过程很长,主要考虑是线程数量的优化,以及使用非阻塞函数pcap_dispatch过程中产生pcap实例延迟问题。记下此文希望大家都能掌握这些技巧。

二次元怪兽的博客 1247

libpcap中主要函数使用介绍

PCAP_OPEN_LIVE 名字含义: open a device for capturing 使用方法: #include<pcap.h> char errbuf[PCAP_ERRBUF_SIZE]; pcap_t *pcap_open_live(const char *device,int snaplen,int promisc,int to_ms,char *errbuf); 简要描述: 这个函数用于获取一个在网络上查找并捕获包的句柄。 参数: device指代所指定要开启的网.

kking_edc的博客 4304

临近毕业了才搞明白pcap的一点用法

首先,PCAP_OPENFLAG_MAX_RESPONSIVENESS 就是设置最小拷贝为0   有数据包,立即触发回调函数 pcap_dispatch行为受以下几个设置的影响: 若pcap_setnonblock(0),表示阻塞模式,pcap_dispatch只有在mintocopy满,或者是timeout到时才返回,返回捕捉到的数据包数 pcap_setnonblock(1),非

zhiying678的专栏 2174

Libpcap的介绍与简单使用

Libpcap的介绍与简单使用

qq_43688708的博客 1798

winpcap 抓包函数pcap_loop(),停止问题

pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 第二个参数 cnt为指定的捕获包的个数 cnt=-1,无限捕获 cnt=0,捕获所有数据包,知道读取到EOF

zhangyixing_mj的博客 2047

winpcap抓包函数pcap_loop()

winpcap抓包函数pcap_loop()    VC6.0使用winpcap 1.下载winpcap的安装包,程序员开发包。(两个包) 2.执行安装包,这样你的机子就能运行winpcap程序了 3.解压开发包,在VC的option的include和lib中加入winpcap的include和lib 4. 在工程的setting中导入wpcap.

wjeson的专栏 6162

pcap_dispatch与pcap_loop使用区别

1.pcap_dispatch和pcap_loop使用回调函数结构都一样: static void process_packet(u_char *user, struct pcap_pkthdr *pHeadr, u_char *pkt_data) { // 如果process_packet定义在类中,那么必须以static修饰 } 2.pcap_dispatch和pcap_loop函数参数都一样: int pkts_read = -1; // 让libpcap一直抓包,如果pkts

wangzhicheng2013的专栏 5138

pcap编程深入解析

首先,该文章不限定OS不单针对Winpcap或者libpcap,对于Winpcap的特殊扩展使用了PS标示。        我以前使用过Winpcap,但并没有对pcap开发进行过深入解析。希望这篇文章可以深入浅出的讲清楚这个问题。Pcap是什么?它是个监视器,或者发生器,它可以监视,也可以发生,但它不能拦截。它可以在网络上增加一些消息,但不能阻止已经存在的消息。        获取设备列表

qdsuiyuan1984的专栏 1593
上一篇: 几个可运行的,可以说明问题的Ajax实例
下一篇: IBM Summer Intern、简历、笔试、一面
manio
博客等级 码龄21年 61粉丝 151原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值