网络编程:拆分数据包---libpcap库

使用libpcap对抓到的数据报进行拆分
安装:sudo apt-get install libpcap-dev
1、打开网络设备
获取可用的网络设备名指针

char *pcap_lookupdev(char *errbuf)

打开一个用于捕获数据的网络接口

pcap_t *pcap_open_live(const char *device,
					   int snaplen,
					   int promise,
					   int to_ms,
					   char *ebuf)

捕获一个网络数据

const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)

2、设置过滤规则

​ 1)先编译过滤规则

int pcap_compile(pcap_t *p,
 			    struct bpf_program *program,
				char *buf,
				int optimize,
				bpf_u_int32 mask)  2

设置过滤规则

int pcap_setfilter(pcap *p, struct bpf_program *fp)

3、捕获数据 【重要】

4、关闭网络设备

void pcap_close(pcap_t *p)

代码示例:

#include <pcap/pcap.h>

#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>


int main(int argc, char const *argv[])
{
    char error[128]="";
    char *device_name = pcap_lookupdev(error);  // 自动查询网卡设备
    if(device_name == NULL){
        printf("error: %s\n", error);
        return -1;
    }

    uint32_t ip, netmask; // 网络ID和子网掩码
    int n = pcap_lookupnet(device_name,&ip, &netmask,error);
    if(n == -1){
        printf("error: %s\n", error);
        return -1;
    }
    uint8_t ip_[INET_ADDRSTRLEN] = "";
    inet_ntop(AF_INET, &ip, ip_, INET_ADDRSTRLEN);
    printf("网卡名: %s, %s\n", device_name, ip_);  

    
    // 打开网络接口 (混杂模式、打开网络接口可以等待 1s ,可以接收最大1518的数据报)
    pcap_t *cap = pcap_open_live(device_name, 1518, 0, 0, error);
    if(cap == NULL){
        printf("error: %s\n", error);
        return -1;
    }

    // 获取数据报
    while(1){
        struct pcap_pkthdr hdr;  // 抓包的时间, 数据长度,实际数据长度(报文长度)
        const u_char *data = pcap_next(cap, &hdr);
       
        // 从data中获取源/目标ip和源/目标端口号
        // data: 14 mac报文
        uint16_t type = ntohs( *((uint16_t *)(data + 12))) ; // 获取mac报文的type       
        if(type == 0x0800){ // 是IP报文
            uint32_t sip = *((uint32_t *)(data+26));
            uint32_t dip = *((uint32_t *)(data+30));
            uint8_t  protocal = *(data+23);  // 14+8+1

            uint8_t srcip[16]= "", dstip[16]="";
            inet_ntop(AF_INET, &sip, srcip, 16);
            inet_ntop(AF_INET, &dip, dstip, 16);

            if(protocal == 17){
                const uint8_t *udp_data = data+14+20+8;
                if(strncmp(udp_data, "hi",2) == 0)
                    printf("%s -> %s protocol(%d): %s\n", srcip, dstip, protocal, data+14+20+8);
                else if(strncmp(udp_data, "bye",3) == 0) break;
            }
        }
    }
    pcap_close(cap); // 关闭网络接口
    return 0;
}

代码示例 2:

#include <pcap/pcap.h>

#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

// 获取数据的回调函数
void capdata_callback(u_char *usrarg, const struct pcap_pkthdr *hdr, const u_char *data){
    if(hdr->caplen <= 0 || data == NULL) return;
    printf("datalen : %d ", hdr->caplen);

     // 获取mac报文中的类型
     uint16_t type = ntohs(*( (uint16_t *)(data+12) ));
     printf("\ntype : %x", type);

     if(type == 0x0800){  // IP 报文
         // 获取IP报文的协议类型
         uint8_t protocol = *(data+14+9);
          printf("\nprotocl : %d\n", protocol);
         if(protocol == 17){
            // 获取UDP的端口号
            uint16_t srcport = ntohs( *(uint16_t *)(data+14+20) );
            uint16_t dstport = ntohs( *(uint16_t *)(data+14+20+2) );
            const uint8_t *udp_data = data+14+20+8;
            printf("udp %d -> %d: %s\n", srcport, dstport, udp_data);
         }
     }
}

int main(int argc, char const *argv[])
{
    char error[128]="";
    char *device_name = pcap_lookupdev(error);  // 自动查询网卡设备
    if(device_name == NULL){
        printf("error: %s\n", error);
        return -1;
    }

    
    // 打开网络接口 (非混杂模式、打开网络接口可以不等待 ,可以接收最大1518的数据报)
    pcap_t *cap = pcap_open_live(device_name, 1518, 0, 0, error);
    if(cap == NULL){
        printf("error: %s\n", error);
        return -1;
    }

    // 获取网络掩码
    bpf_u_int32 netmask, netip;
    pcap_lookupnet(device_name, &netip, &netmask, NULL);

    // 设置过滤条件
    struct bpf_program program; // bpf的规则程序
    if(pcap_compile(cap, &program, "host 10.35.184.190 and src port 8000", 0, netmask) != 0){
        perror("pcap_compile");
        return -1;
    }

    pcap_setfilter(cap, &program);  // 设置bpf过滤规则程序

    // 获取数据报
    int n = pcap_loop(cap, 10, capdata_callback, NULL);  // 内部循环获取数据,并调用回调函数将数据传入
    printf("pcap_loop ->%d \n", n);

    pcap_close(cap); // 关闭网络接口
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值