immortalwrt/package/jsda/njitclient/src/auth.c
2019-09-30 13:42:16 +08:00

767 lines
23 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* File: auth.c
* ------------
* 注核心函数为Authentication()由该函数执行801.1X认证
*/
int Authentication(const char *UserName, const char *Password, const char *DeviceName, const char *Version, const char *Key);
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include "h3c_AES_MD5.h"
#include <stdbool.h>
#include <pcap.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <arpa/inet.h>
#include "debug.h"
// 自定义常量
typedef enum { REQUEST = 1,
RESPONSE = 2,
SUCCESS = 3,
FAILURE = 4,
H3CDATA = 10 } EAP_Code;
typedef enum { IDENTITY = 1,
NOTIFICATION = 2,
MD5 = 4,
ALLOCATED = 7,
AVAILABLE = 20 } EAP_Type;
typedef uint8_t EAP_ID;
const uint8_t BroadcastAddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // 广播MAC地址
const uint8_t MultcastAddr[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03}; // 多播MAC地址
char H3C_VERSION[16];
char H3C_KEY[64];
//const char H3C_VERSION[16]="CH\x11V7.10-0313"; // 华为客户端版本号
//const char H3C_KEY[64] ="HuaWei3COM1X"; // H3C的固定密钥
//const char H3C_KEY[64] ="Oly5D62FaE94W7"; // H3C的另一个固定密钥网友取自MacOSX版本的iNode官方客户端
uint8_t AES_MD5req[32];
uint8_t AES_MD5data[32];
// 子函数声明
static void SendStartPkt(pcap_t *adhandle, const uint8_t mac[]);
static void SendLogoffPkt(pcap_t *adhandle, const uint8_t mac[]);
static void SendResponseIdentity(pcap_t *adhandle,
const uint8_t request[],
const uint8_t ethhdr[],
const uint8_t ip[4],
const char username[]);
static void SendFirstResponseIdentity(pcap_t *adhandle,
const uint8_t request[],
const uint8_t ethhdr[],
const uint8_t ip[4],
const char username[]);
static void SendResponseMD5(pcap_t *adhandle,
const uint8_t request[],
const uint8_t ethhdr[],
const char username[],
const char passwd[]);
static void SendResponsePassword(pcap_t *handle,
const uint8_t request[],
const uint8_t ethhdr[],
const char username[],
const char passwd[]);
static void SendResponseAvailable(pcap_t *adhandle,
const uint8_t request[],
const uint8_t ethhdr[],
const uint8_t ip[4],
const char username[]);
static void SendResponseNotification(pcap_t *handle,
const uint8_t request[],
const uint8_t ethhdr[]);
static void GetMacFromDevice(uint8_t mac[6], const char *devicename);
static void FillClientVersionArea(uint8_t area[]);
static void FillWindowsVersionArea(uint8_t area[]);
static void FillBase64Area(char area[]);
// From fillmd5.c
extern void FillMD5Area(uint8_t digest[],
uint8_t id, const char passwd[], const uint8_t srcMD5[]);
// From ip.c
extern void GetIpFromDevice(uint8_t ip[4], const char DeviceName[]);
int mode = 1; //auto reconnect
/**
* 函数Authentication()
*
* 使用以太网进行802.1X认证(802.1X Authentication)
* 该函数将不断循环应答802.1X认证会话,直到遇到错误后才退出
*/
int Authentication(const char *UserName, const char *Password, const char *DeviceName, const char *Version, const char *Key)
{
strcpy(H3C_VERSION, Version);
strcpy(H3C_KEY, Key);
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *adhandle; // adapter handle
uint8_t MAC[6];
char FilterStr[100];
struct bpf_program fcode;
const int DefaultTimeout = 2000; //设置接收超时参数单位ms
// NOTE: 这里没有检查网线是否已插好,网线插口可能接触不良
/* 打开适配器(网卡) */
adhandle = pcap_open_live(DeviceName, 65536, 1, DefaultTimeout, errbuf);
if (adhandle == NULL)
{
fprintf(stderr, "%s\n", errbuf);
exit(-1);
}
/* 查询本机MAC地址 */
GetMacFromDevice(MAC, DeviceName);
/* 生成随机数 */
srand((unsigned)time(NULL));
START_AUTHENTICATION:
{
/*
* 设置过滤器:
* 初始情况下只捕获发往本机的802.1X认证会话,不接收多播信息(避免误捕获其他客户端发出的多播信息)
* 进入循环体前可以重设过滤器,那时再开始接收多播信息
*/
sprintf(FilterStr, "(ether proto 0x888e) and (ether dst host %02x:%02x:%02x:%02x:%02x:%02x)",
MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]);
pcap_compile(adhandle, &fcode, FilterStr, 1, 0xff);
pcap_setfilter(adhandle, &fcode);
int i;
int retcode;
struct pcap_pkthdr *header = NULL;
const uint8_t *captured = NULL;
uint8_t ethhdr[14] = {0}; // ethernet header
uint8_t ip[4] = {10, 0, 0, 0}; // ip address
// 使用本机MAC地址生成伪装IP地址。
ip[1] = MAC[2] ^ (uint8_t)rand();
ip[2] = MAC[4] ^ (uint8_t)rand();
ip[3] = MAC[5] ^ (uint8_t)rand();
/* 主动发起认证会话 */
SendStartPkt(adhandle, MAC);
DPRINTF("[ ] Client: Start.\n");
/* 等待认证服务器的回应 */
bool serverIsFound = false;
while (!serverIsFound)
{
retcode = pcap_next_ex(adhandle, &header, &captured);
if (retcode == 1 && (EAP_Code)captured[18] == REQUEST)
serverIsFound = true;
else
{ // 延时后重试
sleep(1);
//DPRINTF(".");
SendStartPkt(adhandle, MAC);
// NOTE: 这里没有检查网线是否接触不良或已被拔下
}
}
// 填写应答包的报头(以后无须再修改)
// 默认以单播方式应答802.1X认证设备发来的Request
memcpy(ethhdr + 0, captured + 6, 6);
memcpy(ethhdr + 6, MAC, 6);
ethhdr[12] = 0x88;
ethhdr[13] = 0x8e;
// 收到的第一个包可能是Request Notification。取决于校方网络配置
if ((EAP_Type)captured[22] == NOTIFICATION)
{
DPRINTF("[%d] Server: Request Notification!\n", captured[19]);
// 发送Response Notification
SendResponseNotification(adhandle, captured, ethhdr);
DPRINTF(" Client: Response Notification.\n");
// 继续接收下一个Request包
retcode = pcap_next_ex(adhandle, &header, &captured);
assert(retcode == 1);
assert((EAP_Code)captured[18] == REQUEST);
}
// 分情况应答下一个包
if ((EAP_Type)captured[22] == IDENTITY)
{ // 通常情况会收到包Request Identity应回答Response Identity
DPRINTF("[%d] Server: Request Identity!\n", captured[19]);
GetIpFromDevice(ip, DeviceName);
SendFirstResponseIdentity(adhandle, captured, ethhdr, ip, UserName);
DPRINTF("[%d] Client: Response First Identity.\n", (EAP_ID)captured[19]);
}
else if ((EAP_Type)captured[22] == AVAILABLE)
{ // 遇到AVAILABLE包时需要特殊处理
// 中南财经政法大学目前使用的格式:
// 收到第一个Request AVAILABLE时要回答Response Identity
DPRINTF("[%d] Server: Request AVAILABLE!\n", captured[19]);
GetIpFromDevice(ip, DeviceName);
SendResponseIdentity(adhandle, captured, ethhdr, ip, UserName);
DPRINTF("[%d] Client: Response Identity.\n", (EAP_ID)captured[19]);
}
// 重设过滤器只捕获华为802.1X认证设备发来的包包括多播Request Identity / Request AVAILABLE
sprintf(FilterStr, "(ether proto 0x888e) and (ether src host %02x:%02x:%02x:%02x:%02x:%02x)",
captured[6], captured[7], captured[8], captured[9], captured[10], captured[11]);
pcap_compile(adhandle, &fcode, FilterStr, 1, 0xff);
pcap_setfilter(adhandle, &fcode);
// 进入循环体
for (;;)
{
// 调用pcap_next_ex()函数捕获数据包
while (pcap_next_ex(adhandle, &header, &captured) != 1)
{
//DPRINTF("."); // 若捕获失败则等1秒后重试
sleep(1); // 直到成功捕获到一个数据包后再跳出
// NOTE: 这里没有检查网线是否已被拔下或插口接触不良
}
// 根据收到的Request回复相应的Response包
if ((EAP_Code)captured[18] == REQUEST)
{
switch ((EAP_Type)captured[22])
{
case IDENTITY:
DPRINTF("[%d] Server: Request Identity!\n", (EAP_ID)captured[19]);
GetIpFromDevice(ip, DeviceName);
SendResponseIdentity(adhandle, captured, ethhdr, ip, UserName);
DPRINTF("[%d] Client: Response Identity.\n", (EAP_ID)captured[19]);
break;
case AVAILABLE:
DPRINTF("[%d] Server: Request AVAILABLE!\n", (EAP_ID)captured[19]);
GetIpFromDevice(ip, DeviceName);
SendResponseAvailable(adhandle, captured, ethhdr, ip, UserName);
DPRINTF("[%d] Client: Response AVAILABLE.\n", (EAP_ID)captured[19]);
break;
case MD5:
DPRINTF("[%d] Server: Request MD5-Challenge!\n", (EAP_ID)captured[19]);
SendResponseMD5(adhandle, captured, ethhdr, UserName, Password);
DPRINTF("[%d] Client: Response MD5-Challenge.\n", (EAP_ID)captured[19]);
break;
case ALLOCATED: //newtype:7;EAP_REQUEST ALLOCATED PACKAGE;
DPRINTF("[%d] Server: Request Allocated(Password)!\n", (EAP_ID)captured[19]);
SendResponsePassword(adhandle, captured, ethhdr, UserName, Password); //Send Password;
DPRINTF("[%d] Client: Response Allocated(Password).\n", (EAP_ID)captured[19]);
break;
case NOTIFICATION:
DPRINTF("[%d] Server: Request Notification!\n", captured[19]);
SendResponseNotification(adhandle, captured, ethhdr);
DPRINTF(" Client: Response Notification.\n");
break;
default:
DPRINTF("[%d] Server: Request (type:%d)!\n", (EAP_ID)captured[19], (EAP_Type)captured[22]);
DPRINTF("Error! Unexpected request type\n");
exit(-1);
break;
}
}
else if ((EAP_Code)captured[18] == FAILURE)
{ // 处理认证失败信息
uint8_t errtype = captured[22];
uint8_t msgsize = captured[23];
const char *msg = (const char *)&captured[24];
DPRINTF("[%d] Server: Failure.\n", (EAP_ID)captured[19]);
if (errtype == 0x09 && msgsize > 0)
{ // 输出错误提示消息
fprintf(stderr, "%s\n", msg);
// 已知的几种错误如下
// E2531:用户名不存在
// E2535:Service is paused
// E2542:该用户帐号已经在别处登录
// E2547:接入时段限制
// E2553:密码错误
// E2602:认证会话不存在
// E3137:客户端版本号无效
if (mode == 1)
{
goto START_AUTHENTICATION;
}
else
{
return 0; //exit(-1);
}
}
else if (errtype == 0x08) // 可能网络无流量时朊务器结束此次802.1X认证会话
{ // 遇此情况客户端立刻发起新的认证会话
goto START_AUTHENTICATION;
}
else
{
DPRINTF("errtype=0x%02x\n", errtype);
exit(-1);
}
}
else if ((EAP_Code)captured[18] == SUCCESS)
{
DPRINTF("[%d] Server: Success.\n", captured[19]);
}
else if ((EAP_Code)captured[18] == 0x0A)
{
DPRINTF("[%d] Server: (H3C data)\n", captured[19]);
if (captured[26] == 0x35)
{
for (i = 0; i < 32; i++)
{
AES_MD5req[i] = captured[i + 27];
}
h3c_AES_MD5_decryption(AES_MD5data, AES_MD5req);
}
}
else
{
DPRINTF("[%d] Server: (unknown data)\n", captured[19]);
}
}
}
return (0);
}
static void GetMacFromDevice(uint8_t mac[6], const char *devicename)
{
int fd;
int err;
struct ifreq ifr;
fd = socket(PF_PACKET, SOCK_RAW, htons(0x0806));
assert(fd != -1);
assert(strlen(devicename) < IFNAMSIZ);
strncpy(ifr.ifr_name, devicename, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
err = ioctl(fd, SIOCGIFHWADDR, &ifr);
assert(err != -1);
memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
err = close(fd);
assert(err != -1);
return;
}
static void SendStartPkt(pcap_t *handle, const uint8_t localmac[])
{
uint8_t packet[18];
// Ethernet Header (14 Bytes)
memcpy(packet, BroadcastAddr, 6);
memcpy(packet + 6, localmac, 6);
packet[12] = 0x88;
packet[13] = 0x8e;
// EAPOL (4 Bytes)
packet[14] = 0x01; // Version=1
packet[15] = 0x01; // Type=Start
packet[16] = packet[17] = 0x00; // Length=0x0000
// 为了兼容不同院校的网络配置这里发送两遍Start包
// 1、广播发送Strat包
pcap_sendpacket(handle, packet, sizeof(packet));
// 2、多播发送Strat包
//memcpy(packet, MultcastAddr, 6);
//pcap_sendpacket(handle, packet, sizeof(packet));
}
static void SendResponseAvailable(pcap_t *handle, const uint8_t request[], const uint8_t ethhdr[], const uint8_t ip[4], const char username[])
{
int i;
uint16_t eaplen;
int usernamelen;
uint8_t response[128];
assert((EAP_Code)request[18] == REQUEST);
assert((EAP_Type)request[22] == AVAILABLE);
// Fill Ethernet header
memcpy(response, ethhdr, 14);
// 802,1X Authentication
// {
response[14] = 0x1; // 802.1X Version 1
response[15] = 0x0; // Type=0 (EAP Packet)
//response[16~17]留空 // Length
// Extensible Authentication Protocol
// {
response[18] = (EAP_Code)RESPONSE; // Code
response[19] = request[19]; // ID
//response[20~21]留空 // Length
response[22] = (EAP_Type)AVAILABLE; // Type
// Type-Data
// {
i = 23;
response[i++] = 0x00; // 上报是否使用代理
response[i++] = 0x15; // 上传IP地址
response[i++] = 0x04; //
memcpy(response + i, ip, 4); //
i += 4; //
response[i++] = 0x06; // 携带版本号
response[i++] = 0x07; //
FillBase64Area((char *)response + i); //
i += 28; //
response[i++] = ' '; // 两个空格符
response[i++] = ' '; //
usernamelen = strlen(username);
memcpy(response + i, username, usernamelen); //
i += usernamelen; //
// }
// }
// }
// 补填前面留空的两处Length
eaplen = htons(i - 18);
memcpy(response + 16, &eaplen, sizeof(eaplen));
memcpy(response + 20, &eaplen, sizeof(eaplen));
// 发送
pcap_sendpacket(handle, response, i);
}
static void SendResponseIdentity(pcap_t *adhandle, const uint8_t request[], const uint8_t ethhdr[], const uint8_t ip[4], const char username[])
{
uint8_t response[256];
size_t i;
uint16_t eaplen;
int usernamelen;
assert((EAP_Code)request[18] == REQUEST);
assert((EAP_Type)request[22] == IDENTITY || (EAP_Type)request[22] == AVAILABLE); // 兼容中南财经政法大学情况
// Fill Ethernet header
memcpy(response, ethhdr, 14);
// 802,1X Authentication
// {
response[14] = 0x1; // 802.1X Version 1
response[15] = 0x0; // Type=0 (EAP Packet)
//response[16~17]留空 // Length
// Extensible Authentication Protocol
// {
response[18] = (EAP_Code)RESPONSE; // Code
response[19] = request[19]; // ID
//response[20~21]留空 // Length
response[22] = (EAP_Type)IDENTITY; // Type
response[23] = 0x16;
response[24] = 0x20;
memcpy(response + 25, AES_MD5data, 32);
// Type-Data
// {
i = 57;
response[i++] = 0x15; // 上传IP地址
response[i++] = 0x04; //
memcpy(response + i, ip, 4); //
i += 4; //
response[i++] = 0x06; // 携带版本号
response[i++] = 0x07; //
FillBase64Area((char *)response + i); //
i += 28; //
response[i++] = ' '; // 两个空格符
response[i++] = ' '; //
usernamelen = strlen(username); //末尾添加用户名
memcpy(response + i, username, usernamelen);
i += usernamelen;
assert(i <= sizeof(response));
// }
// }
// }
// 补填前面留空的两处Length
eaplen = htons(i - 18);
memcpy(response + 16, &eaplen, sizeof(eaplen));
memcpy(response + 20, &eaplen, sizeof(eaplen));
// 发送
pcap_sendpacket(adhandle, response, i);
return;
}
void SendFirstResponseIdentity(pcap_t *adhandle, const uint8_t request[], const uint8_t ethhdr[], const uint8_t ip[4], const char username[])
{
uint8_t response[128];
size_t i;
uint16_t eaplen;
int usernamelen;
assert((EAP_Code)request[18] == REQUEST);
assert((EAP_Type)request[22] == IDENTITY || (EAP_Type)request[22] == AVAILABLE); // 兼容中南财经政法大学情况
// Fill Ethernet header
memcpy(response, ethhdr, 14);
// 802,1X Authentication
// {
response[14] = 0x1; // 802.1X Version 1
response[15] = 0x0; // Type=0 (EAP Packet)
//response[16~17]留空 // Length
// Extensible Authentication Protocol
// {
response[18] = (EAP_Code)RESPONSE; // Code
response[19] = request[19]; // ID
//response[20~21]留空 // Length
response[22] = (EAP_Type)IDENTITY; // Type
// Type-Data
// {
i = 23;
//response[i++] = 0x15; // 上传IP地址
//response[i++] = 0x04; //
//memcpy(response+i, ip, 4);//
//i += 4; //
response[i++] = 0x06; // 携带版本号
response[i++] = 0x07; //
FillBase64Area((char *)response + i); //
i += 28; //
response[i++] = ' '; // 两个空格符
response[i++] = ' '; //
usernamelen = strlen(username); //末尾添加用户名
memcpy(response + i, username, usernamelen);
i += usernamelen;
assert(i <= sizeof(response));
// }
// }
// }
// 补填前面留空的两处Length
eaplen = htons(i - 18);
memcpy(response + 16, &eaplen, sizeof(eaplen));
memcpy(response + 20, &eaplen, sizeof(eaplen));
// 发送
pcap_sendpacket(adhandle, response, i);
return;
}
static void SendResponseMD5(pcap_t *handle, const uint8_t request[], const uint8_t ethhdr[], const char username[], const char passwd[])
{
uint16_t eaplen;
size_t usernamelen;
size_t packetlen;
uint8_t response[128];
assert((EAP_Code)request[18] == REQUEST);
assert((EAP_Type)request[22] == MD5);
usernamelen = strlen(username);
eaplen = htons(22 + usernamelen);
packetlen = 14 + 4 + 22 + usernamelen; // ethhdr+EAPOL+EAP+usernamelen
// Fill Ethernet header
memcpy(response, ethhdr, 14);
// 802,1X Authentication
// {
response[14] = 0x1; // 802.1X Version 1
response[15] = 0x0; // Type=0 (EAP Packet)
memcpy(response + 16, &eaplen, sizeof(eaplen)); // Length
// Extensible Authentication Protocol
// {
response[18] = (EAP_Code)RESPONSE; // Code
response[19] = request[19]; // ID
response[20] = response[16]; // Length
response[21] = response[17]; //
response[22] = (EAP_Type)MD5; // Type
response[23] = 16; // Value-Size: 16 Bytes
FillMD5Area(response + 24, request[19], passwd, request + 24);
memcpy(response + 40, username, usernamelen);
// }
// }
pcap_sendpacket(handle, response, packetlen);
}
static void SendResponsePassword(pcap_t *handle, const uint8_t request[], const uint8_t ethhdr[], const char username[], const char passwd[]) //SendResponsePassword(adhandle, captured, ethhdr, UserName, Password);
{
uint16_t eaplen;
size_t usernamelen;
size_t passwordlen;
size_t packetlen;
uint8_t response[128];
assert((EAP_Code)request[18] == REQUEST);
assert((EAP_Type)request[22] == ALLOCATED);
usernamelen = strlen(username);
passwordlen = strlen(passwd);
eaplen = htons(6 + usernamelen + passwordlen);
packetlen = 24 + usernamelen + passwordlen; //14+4+22+usernamelen; // ethhdr+EAPOL+EAP+usernamelen
// Fill Ethernet header
memcpy(response, ethhdr, 14);
// 802.1X Authentication
// {
response[14] = 0x1; // 802.1X Version 1
response[15] = 0x0; // Type=0 (EAP Packet)
memcpy(response + 16, &eaplen, sizeof(eaplen)); // Length
// Extensible Authentication Protocol
// {
response[18] = (EAP_Code)RESPONSE; // Code
response[19] = request[19]; // ID
response[20] = response[16]; // Length
response[21] = response[17]; //
response[22] = (EAP_Type)ALLOCATED; // Type
response[23] = passwordlen; // Value-Size: 16 Bytes
memcpy(response + 24, passwd, passwordlen);
memcpy(response + 24 + passwordlen + 1, username, usernamelen); //?????
// }
pcap_sendpacket(handle, response, packetlen);
}
static void SendLogoffPkt(pcap_t *handle, const uint8_t localmac[])
{
uint8_t packet[18];
// Ethernet Header (14 Bytes)
memcpy(packet, MultcastAddr, 6);
memcpy(packet + 6, localmac, 6);
packet[12] = 0x88;
packet[13] = 0x8e;
// EAPOL (4 Bytes)
packet[14] = 0x01; // Version=1
packet[15] = 0x02; // Type=Logoff
packet[16] = packet[17] = 0x00; // Length=0x0000
// 发包
pcap_sendpacket(handle, packet, sizeof(packet));
}
// 函数: XOR(data[], datalen, key[], keylen)
//
// 使用密钥key[]对数据data[]进行异或加密
//(注:该函数也可反向用于解密)
static void XOR(uint8_t data[], unsigned dlen, const char key[], unsigned klen)
{
unsigned int i, j;
// 先按正序处理一遍
for (i = 0; i < dlen; i++)
data[i] ^= key[i % klen];
// 再按倒序处理第二遍
for (i = dlen - 1, j = 0; j < dlen; i--, j++)
data[i] ^= key[j % klen];
}
static void FillClientVersionArea(uint8_t area[20])
{
uint32_t random;
char RandomKey[8 + 1];
random = (uint32_t)time(NULL); // 注可以选任意32位整数
sprintf(RandomKey, "%08x", random); // 生成RandomKey[]字符串
// 第一轮异或运算以RandomKey为密钥加密16字节
memcpy(area, H3C_VERSION, sizeof(H3C_VERSION));
XOR(area, 16, RandomKey, strlen(RandomKey));
// 此16字节加上4字节的random组成总计20字节
random = htonl(random); // (需调整为网络字节序)
memcpy(area + 16, &random, 4);
// 第二轮异或运算以H3C_KEY为密钥加密前面生成的20字节
XOR(area, 20, H3C_KEY, strlen(H3C_KEY));
}
static void FillWindowsVersionArea(uint8_t area[20])
{
const uint8_t WinVersion[20] = "r70393861";
memcpy(area, WinVersion, 20);
XOR(area, 20, H3C_KEY, strlen(H3C_KEY));
}
static void SendResponseNotification(pcap_t *handle, const uint8_t request[], const uint8_t ethhdr[])
{
uint8_t response[67];
assert((EAP_Code)request[18] == REQUEST);
assert((EAP_Type)request[22] == NOTIFICATION);
// Fill Ethernet header
memcpy(response, ethhdr, 14);
// 802,1X Authentication
// {
response[14] = 0x1; // 802.1X Version 1
response[15] = 0x0; // Type=0 (EAP Packet)
response[16] = 0x00; // Length
response[17] = 0x31; //
// Extensible Authentication Protocol
// {
response[18] = (EAP_Code)RESPONSE; // Code
response[19] = (EAP_ID)request[19]; // ID
response[20] = response[16]; // Length
response[21] = response[17]; //
response[22] = (EAP_Type)NOTIFICATION; // Type
int i = 23;
/* Notification Data (44 Bytes) */
// 其中前2+20字节为客户端版本
response[i++] = 0x01; // type 0x01
response[i++] = 22; // lenth
FillClientVersionArea(response + i);
i += 20;
// 最后2+20字节存储加密后的Windows操作系统版本号
response[i++] = 0x02; // type 0x02
response[i++] = 22; // length
FillWindowsVersionArea(response + i);
i += 20;
// }
// }
pcap_sendpacket(handle, response, sizeof(response));
}
static void FillBase64Area(char area[])
{
uint8_t version[20];
const char Tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/"; // 标准的Base64字符映射表
uint8_t c1, c2, c3;
int i, j;
// 首先生成20字节加密过的H3C版本号信息
FillClientVersionArea(version);
// 然后按照Base64编码法将前面生成的20字节数据转换为28字节ASCII字符
i = 0;
j = 0;
while (j < 24)
{
c1 = version[i++];
c2 = version[i++];
c3 = version[i++];
area[j++] = Tbl[(c1 & 0xfc) >> 2];
area[j++] = Tbl[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)];
area[j++] = Tbl[((c2 & 0x0f) << 2) | ((c3 & 0xc0) >> 6)];
area[j++] = Tbl[c3 & 0x3f];
}
c1 = version[i++];
c2 = version[i++];
area[24] = Tbl[(c1 & 0xfc) >> 2];
area[25] = Tbl[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)];
area[26] = Tbl[((c2 & 0x0f) << 2)];
area[27] = '=';
}