Libpcap 作用 安装 socket 原始套接字 pcap_lookupdev pcap_open_live pcap_lookupnet pcap_compile pcap_loop

                                      粉丝不过W

socket 原始套接字回顾

   原始套接字

      开发者可发送任意的数据包到网上

      开发网络攻击等特殊软件

      需要开发者手动组织数据、各种协议包头、校验和计算

   创建方法:

//创建数据链路层的原始套接字
int sock_raw_fd = 0;
sock_raw_fd = socket(PF_PACKET, SOCK_RAM, htons(ETH_P_ALL));

 Libpcap 概念

      一个网络数据捕获开发包

     平台独立具有强大功能

    一套高层的编程接口的集合;隐藏了操作系统的细节,可捕获网上的所有,包括到达其他主机的数据包

      使用非常广泛,几乎只要涉及到网络数据包的捕获的功能,都可以用它开发,如 wireshark

      开发语言为 C 语言,也有基于其它语言的开发包,如 Python 语言的开发包 pycap

  Libpcap 主要的作用

        捕获各种数据包

          如:网络流量统计

       过滤网络数据包

         如:过滤掉本地上的一些数据,类似防火墙

      分析网络数据包

         如:分析网络协议,数据的采集

     存储网络数据包

        如:保存捕获的数据以为将来进行分析

Libpcap 的安装:

sudo apt-get install libpcap-dev

libpcap 开发实例

   libpcap 函数库开发应用程序基本步骤:

      打开网络设备

     设置过滤规则

     捕获数据

     关闭网络设备

  捕获网络数据包常用函数:

     pcap_lookupdev( )

    pcap_open_live()

    pcap_lookupnet( )

    pcap_compile( )

    pcap_setfilter( )

     pcap_next( )

     pcap_loop( )

      pcap_close( )

pcap_lookupdev

/*
 *function:
 *  得到可用的网络设备名指针
 *parameter:
 *  errbuf: 存放相关的错误信息
 *return:
 *  成功:设备名指针
 *  失败: NULL
 */
char *pcap_lookupdev(char *errbuf)

  如: 

    char *dev = NULL;
    char err_buf[100] = "";
    dev = pcap_lookupdev(err_buf);
    if(NULL == dev)
    {
        perror("pcap_lookupdev");
        exit(-1);
    } 

 pcap_open_live

/*
 *function:
 *  打开一个用于捕获数据的网络接口
 *parameter:
 *  device:  网络接口的名字
 *  snaplen:捕获数据包的长度
 *  promise:1 代表混杂模式, 其它非混杂模式
 *  to_ms:  等待时间
 *  ebuf:   存储错误信息
 *return:
 *  返回一个 Libpcap 句柄
 */
pcap_t *pcap_open_live(const char *device,int snaplen,int promisc,int to_ms,har *ebuf);

  如:

char error_content[PCAP_ERRBUF_SIZE] = "";
pcap_t *pcap_handle = NULL;
pcap_handle = pcap_open_live("eth0", 1024, 1, 0, error_content);

 pcap_lookupnet

/*
 *function:
 *  获得指定网络设备的网络号和掩码
 *parameter:
 *  device:网络设备名
 *  netp:存放网络号的指针
 *  maskp:存放掩码的指针
 *  errbuf:存放出错信息
 *retrun:
 *  成功: 0
 *  失败: -1
 */
int pcap_lookupnet(char *device, buf_u_int32 *netp, bpf_u_int32 *maskp, char *errbuf);
unsigned int net_ip;    //网络地址
unsigned int net_mask;    //子网掩码

res = pcap_lookupnet(dev, &net_ip, &net_mask, error_content);
if(res == -1)
{
    perror("pcap_lookupnet");
    exit(-1);
}

 pcap_compile

/*
 *function:
 *  编译 BPF 过滤规则
 *parameter:
 *  p:       Libpcap 句柄
 *  program: bpf 过滤规则
 *  buf:     过滤规则字符串
 *  optimize:优化
 *  mask:    掩码
 *retrun:
 *  成功: 0
 *  失败: -1
 */
int pcap_compile(pcap_t *p, struct bpf_program *program, char *buf, int optimize, bpf_u_int32 mask);

  如:

struct buf_program buf_filter;
char *bpf_filter_string = "arp or ip";

