• Linux C/C++ 嗅探数据包并显示流量统计信息


    嗅探数据包并显示流量统计信息是网络分析中的一种重要技术,常用于网络故障诊断、网络安全监控等方面。具体来说,嗅探器是一种可以捕获网络上传输的数据包,并将其展示给分析人员的软件工具。在嗅探器中,使用pcap库是一种常见的方法,因为它提供了一种跨平台的接口,可以有效地访问操作系统的数据包捕获功能。

    数据包捕获函数库(Libpcap)

    Libpcap是一种独立于系统的用户层包捕获API接口,为底层网络监测提供了一个可移植的框架。它允许程序员使用简单的C语言编程接口,来捕获和分析网络数据包。要使用libpcap来嗅探数据包并显示流量统计信息,可以按照以下步骤进行:

    • 1.安装libpcap库:首先需要安装libpcap库,可以在大多数Linux发行版中使用包管理器进行安装,例如在Ubuntu中可以使用以下命令:sudo yum install libpcap-dev。
    • 2.创建数据包捕获程序:使用C语言编写程序,并引入libpcap库。在程序中,需要使用libpcap的函数来打开网络接口、捕获数据包、解码数据包等。
    • 3.数据包捕获:使用libpcap的pcap_open_live()函数打开网络接口(如eth0),并获取该接口的原始套接字(raw socket)。然后使用pcap_next()或pcap_next_ex()函数从原始套接字中读取数据包。
    • 4.数据包解码:对捕获到的数据包进行解码,提取协议字段和数据内容。
    • 5.流量统计和分析:对解码后的数据包进行流量统计和分析。例如,可以计算每个数据包的长度、接收到的数据包数量、每个协议的数据流量等。
    • 6.数据包过滤:使用BPF(Berkeley Packet Filter)算法对捕获到的数据包进行过滤。BPF算法的基本思想是在有BPF监听的网络中,网卡驱动将接收到的数据包复制一份交给BPF过滤器,过滤器根据用户定义的规则决定是否接收此数据包以及需要拷贝该数据包的那些内容,然后将过滤后的数据给与过滤器相关联的上层应用程序。
    • 7.数据展示:将分析结果以图形化或文本形式展示给用户。

    实现上述功能的需要准备的知识点包括:C语言编程、网络协议知识、libpcap库的使用、BPF算法原理等。同时,需要对底层网络监测技术有一定的了解,以便更好地理解和实现嗅探器程序的功能。

    怎样使用Wireshark/tcpdump进行数据包嗅探

    嗅探数据包并显示统计信息,可以使用Wireshark这个网络协议分析工具。以下是使用Wireshark进行数据包嗅探的步骤:

    • 1.下载并安装Wireshark:访问Wireshark官网(https://www.wireshark.org/)下载适合你操作系统的版本,然后按照提示进行安装。
    • 2.打开Wireshark:在开始菜单或应用程序列表中找到Wireshark,双击打开。
    • 3.选择网络接口:在Wireshark主界面的顶部,点击“捕获”选项卡,然后选择你想要嗅探的网络接口。如果你不确定应该选择哪个接口,可以查看网络连接详细信息,找到正确的接口名称。
    • 4.开始嗅探:点击“捕获选项”按钮,设置捕获过滤器(可选),然后点击“开始”按钮开始嗅探数据包。
    • 5.停止嗅探:当你完成数据包嗅探后,点击“停止”按钮停止捕获。
    • 6.显示统计信息:在Wireshark主界面的顶部,点击“统计”选项卡,可以看到各种统计信息,如捕获的数据包数量、各层协议的数量等(在“每秒更新”下拉菜单中,选择适当值,例如“1秒”)。
    • 7.分析数据包:在“捕获”选项卡中,你可以看到实时捕获到的数据包。点击一个数据包,可以在右侧面板中查看该数据包的详细信息。你可以根据需要对数据包进行过滤、排序等操作,以便更好地分析网络流量。

    使用tcpdump进行数据包嗅探的步骤如下:

    • 1.打开终端窗口并启动tcpdump。
    • 2.指定要嗅探的网络接口,例如:tcpdump -i eth0,其中“-i”后面跟着的是网络接口名称。
    • 3.抓取数据包,例如:tcpdump -i eth0 -w data.pcap,其中“-w”后面跟着的是输出文件的名称。
    • 4.分析和过滤数据包,例如:tcpdump -i eth0 host 192.168.1.101,表示只抓取目标主机为192.168.1.101的数据包。
    • 5.分析数据包的内容,可以使用工具如Wireshark打开刚刚保存的pcap文件进行进一步分析。

    请注意,使用tcpdump需要具有管理员权限(sudo)。

    对于网络安全人员,需要关注那些点

    Sniff数据包实现流量统计的原理是基于网络数据包的捕获和解析。Sniff工具通过监听网络接口上的数据传输,对每个经过的数据包进行截获、分析和解码。然后,根据协议类型、源IP、目标IP、数据包长度等属性对数据包进行分类和统计。

    对于网络安全人员,需要关注以下几点:

    • 1.Sniff工具的合法使用:Sniff工具主要用于网络管理、故障排查和程序调试等方面,也可以被黑客用来进行非法活动,如窃取敏感信息、进行网络攻击等。
    • 2.网络隔离和安全措施:为了保护网络安全,需要对网络进行适当的隔离和安全措施。例如,使用VLAN、防火墙等设备来限制网络访问和数据流动,以防止未经授权的访问和恶意攻击。
    • 3.数据包的过滤和分析:Sniff工具虽然可以对网络流量进行全面分析,但在实际应用中,可能需要对数据包进行过滤和筛选,以便更准确地掌握网络流量情况。例如,可以针对特定的协议、IP地址、端口等进行过滤,以排除无关数据包的干扰。
    • 4.警惕ARP欺骗攻击:ARP欺骗是一种常见的网络攻击手段,黑客通过伪造IP地址和MAC地址映射关系,可以截获网络数据包并进行恶意篡改。在使用Sniff工具时,需要防范ARP欺骗攻击,例如通过设置静态ARP映射表、使用ARP欺骗防御软件等措施来保护网络安全。

    Linux C/C++ 嗅探数据包并显示流量统计信息

    要实现嗅探数据包并根据网卡流量输出 TCP/UDP 流量信息,你可以参考以下步骤进行实现:安装并导入必要的库:首先,你需要安装一些库,如 libpcap(用于捕获和解析数据包)和 sys(用于获取系统时间)。

    打开网络接口并捕获数据包:使用 libpcap 库打开网络接口(如 eth0),并设置过滤器(例如,仅捕获 TCP 和 UDP 数据包):

    ...
    /* IP header */
    struct sniff_ip {
        u_char  ip_vhl;                 /* version << 4 | header length >> 2 */
        u_char  ip_tos;                 /* type of service */
        u_short ip_len;                 /* total length */
        u_short ip_id;                  /* identification */
        u_short ip_off;                 /* fragment offset field */
    #define IP_RF 0x8000            /* reserved fragment flag */
    #define IP_DF 0x4000            /* dont fragment flag */
    #define IP_MF 0x2000            /* more fragments flag */
    #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
        u_char  ip_ttl;                 /* time to live */
        u_char  ip_p;                   /* protocol */
        u_short ip_sum;                 /* checksum */
        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    };
    #define IP_HL(ip)               (((ip)->ip_vhl) & 0x0f)
    #define IP_V(ip)                (((ip)->ip_vhl) >> 4)
    
    /* 剩下的TCP和UDP标头结构仅用于学习目的,因为计算ip报头中的总分组长度 */
    
    /* TCP header */
    typedef u_int tcp_seq;
    
    struct sniff_tcp {
        u_short th_sport;               /* source port */
        u_short th_dport;               /* destination port */
        tcp_seq th_seq;                 /* sequence number */
        tcp_seq th_ack;                 /* acknowledgement number */
        u_char  th_offx2;               /* data offset, rsvd */
    #define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)
        u_char  th_flags;
    #define TH_FIN  0x01
    #define TH_SYN  0x02
    #define TH_RST  0x04
    #define TH_PUSH 0x08
    #define TH_ACK  0x10
    #define TH_URG  0x20
    #define TH_ECE  0x40
    #define TH_CWR  0x80
    #define TH_FLAGS        (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
        u_short th_win;                 /* window */
        u_short th_sum;                 /* checksum */
        u_short th_urp;                 /* urgent pointer */
    };
    
    struct sniff_udp {
        u_short	uh_sport;		/* source port */
        u_short	uh_dport;		/* destination port */
        u_short	uh_ulen;		/* datagram length */
        u_short	uh_sum;			/* datagram checksum */
    };
    ...
    int main(int argc, char **argv) 
    {
    ...
    
        while((argch = getopt(argc, argv, "Bkmgdi:t:")) != -1) {
            switch(argch) {
                case 'B':
                    batch_mode = 1;
                    break;
    
                case 'k':
                    strncpy(show_suffix, "kByte/s", 32);
                    traffic_unit = 1;
                    break;
    
                case 'm':
                    strncpy(show_suffix, "MByte/s", 32);
                    traffic_unit = 2;
                    break;
    
                case 'g':
                    strncpy(show_suffix, "GByte/s", 32);
                    traffic_unit = 3;
                    break;
    
                case 't':
                    sniff_timeout = atoi(optarg);
                    break;
    
                case 'i':
                    strncpy(ifname, optarg, IFNAMSIZ);
                    break;
    
                case 'd':
                    dflag = 1;
                    break;
    
                default:
                    fprintf(stderr, "Incorrect argument provided\n");
                    usage();
                    exit(1);
    
            }
        }
    
        /* 如果缺少位置筛选器参数,请退出。 */
        if(argc - optind < 1) {
            usage();
            exit(1);
        }
    
        /* 最后一个参数现在应该是筛选器字符串 */
        filter = argv[optind];
    
        /* 确定设备ifname的IPv4网络和网络掩码. */
        if(pcap_lookupnet(ifname, &netp, &netmask, errbuf) == -1) {
            fprintf(stderr, "pcap_lookupnet: %s\n", errbuf);
            exit(1);
        }
    
    
        if((capture = pcap_open_live(ifname, 65535, 1, 10, errbuf)) == NULL) {
            fprintf(stderr, "pcap_open_live: %s\n", errbuf);
            exit(1);
        }
    
        if(pcap_compile(capture, &comp_filter, filter, 0, netmask) != 0) {
            fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(capture));
            exit(1);
        }
    
        if(pcap_setfilter(capture, &comp_filter) == -1) {
            fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(capture));
            exit(1);
        }
    
        /* 清理回调 */
        if(atexit(exit_callback) != 0) {
            perror("atexit: ");
            exit(1);
        }
    
        /* 发出数据包捕获结束的信号. */
        if(signal(SIGALRM, output_data) == SIG_ERR) {
            perror("signal: failed to capture SIGALRM");
            exit(1);
        }
    
        /* 捕获中断信号以实现整洁的清理. */
        if(signal(SIGINT, cleanup_capture) == SIG_ERR) {
            perror("signal: failed to capture SIGINT");
            exit(1);
        }
    
        /* 获取NIC硬件地址以稍后确定数据包流. */
        if((mac_address = get_hw_address(ifname, dflag)) == NULL) {
            fprintf(stderr, "get_hw_address: failed to get hw address from %s\n", ifname);
            exit(1);
        }
    
        nic_dlt = pcap_datalink(capture);
    
        /* 选择一个物理层段大小 */
        switch(nic_dlt) {
            case DLT_EN10MB: /* Ethernet */
                phys_size = 14;
                break;
    
            case DLT_IEEE802: /* WiFi */
                phys_size = 22;
                break;
    
            case DLT_FDDI: /* Fiber interface */
                phys_size = 21;
                break;
    
            case DLT_LOOP: /* OpenBSD loop device or RAW device */
                phys_size = 12;
                break;
    
            case DLT_NULL:
                phys_size = 4;
    
            default:
                phys_size = 0;
                break;
        }
    
        if(dflag)
            fprintf(stderr, "phys_size: %d, nic_dlt: %d\n", phys_size, nic_dlt);
    
        /* 清除计时器结构并设置sniff_timeout秒的超时. */
    ...
    
        /* 这将导致发送SIGALARM以输出当前流量统计信息。. */
        if(setitimer(ITIMER_REAL, itvp, &oitv) < 0) {
            fprintf(stderr, "setitimer: failed setting timer\n");
            exit(1);
        }
    
        if(batch_mode == 0)
            output_header(ifname);
    
        /* 将捕获缓冲区中数据包的主pcap循环. */
        loop_status = pcap_loop(capture, -1, capture_callback, NULL);
    ...
    }
    
    ...
    void fprint_data(double in, double out) 
    {
        switch(traffic_unit) 
        {
            case 1:
                in /= 1000;
                out /= 1000;
                break;
            case 2:
                in /= 1000000;
                out /= 1000000;
                break;
            case 3:
                in /= 1000000000;
                out /= 1000000000;
                break;
            default:
                in /= 1;
                out /= 1;
                break;
        }
    
    ...
    }
    ...
    unsigned short get_windowsize(void) {
        struct winsize ws;
    
        if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) {
            return(-1);
        }
    
        return(ws.ws_row);
    }
    ...
    uint8_t * get_hw_address(char *ifname, int dflag) 
    {
    ...
    
        ifap = ifa;
    
        if(sd < 0) 
        {
            freeifaddrs(ifap);
            return(NULL);
        }
    
        for(;ifa;ifa = ifa->ifa_next) 
        {
            if(ifa->ifa_data != 0) 
            {
                continue;
            }
    
            /* 查找是否与ifname匹配 */
            if(strncmp(ifname, ifa->ifa_name, sizeof(*ifname)) == 0) 
            {
                strncpy(req.ifr_name, ifa->ifa_name, IFNAMSIZ);
                if(ioctl(sd, SIOCGIFHWADDR, &req ) != -1 ) 
                {
                    if((mac = malloc(sizeof(uint8_t)*MAX_ETHER_LEN)) == NULL) 
                    {
                        perror("malloc: ");
                        return(NULL);
                    }
                    memcpy(mac, (uint8_t*)req.ifr_ifru.ifru_hwaddr.sa_data, MAX_ETHER_LEN);
                    break;
                }
            }
        }
    
        freeifaddrs(ifap);
        return mac;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277

    If you need the complete source code, please add the WeChat number (c17865354792)

    运行结果:

    根据字节数和时间计算 TCP 和 UDP 的流量(以字节/秒为单位),将 TCP 和 UDP 的流量信息按照指定的格式(如 k/s、m/s 等)输出到控制台。

    总结

    嗅探数据包是一种网络抓包技术,可以捕获网络上传输的数据包并进行分析。通过统计流量,可以了解网络的使用情况、发现异常行为和攻击等。

    Welcome to follow WeChat official account【程序猿编码

  • 相关阅读:
    计算机网络基础概念入门
    resnet解释--突破层数理论限制
    Vue 3入门指南
    基于Python+OpenCV高速公路行驶车辆的速度检测系统
    中国古代数学问题——鸡兔同笼
    docker安装minio,从入门到放弃
    HTML 实时显示本地电脑时间(精确到毫秒)
    无线蓝牙耳机哪款性价比高?蓝牙耳机性价比排行
    WebGL笔记:使用鼠标绘制多个线条应用及绘制动感线性星座
    MIME(Multipurpose Internet Mail Extensions)类型绕过
  • 原文地址:https://blog.csdn.net/chen1415886044/article/details/133842432