关键部分代码如下。
- // VCRouterDlg.cpp : 实现文件
- //
- #include "stdafx.h"
- #include "VCRouter.h"
- #include "VCRouterDlg.h"
- #include "afxdialogex.h"
- #include "pcap.h"
- #include <stdlib.h>
- #include <string.h>
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- #define MAX_IF 5 // 最大接口数目
- #pragma pack(1)
- typedef struct FrameHeader_t { // 帧首部
- UCHAR DesMAC[6]; // 目的地址
- UCHAR SrcMAC[6]; // 源地址
- USHORT FrameType; // 帧类型
- } FrameHeader_t;
- typedef struct ARPFrame_t { // ARP 帧
- FrameHeader_t FrameHeader; // 帧首部
- WORD HardwareType; // 硬件类型
- WORD ProtocolType; // 协议类型
- BYTE HLen; // 硬件地址长度
- BYTE PLen; // 协议地址长度
- WORD Operation; // 操作值
- UCHAR SendHa[6]; // 源MAC 地址
- ULONG SendIP; // 源IP 地址
- UCHAR RecvHa[6]; // 目的MAC 地址
- ULONG RecvIP; // 目的IP 地址
- } ARPFrame_t;
- typedef struct IPHeader_t { // IP 首部
- BYTE Ver_HLen; // 版本+头部长度
- BYTE TOS; // 服务类型
- WORD TotalLen; // 总长度
- WORD ID; // 标识
- WORD Flag_Segment; // 标志+片偏移
- BYTE TTL; // 生存时间
- BYTE Protocol; // 协议
- WORD Checksum; // 头部校验和
- ULONG SrcIP; // 源IP 地址
- ULONG DstIP; // 目的IP 地址
- } IPHeader_t;
- typedef struct ICMPHeader_t { // ICMP 首部
- BYTE Type; // 类型
- BYTE Code; // 代码
- WORD Checksum; // 校验和
- WORD Id; // 标识
- WORD Sequence; // 序列号
- } ICMPHeader_t;
- typedef struct IPFrame_t { // IP 帧
- FrameHeader_t FrameHeader; // 帧首部
- IPHeader_t IPHeader; // IP 首部
- } IPFrame_t;
- typedef struct ip_t { // 网络地址
- ULONG IPAddr; // IP 地址
- ULONG IPMask; // 子网掩码
- } ip_t;
- typedef struct IfInfo_t { // 接口信息
- CString DeviceName; // 设备名
- CString Description; // 设备描述
- UCHAR MACAddr[6]; // MAC 地址
- CArray <ip_t, ip_t&> ip; // IP 地址列表
- pcap_t *adhandle; // pcap 句柄
- } IfInfo_t;
- typedef struct SendPacket_t { // 发送数据包结构
- int len; // 长度
- BYTE PktData[2000];// 数据缓存
- ULONG TargetIP; // 目的IP 地址
- UINT_PTR n_mTimer; // 定时器
- UINT IfNo; // 接口序号
- } SendPacket_t;
- typedef struct RouteTable_t { // 路由表结构
- ULONG Mask; // 子网掩码
- ULONG DstIP; // 目的地址
- ULONG NextHop; // 下一跳步
- UINT IfNo; // 接口序号
- } RouteTable_t;
- typedef struct IP_MAC_t { // IP-MAC 地址映射结构
- ULONG IPAddr; // IP 地址
- UCHAR MACAddr[6]; // MAC 地址
- } IP_MAC_t;
- // 全局变量
- /******************************************************************
- *******/
- IfInfo_t IfInfo[MAX_IF]; // 接口信息数组
- int IfCount; // 接口个数
- UINT_PTR TimerCount; // 定时器个数
- CList <SendPacket_t, SendPacket_t&> SP; // 发送数据包缓存队列
- CList <IP_MAC_t, IP_MAC_t&> IP_MAC; // IP-MAC 地址映射列表
- CList <RouteTable_t, RouteTable_t&> RouteTable; // 路由表
- //CMyRouterDlg *pDlg; // 对话框指针
- CVCRouterDlg *pDlg;
- CMutex mMutex(0, 0, 0); // 互斥
- /******************************************************************
- *******/
- // 全局函数
- /******************************************************************
- *******/
- // IP 地址转换
- CString IPntoa(ULONG nIPAddr);
- // MAC 地址转换
- CString MACntoa(UCHAR *nMACAddr);
- // MAC 地址比较
- bool cmpMAC(UCHAR *MAC1, UCHAR *MAC2);
- // MAC 地址复制
- void cpyMAC(UCHAR *MAC1, UCHAR *MAC2);
- // MAC 地址设置
- void setMAC(UCHAR *MAC, UCHAR ch);
- // IP 地址查询
- bool IPLookup(ULONG ipaddr, UCHAR *p);
- // 数据包捕获线程
- UINT Capture(PVOID pParam);
- // 获取本地接口MAC 地址线程
- UINT CaptureLocalARP(PVOID pParam);
- // 发送ARP 请求
- void ARPRequest(pcap_t *adhandle, UCHAR *srcMAC, ULONG srcIP, ULONG targetIP);
- // 查询路由表
- DWORD RouteLookup(UINT &ifNO, DWORD desIP, CList <RouteTable_t,
- RouteTable_t&> *routeTable);
- // 处理ARP 数据包
- void ARPPacketProc(struct pcap_pkthdr *header, const u_char *pkt_data);
- // 处理IP 数据包
- void IPPacketProc(IfInfo_t *pIfInfo, struct pcap_pkthdr *header, const u_char
- *pkt_data);
- // 处理ICMP 数据包
- void ICMPPacketProc(IfInfo_t *pIfInfo, BYTE type, BYTE code, const u_char
- *pkt_data);
- // 检查IP 数据包头部校验和是否正确
- int IsChecksumRight(char * buffer);
- // 计算校验和
- unsigned short ChecksumCompute(unsigned short *buffer, int size);
- //下一部分
- // 获取本地接口MAC 地址线程
- UINT CaptureLocalARP(PVOID pParam)
- {
- int res;
- struct pcap_pkthdr *header;
- const u_char *pkt_data;
- IfInfo_t *pIfInfo;
- ARPFrame_t *ARPFrame;
- CString DisplayStr;
- pIfInfo = (IfInfo_t *)pParam;
- while (true)
- {
- Sleep(50);
- res = pcap_next_ex(pIfInfo->adhandle, &header, &pkt_data);
- // 超时
- if (res == 0)
- continue;
- if (res > 0)
- {
- ARPFrame = (ARPFrame_t *)(pkt_data);
- // 得到本接口的MAC 地址
- if ((ARPFrame->FrameHeader.FrameType == htons(0x0806))
- && (ARPFrame->Operation == htons(0x0002))
- && (ARPFrame->SendIP == pIfInfo->ip[0].IPAddr))
- {
- cpyMAC(pIfInfo->MACAddr, ARPFrame->SendHa);
- return 0;
- }
- }
- }
- }
- void setMAC(UCHAR *MAC, UCHAR ch)
- {
- for (int i = 0; i < 6; i++)
- {
- MAC[i] = ch;
- }
- return;
- }
- // 发送ARP 请求
- void ARPRequest(pcap_t *adhandle, UCHAR *srcMAC, ULONG srcIP, ULONG
- targetIP)
- {
- ARPFrame_t ARPFrame;
- int i;
- for (i = 0; i < 6; i++)
- {
- ARPFrame.FrameHeader.DesMAC[i] = 255;
- ARPFrame.FrameHeader.SrcMAC[i] = srcMAC[i];
- ARPFrame.SendHa[i] = srcMAC[i];
- ARPFrame.RecvHa[i] = 0;
- }
- ARPFrame.FrameHeader.FrameType = htons(0x0806);
- ARPFrame.HardwareType = htons(0x0001);
- ARPFrame.ProtocolType = htons(0x0800);
- ARPFrame.HLen = 6;
- ARPFrame.PLen = 4;
- ARPFrame.Operation = htons(0x0001);
- ARPFrame.SendIP = srcIP;
- ARPFrame.RecvIP = targetIP;
- pcap_sendpacket(adhandle, (u_char *)&ARPFrame, sizeof(ARPFrame_t));
- }
- void cpyMAC(UCHAR *MAC1, UCHAR *MAC2)
- {
- for (int i = 0; i < 6; i++)
- {
- MAC1[i] = MAC2[i];
- }
- }
- // 比较两个MAC 地址是否相同
- bool cmpMAC(UCHAR *MAC1, UCHAR *MAC2)
- {
- for (int i = 0; i < 6; i++)
- {
- if (MAC1[i] == MAC2[i])
- {
- continue;
- }
- else
- {
- return false;
- }
- }
- return true;
- }
- // 把IP 地址转换成点分十进制形式
- CString IPntoa(ULONG nIPAddr)
- {
- char strbuf[50];
- u_char *p;
- CString str;
- p = (u_char *)&nIPAddr;
- sprintf_s(strbuf, "%03d.%03d.%03d.%03d", p[0], p[1], p[2], p[3]);
- str = strbuf;
- return str;
- }
- // 把MAC 地址转换成“%02X:%02X:%02X:%02X:%02X:%02X”的格式
- CString MACntoa(UCHAR *nMACAddr)
- {
- char strbuf[50];
- CString str;
- sprintf_s(strbuf, "%02X:%02X:%02X:%02X:%02X:%02X", nMACAddr[0],
- nMACAddr[1],
- nMACAddr[2], nMACAddr[3], nMACAddr[4], nMACAddr[5]);
- str = strbuf;
- return str;
- }
- // 数据包捕获线程
- UINT Capture(PVOID pParam)
- {
- int res;
- IfInfo_t *pIfInfo;
- struct pcap_pkthdr *header;
- const u_char *pkt_data;
- pIfInfo = (IfInfo_t *)pParam;
- // 开始正式接收并处理帧
- while (true)
- {
- res = pcap_next_ex(pIfInfo->adhandle, &header, &pkt_data);
- if (res == 1)
- {
- FrameHeader_t *fh;
- fh = (FrameHeader_t *)pkt_data;
- switch (ntohs(fh->FrameType))
- {
- case 0x0806:
- ARPFrame_t *ARPf;
- ARPf = (ARPFrame_t *)pkt_data;
- //TRACE1(" 收到 ARP 包 源 IP 为: %d\n", ARPf->SendIP);
- // ARP 包,转到ARP 包处理函数
- ARPPacketProc(header, pkt_data);
- break;
- case 0x0800:
- IPFrame_t *IPf;
- IPf = (IPFrame_t*)pkt_data;
- //TRACE1(" 收 到 IP 包 源IP 为:%d\n",IPf->IPHeader.SrcIP );
- // IP 包,转到IP 包处理函数
- IPPacketProc(pIfInfo, header, pkt_data);
- break;
- default:
- break;
- }
- }
- else if (res == 0) // 超时
- {
- continue;
- }
- else
- {
- AfxMessageBox(_T("pcap_next_ex 函数出错!"));
- }
- }
- return 0;
- }
- // 处理ARP 数据包
- void ARPPacketProc(struct pcap_pkthdr *header, const u_char *pkt_data)
- {
- bool flag;
- ARPFrame_t ARPf;
- IPFrame_t *IPf;
- SendPacket_t sPacket;
- POSITION pos, CurrentPos;
- IP_MAC_t ip_mac;
- UCHAR macAddr[6];
- ARPf = *(ARPFrame_t *)pkt_data;
- if (ARPf.Operation == ntohs(0x0002))
- {
- pDlg->Logger.InsertString(-1, _T("收到ARP响应包"));
- pDlg->Logger.InsertString(-1, (_T(" ARP ") + (IPntoa(ARPf.SendIP)) + _T(" -- ")
- + MACntoa(ARPf.SendHa)));
- // IP -MAC 地址映射表中已经存在该对应关系
- if (IPLookup(ARPf.SendIP, macAddr))
- {
- pDlg->Logger.InsertString(-1, _T(" 该对应关系已经存在于 IP - MAC 地址映射表中"));
- return;
- }
- else
- {
- ip_mac.IPAddr = ARPf.SendIP;
- memcpy(ip_mac.MACAddr, ARPf.SendHa, 6);
- // 将IP-MAC 映射关系存入表中
- IP_MAC.AddHead(ip_mac);
- // 日志输出信息
- pDlg->Logger.InsertString(-1, _T(" 将该对应关系存入 IP -MAC 地址映射表中"));
- }
- mMutex.Lock(INFINITE);
- do{
- // 查看是否能转发缓存中的IP 数据报
- flag = false;
- // 没有需要处理的内容
- if (SP.IsEmpty())
- {
- break;
- }
- // 遍历转发缓存区
- pos = SP.GetHeadPosition();
- for (int i = 0; i < SP.GetCount(); i++)
- {
- CurrentPos = pos;
- sPacket = SP.GetNext(pos);
- if (sPacket.TargetIP == ARPf.SendIP)
- {
- IPf = (IPFrame_t *)sPacket.PktData;
- cpyMAC(IPf->FrameHeader.DesMAC, ARPf.SendHa);
- for (int t = 0; t < 6; t++)
- {
- IPf->FrameHeader.SrcMAC[t] =
- IfInfo[sPacket.IfNo].MACAddr[t];
- }
- // 发送IP 数据包
- pcap_sendpacket(IfInfo[sPacket.IfNo].adhandle, (u_char
- *)sPacket.PktData, sPacket.len);
- SP.RemoveAt(CurrentPos);
- // 日志输出信息
- pDlg->Logger.InsertString(-1, _T(" 转发缓存区中目的地址是该MAC 地址的IP 数据包"));
- pDlg->Logger.InsertString(-1, (_T(" 发送 IP 数据包:") + IPntoa(IPf->IPHeader.SrcIP)
- + "->"
- + IPntoa(IPf->IPHeader.DstIP) + " " +
- MACntoa(IPf->FrameHeader.SrcMAC)
- + "->" + MACntoa(IPf->FrameHeader.DesMAC)));
- flag = true;
- break;
- }
- }
- } while (flag);
- mMutex.Unlock();
- }
- }
- // 查询IP-MAC 映射表
- bool IPLookup(ULONG ipaddr, UCHAR *p)
- {
- IP_MAC_t ip_mac;
- POSITION pos;
- if (IP_MAC.IsEmpty()) return false;
- pos = IP_MAC.GetHeadPosition();
- for (int i = 0; i < IP_MAC.GetCount(); i++)
- {
- ip_mac = IP_MAC.GetNext(pos);
- if (ipaddr == ip_mac.IPAddr)
- {
- for (int j = 0; j < 6; j++)
- {
- p[j] = ip_mac.MACAddr[j];
- }
- return true;
- }
- }
- return false;
- }
- // 处理IP 数据包
- void IPPacketProc(IfInfo_t *pIfInfo, struct pcap_pkthdr *header, const u_char
- *pkt_data)
- {
- IPFrame_t *IPf;
- SendPacket_t sPacket;
- IPf = (IPFrame_t *)pkt_data;
- pDlg->Logger.InsertString(-1, (_T(" 收 到 IP 数 据 包 :") +
- IPntoa(IPf->IPHeader.SrcIP) + "->"
- + IPntoa(IPf->IPHeader.DstIP)));
- // ICMP 超时
- if (IPf->IPHeader.TTL <= 0)
- {
- ICMPPacketProc(pIfInfo, 11, 0, pkt_data);
- return;
- }
- IPHeader_t *IpHeader = &(IPf->IPHeader);
- // ICMP 差错
- if (IsChecksumRight((char *)IpHeader) == 0)
- {
- // 日志输出信息
- pDlg->Logger.InsertString(-1, _T(" IP 数据包包头校验和错误,丢弃数据包"));
- return;
- }
- // 路由查询
- DWORD nextHop; // 经过路由选择算法得到的下一站目的IP 地址
- UINT ifNo; // 下一跳的接口序号
- // 路由查询
- if ((nextHop = RouteLookup(ifNo, IPf->IPHeader.DstIP, &RouteTable)) == -1)
- {
- // ICMP 目的不可达
- ICMPPacketProc(pIfInfo, 3, 0, pkt_data);
- return;
- }
- else
- {
- sPacket.IfNo = ifNo;
- sPacket.TargetIP = nextHop;
- cpyMAC(IPf->FrameHeader.SrcMAC, IfInfo[sPacket.IfNo].MACAddr);
- // TTL 减1
- IPf->IPHeader.TTL -= 1;
- unsigned short check_buff[sizeof(IPHeader_t)];
- // 设IP 头中的校验和为0
- IPf->IPHeader.Checksum = 0;
- memset(check_buff, 0, sizeof(IPHeader_t));
- IPHeader_t * ip_header = &(IPf->IPHeader);
- memcpy(check_buff, ip_header, sizeof(IPHeader_t));
- // 计算IP 头部校验和
- IPf->IPHeader.Checksum = ChecksumCompute(check_buff,
- sizeof(IPHeader_t));
- // IP-MAC 地址映射表中存在该映射关系
- if (IPLookup(sPacket.TargetIP, IPf->FrameHeader.DesMAC))
- {
- memcpy(sPacket.PktData, pkt_data, header->len);
- sPacket.len = header->len;
- if (pcap_sendpacket(IfInfo[sPacket.IfNo].adhandle, (u_char *)
- sPacket.PktData, sPacket.len) != 0)
- {
- // 错误处理
- AfxMessageBox(_T("发送IP 数据包时出错!"));
- return;
- }
- // 日志输出信息
- pDlg->Logger.InsertString(-1, _T(" 转发IP 数据包:"));
- pDlg->Logger.InsertString(-1, (_T(" ") + IPntoa(IPf->IPHeader.SrcIP)
- + "->"
- + IPntoa(IPf->IPHeader.DstIP) + _T(" ") +
- MACntoa(IPf->FrameHeader.SrcMAC)
- + "->" + MACntoa(IPf->FrameHeader.DesMAC)));
- }
- // IP-MAC 地址映射表中不存在该映射关系
- else
- {
- if (SP.GetCount() < 65530) // 存入缓存队列
- {
- sPacket.len = header->len;
- // 将需要转发的数据报存入缓存区
- memcpy(sPacket.PktData, pkt_data, header->len);
- // 在某一时刻只允许一个线程维护链表
- mMutex.Lock(INFINITE);
- sPacket.n_mTimer = TimerCount;
- if (TimerCount++ > 65533)
- {
- TimerCount = 1;
- }
- pDlg->SetTimer(sPacket.n_mTimer, 10000, NULL);
- SP.AddTail(sPacket);
- mMutex.Unlock();
- // 日志输出信息
- pDlg->Logger.InsertString(-1, _T(" 缺少目的MAC 地址,将IP数据包存入转发缓冲区"));
- pDlg->Logger.InsertString(-1, (_T(" 存入转发缓冲区的数据包为:") + IPntoa(IPf->IPHeader.SrcIP)
- + "->" + IPntoa(IPf->IPHeader.DstIP) + " " +
- MACntoa(IPf->FrameHeader.SrcMAC)
- + "->xx:xx:xx:xx:xx:xx"));
- pDlg->Logger.InsertString(-1, _T(" 发送ARP 请求"));
- // 发送ARP 请求
- ARPRequest(IfInfo[sPacket.IfNo].adhandle,
- IfInfo[sPacket.IfNo].MACAddr,
- IfInfo[sPacket.IfNo].ip[1].IPAddr, sPacket.TargetIP);
- }
- else // 如缓存队列太长,抛弃该报
- {
- // 日志输出信息
- pDlg->Logger.InsertString(-1, _T("转发缓冲区溢出,丢弃IP数据包"));
- pDlg->Logger.InsertString(-1, (_T(" 丢弃的IP 数据包为:") +
- IPntoa(IPf->IPHeader.SrcIP) + "->"
- + IPntoa(IPf->IPHeader.DstIP) + " " +
- MACntoa(IPf->FrameHeader.SrcMAC)
- + "->xx:xx:xx:xx:xx:xx"));
- }
- }
- }
- }
- // 判断IP 数据包头部校验和是否正确
- int IsChecksumRight(char * buffer)
- {
- // 获得IP 头内容
- IPHeader_t * ip_header = (IPHeader_t *)buffer;
- // 备份原来的校验和
- unsigned short checksumBuf = ip_header->Checksum;
- unsigned short check_buff[sizeof(IPHeader_t)];
- // 设IP 头中的校验和为0
- ip_header->Checksum = 0;
- memset(check_buff, 0, sizeof(IPHeader_t));
- memcpy(check_buff, ip_header, sizeof(IPHeader_t));
- // 计算IP 头部校验和
- ip_header->Checksum = ChecksumCompute(check_buff, sizeof(IPHeader_t));
- // 与备份的校验和进行比较
- if (ip_header->Checksum == checksumBuf)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- // 查询路由表
- DWORD RouteLookup(UINT &ifNO, DWORD desIP, CList <RouteTable_t,
- RouteTable_t&> *routeTable)
- {
- // desIP 为网络序
- DWORD MaxMask = 0; // 获得最大的子网掩码的地址,没有获得时初始为 - 1
- int Index = -1; // 获得最大的子网掩码的地址对应的路由表 索引,以便获得下一站路由器的地址
- POSITION pos;
- RouteTable_t rt;
- DWORD tmp;
- pos = routeTable->GetHeadPosition();
- for (int i = 0; i < routeTable->GetCount(); i++)
- {
- rt = routeTable->GetNext(pos);
- if ((desIP & rt.Mask) == rt.DstIP)
- {
- Index = i;
- if (rt.Mask >= MaxMask)
- {
- ifNO = rt.IfNo;
- if (rt.NextHop == 0) // 直接投递
- {
- tmp = desIP;
- }
- else
- {
- tmp = rt.NextHop;
- }
- }
- }
- }
- if (Index == -1) // 目的不可达
- {
- return -1;
- }
- else // 找到了下一跳地址
- {
- return tmp;
- }
- }
- // 发送ICMP 数据包
- void ICMPPacketProc(IfInfo_t *pIfInfo, BYTE type, BYTE code, const u_char
- *pkt_data)
- {
- u_char * ICMPBuf = new u_char[70];
- // 填充帧首部
- memcpy(((FrameHeader_t *)ICMPBuf)->DesMAC, ((FrameHeader_t
- *)pkt_data)->SrcMAC, 6);
- memcpy(((FrameHeader_t *)ICMPBuf)->SrcMAC, ((FrameHeader_t
- *)pkt_data)->DesMAC, 6);
- ((FrameHeader_t *)ICMPBuf)->FrameType = htons(0x0800);
- // 填充IP 首部
- ((IPHeader_t *)(ICMPBuf + 14))->Ver_HLen = ((IPHeader_t
- *)(pkt_data + 14))->Ver_HLen;
- ((IPHeader_t *)(ICMPBuf + 14))->TOS = ((IPHeader_t
- *)(pkt_data + 14))->TOS;
- ((IPHeader_t *)(ICMPBuf + 14))->TotalLen = htons(56);
- ((IPHeader_t *)(ICMPBuf + 14))->ID = ((IPHeader_t *)(pkt_data + 14))->ID;
- ((IPHeader_t *)(ICMPBuf + 14))->Flag_Segment = ((IPHeader_t
- *)(pkt_data + 14))->Flag_Segment;
- ((IPHeader_t *)(ICMPBuf + 14))->TTL = 64;
- ((IPHeader_t *)(ICMPBuf + 14))->Protocol = 1;
- ((IPHeader_t *)(ICMPBuf + 14))->SrcIP = ((IPHeader_t
- *)(pkt_data + 14))->DstIP;
- ((IPHeader_t *)(ICMPBuf + 14))->DstIP = ((IPHeader_t
- *)(pkt_data + 14))->SrcIP;
- ((IPHeader_t *)(ICMPBuf + 14))->Checksum =
- htons(ChecksumCompute((unsigned short *)(ICMPBuf + 14), 20));
- // 填充ICMP 首部
- ((ICMPHeader_t *)(ICMPBuf + 34))->Type = type;
- ((ICMPHeader_t *)(ICMPBuf + 34))->Code = code;
- ((ICMPHeader_t *)(ICMPBuf + 34))->Id = 0;
- ((ICMPHeader_t *)(ICMPBuf + 34))->Sequence = 0;
- ((ICMPHeader_t *)(ICMPBuf + 34))->Checksum =
- htons(ChecksumCompute((unsigned short *)(ICMPBuf + 34), 8));
- // 填充数据
- memcpy((u_char *)(ICMPBuf + 42), (IPHeader_t *)(pkt_data + 14), 20);
- memcpy((u_char *)(ICMPBuf + 62), (u_char *)(pkt_data + 34), 8);
- // 发送数据包
- pcap_sendpacket(pIfInfo->adhandle, (u_char *)ICMPBuf, 70);
- // 日志输出信息
- if (type == 11)
- {
- pDlg->Logger.InsertString(-1, _T(" 发送ICMP 超时数据包:"));
- }
- if (type == 3)
- {
- pDlg->Logger.InsertString(-1, _T(" 发送ICMP 目的不可达数据包:"));
- }
- pDlg->Logger.InsertString(-1, (_T(" ICMP ->") + IPntoa(((IPHeader_t
- *)(ICMPBuf + 14))->DstIP)
- + "-" + MACntoa(((FrameHeader_t *)ICMPBuf)->DesMAC)));
- delete[] ICMPBuf;
- }
- // 计算校验和
- unsigned short ChecksumCompute(unsigned short * buffer, int size)
- {
- // 32 位,延迟进位
- unsigned long cksum = 0;
- while (size > 1)
- {
- cksum += *buffer++;
- // 16 位相加
- size -= sizeof(unsigned short);
- }
- if (size)
- {
- // 最后可能有单独8 位
- cksum += *(unsigned char *)buffer;
- }
- // 将高 16 位进位加至低16 位
- cksum = (cksum >> 16) + (cksum & 0xffff);
- cksum += (cksum >> 16);
- // 取反
- return (unsigned short)(~cksum);
- }
- // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
- class CAboutDlg : public CDialogEx
- {
- public:
- CAboutDlg();
- // 对话框数据
- enum { IDD = IDD_ABOUTBOX };
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
- // 实现
- protected:
- DECLARE_MESSAGE_MAP()
- };
- CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
- {
- }
- void CAboutDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- }
- BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
- END_MESSAGE_MAP()
- // CVCRouterDlg 对话框
- CVCRouterDlg::CVCRouterDlg(CWnd* pParent /*=NULL*/)
- : CDialogEx(CVCRouterDlg::IDD, pParent)
- {
- m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
- }
- void CVCRouterDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- DDX_Control(pDX, LOGGER_LIST, Logger);
- DDX_Control(pDX, ROUTER_LIST, m_RouteTable);
- DDX_Control(pDX, IDC_NEXTHOP, m_NextHop);
- DDX_Control(pDX, IDC_NETMASK, m_Mask);
- DDX_Control(pDX, IDC_IPADDRESS, m_Destination);
- }
- BEGIN_MESSAGE_MAP(CVCRouterDlg, CDialogEx)
- ON_WM_SYSCOMMAND()
- ON_WM_PAINT()
- ON_WM_QUERYDRAGICON()
- ON_BN_CLICKED(ONSTART_BUTTON, &CVCRouterDlg::OnStartClickedButton)
- ON_BN_CLICKED(ONSTOP_BUTTON, &CVCRouterDlg::OnBnClickedButton)
- ON_BN_CLICKED(ADD_ROUTER_BUTTON, &CVCRouterDlg::OnAddRouterButton)
- ON_BN_CLICKED(DELETE_ROUTER_BUTTON, &CVCRouterDlg::OnDeleteRouterButton)
- ON_WM_DESTROY()
- ON_WM_TIMER()
- END_MESSAGE_MAP()
- // CVCRouterDlg 消息处理程序
- BOOL CVCRouterDlg::OnInitDialog()
- {
- CDialogEx::OnInitDialog();
- CVCRouterApp* pApp = (CVCRouterApp*)AfxGetApp();
- pDlg = (CVCRouterDlg*)pApp->m_pMainWnd;
- // 将“关于...”菜单项添加到系统菜单中。
- // IDM_ABOUTBOX 必须在系统命令范围内。
- ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
- ASSERT(IDM_ABOUTBOX < 0xF000);
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != NULL)
- {
- BOOL bNameValid;
- CString strAboutMenu;
- bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
- ASSERT(bNameValid);
- if (!strAboutMenu.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
- }
- }
- // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
- // 执行此操作
- SetIcon(m_hIcon, TRUE); // 设置大图标
- SetIcon(m_hIcon, FALSE); // 设置小图标
- // TODO: 在此添加额外的初始化代码
- return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
- }
- void CVCRouterDlg::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if ((nID & 0xFFF0) == IDM_ABOUTBOX)
- {
- CAboutDlg dlgAbout;
- dlgAbout.DoModal();
- }
- else
- {
- CDialogEx::OnSysCommand(nID, lParam);
- }
- }
- // 如果向对话框添加最小化按钮,则需要下面的代码
- // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
- // 这将由框架自动完成。
- void CVCRouterDlg::OnPaint()
- {
- if (IsIconic())
- {
- CPaintDC dc(this); // 用于绘制的设备上下文
- SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
- // 使图标在工作区矩形中居中
- int cxIcon = GetSystemMetrics(SM_CXICON);
- int cyIcon = GetSystemMetrics(SM_CYICON);
- CRect rect;
- GetClientRect(&rect);
- int x = (rect.Width() - cxIcon + 1) / 2;
- int y = (rect.Height() - cyIcon + 1) / 2;
- // 绘制图标
- dc.DrawIcon(x, y, m_hIcon);
- }
- else
- {
- CDialogEx::OnPaint();
- }
- }
- //当用户拖动最小化窗口时系统调用此函数取得光标
- //显示。
- HCURSOR CVCRouterDlg::OnQueryDragIcon()
- {
- return static_cast<HCURSOR>(m_hIcon);
- }
- void CVCRouterDlg::OnStartClickedButton()
- {
- // TODO: 在此添加控件通知处理程序代码
- pcap_if_t *alldevs, *d;
- pcap_addr_t *a;
- struct bpf_program fcode;
- char errbuf[PCAP_ERRBUF_SIZE], strbuf[1000];
- int i, j, k;
- ip_t ipaddr;
- UCHAR srcMAC[6];
- ULONG srcIP;
- SetTimer(3999, 10000, 0);
- // 获得本机的设备列表
- if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* 无 需 认 证 */,
- &alldevs, errbuf) == -1)
- {
- // 错误,返回错误信息
- sprintf_s(strbuf, "pcap_findalldevs_ex 错误: %s", errbuf);
- MessageBox((LPCTSTR)strbuf);
- PostMessage(WM_QUIT, 0, 0);
- }
- i = 0;
- j = 0;
- k = 0;
- // 获取 IP 地址信息
- for (d = alldevs; d != NULL; d = d->next)
- {
- if (d->addresses != NULL) // 排除集成 modem 的影响(没有 IP 地址)
- {
- // 得到一个有效的接口和其 IP 地址列表
- IfInfo[i].DeviceName = d->name;
- IfInfo[i].Description = d->description;
- for (a = d->addresses; a; a = a->next)
- {
- if (a->addr->sa_family == AF_INET)
- {
- ipaddr.IPAddr = (((struct sockaddr_in
- *)a->addr)->sin_addr.s_addr);
- ipaddr.IPMask = (((struct sockaddr_in
- *)a->netmask)->sin_addr.s_addr);
- IfInfo[i].ip.Add(ipaddr);
- j++;
- }
- }
- if (i == MAX_IF) // 最多处理 MAX_IF 个接口
- {
- break;
- }
- else
- {
- i++;
- }
- }
- }
- // 不符合路由器 IP 地址数目要求
- if (j < 2)
- {
- MessageBox("该路由程序要求本地主机至少应具有 2 个 IP 地址");
- PostMessage(WM_QUIT, 0, 0);
- }
- // 保存实际的网卡数
- IfCount = i;
- // 打开接口
- for (i = 0; i < IfCount; i++)
- {
- if ((IfInfo[i].adhandle = pcap_open(IfInfo[i].DeviceName, // 设备名
- 65536, // 最大包长度
- PCAP_OPENFLAG_PROMISCUOUS,
- // 混杂模式
- 1000, // 超时时间
- NULL, // 远程认证
- errbuf // 错误缓存
- )) == NULL)
- {
- // 错误,显示错误信息
- sprintf_s(strbuf, " 接 口 未 能 打 开 。 WinPcap 不 支 持 %s 。 ",
- IfInfo[i].DeviceName);
- MessageBox((LPCTSTR)strbuf);
- PostMessage(WM_QUIT, 0, 0);
- }
- }
- // 开启数据包捕获线程,获取本地接口的 MAC 地址,线程数目为网卡个数
- CWinThread* pthread;
- for (i = 0; i < IfCount; i++)
- {
- pthread = AfxBeginThread(CaptureLocalARP, &IfInfo[i],
- THREAD_PRIORITY_NORMAL);
- if (!pthread)
- {
- MessageBox(_T("创建数据包捕获线程失败! "));
- PostMessage(WM_QUIT, 0, 0);
- }
- }
- // 将列表中网卡硬件地址清 0
- for (i = 0; i < IfCount; i++)
- {
- setMAC(IfInfo[i].MACAddr, 0);
- }
- // 为得到真实网卡地址,使用虚假的 MAC 地址和 IP 地址向本机发送 ARP 请求
- setMAC(srcMAC, 66); // 设置虚假的 MAC 地址
- srcIP = inet_addr("112.112.112.112"); // 设置虚假的 IP 地址
- for (i = 0; i < IfCount; i++)
- {
- ARPRequest(IfInfo[i].adhandle, srcMAC, srcIP, IfInfo[i].ip[0].IPAddr);
- }
- // 确保所有接口的 MAC 地址完全收到
- setMAC(srcMAC, 0);
- do {
- Sleep(1000);
- k = 0;
- for (i = 0; i < IfCount; i++)
- {
- if (!cmpMAC(IfInfo[i].MACAddr, srcMAC))
- {
- k++;
- continue;
- }
- else
- {
- break;
- }
- }
- } while (!((j++ > 10) || (k == IfCount)));
- if (k != IfCount)
- {
- MessageBox(_T("至少有一个接口的 MAC 地址没能得到! "));
- PostMessage(WM_QUIT, 0, 0);
- }
- // 日志输出接口信息
- for (i = 0; i < IfCount; i++)
- {
- Logger.InsertString(-1, _T("接口:"));
- Logger.InsertString(-1, _T(" 设备名: ") + IfInfo[i].DeviceName);
- Logger.InsertString(-1, _T(" 设备描述: ") + IfInfo[i].Description);
- Logger.InsertString(-1, (_T("MAC 地址:") + MACntoa(IfInfo[i].MACAddr)));
- for (j = 0; j < IfInfo[i].ip.GetSize(); j++)
- {
- Logger.InsertString(-1, (_T("IP 地址: ") + IPntoa(IfInfo[i].ip[j].IPAddr)));
- }
- }
- // 初始化路由表并显示
- RouteTable_t rt;
- for (i = 0; i < IfCount; i++)
- {
- for (j = 0; j < IfInfo[i].ip.GetSize(); j++)
- {
- rt.IfNo = i;
- rt.DstIP = IfInfo[i].ip[j].IPAddr & IfInfo[i].ip[j].IPMask;
- rt.Mask = IfInfo[i].ip[j].IPMask;
- rt.NextHop = 0; // 直接投递
- RouteTable.AddTail(rt);
- m_RouteTable.InsertString(-1, IPntoa(rt.Mask) + " -- " +
- IPntoa(rt.DstIP) + " -- " + IPntoa(rt.NextHop) + " (直接投递)");
- }
- }
- // 设置过滤规则:仅仅接收 arp 响应帧和需要路由的帧
- CString Filter, Filter0, Filter1;
- Filter0 = "(";
- Filter1 = "(";
- for (i = 0; i < IfCount; i++)
- {
- Filter0 += _T("(ether dst ") + MACntoa(IfInfo[i].MACAddr) + _T(")");
- for (j = 0; j < IfInfo[i].ip.GetSize(); j++)
- {
- Filter1 += _T("(ip dst host ") + IPntoa(IfInfo[i].ip[j].IPAddr) + _T(")");
- if (((j == (IfInfo[i].ip.GetSize() - 1))) && (i == (IfCount - 1)))
- {
- Filter1 += ")";
- }
- else
- {
- Filter1 += " or ";
- }
- }
- if (i == (IfCount - 1))
- {
- Filter0 += ")";
- }
- else
- {
- Filter0 += " or ";
- }
- }
- Filter = Filter0 + _T(" and ((arp and (ether[21]=0x2)) or (not") + Filter1 + _T("))");
- sprintf_s(strbuf, "%s", Filter);
- //TRACE1("filter:%s /n",strbuf);
- for (i = 0; i < IfCount; i++)
- {
- if (pcap_compile(IfInfo[i].adhandle, &fcode, strbuf, 1,
- IfInfo[i].ip[0].IPMask) < 0)
- {
- MessageBox(_T("过滤规则编译不成功,请检查书写的规则语法是否正确! "));
- PostMessage(WM_QUIT, 0, 0);
- }
- if (pcap_setfilter(IfInfo[i].adhandle, &fcode) < 0)
- {
- MessageBox(_T("设置过滤器错误! "));
- PostMessage(WM_QUIT, 0, 0);
- }
- }
- // 不再需要该设备列表,释放之
- pcap_freealldevs(alldevs);
- TimerCount = 1;
- // 开始捕获数据包
- for (i = 0; i < IfCount; i++)
- {
- pthread = AfxBeginThread(Capture, &IfInfo[i],
- THREAD_PRIORITY_NORMAL);
- if (!pthread)
- {
- MessageBox(_T("创建数据包捕获线程失败! "));
- PostMessage(WM_QUIT, 0, 0);
- }
- }
- }
- void CVCRouterDlg::OnBnClickedButton()
- {
- // TODO: 在此添加控件通知处理程序代码
- SendMessage(WM_CLOSE);
- }
- void CVCRouterDlg::OnAddRouterButton()
- {
- // TODO: 在此添加控件通知处理程序代码
- bool flag;
- int i, j;
- DWORD ipaddr;
- RouteTable_t rt;
- m_NextHop.GetAddress(ipaddr);
- ipaddr = htonl(ipaddr);
- // 检查合法性
- flag = false;
- for (i = 0; i < IfCount; i++)
- {
- for (j = 0; j < IfInfo[i].ip.GetSize(); j++)
- {
- if (((IfInfo[i].ip[j].IPAddr) & (IfInfo[i].ip[j].IPMask)) ==
- ((IfInfo[i].ip[j].IPMask) & ipaddr))
- {
- rt.IfNo = i;
- // 记录子网掩码
- m_Mask.GetAddress(ipaddr);
- rt.Mask = htonl(ipaddr);
- // 记录目的 IP
- m_Destination.GetAddress(ipaddr);
- rt.DstIP = htonl(ipaddr);
- // 记录下一跳
- m_NextHop.GetAddress(ipaddr);
- rt.NextHop = htonl(ipaddr);
- // 把该条路由表项添加到路由表
- RouteTable.AddTail(rt);
- // 在路由表窗口中显示该路由表项
- m_RouteTable.InsertString(-1, IPntoa(rt.Mask) + " -- "
- + IPntoa(rt.DstIP) + " -- " + IPntoa(rt.NextHop));
- flag = true;
- }
- }
- }
- if (!flag)
- {
- MessageBox(_T("输入错误,请重新输入! "));
- }
- }
- void CVCRouterDlg::OnDeleteRouterButton()
- {
- // TODO: 在此添加控件通知处理程序代码
- int i;
- char str[100], ipaddr[20];
- ULONG mask, destination, nexthop;
- RouteTable_t rt;
- POSITION pos, CurrentPos;
- str[0] = NULL;
- ipaddr[0] = NULL;
- if ((i = m_RouteTable.GetCurSel()) == LB_ERR)
- {
- return;
- }
- m_RouteTable.GetText(i, (LPTSTR)str);
- // 取得子网掩码选项
- strncat_s(ipaddr, str, 15);
- mask = inet_addr(ipaddr);
- // 取得目的地址选项
- ipaddr[0] = 0;
- strncat_s(ipaddr, &str[19], 15);
- destination = inet_addr(ipaddr);
- // 取得下一跳选项
- ipaddr[0] = 0;
- strncat_s(ipaddr, &str[38], 15);
- nexthop = inet_addr(ipaddr);
- if (nexthop == 0)
- {
- MessageBox(_T("直接连接路由,不允许删除! "));
- return;
- }
- // 把该路由表项从路由表窗口中删除
- m_RouteTable.DeleteString(i);
- // 路由表中没有需要处理的内容,则返回
- if (RouteTable.IsEmpty())
- {
- return;
- }
- // 遍历路由表,把需要删除的路由表项从路由表中删除
- pos = RouteTable.GetHeadPosition();
- for (i = 0; i < RouteTable.GetCount(); i++)
- {
- CurrentPos = pos;
- rt = RouteTable.GetNext(pos);
- if ((rt.Mask == mask) && (rt.DstIP == destination) && (rt.NextHop ==
- nexthop))
- {
- RouteTable.RemoveAt(CurrentPos);
- return;
- }
- }
- }
- //????????????
- void CVCRouterDlg::OnDestroy()
- {
- // TODO: Add your control notification handler code here
- CDialog::OnDestroy();
- // TODO: Add your message handler code here
- SP.RemoveAll();
- IP_MAC.RemoveAll();
- RouteTable.RemoveAll();
- for (int i = 0; i < IfCount; i++)
- {
- IfInfo[i].ip.RemoveAll();
- }
- }
- void CVCRouterDlg::OnTimer(UINT nIDEvent)
- {
- // TODO: Add your message handler code here and/or call default
- SendPacket_t sPacket;
- POSITION pos, CurrentPos;
- IPFrame_t *IPf;
- // 没有需要处理的内容
- if (SP.IsEmpty())
- {
- return;
- }
- mMutex.Lock(INFINITE);
- // 遍历转发缓存区
- pos = SP.GetHeadPosition();
- for (int i = 0; i < SP.GetCount(); i++)
- {
- CurrentPos = pos;
- sPacket = SP.GetNext(pos);
- if (sPacket.n_mTimer == nIDEvent)
- {
- IPf = (IPFrame_t *)sPacket.PktData;
- // 日志输出信息
- Logger.InsertString(-1, _T("IP 数据报在转发队列中等待 10 秒后还未能被转发"));
- Logger.InsertString(-1, (_T(" 定时器中删除该 IP 数据报: ") +
- IPntoa(IPf->IPHeader.SrcIP) + "->"
- + IPntoa(IPf->IPHeader.DstIP) + " " +
- MACntoa(IPf->FrameHeader.SrcMAC)
- + _T("->xx:xx:xx:xx:xx:xx")));
- KillTimer(sPacket.n_mTimer);
- SP.RemoveAt(CurrentPos);
- }
- }
- mMutex.Unlock();
- CDialog::OnTimer(nIDEvent);
- }