通过libpcap监控相关ip和端口流量

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcap.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>

#define SAMPLE_COUNT 0  // 0表示无限采样
#define TARGET_MAX 32
#define INTERVAL 2      // 采样间隔(秒)

typedef struct {
    const char *ip;
    int port;
    unsigned long long bytes_sent;
    unsigned long long bytes_recv;
    double send_mbps;
    double recv_mbps;
} target_t;

target_t targets[TARGET_MAX];
int target_count = 0;
int link_offset = 14;
volatile int running = 1;

void signal_handler(int sig) {
    running = 0;
}

void add_target(const char *ip, int port) {
    if(target_count >= TARGET_MAX) {
        fprintf(stderr, "Too many targets!\n");
        exit(1);
    }
    targets[target_count].ip = ip;
    targets[target_count].port = port;
    targets[target_count].bytes_sent = 0;
    targets[target_count].bytes_recv = 0;
    targets[target_count].send_mbps = 0.0;
    targets[target_count].recv_mbps = 0.0;
    target_count++;
}

int get_link_offset(pcap_t *handle) {
    int linktype = pcap_datalink(handle);
    if(linktype == DLT_EN10MB) return 14;
    else if(linktype == DLT_LINUX_SLL) return 16;
    else {
        fprintf(stderr, "Unsupported datalink type: %d\n", linktype);
        exit(1);
    }
}

void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {
    (void)user;
    
    if (h->len < link_offset + 20) return;
    
    struct ip *ip_hdr = (struct ip*)(bytes + link_offset);
    if(ip_hdr->ip_v != 4) return;

    int ip_hdr_len = ip_hdr->ip_hl * 4;
    if (h->len < link_offset + ip_hdr_len + 20) return;
    
    struct tcphdr *tcp_hdr = (struct tcphdr*)((u_char*)ip_hdr + ip_hdr_len);

    char src_ip[16], dst_ip[16];
    inet_ntop(AF_INET, &ip_hdr->ip_src, src_ip, sizeof(src_ip));
    inet_ntop(AF_INET, &ip_hdr->ip_dst, dst_ip, sizeof(dst_ip));

    // 使用标准的TCP头字段名
    int src_port = ntohs(tcp_hdr->source);
    int dst_port = ntohs(tcp_hdr->dest);

    for(int i = 0; i < target_count; i++) {
        // 本机发向目标
        if(strcmp(dst_ip, targets[i].ip) == 0 && dst_port == targets[i].port) {
            targets[i].bytes_sent += h->len;
        }
        // 目标发向本机
        if(strcmp(src_ip, targets[i].ip) == 0 && src_port == targets[i].port) {
            targets[i].bytes_recv += h->len;
        }
    }
}

void print_header() {
    printf("\033[2J\033[H");
    printf("================================================================================\n");
    printf("                   实时带宽监控 (基于libpcap) - 端口: 9092\n");
    printf("================================================================================\n");
    printf("%-20s %-8s %-12s %-12s %-8s\n", 
           "IP地址", "端口", "发送(Mbps)", "接收(Mbps)", "总带宽(Mbps)");
    printf("--------------------------------------------------------------------------------\n");
}

void print_stats() {
    double total_send_mbps = 0.0;
    double total_recv_mbps = 0.0;
    int active_targets = 0;
    
    for(int i = 0; i < target_count; i++) {
        double total_mbps = targets[i].send_mbps + targets[i].recv_mbps;
        
        printf("%-20s %-8d %-12.2f %-12.2f %-8.2f\n",
               targets[i].ip, 
               targets[i].port,
               targets[i].send_mbps,
               targets[i].recv_mbps,
               total_mbps);
        
        total_send_mbps += targets[i].send_mbps;
        total_recv_mbps += targets[i].recv_mbps;
        
        if (targets[i].send_mbps > 0 || targets[i].recv_mbps > 0) {
            active_targets++;
        }
    }
    
    printf("--------------------------------------------------------------------------------\n");
    printf("总计: %d个目标 | 总发送: %.2f Mbps | 总接收: %.2f Mbps | 总带宽: %.2f Mbps\n",
           active_targets, total_send_mbps, total_recv_mbps, total_send_mbps + total_recv_mbps);
    printf("================================================================================\n");
    printf("按 Ctrl+C 停止监控\n");
}

