libcap应用:按协议抓取网络包

本文介绍了一个使用C++实现的网络包捕获与解析程序,通过libpcap库进行网络监听,解析并打印出捕获的数据包的详细信息,包括源MAC、目的MAC、源IP、目的IP、端口号及载荷等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <stdint.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <pcap.h>
#include <netdb.h>
#include <iostream>
#include <string>
class capature_packet_show {
public:
    capature_packet_show() = default;
    virtual ~capature_packet_show() = default;
    capature_packet_show(const capature_packet_show &) = delete;
    capature_packet_show & operator = (const capature_packet_show &) = delete;
public:
    bool init() {
        return init_pcap_handle();
    }
    inline unsigned int get_net() const {
        return net_;
    }
    inline unsigned int get_mask() const {
        return mask_;
    }
    inline const char *get_net_string() const {
        return net_string_;
    }
    inline const char *get_mask_string() const {
        return mask_string_;
    }
    inline void set_filter(const char *filter) {
        filter_ = filter;
    }
private:
    inline void init_net_addr() {
        struct in_addr addr = { 0 };
        addr.s_addr = net_;
        net_string_ = inet_ntoa(addr);
        std::cout << "网络地址:" << net_string_ << std::endl;
        addr.s_addr = mask_;
        mask_string_ = inet_ntoa(addr);
        std::cout << "网络掩码:" << mask_string_ << std::endl;
    }
    bool init_pcap_handle() {
        char err[PCAP_ERRBUF_SIZE] = "";
        char *dev = pcap_lookupdev(err);
        if (!dev) {
            std::cerr << "查询网络设备错误:" << err << std::endl;
            return false;
        }
        std::cout << "获取网络设备:" << dev << std::endl;
        if (pcap_lookupnet(dev, &net_, &mask_, err) < 0) {
            std::cerr << "查询网络号和掩码失败:" << err << std::endl;
            return false;
        }
        std::cout << "网络号:" << net_ << " 掩码:" << mask_ << std::endl;
        init_net_addr();
        handle_ = pcap_open_live(dev, BUFSIZ, 1, 1000, err);        // 1 -- 混杂模式 1000 - 1000毫秒超时
        if (!handle_) {
            std::cerr << "打开网络设备失败:" << err << std::endl;
            return false;
        }
        struct bpf_program fp = { 0 };
        if (pcap_compile(handle_, &fp, filter_, 1, mask_) < 0) {
            std::cerr << "过滤器解析失败" << pcap_geterr(handle_) << std::endl;
            pcap_close(handle_);
            return false;
        }
        if (pcap_setfilter(handle_, &fp) < 0) {
            std::cerr << "过滤器安装失败" << pcap_geterr(handle_) << std::endl;
            pcap_close(handle_);
            return false;
        }
        std::cout << "开始循环抓包..." << std::endl;
        int id = 0;
        if (pcap_loop(handle_, -1, get_packet, (u_char *)(&id)) < 0) {
            std::cerr << "循环抓包失败" << pcap_geterr(handle_) << std::endl;
            pcap_close(handle_);
            return false;
        }
        pcap_close(handle_);
        return true;
    }
private:
    static void print_mac(const unsigned char* mac_addr) {
        int i = 0;
        for (;i < 5;i++) {
            printf("%.2x:", mac_addr[i]);       // 16进制,两位宽度
		}
        printf("%.2x", mac_addr[i]); 
    }
    static void print_ip(const unsigned char* ip_addr) {
        int i = 0;
        for (;i < 3;++i) {
            printf("%d.", ip_addr[i]);
        }
        printf("%d", ip_addr[i]);
    }
    static void print_protocol_type(unsigned int protocol_type) {
        switch (protocol_type) {
        case ETHERTYPE_IP:
            std::cout << "IPV4" << std::endl;
            break;
        case ETHERTYPE_PUP:
            std::cout << "PUP" << std::endl;
            break;
        case ETHERTYPE_ARP:
            std::cout << "ARP" << std::endl;
            break;
        default:
            std::cout << "unknow protocal." << std::endl;
            break;
        }
    }
    static void process_ip_packet(const struct pcap_pkthdr *pkthdr, const u_char *packet) {
        struct ip *ip_header = nullptr;
        struct icmphdr *icmp_header = nullptr;
        struct tcphdr *tcp_header = nullptr;
        struct udphdr *udp_header = nullptr;
        struct ether_arp *arp_packet = nullptr;
        ip_header = (struct ip *)(packet + sizeof(struct ether_header));
        std::cout << "源IP地址:";
        print_ip((unsigned char *)&(ip_header->ip_src));
        std::cout << std::endl;
        std::cout << "目的IP地址:";
        print_ip((unsigned char *)&(ip_header->ip_dst));
        std::cout << std::endl;
        switch (ip_header->ip_p) {
        case 1:
            std::cout << "传输层协议是ICMP" << std::endl;
            break;
        case 2:
            std::cout << "传输层协议是IGMP" << std::endl;
            break;
        case 6:
            std::cout << "传输层协议是TCP" << std::endl;
            tcp_header = (struct tcphdr*)(packet + sizeof(struct ether_header) + sizeof(struct ip));
            std::cout << "目的端口:" << ntohs(tcp_header->dest) << std::endl;
            std::cout << "源端口:" << ntohs(tcp_header->source) << std::endl;
            std::cout << "Payload:" << std::endl;
            std::cout << "字节数:" << pkthdr->len << std::endl;
            print_payload(packet, pkthdr->len);
            break;
        case 7:
            std::cout << "传输层协议是UDP" << std::endl;
            udp_header = (struct udphdr*)(packet + sizeof(struct ether_header) + sizeof(struct ip));
            std::cout << "目的端口:" << ntohs(udp_header->dest) << std::endl;
            std::cout << "源端口:" << ntohs(udp_header->source) << std::endl;
            std::cout << "Payload:" << std::endl;
            std::cout << "字节数:" << pkthdr->len << std::endl;
            print_payload(packet, pkthdr->len);
            break;
        default:
            std::cerr << "未知协议." << std::endl;
            break;
        }
    }
    static void print_payload(const unsigned char *payload, int len, int text) {
        for (int i = 0;i < len;i++) {
            if (1 == text) {
                printf("%c", payload[i]);
            }
            else {
                printf("%.2x", payload[i]);
            }
            if (0 == (i + 1) % 16) {
                std::cout << std::endl;
            }
        }
    }
    static void print_payload(const unsigned char *payload, int len) {
        print_payload(payload, len, 0);
        print_payload(payload, len, 1);
    }
    static void get_packet(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet) {
        static uint64_t packet_num_ = 0;
        std::cout << "收到包的时间:" << ctime((const time_t*)&(pkthdr->ts).tv_sec) << std::endl;
        std::cout << "收到包的数量:" << ++packet_num_ << std::endl;
        std::cout << "收到包的字节数:" << pkthdr->len << std::endl;
        struct ether_header *eth = (struct ether_header *)(packet);
        std::cout << "源MAC地址:";
        print_mac(eth->ether_shost);
        std::cout << std::endl;
        std::cout << "目的MAC地址:";
        print_mac(eth->ether_dhost);
        std::cout << std::endl;
        unsigned int protocol_type = ntohs(eth->ether_type);
        print_protocol_type(protocol_type);
        if (ETHERTYPE_IP == ETHERTYPE_IP) {
            process_ip_packet(pkthdr, packet);
        }
    }
private:
    bpf_u_int32 net_ = 0;
    bpf_u_int32 mask_ = 0;
    const char *net_string_ = "";
    const char *mask_string_ = "";
    const char *filter_ = "ip";
    pcap_t *handle_ = nullptr;         // libpcap设备描述符号

};
int main() {
    capature_packet_show cps;
    if (false == cps.init()) {
        std::cerr << "init failed." << std::endl;
        return -1;
    }

    return 0;
}
g++ -std=c++11 -g -o test capture_packet_show.cpp -I ./  -lpcap 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值