网络报文分析程序的设计与实现(2024)

1.题目描述

在上一题的基础上,参照教材中各层报文的头部结构,结合使用 wireshark 软件(下载地址 https://www.wireshark.org/download.html#releases)观察网络各层报文捕获,解析和分析的过程(如下 图所示),尝试编写一个网络报文的解析程序。


2.演示Demo

设备选择


3.导入WinPcap三方库到项目

(博主用的是Clion,若是VC,CodeBlocks,Dev-C等导入方式大同小异)

首先下载: 文件https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip

解压到项目路径下:

在CMakeLists.txt修改成下面代码:(连接第三方库WinPcap):

Dart 复制代码
cmake_minimum_required(VERSION 3.27)
project(Problem08)
set(CMAKE_CXX_STANDARD 17)

include_directories("./Include")  #导入.h头文件

link_directories("./Lib/x64")     #导入.a库文件(./Lib/x64是64位  ./Lib 是32位机器使用)

link_libraries(Packet wpcap  ws2_32)  #导入wpcap,ws2_32库文件

add_executable(Problem08 main.cpp)

target_link_libraries(Problem08 Packet wpcap) #连接wpcap,ws2_32库文件

刷新项目 :

成功运行


4.参考代码

cpp 复制代码
#define HAVE_REMOTE
#define LINE_LEN 16
#define IPPROTO_ICMP 1 /* control message protocol */
#define IPPROTO_TCP  6 /* tcp */
#define IPPROTO_UDP 17 /* user datagram protocol */

#include <WinSock2.h>
#include <algorithm>
#include <string>
#include <cstdio>
#include <pcap.h>
#include <sys/time.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")

using namespace std;


typedef struct ip_address { //ip地址
    u_char b1;
    u_char b2;
    u_char b3;
    u_char b4;
} ip_address;

typedef struct mac_address {//mac地址
    u_char b1;
    u_char b2;
    u_char b3;
    u_char b4;
    u_char b5;
    u_char b6;
} mac_address;

typedef struct ethe_header { //mac帧首部
    mac_address mac_dest_address;
    mac_address mac_source_address;
    u_short ether_type;
} ethe_header;

typedef struct ip_header { //ip地址首部
    u_char ver_ihl;
    u_char tos;
    u_short tlen;
    u_short identification;
    u_short flags_fo;
    u_char ttl;
    u_char proto;
    u_short crc;
    ip_address saddr;
    ip_address daddr;
    u_int op_pad;
} ip_header;

typedef struct udp_header { //UPD首部
    u_short sport;
    u_short dport;
    u_short len;
    u_short crc;
} udp_header;

typedef struct tcp_header { //TCP首部
    u_short sport;
    u_short dport;
    u_int num;
    u_int ack;
    u_short sum;
    u_short windonw;
    u_short crc;
    u_short ugr;
} tcp_header;

//------------------------------------------------
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

void cls();

void Sync_NetData();
void GotoXY(int x, int y) ; // 移动
//-----------------------------------------------
char judge;
int length;
long NeedPacket = 999;
long NowPacket = 0;
//变量--------------------------------------------

long Now_Y=10;

long Tcp_Num = 0;
long Udp_Num = 0;
long ICMP_Num = 0;
long Tcp_Size = 0;
long ICMP_Size = 0;
long Udp_Size = 0;

//-----------------------------------------------
int main() {
    cout << " *============网络报文分析程序的设计与实现Demo============*" << endl << endl;
    pcap_if_t *alldevs, *device;
    int i = 0;
    int iNum;
    u_int netmask;
    struct bpf_program fcode;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];
    //修改这里可以更改捕获的数据包使用的协议类型
    char packet_filter[] = "(ip and udp) or (ip and tcp) or (ip and icmp)";
    //获取设备列表
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) {
        fprintf(stderr, "无法打开网络设备:%s\n", errbuf);
        return 1;
    }
    for (device = alldevs; device != NULL; device = device->next) { //打印列表
        if (i == 0) {
            printf("------------------------------网络设备-------------------------------\n");
        }
        if (device->description)
            printf(" 序号:%d (%s)\n", ++i, device->description);
        else {
            i++;
            printf("没有设备描述信息!");
        }
    }
    printf("-------------------------------------------------------------------\n");
    if (i == 0) {
        printf("\n请先安装WinPcap!");
        return -1;
    }
    printf("\n #请选择网络设备接口:(1 - %d):", i);
    scanf("%d", &iNum);
    getchar();
    if (iNum < 1 || iNum > i) {
        printf("设备不存在!\n");
        pcap_freealldevs(alldevs);
        return -1;
    }
    //跳转到已选设备
    for (device = alldevs, i = 0; i < iNum - 1; device = device->next, i++);

    // 打开适配器
    if ((adhandle = pcap_open(device->name,  // 设备名
                              65536,     // 要捕捉的数据包的部分
            // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
                              PCAP_OPENFLAG_PROMISCUOUS,         // 混杂模式
                              1000,      // 读取超时时间
                              NULL,      // 远程机器验证
                              errbuf     // 错误缓冲池
    )) == NULL) {
        fprintf(stderr, "\n不能打开适配器!\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    if (pcap_datalink(adhandle) != DLT_EN10MB) { //检查数据链路层,为了简单,只考虑以太网
        fprintf(stderr, "\n系统网卡链路出错!\n");
        pcap_freealldevs(alldevs); //释放设备列表
        return -1;
    }

    if (device->addresses != NULL) //获得接口第一个地址的掩码
        netmask = ((struct sockaddr_in *) (device->addresses->netmask))->sin_addr.S_un.S_addr;
    else //如果接口没有地址,那么我们假设一个C类的掩码
        netmask = 0xffff00;
    if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0) { //编译过滤器
        fprintf(stderr, "不能监听过滤该数据报!\n");
        pcap_freealldevs(alldevs);
        return -1;
    }

    if (pcap_setfilter(adhandle, &fcode) < 0) { //设置过滤器
        fprintf(stderr, "过滤设置错误!\n");
        pcap_freealldevs(alldevs);
        return -1;
    }
    cout << " #请输入抓包数量:";
    cin >> NeedPacket;
    printf("\n\n 正在监听%s的数据报...\n\n", device->description);
    pcap_freealldevs(alldevs); //释放设备列表
    system("cls");
    pcap_loop(adhandle, NeedPacket, packet_handler, NULL); //开始捕捉
    GotoXY(0,Now_Y);
    cout << endl << " * 嗅探结束 " << endl << endl;
    system("pause");
    return 0;
}

