基于MFC和winpcap的简单路由器实现
2015-06-15 09:51
856 查看
关键部分代码如下。
// 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); }
相关文章推荐
- Ubuntu 14.04 java环境安装配置(不是openJAVA)
- java打地鼠游戏
- 黑马程序员——方法覆盖、重载 、多态与动态绑定
- 将异常(getStackTrace)转化成String
- Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)
- RTMP流媒体播放过程
- HLS播放器开发难点
- 内存分配2
- 概率随机奖品
- About Perl(翻译Perl官网介绍)
- 企业信息门户平台整体解决方案研究(概述与案例分享)
- 每天进步一点点——linux——ls
- Fixing Typos
- 【hihoCoder】【挑战赛#12】
- 基于jQuery左侧大图右侧小图切换代码
- Android Jni笔记--创建一个String
- Python修改MP3文件的方法
- ExtJs学习之MessAgeBox的使用
- 用户数据库:QPAccountsDB
- IIS一些错误集锦