示例#1
0
/*不涉及ether设备未运行处理,比如休眠后唤醒,网卡重置处理*/
int auth802x()
{

	//pcap_if_t *alldevs;
	//pcap_if_t *d;
	//int inum;
	int i = 0;
	pcap_t *adhandle;
	int res;
	char errbuf[PCAP_ERRBUF_SIZE];
	//时间相关
	struct tm *ltime;
	char timestr[16];
	time_t local_tv_sec;
	//抓去相关
	struct pcap_pkthdr *header;
	const u_char *pkt_data;
	u_short len;

	//过滤相关
	//uint8_t	MAC[6];
	//char devicename[100];
	//uint8_t	MAC[6];
	Setting setting;
	
	struct bpf_program fcode;
	char	FilterStr[100];
	bool serverIsFound = false;

	FILE *fp;
	


	long filesize = file_size("setting.ini");
	if (filesize>0)
	{
		fp = fopen("setting.ini", "rb");
		//-------------------OK-----------------------
		//fscanf(fp, "%s\n", dev1.devicename1);
		//fscanf(fp, "%x\t%x\t%x\t%x\t%x\t%x", dev1.MAC1, dev1.MAC1 + 1, dev1.MAC1 + 2, dev1.MAC1 + 3, 
		//	dev1.MAC1 + 4, dev1.MAC1 + 5);
		//------------------OK------------------------
		fscanf(fp, "%s\n%x\t%x\t%x\t%x\t%x\t%x", setting.device, setting.mac, setting.mac + 1, setting.mac + 2, setting.mac + 3,
			setting.mac + 4, setting.mac + 5);
		//------------------BAD--------------------
		//scanf("%x\t%x\t%x\t%x\t%x\t%x", &devicename, &MAC[0], &MAC[1], &MAC[2], &MAC[3], &MAC[4], &MAC[5]);
		//fscanf(fp, "%s\n", &dev1.devicename1);
		//fscanf(stdin, "%s\n%x\t%x\t%x\t%x\t%x\t%x", dev1.devicename1, &dev1.MAC1[0], &dev1.MAC1[1], &dev1.MAC1[2], &dev1.MAC1[3], dev1.MAC1[4], &dev1.MAC1[5]);
		//------------------BAD-------------------
		//fscanf(fp,"%s\n%x\t%x\t%x\t%x\t%x\t%x", &devicename, &MAC[0], &MAC[1], &MAC[2], &MAC[3], &MAC[4], &MAC[5]);
		//fscanf(fp, "%s%x%x%x%x%x%x", devicename, &MAC[0], &MAC[1], &MAC[2], &MAC[3], &MAC[4], &MAC[5]);
		//-----------------BAD----------------
		//fscanf(fp, "%s\n%x\t%x\t%x\t%x\t%x\t%x", devicename, MAC, MAC+1, MAC+2, MAC+3, MAC+4, MAC+5);
		//----------------BAD-------------
		//fscanf(fp, "%s\n%x\t%x\t%x\t%x\t%x\t%x", &devicename, MAC, MAC + 1, MAC + 2, MAC + 3, MAC + 4, MAC + 5);
		//------------------BAD---------------
		//fscanf(fp, "%s\n%x\t%x\t%x\t%x\t%x\t%x", &devicename, &MAC, MAC + 1, MAC + 2, MAC + 3, MAC + 4, MAC + 5);


		printf("\n");
		
		printf("AdapterName:\t%s\n", setting.device);
		printf("AdapterAddr:\t");
		for (i = 0; i < 6; i++){
			printf("%02X%c", setting.mac[i], i == 6 - 1 ? '\n' : '-');
		}
		
		/*
		printf("AdapterName:\t%s\n", devicename);
		printf("AdapterAddr:\t");
		for (i = 0; i < 6; i++){
			printf("%02X%c", MAC[i], i == 6 - 1 ? '\n' : '-');
		}
		*/
	}
	else
	{
		//-----------------------------------------------------------------------------------------------
		fp = fopen("setting.ini", "wb");
		/* 查询本机MAC地址 */
		if (GetNameMacfromDevice(setting.mac, setting.device) == -1)
			exit(-1);

		printf("AdapterName:\t%s\n", setting.device);

		printf("AdapterAddr:\t");
		for (i = 0; i < 6; i++){
			printf("%02X%c", setting.mac[i], i == 6 - 1 ? '\n' : '-');
		}

		fprintf(fp, "%s\n%2x\t%2x\t%2x\t%2x\t%2x\t%2x", setting.device, setting.mac[0], setting.mac[1], 
			setting.mac[2], setting.mac[3], setting.mac[4], setting.mac[5]);
	}
	fclose(fp);
	printf("debug:%d\n", file_size("setting.ini"));
	//------------------------------------------------------------------------------
	/* 打开设备 */
	if ((adhandle = pcap_open(setting.device,          // 设备名
		65536,            // 要捕捉的数据包的部分 
		// 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
		PCAP_OPENFLAG_PROMISCUOUS,    // 混杂模式
		1000,             // 读取超时时间
		NULL,             // 远程机器验证
		errbuf            // 错误缓冲池
		)) == NULL)
	{
		fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", setting.device);
		/* 释放设列表 */
		//pcap_freealldevs(alldevs);
		return -1;
	}

	//printf("\nlistening on %s...\n", d->description);

	//----------------------------------------------------------------------------
	
	

	//捕获发往本机的eap数据包
	sprintf(FilterStr, "(ether proto 0x888e) and (ether dst host %02x:%02x:%02x:%02x:%02x:%02x)",
		setting.mac[0], setting.mac[1], setting.mac[2], setting.mac[3], setting.mac[4], setting.mac[5]);
	pcap_compile(adhandle, &fcode, FilterStr, 1, 0xff);
	pcap_setfilter(adhandle, &fcode);
	/* 主动发起认证会话 */
	SendStartPkt(adhandle, setting.mac);
	printf("client: Start.\n");
	//------------------------------------------------------------------
	while (!serverIsFound )
	{
		res = pcap_next_ex(adhandle, &header, &pkt_data);
		// NOTE: 这里没有检查网线是否接触不良或已被拔下,已处理
		if (res == -1)
		  return -1;

		/* 将时间戳转换成可识别的格式 */
		local_tv_sec = header->ts.tv_sec;
		ltime = localtime(&local_tv_sec);
		strftime(timestr, sizeof timestr, "%H:%M:%S", ltime);

		//dprintf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);

		//printf("\n----%d-----\n", res);
		if (res==1 && pkt_data[18] == 1)
		{
			serverIsFound = true;
			len = *(u_short *)(pkt_data + 20);
			len = htons(len);
			//dprintf("\nServer( %02x:%02x:%02x:%02x:%02x:%02x )-->(%02x:%02x:%02x:%02x:%02x:%02x)\neap_id=%d,len=%d\n", 
			//	pkt_data[6], pkt_data[7], pkt_data[8], pkt_data[9], pkt_data[10], pkt_data[11], 
			//	pkt_data[0], pkt_data[1], pkt_data[2], pkt_data[3], pkt_data[4], pkt_data[5], pkt_data[19], len);
		}
		else
		{	// 延时后重试
			if (1 == times)
			{
				printf("\nReconnection is failed.\n");
				return -1;
			}
			printf(",");
			Sleep(1000);
			SendStartPkt(adhandle, setting.mac);
			times--;
			// NOTE: 这里没有检查网线是否接触不良或已被拔下
		}
		
	}
	//-----------------------------------------------------------------------
	// 分情况应答下一个包

	res = pcap_next_ex(adhandle, &header, &pkt_data);
	// NOTE: 这里没有检查网线是否接触不良或已被拔下,已处理
	if (res == -1)
		return -1;
	if (pkt_data[22] == 1)
	{	// 通常情况会收到包Request Identity,应回答Response Identity
		printf("\n[%d] Server: Request Identity!\n", pkt_data[19]);//打印ID
		SendResponseIdentity(adhandle, pkt_data, setting.mac);
		printf("[%d] client: Response Identity.\n", pkt_data[19]);
	}

	// 重设过滤器,只捕获华为802.1X认证设备发来的包(包括多播Request Identity / Request AVAILABLE)
	sprintf(FilterStr, "(ether proto 0x888e) and (ether src host %02x:%02x:%02x:%02x:%02x:%02x)",
		pkt_data[6], pkt_data[7], pkt_data[8], pkt_data[9], pkt_data[10], pkt_data[11]);
	//printf("%s", FilterStr);
	pcap_compile(adhandle, &fcode, FilterStr, 1, 0xff);
	pcap_setfilter(adhandle, &fcode);

	//------------------------------------------------------------------------
	times = 30;//重置最大请求数
	// 进入循环体,不断处理认证请求
	for (;;)
	{
		// 调用pcap_next_ex()函数捕获数据包
		//-------------------------------------------进入等代阶段----------
		while ((res = pcap_next_ex(adhandle, &header, &pkt_data) )!= 1)
		{
			printf("."); // 若捕获失败或无数据,则等1秒后重试
			Sleep(1000);     // 直到成功捕获到一个数据包后再跳出
			// NOTE: 这里没有检查网线是否已被拔下或插口接触不良,已处理
			if (res == -1){
				printf("Error reading the packets: %s\n", pcap_geterr(adhandle));
				return -1;
			}
		}
		//-------------------------------------------------------------------

		// 根据收到的Request,回复相应的Response包
		if (pkt_data[18] == REQUEST)
		{
			switch ((EAP_Type)pkt_data[22])
			{
			case IDENTITY:
				printf("\n[%d] Server: Request Identity!\n", pkt_data[19]);
				SendResponseIdentity(adhandle, pkt_data, setting.mac);
				printf("\n[%d] client: Response Identity.\n", pkt_data[19]);
				break;
			case MD5:
				printf("\n[%d] Server: Request MD5-Challenge!\n", pkt_data[19]);
				SendResponseMD5(adhandle, pkt_data);
				printf("\n[%d] client: Response MD5-Challenge.\n", pkt_data[19]);
				break;
			default:
				printf("\n[%d] Server: Request (type:%d)!\n", pkt_data[19], (EAP_Type)pkt_data[22]);
				printf("Error! Unexpected request type\n");
				exit(-1);
				break;
			}
			//break;//退出for循环
		}
		else if ((EAP_Code)pkt_data[18] == FAILURE)
		{	// 处理认证失败信息
			printf("\n[%d] Server: Failure.\n", pkt_data[19]);
			if (1 == times)
			{
				printf("Reconnection is failed.---from Forward @SCUT\n");
				return -1;
			}
			//重新认证开始
			Sleep(1000);
			SendStartPkt(adhandle, setting.mac);
			times--;
			//break;
		}
		else if ((EAP_Code)pkt_data[18] == SUCCESS)
		{
			printf("\n[%d] Server: Success.\n", pkt_data[19]);
			// 刷新IP地址
			times = 20;
			//break;
		}
		else
		{
			printf("\n[%d] Server: (H3C data)\n", pkt_data[19]);
			// TODO: 这里没有处理华为自定义数据包
			break;
		}
	}

	return 0;
}
示例#2
0
int Authentication(const char *UserName, const char *Password, const char *DeviceName)
{
	char    errbuf[PCAP_ERRBUF_SIZE];
	pcap_t    *adhandle; // adapter handle
	uint8_t    MAC[6];

	char    FilterStr[100];
	struct bpf_program    fcode;
	const int DefaultTimeout=1000;//设置接收超时参数,单位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);

	/*
	* 设置过滤器:
	* 初始情况下只捕获发往本机的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);


START_AUTHENTICATION:
	{
		int retcode;
		struct pcap_pkthdr *header;
		const uint8_t    *captured;
		uint8_t    ethhdr[14]={0}; // ethernet header
		uint8_t    ip[4]={0};    // ip address

		/* 主动发起认证会话 */
		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);
			SendResponseIdentity(adhandle, captured, ethhdr, ip, UserName);
			DPRINTF("[%d] Client: Response 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]);
		}
		else if ((EAP_Type)captured[22] == ALLOCATED)
		{
			//ALLOCATED
		}
		// 重设过滤器,只捕获华为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 NOTIFICATION:
					DPRINTF("[%d] Server: Request Notification!\n", captured[19]);
					SendResponseNotification(adhandle, captured, ethhdr);
					DPRINTF("Client: Response Notification.\n");
					break;
				case ALLOCATED:
					DPRINTF("[%d] Server:Request Normal Verfication.\n",captured[19]);
					SendResponseH3C(adhandle,captured,ethhdr,UserName,Password);
					DPRINTF("[%d] Client: Response Allocated(Password).\n", (EAP_ID)captured[19]);
					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:客户端版本号无效
					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]);
				// 刷新IP地址
				system("ipconfig /release");
				system("ipconfig /release6");
				system("ipconfig /renew");
				system("ipconfig /renew6");
				break;
			}
			else
			{
				DPRINTF("[%d] Server: (H3C data)\n", captured[19]);
				// TODO: 这里没有处理华为自定义数据包 
			}
		}
	}
	return (0);
}