void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header,
                    const u_char *pkt_data) { //回调函数,当收到每一个数据包时会被libpcap所调用
    if (header->caplen > 400) return;
    int len;
    struct tm *ltime;
    char timestr[16];
    ip_header *ip_hd,ip_hd_ok;
    udp_header *udp_hd;
    tcp_header *tcp_hd;
    ethe_header *ethe_hd;
    int ip_len, tcp_len, start;
    u_short sport, dport;
    string  Type_net;
    char now[64];
    struct tm *ttime;
    time_t tt;
    tt = header->ts.tv_sec;
    ttime = localtime(&tt);
    strftime(now, 64, "%Y-%m-%d %H:%M:%S", ttime);
    // printf("时间:%s\n", now);

    ethe_hd = (ethe_header *) pkt_data;
    ip_hd = (ip_header *) (pkt_data + 14);
    ip_hd_ok=*ip_hd;
    ip_len = (ip_hd_ok.ver_ihl & 0xf) * 4; //ip首部长度
    udp_hd = (udp_header *) ((u_char *) ip_hd + ip_len);
    sport = ntohs(udp_hd->sport);
    dport = ntohs(udp_hd->dport);

    if (ip_hd_ok.proto == IPPROTO_UDP) {
        Type_net="UDP";
        start = ip_len + 8;
        Udp_Num++;
        Udp_Size += header->caplen;
    } else if (ip_hd_ok.proto == IPPROTO_TCP) {
        Type_net="TCP";
        Tcp_Num++;
        Tcp_Size += header->caplen;
        tcp_hd = (tcp_header *) ((u_char *) ip_hd + ip_len);
        tcp_len = ntohs(tcp_hd->sum) >> 12;
        start = ip_len + tcp_len * 4;
    } else if (ip_hd_ok.proto == IPPROTO_ICMP) {
        Type_net="ICMP";
        start = ip_len + 23;
        ICMP_Num++;
        ICMP_Size += header->caplen;
    }

    GotoXY(0,Now_Y);
    printf("数据类型: %s\t"
           "源IP地址: %d.%d.%d.%d:%d\t"
           "目的IP地址: %d.%d.%d.%d:%d\t"
           "目的物理地址: %x-%x-%x-%x-%x-%x\n",
           Type_net.c_str(),
           ip_hd->saddr.b1, ip_hd->saddr.b2, ip_hd->saddr.b3, ip_hd->saddr.b4,sport,
           ip_hd->daddr.b1, ip_hd->daddr.b2, ip_hd->daddr.b3, ip_hd->daddr.b4, dport,
           ethe_hd->mac_dest_address.b1, ethe_hd->mac_dest_address.b2, ethe_hd->mac_dest_address.b3,
           ethe_hd->mac_dest_address.b4, ethe_hd->mac_dest_address.b5, ethe_hd->mac_dest_address.b6);
    Now_Y++;
    Sync_NetData();//更新网络
}

