计网实验c/c++、网络嗅探器的设计与实现

参照附录 4 raw socket 编程例子,设计一个可以监视网络的状态、数据流动情况以及网络上传输 的信息的网络嗅探器。
显示了流量信息,若要查看报文信息请修改注释。
自动获取ip

#include <iostream>
#include <winsock2.h>
#include <time.h>
#pragma comment(lib, "WS2_32")
using namespace std;

void DecodeIPPacket(char *pData);

void DecodeTCPPacket(char *pData);

void DecodeUDPPacket(char *pData);

void DecodeICMPPacket(char *pData);

#define SIO_RCVALL            _WSAIOW(IOC_VENDOR,1)
double all=0;
/*****IP分组首部结构******/
//IP首部结构
typedef struct _IPHeader {
    unsigned char iphVerLen; // 版本号和头长度各占4位
    unsigned char ipTOS;  // 服务类型
    unsigned short ipLength; // 分组总长度
    unsigned short ipID; //分组标识,惟一标识发送的每一个数据报
    unsigned short ipFlags; // 标志
    unsigned char ipTTL; // 生存时间,TTL
    unsigned char ipProtocol; // 协议可以是TCP、UDP、ICMP等
    unsigned short ipChecksum; // 校验和
    unsigned long ipSource; // 源IP地址
    unsigned long ipDestination; // 目的IP地址
} IPHeader, *PIPHeader;

//ICMP报头结构******/
typedef struct icmphdr {
    char i_type;  //8 位类型字段
    char i_code;  //8 位代码字段
    unsigned short i_cksum;  //16位校验和
    unsigned short i_id;    //标识符,一般可设为发送进程的ID
    unsigned short i_seq;   //序列号
    unsigned long timestamp;  //时间戳
} ICMPHeader;

//UDP报头结构
typedef struct _UDPHeader {
    unsigned short sourcePort;    // 源端口号
    unsigned short destinationPort; // 目的端口号
    unsigned short len;          // 包长度
    unsigned short checksum;    // 校验和
} UDPHeader;

//TCP报头结构
typedef struct _TCPHeader {
    unsigned short sourcePort;        // 16位源端口号
    unsigned short destinationPort;    // 16位目的端口号
    unsigned long sequenceNumber;    // 32位序列号
    unsigned long acknowledgeNumber;    // 32位确认号
    char dataoffset;    //高4位表示数据偏移
    char flags;    //低6位为URG、ACK、PSH、RST、SYNhe FIN六个标志位
    unsigned short windows;        // 16位窗口大小
    unsigned short checksum;        // 16位校验和
    unsigned short urgentPointer;        // 16位紧急数据偏移量
} TCPHeader;