//编译BPF过滤规则
if(pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, 0xffffff00) < 0)
{
    perror("pcap_compile");
}

 pcap_setfilter

/*
 *function:
 *  设置 BPF 过滤规则
 *parameter:
 *  p:Libpcap 句柄
 *  fp:BPF 过滤规则
 *return:
 *  成功: 0
 *  失败: -1
 */
int pcap_setfilter(pcap *p, struct bpf_program *fp);
//设置过滤规则
if(pcap_setfilter(pcap_handle, &bpf_filter) < 0)
{
    perror("pcap_setfilter");
}

 pcap_next

/*
 *function:
 *  捕获一个网络数据包
 *parameter:
 *  p:Libpcap 句柄
 *  h:数据包头
 *return:
 *  捕获的数据包的地址
 */
const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h);
struct pcap_pkthdr protocol_header;
unsigned char *p_packet_content = NULL;
p_packet_content = pcap_next(pcap_handle, &protocol_header);

 pcap_loop

/*
 *function:
 *  循环捕获网络数据包,直到遇到错误或者满足退出条件;
 *每次捕获一个数据包就会调用 callback 指示的回调函数,所以可在回调函数中进行数据包的处理操作
 *parameter:
 *  p:       Libpcap 句柄
 *  cnt:     指定捕获数据包的个数,如 -1,会永无休止的捕获
 *  callback:回调函数
 *  user:    向回调函数中传递的参数
 */
int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
if(pcap_loop(pcap_handle, -1, ethernet_protocol_callback, NULL) < 0)
{
    perror("pcap_loop");
}

 pcap_close

/*
 *function:
 *  关闭 Libpcap 操作,并销毁相应的资源
 *parameter:
 *  p:关闭的 Libpcap 句柄
 */
void pcap_close(pcap_t *p);
pcap_close(pcap_handle);

捕获第一个网络数据包

/*
 *function:
 *  通过捕获一个网络数据包,然后对其进行数据的解析分析
 */
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <arpa/inet.h>
#include <time.h>

#define BUFSIZE 1514

struct ether_header
{
    unsigned char ether_dhost[6];	//目的mac
    unsigned char ether_shost[6];	//源mac
    unsigned short ether_type;		//以太网类型
};

/*
 *function:
 *  通过使用libpcap接收一个数据包,然后对数据包进行解析
 */
int main(int argc,char *argv[])
{
    pcap_t * pcap_handle = NULL;
    char error_content[100] = "";	                // 出错信息
    unsigned char *p_packet_content = NULL;		// 保存接收到的数据包的起始地址
    unsigned char *p_mac_string = NULL;			// 保存mac的地址,临时变量
    unsigned short ethernet_type = 0;			// 以太网类型
    char *p_net_interface_name = NULL;	    	// 接口名字
    struct pcap_pkthdr protocol_header;
    struct ether_header *ethernet_protocol;

    //获得接口名
    p_net_interface_name = pcap_lookupdev(error_content);
    if(NULL == p_net_interface_name)
    {
        perror("pcap_lookupdev");
        exit(-1);
    }

    //打开网络接口
    pcap_handle = pcap_open_live(p_net_interface_name, BUFSIZE, 1, 0, error_content);
    p_packet_content = pcap_next(pcap_handle, &protocol_header);

    printf("----------------------------------------------------\n");
    printf("capture a Packet from p_net_interface_name :%s\n", p_net_interface_name);
    printf("Capture Time is :%s", ctime((const time_t *)&protocol_header.ts.tv_sec));
    printf("Packet Lenght is :%d\n",protocol_header.len);

    //分析以太网中的 源mac、目的mac
    ethernet_protocol = (struct ether_header *)p_packet_content;

    p_mac_string = (unsigned char *)ethernet_protocol -> ether_shost;//获取源mac
    printf("Mac Source Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(p_mac_string + 0),
                                                                   *(p_mac_string + 1),
                                                                   *(p_mac_string + 2),
                                                                   *(p_mac_string + 3),
                                                                   *(p_mac_string + 4),
                                                                   *(p_mac_string + 5));

    p_mac_string = (unsigned char *)ethernet_protocol->ether_dhost;//获取目的mac
    printf("Mac Destination Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(p_mac_string + 0),    
                                                                        *(p_mac_string + 1),
                                                                        *(p_mac_string + 2),
                                                                        *(p_mac_string + 3),
                                                                        *(p_mac_string + 4),
                                                                        *(p_mac_string + 5));

    //获得以太网的数据包的地址,然后分析出上层网络协议的类型
    ethernet_type = ntohs(ethernet_protocol->ether_type);
    printf("Ethernet type is :%04x\t",ethernet_type);
    switch(ethernet_type)
    {
        case 0x0800 : 
            printf("The network layer is IP protocol\n");    //ip
            break;    
        case 0x0806 :
            printf("The network layer is ARP protocol\n");    //arp
            break;
        case 0x0835 :
            printf("The network layer is RARP protocol\n");    //rarp
            break;
        default : 
            printf("The network layer unknow!\n");
            break;
    }

    pcap_close(pcap_handle);
    return 0;
}

      gcc 编译时需要加上-lpcap
       运行时需要使用超级权限
 

 捕获指定类型数据包,如 ARP

