dot1x.cpp
来自「802.1x认证客户端」· C++ 代码 · 共 407 行
CPP
407 行
//ThorClient 802.1x (using WinPcap 3.2 alpha1)
//Download: http://thorqq.ys168.com
//E-mail: thorqq@163.com
//Author: Thorqq
//
//CDot1X类通过发送消息与外界通讯
//WM_DOT1X 运行状态提示
//0 正常状态; 1 上线;-1 离线 -2 超时
//公共接口函数:
//CDot1X(HWND hDlg); 类构造函数
// 输入参数:hDlg -- 主窗口句柄
//~CDot1X(); 类析构函数
//void Connect(const USERDATA *UserData);
// *UserData -- 用户数据(用户名,密码,网卡等信息)
// 打开网卡,启动线程,发送请求认证数据帧,触发认证
//void Diconnect(); 终止线程,关闭网卡,发送离线请求数据帧,断开连接
//void ClosAdapter(); 关闭网卡
////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Dot1X.h"
#include "md5.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CDot1X::CDot1X(const HWND hDlg) : m_hDlg(hDlg)
{
m_hThread = NULL;
m_fp = NULL; // 网卡设备
u_char mcast[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03};//多播地址
memcpy(m_DestMac, mcast, 6);//默认目的地址为多播地址
}
CDot1X::~CDot1X()
{
}
bool CDot1X::OpenAdapter()
{
bpf_u_int32 netmask = 0;
char pcap_filter[100]; //filter space
struct bpf_program pcap_fp; //hold the compiled filter.
char errbuf[PCAP_ERRBUF_SIZE] = "";
//打开网卡
if(!(m_fp = pcap_open_live(m_pData->nic,// name of the device
256, // portion of the packet to capture, max 65536
0, // promiscuous mode closed
10, // read timeout
errbuf))) // error buffer
{
// AfxMessageBox(errbuf);
::SendMessage(m_hDlg, WM_DOT1X, -1, (long)errbuf);
return false;
}
//设置过滤器,只接收802.1X的帧
sprintf(pcap_filter, "ether dst %x:%x:%x:%x:%x:%x and ether proto 0x888e",
m_pData->mac[0],m_pData->mac[1],m_pData->mac[2],
m_pData->mac[3],m_pData->mac[4],m_pData->mac[5]);
// sprintf(pcap_filter, " or ether dst 01:80:c2:00:00:03 and ether proto 0x888e",
// m_pData->Mac[0],m_pData->Mac[1],m_pData->Mac[2],
// m_pData->Mac[3],m_pData->Mac[4],m_pData->Mac[5]);
if (pcap_compile(m_fp, &pcap_fp, pcap_filter, 0, netmask) == -1)
return false;
if (pcap_setfilter(m_fp, &pcap_fp) == -1)
return false;
return true;
}
DWORD WINAPI WorkProc(LPVOID lpParam)
{ //帧处理线程
CDot1X *pTalk = (CDot1X *) lpParam;
//提升线程优先级
::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
struct pcap_pkthdr *header;
const u_char *pkt_data;
int res;
DWORD dwTick, dwOldTick;
dwTick = dwOldTick = ::GetTickCount();
int flag = 0;
//逐个读取接收到的帧
while((res = pcap_next_ex( pTalk->m_fp, &header, &pkt_data)) >= 0)
{
if(res == 0)// Timeout elapsed
{
//用::GetTickCount()取得并计算超时的时间
dwTick = ::GetTickCount();
if(dwTick - dwOldTick >= 90000 //ms
&& pTalk->m_pData->relogin == 1)
{
::SendMessage(pTalk->m_hDlg, WM_DOT1X, -2, (long)"超时,重新连接");
dwOldTick = ::GetTickCount();
}
continue;
}
PPKTHDR pbuf = (PPKTHDR)pkt_data;
memcpy(pTalk->m_DestMac, pbuf->SourMAC, 6);//取得接收到帧的源地址
if(pbuf->Code == EAP_REQUEST)
{
switch(pbuf->EapType)
{
case EAP_KEEPONLINE:
pTalk->SendKeeponline(pbuf->Id);
dwOldTick = ::GetTickCount();
break;
case EAP_NOTIFICATION:
pTalk->SendVersion(pbuf->Id);
break;
case EAP_IDENTIFY:
pTalk->SendUsername(pbuf->Id);
break;
case EAP_MD5:
pTalk->SendPassword(pbuf->Id, ((PPASSWORDFRM) pkt_data)->Md5Pwd);
break;
default: ;
}
continue;
}
if(pbuf->Code == EAP_SUCCESS)
{
::SendMessage(pTalk->m_hDlg, WM_DOT1X, 1, (long)"认证成功 :)");
continue;
}
if(pbuf->Code == EAP_FAILURE)
{
if(pbuf->EapType == EAP_LOGOUT)
::SendMessage(pTalk->m_hDlg, WM_DOT1X, -1, (long)"断开连接");
else
::SendMessage(pTalk->m_hDlg, WM_DOT1X, -1, (long)pkt_data+0x18);
break;//jump out of the loop
}
if(pbuf->Code == EAP_OTHER)//这里应该处理两个帧
{//第一个是有关客户端下载地址的,这里不做处理
if(flag == 0)
{
flag = 1;
continue;
}
//认证之后的附加信息
u_char a[0xff] = {0};
memcpy(a, pkt_data+0x1a, *(pkt_data +0x11)-4);
// a[*(pkt_data +0x11)-3] = '\0';
for(int i= 0; i<0xff; i++)
{
if(a[0xff-i] == 0x34)
{
a[0xff-i] = '\t';
a[0xff-i+1] = '\n';
break;
}
}
::SendMessage(pTalk->m_hDlg, WM_DOT1X, 0, (long)a);
continue;
}
}
return res;
}
void CDot1X::ClosAdapter()
{
//此函数会导致主线程阻塞,导致了消息循环的阻塞,最终导致工作线程Crash掉
// ::WaitForSingleObject(m_hThread, 400);//INFINITE);
/////////////////////////////////
/* while(TRUE)
{
DWORD result ;
MSG msg ;
result = MsgWaitForMultipleObjects(1, &m_hThread,
FALSE, INFINITE, QS_ALLINPUT);
if (result == (WAIT_OBJECT_0))
{
break;
}
else
{
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
DispatchMessage(&msg);
}
}
*/////////////////////////////////////
::CloseHandle(m_hThread);//关闭线程
if(m_fp != NULL)
pcap_close(m_fp); //关闭网卡
}
void CDot1X::Connect(const USERDATA *pUserData)
{
m_pData = pUserData;
::SendMessage(m_hDlg, WM_DOT1X, 0, (long)"正在初始化网络适配器...");
if(!OpenAdapter())//打开网卡,设置过滤,启动线程
{
// ::SendMessage(m_hDlg, WM_DOT1X, -1, (long)"初始化网络适配器...失败");
return;
}
//启动帧处理线程
m_hThread = ::CreateThread(NULL, 0, WorkProc, this, 0, NULL);
SendLogin();
}
void CDot1X::Disconnect()
{
if(m_fp)
{
SendLogout();
::SendMessage(m_hDlg, WM_DOT1X, -1, (long)"断开连接");
// m_bQuit = true;
// ClosAdapter();
::SendMessage(m_hDlg, WM_DOT1X, 0, (long)"网络适配器已关闭");
}
}
bool CDot1X::SendLogin()
{ //发送EAPOL-START帧
u_char buf[100] = { 0 };
PLOGINFRM pbuf = (PLOGINFRM) buf;
InitBuf(buf);//Set Dest MAC, Source MAC, Protocol Type and Version
if(m_pData->morb == 'b')
memset(buf, 0xff, 6);//广播发送EAPOL-START(默认为多播发送)
pbuf->PktType = 0x01; //EAPOL-START
if(!pcap_sendpacket(m_fp, buf, 60))
{
::SendMessage(m_hDlg, WM_DOT1X, 0, (long)"查找接入设备...");
return true;
}
return false;
}
bool CDot1X::SendLogout()
{ //发送断线请求帧
u_char buf[100] = { 0 };
PLOGOUTFRM pbuf = (PLOGOUTFRM) buf;
InitBuf(buf);//set Dest MAC, Source MAC, Protocol Type and Version
pbuf->PktType = 0x02;//EAPOL-LOGOUT
if(!pcap_sendpacket(m_fp, buf, 60))
{
::SendMessage(m_hDlg, WM_DOT1X, 0, (long)"正在断开连接...");
return true;
}
return false;
}
bool CDot1X::SendVersion(const u_char Id)
{ //发送版本确认帧
/* u_char buf[100] = {
0x2e, 0x25, 0x4d, 0x3b, 0x5f, 0x43, 0x5f,
0x5d, 0x40, 0x5d, 0x5f, 0x5e, 0x5c, 0x6d, 0x6d,
0x6d, 0x6d, 0x6d, 0x6d, 0x6d,
*/
u_char buf[100] = {
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x88, 0x8e, 0x01, 0x00,
0x00, 0x31, 0x02, 0x01 ,0x00, 0x31, 0x02, 0x01,
0x16,
////
0x2e, 0x25,
////
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x16, 0x5f,
0x59, 0x55, 0x5e, 0xbb, 0x5c, 0x54, 0x58, 0x5a,
0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d,
0x6d, 0x6d, 0x6d
};
// PVERSIONFRM pbuf = (PVERSIONFRM) m_buf;
InitBuf(buf);
if(!pcap_sendpacket(m_fp, buf, 67))
{
::SendMessage(m_hDlg, WM_DOT1X, 0, (long)"查找认证服务器...");
return true;
}
return false;
}
bool CDot1X::SendUsername(const u_char Id)
{ //发送用户名帧
u_char buf[100] = { 0 };
PUSERNAMEFRM pbuf = (PUSERNAMEFRM) buf;
InitBuf(buf);
pbuf->Hdr.Len1 = ::htons(strlen(m_pData->username) + 0x0b);
pbuf->Hdr.Code = 0x02;
pbuf->Hdr.Id = Id;
pbuf->Hdr.Len2 = pbuf->Hdr.Len1;
pbuf->Hdr.EapType = 0x01;
pbuf->Unknown[0] = 0x15;
pbuf->Unknown[1] = 0x04;
if(m_pData->updateip == 0x01)
memcpy(pbuf->Ip, m_pData->ip, 4);//上传本机IP
memcpy(&pbuf->Username, &m_pData->username, strlen(m_pData->username));
if(!pcap_sendpacket(m_fp, buf, 60))
{
::SendMessage(m_hDlg, WM_DOT1X, 0, (long)"验证用户名...");
return true;
}
return false;
}
bool CDot1X::SendPassword(const u_char Id, const u_char *Chap)
{ // 发送密码帧
u_char buf[100] = { 0 };
PPASSWORDFRM pbuf = (PPASSWORDFRM) buf;
InitBuf(buf);
pbuf->Hdr.Len1 = ::htons(strlen(m_pData->username) + 0x16);
pbuf->Hdr.Code = 0x02;
pbuf->Hdr.Id = Id;
pbuf->Hdr.Len2 = pbuf->Hdr.Len1;
pbuf->Hdr.EapType = 0x04;
pbuf->Unknown[0] = 0x10;
SetMd5Buf(pbuf, Id, Chap);//计算MD5
memcpy(pbuf->Username, m_pData->username, strlen(m_pData->username));
if(!pcap_sendpacket(m_fp, buf, 60))
{
::SendMessage(m_hDlg, WM_DOT1X, 0, (long)"验证密码...");
return true;
}
return false;
}
bool CDot1X::SendKeeponline(const u_char Id)
{ //发送保持在线帧
u_char buf[100] = { 0 };
PKEEPONLINEFRM pbuf = (PKEEPONLINEFRM) buf;
InitBuf(buf);
pbuf->Hdr.Len1 = ::htons(strlen(m_pData->username) + 0x0b);
pbuf->Hdr.Code = 0x02;
pbuf->Hdr.Id = Id;
pbuf->Hdr.Len2 = pbuf->Hdr.Len1;
pbuf->Hdr.EapType = 0x14;
pbuf->Unknown[0] = 0x00;
pbuf->Unknown[1] = 0x15;
pbuf->Unknown[2] = 0x04;
if(m_pData->updateip == 0x01)
memcpy(pbuf->Ip, m_pData->ip, 4);
memcpy(pbuf->Username, m_pData->username, strlen(m_pData->username));
return !pcap_sendpacket(m_fp, buf, 60);
}
void CDot1X::SetMd5Buf(PPASSWORDFRM pBuf, const u_char ID, const u_char *chap)
{ //计算MD5
u_char TmpBuf[1 + 64 + 16];
MD5_CTX md5T;
u_char digest[16];
int PasswdLen = strlen(m_pData->password);
TmpBuf[0] = ID;// memcpy(TmpBuf + 0x00, ID, 1);
memcpy(TmpBuf + 0x01, m_pData->password, PasswdLen);
memcpy(TmpBuf + 0x01 + PasswdLen, chap, 16);
md5T.MD5Update(TmpBuf, 17 + PasswdLen);
md5T.MD5Final(digest);
memcpy(pBuf->Md5Pwd, digest, 16);
}
void CDot1X::InitBuf(u_char *buf)
{ //初始化各个帧
u_char prototype[3] = {0x88, 0x8e, 0x01};
if(m_pData->multisend == 0x00) //set destination MAC
memcpy(buf, m_DestMac, 6);
memcpy(buf+6 , m_pData->mac, 6); //set source MAC
memcpy(buf+12, prototype, 3); //set protocol type and its version
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?