//更新数据
void Sync_NetData() {
    cls();
    cout << " *==========网络报文分析程序的设计与实现Demo==========*" << endl;
    cout << endl << " 捕获网络报文分析:------------------------" << endl;
    cout << "\tTCP包数量:" << Tcp_Num << " 个" << endl;
    cout << "\tUDP包数量:" << Udp_Num << " 个" << endl;
    cout << "\tICMP包数量:" << ICMP_Num << " 个" << endl;
    cout << "\t捕获TCP包的总大小:" << Tcp_Size / 1024 << "KB" << endl;
    cout << "\t捕获UDP包的总大小:" << Udp_Size / 1024 << "KB" << endl;
    cout << "\t捕获ICMP包的总大小:" << ICMP_Size / 1024 << "KB" << endl;
    cout << " -------------------------------------" << endl;

}

//清屏函数
void cls() {
    COORD pos;
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    pos.Y = pos.X = 0;
    SetConsoleCursorPosition(hOut, pos);
}
void GotoXY(int x, int y)  // 移动
{
    COORD pos;
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    pos.Y =y; pos.X = x;
    SetConsoleCursorPosition(hOut, pos);
}

2024 HNUST计算机网络课程设计-(ᕑᗢᓫ∗)˒芒果酱-参考文章

代码可以参考,૮₍ ˃ ⤙ ˂ ₎ა 但同学们要认真编写哦


1、网络聊天程序的设计与实现
C++ Socket 多线程 网络聊天室 支持用户端双向交流(2023)-CSDN博客

2、Tracert 与 Ping 程序设计与实现
Tracert 与 Ping 程序设计与实现(2024)-CSDN博客

3、滑动窗口协议仿真
滑动窗口协议仿真(2024)-CSDN博客

4、OSPF 路由协议原型系统设计与实现
OSPF 路由协议原型系统设计与实现-CSDN博客

5、基于 IP 多播的网络会议程序
基于 IP 多播的网络会议程序(2024)-CSDN博客

6、编程模拟 NAT 网络地址转换
编程模拟 NAT 网络地址转换(2024)-CSDN博客

7、网络嗅探器的设计与实现
网络嗅探器的设计与实现(2024)-转载-CSDN博客

8、网络报文分析程序的设计与实现
网络报文分析程序的设计与实现(2024)-CSDN博客

9、简单 Web Server 程序的设计与实现
简单 Web Server 程序的设计与实现 (2024)-CSDN博客

10、路由器查表过程模拟

计算机网络 - 路由器查表过程模拟 C++(2024)-CSDN博客

相关推荐
南东山人3 小时前
一文说清:C和C++混合编程
c语言·c++
麻瓜也要学魔法4 小时前
链路状态路由协议-OSPF
网络
Estar.Lee4 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
傻啦嘿哟5 小时前
代理IP在后端开发中的应用与后端工程师的角色
网络·网络协议·tcp/ip
Red Red5 小时前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全
Ysjt | 深6 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
ephemerals__6 小时前
【c++丨STL】list模拟实现(附源码)
开发语言·c++·list
Microsoft Word6 小时前
c++基础语法
开发语言·c++·算法
亚远景aspice6 小时前
ISO 21434标准:汽车网络安全管理的利与弊
网络·web安全·汽车