/*
 *function:
 *  安排规则,接收一个数据包
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <pcap.h>

#define BUFSIZE 1514

struct ether_header
{
    unsigned char ether_dhost[6];	//目的mac
    unsigned char ether_shost[6];	//源mac
    unsigned short ether_type;		//以太网类型
};

int main(int argc,char *argv[])
{
    pcap_t * pcap_handle;
    int ret = 0;
    char error_content[512] = "";	// 出错信息
    const unsigned char *p_packet_content = NULL; // 保存接收到的数据包的起始地址
    unsigned char *p_mac_string = NULL;			// 保存mac的地址,临时变量
    unsigned short ethernet_type = 0;			// 以太网类型
    char *p_net_interface_name = "eth0";		// 接口名字
    struct pcap_pkthdr protocol_header;
    struct ether_header *ethernet_protocol = NULL;
    struct bpf_program bpf_filter;
    char *bpf_filter_string = "arp or ip";
    bpf_u_int32 netp = 0, maskp = 0;

    //打开网络接口
    p_net_interface_name = pcap_lookupdev(error_content);
    if(NULL == p_net_interface_name)
    {
        perror("pcap_lookupdev");
		exit(-1);
    }

    pcap_handle = pcap_open_live(p_net_interface_name, 1024, 1, 0, error_content);

    //获得网络号和掩码
    ret = pcap_lookupnet(p_net_interface_name, &netp, &maskp, error_content);
    if(ret == -1)
    {
        perror("pcap_lookupnet");
        exit(-1);
    }

    //编译BPF过滤规则
    if(pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, maskp) < 0)
    {
        perror("pcap_compile");
    }

    //设置过滤规则
    if(pcap_setfilter(pcap_handle,&bpf_filter) < 0)
    {
        perror("pcap_setfilter");
    }

    while(1)
    {
        //所捕获的数据包的地址
        p_packet_content = pcap_next(pcap_handle, &protocol_header);
        printf("-----------------------------------------------\n");
        printf("capture a Packet from p_net_interface_name :%s\n",p_net_interface_name);
        printf("Capture Time is :%s",ctime((const time_t *)&protocol_header.ts.tv_sec));
        printf("Packet Lenght is :%d\n",protocol_header.len);
        //分析以太网中的 源mac、目的mac
        ethernet_protocol = (struct ether_header *)p_packet_content;  //以太网帧头部
        p_mac_string = (unsigned char *)ethernet_protocol->ether_shost;//获取源mac
        printf("Mac Source Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(p_mac_string + 0),
                                                                        *(p_mac_string + 1),
                                                                        *(p_mac_string + 2),
                                                                        *(p_mac_string + 3),
                                                                        *(p_mac_string + 4),
                                                                        *(p_mac_string + 5));
        p_mac_string = (unsigned char *)ethernet_protocol->ether_dhost;//获取目的mac
        printf("Mac Destination Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(p_mac_string + 0),
                                                                            *(p_mac_string + 1),
                                                                            *(p_mac_string + 2),
                                                                            *(p_mac_string + 3),
                                                                            *(p_mac_string + 4),
                                                                            *(p_mac_string + 5));

        //获得以太网的数据包的地址,然后分析出上层网络协议的类型
        ethernet_type = ntohs(ethernet_protocol->ether_type);
        printf("Ethernet type is :%04x\n",ethernet_type);
        switch(ethernet_type)
        {
            case 0x0800:
                printf("The network layer is IP protocol\n");    //ip
                break;
            case 0x0806:
                printf("The network layer is ARP protocol\n");    //arp
                break;
            case 0x0835:
                printf("The network layer is RARP protocol\n");    //rarp
                break;
            default:
                printf("The network layer unknow!!!\n");
                break;
        }
    }
    pcap_close(pcap_handle);
    return 0;
}

捕获多个网络数据包

/*
 *function:
 *  通过回调函数的方式,来抓取多个网络数据包
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pcap.h>
#include <arpa/inet.h>
#include <unistd.h>

#define BUFSIZE 1514

struct ether_header
{
    unsigned char ether_dhost[6];	//目的mac
    unsigned char ether_shost[6];	//源mac
    unsigned short ether_type;		//以太网类型
};

void ethernet_protocol_callback(unsigned char *argument,
                                const struct pcap_pkthdr *packet_heaher,
                                const unsigned char *packet_content);

int main(int argc, char *argv[])
{
    char error_content[100];	//出错信息
    pcap_t * pcap_handle;
    unsigned char *mac_string;
    unsigned short ethernet_type;    //以太网类型
    unsigned int net_ip;			//网络地址
    unsigned int net_mask;			//子网掩码
    char *net_interface = NULL;	    //接口名字
    int res = 0;
    struct pcap_pkthdr protocol_header;
    struct ether_header *ethernet_protocol;
    struct bpf_program bpf_filter;
    char bpf_filter_string[] = "ip";

    //获取网络接口
    net_interface = pcap_lookupdev(error_content);
    if(NULL == net_interface)
    {
        perror("pcap_lookupdev");
        exit(-1);
    }

    res = pcap_lookupnet(net_interface, &net_ip, &net_mask, error_content);
    if(-1 == res)
    {
        perror("pcap_loopupnet");
        exit(-1);
    }

    //打开网络接口
    pcap_handle = pcap_open_live(net_interface, BUFSIZE, 1, 0, error_content);
    //编译BPF过滤规则
    pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, net_mask);
    pcap_setfilter(pcap_handle, &bpf_filter);//设置过滤规则

    if(pcap_loop(pcap_handle,-1,ethernet_protocol_callback,NULL) < 0)
    {
        perror("pcap_loop");
    }

    pcap_close(pcap_handle);
	return 0;
}

// 回调函数
void ethernet_protocol_callback(unsigned char *argument,
                                const struct pcap_pkthdr *packet_heaher,
                                const unsigned char *packet_content)
{
    unsigned char *mac_string;
    struct ether_header *ethernet_protocol;
    unsigned short ethernet_type;	//以太网类型

    printf("----------------------------------------------------\n");
    printf("%s\n", ctime((time_t *)&(packet_heaher->ts.tv_sec))); //转换时间
    ethernet_protocol = (struct ether_header *)packet_content;

    mac_string = (unsigned char *)ethernet_protocol->ether_shost;   //获取源mac地址
    printf("Mac Source Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(mac_string + 0),
                                                                   *(mac_string + 1),
                                                                   *(mac_string + 2),
                                                                   *(mac_string + 3),
                                                                   *(mac_string + 4),
                                                                   *(mac_string + 5));

    mac_string = (unsigned char *)ethernet_protocol->ether_dhost;  //获取目的mac
    printf("Mac Destination Address is %02x:%02x:%02x:%02x:%02x:%02x\n",*(mac_string + 0),
                                                                        *(mac_string + 1),
                                                                        *(mac_string + 2),
                                                                        *(mac_string + 3),
                                                                        *(mac_string + 4),
                                                                        *(mac_string + 5));

    ethernet_type = ntohs(ethernet_protocol->ether_type);    //获得以太网的类型
    printf("Ethernet type is :%04x\n",ethernet_type);
    switch(ethernet_type)
    {
        case 0x0800:
            printf("The network layer is IP protocol\n");    //ip
            break;
        case 0x0806:
            printf("The network layer is ARP protocol\n");    //arp
            break;
        case 0x0835:
            printf("The network layer is RARP protocol\n");    //rarp
            break;
        default:
            break;
    }

    usleep(800*1000);
}

猜你喜欢

转载自blog.csdn.net/qq_44226094/article/details/105714053