int main() {
    signal(SIGINT, signal_handler);
    
    // 添加目标 IP:Port
    add_target("10.252.12.100", 9092);
    add_target("10.252.134.67", 9092);
    add_target("10.252.134.68", 9092);
    add_target("10.252.134.69", 9092);
    add_target("10.252.134.70", 9092);
    add_target("10.252.134.71", 9092);
    add_target("10.52.16.68", 9092);
    add_target("10.52.16.69", 9092);
    add_target("10.52.16.70", 9092);
    add_target("10.52.16.71", 9092);
    add_target("10.52.16.72", 9092);
    add_target("10.252.12.83", 9092);
    add_target("10.252.12.84", 9092);
    add_target("10.252.12.85", 9092);
    add_target("10.252.12.86", 9092);
    add_target("10.252.12.87", 9092);
    add_target("10.252.12.88", 9092);
    add_target("10.252.12.89", 9092);
    add_target("10.252.145.44", 9092);
    add_target("10.252.12.99", 9092);

    char errbuf[PCAP_ERRBUF_SIZE];
    
    // 直接使用 eth0
    const char *iface = "eth0";
    
    // 显示可用网卡
    pcap_if_t *alldevs;
    if (pcap_findalldevs(&alldevs, errbuf) == 0) {
        printf("可用网卡:\n");
        for(pcap_if_t *d = alldevs; d; d = d->next) {
            printf("  %s", d->name);
            if (d->description) printf(" (%s)", d->description);
            printf("\n");
        }
        pcap_freealldevs(alldevs);
    }

    printf("使用网卡: %s\n", iface);

    pcap_t *handle = pcap_open_live(iface, 65536, 1, 1000, errbuf);
    if(!handle) {
        fprintf(stderr, "pcap_open_live failed on %s: %s\n", iface, errbuf);
        fprintf(stderr, "请检查网卡名称是否正确,或尝试使用 'any'\n");
        return 1;
    }

    link_offset = get_link_offset(handle);

    // 构建 BPF 过滤器
    char filter_exp[2048] = "tcp and (";
    for(int i = 0; i < target_count; i++) {
        char tmp[64];
        snprintf(tmp, sizeof(tmp), "host %s and port %d", targets[i].ip, targets[i].port);
        if (i > 0) strcat(filter_exp, " or ");
        strcat(filter_exp, tmp);
    }
    strcat(filter_exp, ")");

    printf("使用过滤器: %s\n", filter_exp);

    struct bpf_program fp;
    if(pcap_compile(handle, &fp, filter_exp, 1, PCAP_NETMASK_UNKNOWN) == -1) {
        fprintf(stderr, "pcap_compile failed: %s\n", pcap_geterr(handle));
        pcap_close(handle);
        return 1;
    }
    if(pcap_setfilter(handle, &fp) == -1) {
        fprintf(stderr, "pcap_setfilter failed: %s\n", pcap_geterr(handle));
        pcap_close(handle);
        return 1;
    }

    printf("开始监控 %d 个目标,采样间隔: %d 秒...\n", target_count, INTERVAL);
    printf("按 Ctrl+C 停止监控\n\n");
    
    sleep(2);

    int sample_num = 0;
    unsigned long long prev_sent[TARGET_MAX], prev_recv[TARGET_MAX];
    
    for(int i = 0; i < target_count; i++) {
        prev_sent[i] = targets[i].bytes_sent;
        prev_recv[i] = targets[i].bytes_recv;
    }

    while(running) {
        sample_num++;
        
        time_t start = time(NULL);
        while(time(NULL) - start < INTERVAL && running) {
            int ret = pcap_dispatch(handle, 100, packet_handler, NULL);
            if (ret == -1) {
                fprintf(stderr, "pcap_dispatch error: %s\n", pcap_geterr(handle));
                break;
            }
            usleep(1000);
        }

        if (!running) break;

        for(int i = 0; i < target_count; i++) {
            unsigned long long sent_diff = targets[i].bytes_sent - prev_sent[i];
            unsigned long long recv_diff = targets[i].bytes_recv - prev_recv[i];
            
            targets[i].send_mbps = (sent_diff * 8.0) / INTERVAL / 1000000.0;
            targets[i].recv_mbps = (recv_diff * 8.0) / INTERVAL / 1000000.0;
            
            prev_sent[i] = targets[i].bytes_sent;
            prev_recv[i] = targets[i].bytes_recv;
        }

        print_header();
        print_stats();
        
        if (SAMPLE_COUNT > 0 && sample_num >= SAMPLE_COUNT) {
            break;
        }
    }

    pcap_close(handle);
    printf("\n监控已停止。共采样 %d 次。\n", sample_num);
    return 0;
}

  

posted on 2025-11-25 16:27  吃草的青蛙  阅读(1)  评论(0)    收藏  举报

导航