onetouchdlg.cpp
来自「可以一键自动检测局域网内的网关和未被占用的IP地址」· C++ 代码 · 共 2,298 行 · 第 1/5 页
CPP
2,298 行
index = i; //为第一个,退出
break;
}
}
}*/
// out.Format(out+"%d",index);
// AfxMessageBox(out);
if(index < 1 || index > total)
{
pcap_freealldevs(alldevs);
p->m_info = "未检测到可用网卡,配置失败.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
/* Jump to the selected adapter */
i = 0;
for(d=alldevs; i< index-1 ;d=d->next, i++);
//////////////
/* Open the adapter */
if ( (adhandle= pcap_open_live(d->name, // name of the device
65536, // portion of the packet to capture. 制定pcap捕获的最大数目的网络数据包;
// 65536 grants that the whole packet will be captured on all the MACs.
1, // promiscuous mode 混杂模式
-1, // read timeout 制定经过特定时间(ms)后读超时;0表示遇到错误退出,-1指定永不超时;
// remote authentication
errbuf // error buffer
) ) == NULL)
{
pcap_freealldevs(alldevs);
p->m_info = "Unable to open the adapter.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
/* Check the link layer. We support only Ethernet for simplicity. *///检测链路层
if(pcap_datalink(adhandle) != DLT_EN10MB)
{//仅支持以太网,其他类型帧头无法解析
pcap_freealldevs(alldevs);
p->m_info = "This program works only on Ethernet networks.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
if(d->addresses != NULL)
{
/* Retrieve the mask of the first address of the interface */
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
netip = ((struct sockaddr_in *)(d->addresses->addr))->sin_addr.S_un.S_addr; //ip addr
}
else
/* If the interface is without addresses we suppose to be in a C class network */
netmask=0xffffff;
////////////////获取网卡mac
LPADAPTER lpAdapter = PacketOpenAdapter(d->name);
PACKET_OID_DATA* OidData;
OidData = (PACKET_OID_DATA *)malloc(6 + sizeof(PACKET_OID_DATA));
OidData->Oid = OID_802_3_CURRENT_ADDRESS;//Oid=OID_802_3_PERMANENT_ADDRESS;
OidData->Length = 6;
ZeroMemory(OidData->Data, 6);
BOOLEAN Status = PacketRequest(lpAdapter, FALSE, OidData);
unsigned char localMAC[6];
if(Status)
{
for(int k=0; k<6; k++)
localMAC[k] = OidData->Data[k];
}
else
{
pcap_freealldevs(alldevs);
p->m_info = "Error retrieving the MAC address of the adapter!";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
free(OidData);
PacketCloseAdapter(lpAdapter);
////
pcap_freealldevs(alldevs);
////////////////////////////////
/////重复检测detectTimes次数后放弃
int detectTimes = 3;
while(detectTimes-- != 0)
{
repIP_List.clear();
/////////////compile the filter
char* packet_filter = "arp or udp or igmp";//过滤规则
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
{
p->m_info = "Unable to compile the packet filter. Check the syntax.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
////////////////set the filter
if (pcap_setfilter(adhandle, &fcode)<0)
{
p->m_info = "Error setting the filter.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
/////////////////////////////////
///截获一个符合假设要求的数据包
p->m_info = "正在获取网关信息,请稍候...";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
pcap_loop(adhandle, 1, packet_handler, NULL);//超时时间设为-1,即这里读取n个数据包后立即退出。
//超时设为T,则这里必须达到T时刻并且读取完n个数据包才退出。超时设为0则勇不退出.
//经过callback函数处理后,得到srcIP 和 dstIP
if(srcIP.byte1 == 0 && srcIP.byte2 == 0 && srcIP.byte3 == 0 && srcIP.byte4 == 0
|| dstIP.byte1 == 0 && dstIP.byte2 == 0 && dstIP.byte3 == 0 && dstIP.byte4 == 0)
{
pcap_freealldevs(alldevs);
p->m_info = "ERROR: 未截获到数据包!";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
continue;
}
////////////////////////////////
///采用pcap_send_queue队列发送arp请求.假设第一步截取到的数据包的srcIP或dstIP中含有实际的网段地址。
///分别以这两个网段构造2*254个arp请求包。如果有响应,则为正确的网段。此过程可重复两三次,提高假设命中的率
pcap_send_queue *squeue;//发送队列
int caplen = 2*254*76; //2*254个arp请求 76=16+60; 16是pcap_pkthdr大小,60是arp含ether头大小
int sync = 0, res=0;
pcap_pkthdr header;
pcap_pkthdr *pktheader = &header;
bool sent = false;
pktheader->len = 60;//设置pcap头大小(独立与数据包)
pktheader->caplen = 60;
squeue = pcap_sendqueue_alloc(caplen); //分配队列缓存
///////////////////////////////
////生成发送队列
//构造完整arp包
u_char packet[42];
ethernet_header eh;
arp_frame af;
// char ip1[15],ip2[15];
/* localMAC[0] = 0x00;
localMAC[1] = 0x1e;
localMAC[2] = 0x4f;
localMAC[3] = 0xea;
localMAC[4] = 0x9e;
localMAC[5] = 0xa7;*/
for(int k = 0 ;k < 6 ;k ++)
{
eh.eth_dest[k] = 0xff;//广播
eh.eth_src[k] = localMAC[k];//随便
af.Send_HW_Addr[k] = localMAC[k];//自己mac 关系mac-ip绑定
af.Targ_HW_Addr[k] = 0xff;//随便
}
eh.eth_type = htons(0x0806);//0806为arp
af.HW_Type = htons(0x0001);
af.Prot_Type = htons(0x0800);
af.HW_Addr_Len = 6;
af.Prot_Addr_Len = 4;
af.Opcode = htons(0x0001);//1 request 2 apply
// sprintf(ip, "%d.%d.%d.%d", netip&0xff,netip>>8&0xff,netip>>16&0xff,netip>>24&0xff);//从网卡中获取的自己ip
af.Send_Prot_Addr = inet_addr("127.0.0.1");//自己ip设为127.0.0.1
memset(packet, 0 , sizeof(packet));
memcpy(packet, &eh, sizeof(eh));
memcpy(packet + sizeof(eh), &af, sizeof(af));
/* packet[38] = 172;
packet[39] = 16;
packet[40] = 65;
packet[41] = 3;
if (pcap_sendqueue_queue(squeue, pktheader, packet) == -1)
{
sent = false;
printf("Warning: packet buffer too small, not all the packets will be sent.\n");
break;
}
*/
if(!(srcIP.byte1 == 255 && srcIP.byte2 ==255 && srcIP.byte3 ==255))
{//srcIP 排除不可能成为网段的地址
sent = true;
packet[38] = srcIP.byte1;
packet[39] = srcIP.byte2;
packet[40] = srcIP.byte3;
for(k=1; k<255; k++)
{//* 发送数据包
packet[41] = k;
/* if (pcap_sendpacket(adhandle, packet, 42) != 0)
{
p->m_info = "Error sending the packet.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
*/
if (pcap_sendqueue_queue(squeue, pktheader, packet) == -1)
{
sent = false;
printf("Warning: packet buffer too small, not all the packets will be sent.\n");
break;
}
}
}
if(!(dstIP.byte1 == 255 && dstIP.byte2 ==255 && dstIP.byte3 ==255)
&& !(dstIP.byte1 == srcIP.byte1 && dstIP.byte2 ==srcIP.byte2 && dstIP.byte3 ==srcIP.byte3))
{//dstIP 排除不可能成为网段的地址并防止重复往同一网段发送
sent = true;
packet[38] = dstIP.byte1;
packet[39] = dstIP.byte2;
packet[40] = dstIP.byte3;
for(k=1; k<255; k++)
{//* 发送数据包
packet[41] = k;
/* if (pcap_sendpacket(adhandle, packet, 42) != 0)
{
p->m_info = "Error sending the packet.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}*/
if (pcap_sendqueue_queue(squeue, pktheader, packet) == -1)
{
sent = false;
printf("Warning: packet buffer too small, not all the packets will be sent.\n");
break;
}
}
}
if(!sent)
{//两个网段都被排除
p->m_info = "网关检测失败,重新检测.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
continue;
}
///////////////////////////
//开始线程监听,设置监听过滤器
p->m_info = "正在检测IP冲突...";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
packet_filter = "arp and dst host 127.0.0.1";//过滤规则
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
{
p->m_info = "Unable to compile the packet filter. Check the syntax.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
////////////////set the filter
if (pcap_setfilter(adhandle, &fcode)<0)
{
p->m_info = "Error setting the filter.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
///启动监听线程
HANDLE hThread;//句柄跟ID
DWORD ThreadID;
hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)arpListenThread,adhandle,0,&ThreadID);
// AfxBeginThread(arpListenThread,adhandle);
///启动发送队列
if ((res = pcap_sendqueue_transmit(adhandle, squeue, sync)) < squeue->len)
{
char info[50];
sprintf(info,"An error occurred sending the packets: %s. Only %d bytes were sent\n", pcap_geterr(adhandle), res);
p->m_info = info;
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
//释放发送队列
pcap_sendqueue_destroy(squeue);
///等待监听线程结数据包束,确保可以收到响应
WaitForSingleObject(hThread,INFINITE);
if(repIP_List.size() > 1)
break;
else if(repIP_List.size() == 1)
{//如果反馈的ip唯一且是自己网卡的ip,则抛弃,重新开始
if(repIP_List[0].byte1==(netip&0xff)
&& repIP_List[0].byte2==(netip>>8&0xff)
&& repIP_List[0].byte3==(netip>>16&0xff)
&& repIP_List[0].byte4==(netip>>24&0xff))
continue;
}
else if(repIP_List.size() == 0)
{
p->m_info = "网关检测失败,重新检测.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
continue;
}
}//dectecttimes 循环结束
pcap_close(adhandle);
if(detectTimes==0)
{
p->m_info = "网关检测失败,请重新开始.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
///////////////////////////////////////////
///若是响应的ip段不止一个,取数目多者。
int srcCount=0, dstCount=0;
int Index=-1, srcIndex=-1, dstIndex=-1;
bool srcOwnPos[255],dstOwnPos[255];//已经占用的IP。从一开始,对应ip
bool* ownPos;
for(int k=0; k<255; k++)
{
srcOwnPos[k] = false;
dstOwnPos[k] = false;
}
for(k=0; k<repIP_List.size(); k++)
{
if(repIP_List[k].byte1==(netip&0xff)
&& repIP_List[k].byte2==(netip>>8&0xff)
&& repIP_List[k].byte3==(netip>>16&0xff)
&& repIP_List[k].byte4==(netip>>24&0xff))
continue;//跳过获取的响应ip正好为自身网卡ip的情况
if(repIP_List[k].byte1 == srcIP.byte1
&& repIP_List[k].byte2 == srcIP.byte2
&& repIP_List[k].byte3 == srcIP.byte3)
{
srcCount++;
srcIndex = k;
srcOwnPos[repIP_List[k].byte4] = true;
}
else if(repIP_List[k].byte1 == dstIP.byte1
&& repIP_List[k].byte2 == dstIP.byte2
&& repIP_List[k].byte3 == dstIP.byte3)
{
dstCount++;
dstIndex = k;
dstOwnPos[repIP_List[k].byte4] = true;
}
}
Index = srcCount>=dstCount?srcIndex:dstIndex;
ownPos = srcCount>=dstCount?srcOwnPos:dstOwnPos;
if(Index == -1)
{
p->m_info = "网关检测失败,请重新开始.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
ipAutoConfig = false;
return 0;
}
/////////////////////////////
///至此得到了已经占用的ip列表,选择剩余的ip进行设置
p->m_info = "已经获取到可用IP,请按\"确定\"进行设置.";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
CString strIp,strGate;
srand(clock());
int j = rand()%253 + 2;//随机选择一个
while(ownPos[j])
{
j++;
if(j==255)
j = 2;
}
//假设1为网关,考虑改进
strGate.Format("%d.%d.%d.%d",repIP_List[Index].byte1,repIP_List[Index].byte2,repIP_List[Index].byte3,1);//假设1为网关,考虑改进
strIp.Format("%d.%d.%d.%d",repIP_List[Index].byte1,repIP_List[Index].byte2,repIP_List[Index].byte3,j);
if(IDCANCEL == AfxMessageBox("系统分配给您的IP地址是:" + strIp + "。确定设置?" ,MB_OKCANCEL))
{
p->m_info = "";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
netshInUse = false;
ipAutoConfig = false;
return 0;
}
///////////开始配置
while(netshInUse)
Sleep(400);
netshInUse = true;
//ip&mask&gateWay
CString strCommand=sysDir+"/netsh interface ip set address name=\"本地连接\" static ";
strCommand+=strIp;
strCommand+=" mask = 255.255.255.0 gateway= ";
strCommand+=strGate;
strCommand+=" gwmetric = 1";
strChar=strCommand.GetBuffer(strCommand.GetLength());
strCommand.ReleaseBuffer();
if (!CreatePipe(&hRead,&hWrite,&sa,0)) {//创建管道
AfxMessageBox("Error On CreatePipe()");
netshInUse = false;
ipAutoConfig = false;
return 0;
}
si.hStdError = hWrite;
si.hStdOutput = hWrite;
p->m_info = "正在配置IP(网关)地址..";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
if (!CreateProcess(NULL,strChar
,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)) {
AfxMessageBox("Error on CreateProcess()");
netshInUse = false;
ipAutoConfig = false;
return 0;
}
CloseHandle(hWrite);//读管道前必须关掉写句柄
while (true) {//读取管道信息(即netsh返回信息)
if (ReadFile(hRead,buffer,4095,&bytesRead,NULL) == NULL)
break;
buffer[bytesRead] = 0;
s+=buffer;
// Sleep(200);
}
s.TrimRight();
if(s!="确定。" && s!="" && s!="Ok.")
::AfxMessageBox(s);
else
{
p->m_info = "IP(网关)地址配置成功!";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
}
////////////////////// dns1
strCommand=sysDir+"/netsh interface ip set dns name = \"本地连接\" source=static addr= ";
strCommand+="202.119.32.6";
strChar=strCommand.GetBuffer(strCommand.GetLength());
strCommand.ReleaseBuffer();
if (!CreatePipe(&hRead,&hWrite,&sa,0)) {//重新创建管道
AfxMessageBox("Error On CreatePipe()");
netshInUse = false;
ipAutoConfig = false;
return 0;
}
si.hStdError = hWrite;
si.hStdOutput = hWrite;
p->m_info = "正在配置首选DNS服务器....";
m_MWnd->SendMessage(WM_UPDATEDATA, FALSE);
if (!CreateProcess(NULL,strChar
,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)) {
AfxMessageBox("Error on CreateProcess()");
netshInUse = false;
ipAutoConfig = false;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?