int main() {
    setvbuf(stdout, NULL, _IONBF, 0);
    WSADATA wsaData;                              // 用来存储被WSAStartup函数调用后返回的Windows Sockets数据
    WSAStartup(MAKEWORD(2, 2), &wsaData);     // 完成对Winsock服务的初始化
    /**** 创建原始套节字 IPv4 TCP******/
    SOCKET sRaw = socket(PF_INET, SOCK_RAW, 0);
    SOCKADDR_IN addr_in;                            // 目的地址
    /*****输入想要要监听的接口的IP地址******/
    //cout << "请输入要监听接口的IP地址:";
    char snfIP[20];
    //cin.getline(snfIP, sizeof(snfIP));
    char hostname[256];
    gethostname(hostname,sizeof(hostname));   //获取主机信息
    HOSTENT* host=gethostbyname(hostname);
    strcpy(snfIP,inet_ntoa(*(in_addr*)*host->h_addr_list));     //copy主机信息中的ip到snfIP
    addr_in.sin_family = AF_INET;                       // IPv4
    addr_in.sin_port = htons(80);            // 80端口
    addr_in.sin_addr.S_un.S_addr = inet_addr(snfIP);    // 监听的地址

    /****绑定网卡IP地址******/
    bind(sRaw, (PSOCKADDR) &addr_in, sizeof(addr_in));

    /****在调用ioctlsocket将网卡设为混杂模式前,套节字必须绑定该网卡的IP地址******/
    DWORD dwValue = 1;
    // 套接字 SIO_RCVALL操作为所有的IP包无论经不经过
    ioctlsocket(sRaw, SIO_RCVALL, &dwValue);
    // 开始抓取IP分组
    char buff[50][4096];
    int packetNumber;
    int time=0;
    while (1) {
        long t=clock();
        double v=0.0;
        recv(sRaw, buff[0], 4096, 0);
        //cout << endl;
        DecodeIPPacket(buff[0]);//解析IP包
        //cout <<clock()-t<< endl;
        time+=clock()-t;
        if(time>1000){
            v=all/1024;
            //cout <<all<<"Bytes/s"<< endl;
            printf("%.02fKB/s\n",v);
            all=0;
            time=0;
        }
        //v=(all-a)/((clock()-t)*1000);
        //cout <<v <<"bytes/s"<< endl;
    }
    closesocket(sRaw);
    WSACleanup();
    return 0;
}
/**********IP分组解析函数*************/
void DecodeIPPacket(char *pData) {
    int n = 0;
    IPHeader *pIPHdr = (IPHeader *) pData;
    // 源地址和目的地址
    in_addr source, dest;
    char szSourceIp[32], szDestIp[32];
    /***从IP头中取出源IP地址和目的IP地址***/
    source.S_un.S_addr = pIPHdr->ipSource;          // 设置源地址
    dest.S_un.S_addr = pIPHdr->ipDestination;       // 设置目的地址
    strcpy(szSourceIp, inet_ntoa(source));
    strcpy(szDestIp, inet_ntoa(dest));
   /* cout << "源IP:" << szSourceIp;
    cout << "目的IP: " << szDestIp << endl;*/
    int nHeaderLen = (pIPHdr->iphVerLen & 0xf) * sizeof(ULONG);// IP头长度
   // cout << "大小:" << ntohs(pIPHdr->ipLength) << endl;
    all+=ntohs(pIPHdr->ipLength);
    switch (pIPHdr->ipProtocol) // 协议
    {
        case IPPROTO_TCP: // 调用函数解析TCP包
            DecodeTCPPacket(pData + nHeaderLen);
            break;
        case IPPROTO_UDP:// 调用函数解析UDP包
            DecodeUDPPacket(pData + nHeaderLen);
            break;
        case IPPROTO_ICMP:// 调用函数解析ICMP包
            DecodeICMPPacket(pData + nHeaderLen);
            break;
        default:
            cout << " 协议号:" << (int) pIPHdr->ipProtocol << endl;
    }
}

/*********TCP包解析函数***********/
void DecodeTCPPacket(char *pData) {
    TCPHeader *pTCPHdr = (TCPHeader *) pData;
    /*cout << "TCP Source Port: " << ntohs(pTCPHdr->sourcePort);
    cout << "  Destination Port: " << ntohs(pTCPHdr->destinationPort) << endl;
    cout << pTCPHdr ->windows<<endl;*/

}

/***********UDP包解析函数**********/
void DecodeUDPPacket(char *pData) {
    UDPHeader *pUDPHdr = (UDPHeader *) pData;
   /* cout << "UDP Source Port: " << ntohs(pUDPHdr->sourcePort);
    cout << "  Destination Port: " << ntohs(pUDPHdr->destinationPort) << endl;*/
    //cout << ntohs(pUDPHdr ->len)<<endl;
}

/***********ICMP包解析函数 **********/
void DecodeICMPPacket(char *pData) {
    ICMPHeader *pICMPHdr = (ICMPHeader *) pData;
    cout << "ICMP Type: " << pICMPHdr->i_type << "Code: " << pICMPHdr->i_code << endl;

    switch (pICMPHdr->i_type) {
        case 0:
            cout << "Echo Response.\n";
            break;
        case 8:
            cout << "Echo Request.\n";
            break;
        case 3:
            cout << "Destination Unreachable.\n";
            break;
        case 11:
            cout << "Datagram Timeout(TTL=0).\n";
            break;
    }
}


``
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值