簡單的DHCP

使用win7的承載網絡開啓共享wifi,ICS分配IP地址比較慢,自己重新寫了一個簡單的DHCP協議,IP地址可以從2分配到254.可以用winshark來抓包,分析DHCP協議。

mydhcp.cpp

#include "pch.h"
#include "mydhcp.h"
#include <winsock2.h>
#include <iphlpapi.h>
#include <string.h>
#include "windows.h"
#include "Wbemcli.h"
#include <map>
#include <string>
#include <vector>
using namespace std;

struct mac_address {
	int iIndex;
	UINT8 data[6];
};
typedef  struct mac_address MAC_ADDRESS;

DWORD WINAPI message_dispatcher(void);
void init_reply(DHCP_MESSAGE* request, DHCP_MESSAGE* reply);
UINT8 fill_dhcp_reply_offer(DHCP_MESSAGE* request, DHCP_MESSAGE* reply);
INT send_dhcp_reply(sockaddr_in* client_sock, DHCP_MESSAGE* reply, DWORD len);
UINT8 fill_dhcp_reply_ack(DHCP_MESSAGE* request, DHCP_MESSAGE* reply);
int SearchBinding(UINT8* strMac);

vector<MAC_ADDRESS> g_mapIPMAC;


sockaddr_in g_ServerAddr;
sockaddr_in g_ClientAddr;
int g_RecvPort = 67;
int g_SndPort = 68;
char g_RecvBuf[1024];
int g_BufLen;
SOCKET g_ServerSocket;
HANDLE g_hDispatcher;

mydhcp::mydhcp()
{
	g_hDispatcher = NULL;
	//g_ServerSocket = NULL;
}

mydhcp::~mydhcp()
{
	if (g_hDispatcher != NULL) {
		CloseHandle(g_hDispatcher);
	}
	
	//if (g_ServerSocket != NULL) {
	//	closesocket(g_ServerSocket);
	//}	
	//WSACleanup();
	g_hDispatcher = NULL;
	//g_ServerSocket = NULL;
}

int mydhcp::StartMyDHCPServer(void) 
{
	WSADATA wsaData;
	int iRetVal = 0;
	BOOL bOpt = 1;
	
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		int iError = WSAGetLastError();
		CString csError;
		csError.Format(_T("WSAStartup() Failed!:WSAGetLastError = %d"), iError);
		AfxMessageBox(csError);
		return -1;
	}

	memset((void*)&g_ClientAddr, 0, sizeof(g_ClientAddr));
	g_ClientAddr.sin_family = AF_INET;
	g_ClientAddr.sin_port = htons(g_SndPort);
	g_ClientAddr.sin_addr.S_un.S_addr = inet_addr("255.255.255.255"); //reply->YourClientIPAdress;

	g_ServerAddr.sin_family = AF_INET;
	g_ServerAddr.sin_port = htons(g_RecvPort);
	g_ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.237.1");

	g_ServerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (g_ServerSocket != NULL) {
		iRetVal = setsockopt(g_ServerSocket, SOL_SOCKET, SO_BROADCAST, (char FAR*) & bOpt, sizeof(bOpt));
		if (iRetVal == SOCKET_ERROR) {
			int iError = WSAGetLastError();
			CString csError;
			csError.Format(_T("setsockopt() Failed!:WSAGetLastError = %d"), iError);
			//AfxMessageBox(csError);
			closesocket(g_ServerSocket);
			WSACleanup();
		}
		else {
			iRetVal = bind(g_ServerSocket, (SOCKADDR*)&g_ServerAddr, sizeof(g_ServerAddr));
			if (iRetVal == SOCKET_ERROR) {
				int iError = WSAGetLastError();
				CString csError;
				csError.Format(_T("bind() Failed!:WSAGetLastError = %d"), iError);
				/*AfxMessageBox(csError);*/
				closesocket(g_ServerSocket);
				WSACleanup();
			}
			else {
				g_hDispatcher = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)message_dispatcher, NULL, 0, NULL);
			}
		}
	}
	else {
		int iError = WSAGetLastError();
		CString csError;
		csError.Format(_T("socket() Failed!:WSAGetLastError = %d"), iError);
		//AfxMessageBox(csError);
	}
	
	
	return iRetVal;

	
}

DWORD WINAPI message_dispatcher(void)
{
	while (1) {
		sockaddr_in client_sock;
		int  slen = sizeof(client_sock);
		DWORD len;
		DWORD send_len = 0;

		DHCP_MESSAGE request;
		DHCP_MESSAGE reply;

		UINT8 type;
		const UINT8 option_magic[4] = {0x63, 0x82, 0x53, 0x63};
		DHCP_OPTIONS *opt_start, * opt_end;

		if ((len = recvfrom(g_ServerSocket, (char*)& request, sizeof(request), 0, (SOCKADDR*)& client_sock, &slen)) < DHCP_HEADER_SIZE + 5) {
			continue;
		}
		if (request.MessageType != BOOTREQUEST) {
			continue;
		}
		if (request.HardwareAddressLength < 1 || request.HardwareAddressLength >16) {
			continue;
		}
		if((len - DHCP_HEADER_SIZE < 4) || memcmp(request.MagicCookie, option_magic, sizeof(option_magic)) != 0) {
			continue;
		}

		opt_start = (DHCP_OPTIONS*)(request.Options);
		opt_end = (DHCP_OPTIONS*)(((UINT8*)(request.Options))+ len - DHCP_HEADER_SIZE);

		while (opt_start < opt_end && opt_start->id != 0xff) {
			opt_start = (DHCP_OPTIONS*)(((UINT8*)opt_start) + 2 + opt_start->len);
			if (opt_start > opt_end) {
				break;
			}
		}
		if (!(opt_start < opt_end && opt_start->id == 0xff)) {
			continue;
		}

		opt_start = (DHCP_OPTIONS*)(request.Options);
		if (opt_start->id == 0x35) {
			type = opt_start->data[0];
		}
		else {
			continue;
		}

		init_reply(&request, &reply);

		switch (type) {
		case DHCP_DISCOVER:
			type = fill_dhcp_reply_offer(&request, &reply);
			send_len = DHCP_HEADER_SIZE + 62;
			break;
		case DHCP_REQUEST:
			type = fill_dhcp_reply_ack(&request, &reply);
			send_len = DHCP_HEADER_SIZE + 62;
			break;
		case DHCP_DECLINE:
			break;
		case DHCP_RELEASE:
			break;
		case DHCP_INFORM:
			break;
		default:
			break;
		}
		
		if (type > 0) {
			send_dhcp_reply(&client_sock, &reply, send_len);
		}
		send_len = 0;
		
		Sleep(10);

	}
	WSACleanup();
	return 0;
}

void init_reply(DHCP_MESSAGE* request, DHCP_MESSAGE* reply) 
{
	memset(reply, 0, sizeof(DHCP_MESSAGE));

	reply->MessageType = BOOTREPLY;
	reply->HardwareType = request->HardwareType;
	reply->HardwareAddressLength = request->HardwareAddressLength;
	reply->TransactionID = request->TransactionID;
	reply->BootpFlags = request->BootpFlags;
	reply->RelayAgentIPAddress = request->RelayAgentIPAddress;
	memcpy(reply->ClienthardwareAddress, request->ClienthardwareAddress, request->HardwareAddressLength);
	memcpy(reply->MagicCookie, request->MagicCookie, 4);
}

INT send_dhcp_reply(sockaddr_in* client_sock, DHCP_MESSAGE* reply, DWORD len)
{
	INT iRet;

	if ((iRet = sendto(g_ServerSocket, (char*)reply, len, 0, (SOCKADDR*)&g_ClientAddr, sizeof(g_ClientAddr))) < 0) {
		int iError = WSAGetLastError();
		return -1;
	}

	return iRet;

}

UINT8 fill_dhcp_reply_offer(DHCP_MESSAGE* request, DHCP_MESSAGE* reply)
{
	int iIPTemp = SearchBinding(request->ClienthardwareAddress);
	if (iIPTemp < 2 || iIPTemp>254) {
		return 0;
	}
	UINT8 ucTemp = (UINT8)iIPTemp;
	reply->YourClientIPAdress[3] = ucTemp;
	reply->YourClientIPAdress[2] = 0xED;
	reply->YourClientIPAdress[1] = 0xa8;
	reply->YourClientIPAdress[0] = 0xc0;
	reply->Options[0] = DHCP_MESSAGE_TYPE;
	reply->Options[1] = 1;
	reply->Options[2] = DHCP_OFFER;
	reply->Options[3] = SERVER_IDENTIFIER;
	reply->Options[4] = 4;
	reply->Options[5] = 192;
	reply->Options[6] = 168;
	reply->Options[7] = 237;
	reply->Options[8] = 1;
	reply->Options[9] = SUBNET_MASK;
	reply->Options[10] = 4;
	reply->Options[11] = 255;
	reply->Options[12] = 255;
	reply->Options[13] = 255;
	reply->Options[14] = 0;
	reply->Options[15] = ROUTER;
	reply->Options[16] = 4;
	reply->Options[17] = 192;
	reply->Options[18] = 168;
	reply->Options[19] = 237;
	reply->Options[20] = 1;
	reply->Options[21] = DOMAIN_NAME_SERVER;
	reply->Options[22] = 4;
	reply->Options[23] = 192;
	reply->Options[24] = 168;
	reply->Options[25] = 237;
	reply->Options[26] = 1;
	reply->Options[27] = RENEWAL_T1_TIME_VALUE;
	reply->Options[28] = 4;
	reply->Options[29] = 0;
	reply->Options[30] = 0;
	reply->Options[31] = 0x01;
	reply->Options[32] = 0x2c;
	reply->Options[33] = REBINDING_T2_TIME_VALUE;
	reply->Options[34] = 4;
	reply->Options[35] = 0x00;
	reply->Options[36] = 0x06;
	reply->Options[37] = 0xeb;
	reply->Options[38] = 0xe0;
	reply->Options[39] = IP_ADDRESS_LEASE_TIME;
	reply->Options[40] = 4;
	reply->Options[41] = 0x00;
	reply->Options[42] = 0x09;
	reply->Options[43] = 0x3a;
	reply->Options[44] = 0x80;
	reply->Options[45] = NETBIOS_OVER_TCP_IP_NODE_TYPE;
	reply->Options[46] = 1;
	reply->Options[47] = 0x04;
	reply->Options[48] = DOMAIN_NAME;
	reply->Options[49] = 11;
	reply->Options[50] = 0x6d;
	reply->Options[51] = 0x73;
	reply->Options[52] = 0x68;
	reply->Options[53] = 0x6f;
	reply->Options[54] = 0x6d;
	reply->Options[55] = 0x65;
	reply->Options[56] = 0x2e;
	reply->Options[57] = 0x6e;
	reply->Options[58] = 0x65;
	reply->Options[59] = 0x74;
	reply->Options[60] = 0x00;
	reply->Options[61] = END;

	return DHCP_OFFER;
}

UINT8 fill_dhcp_reply_ack(DHCP_MESSAGE* request, DHCP_MESSAGE* reply)
{
	int iIPTemp = SearchBinding(request->ClienthardwareAddress);
	if (iIPTemp < 2 || iIPTemp>254) {
		return 0;
	}
	UINT8 ucTemp = (UINT8)iIPTemp;
	reply->YourClientIPAdress[3] = ucTemp;
	reply->YourClientIPAdress[2] = 0xED;
	reply->YourClientIPAdress[1] = 0xa8;
	reply->YourClientIPAdress[0] = 0xc0;
	reply->Options[0] = DHCP_MESSAGE_TYPE;
	reply->Options[1] = 1;
	reply->Options[2] = DHCP_ACK;
	reply->Options[3] = SERVER_IDENTIFIER;
	reply->Options[4] = 4;
	reply->Options[5] = 192;
	reply->Options[6] = 168;
	reply->Options[7] = 237;
	reply->Options[8] = 1;
	reply->Options[9] = SUBNET_MASK;
	reply->Options[10] = 4;
	reply->Options[11] = 255;
	reply->Options[12] = 255;
	reply->Options[13] = 255;
	reply->Options[14] = 0;
	reply->Options[15] = ROUTER;
	reply->Options[16] = 4;
	reply->Options[17] = 192;
	reply->Options[18] = 168;
	reply->Options[19] = 237;
	reply->Options[20] = 1;
	reply->Options[21] = DOMAIN_NAME_SERVER;
	reply->Options[22] = 4;
	reply->Options[23] = 192;
	reply->Options[24] = 168;
	reply->Options[25] = 237;
	reply->Options[26] = 1;
	reply->Options[27] = RENEWAL_T1_TIME_VALUE;
	reply->Options[28] = 4;
	reply->Options[29] = 0;
	reply->Options[30] = 0;
	reply->Options[31] = 0x01;
	reply->Options[32] = 0x2c;
	reply->Options[33] = REBINDING_T2_TIME_VALUE;
	reply->Options[34] = 4;
	reply->Options[35] = 0x00;
	reply->Options[36] = 0x06;
	reply->Options[37] = 0xeb;
	reply->Options[38] = 0xe0;
	reply->Options[39] = IP_ADDRESS_LEASE_TIME;
	reply->Options[40] = 4;
	reply->Options[41] = 0x00;
	reply->Options[42] = 0x09;
	reply->Options[43] = 0x3a;
	reply->Options[44] = 0x80;
	reply->Options[45] = NETBIOS_OVER_TCP_IP_NODE_TYPE;
	reply->Options[46] = 1;
	reply->Options[47] = 0x04;
	reply->Options[48] = DOMAIN_NAME;
	reply->Options[49] = 11;
	reply->Options[50] = 0x6d;
	reply->Options[51] = 0x73;
	reply->Options[52] = 0x68;
	reply->Options[53] = 0x6f;
	reply->Options[54] = 0x6d;
	reply->Options[55] = 0x65;
	reply->Options[56] = 0x2e;
	reply->Options[57] = 0x6e;
	reply->Options[58] = 0x65;
	reply->Options[59] = 0x74;
	reply->Options[60] = 0x00;
	reply->Options[61] = END;

	return DHCP_ACK;
}

int SearchBinding(UINT8* strMac)
{
	vector<MAC_ADDRESS> ::iterator iter;
	int iRet = 0;
	BOOL bRet;
	string strTemp = "";
	MAC_ADDRESS stuTemp;

	for (int j = 0; j < 6; j++) {
		stuTemp.data[j] = strMac[j];
	}

	if (g_mapIPMAC.empty()) {
		stuTemp.iIndex = 2;
		g_mapIPMAC.push_back(stuTemp);
		return stuTemp.iIndex;
	}
	else {
		for (iter = g_mapIPMAC.begin(); iter != g_mapIPMAC.end(); iter++) {
			bRet = TRUE;
			for (int i = 0; i < 6; i++) {
				if (iter->data[i] != stuTemp.data[i]) {
					bRet = FALSE;
					break;
				}
			}
			if (bRet) {
				return iter->iIndex;
			}
		}
		int iSize = (int)g_mapIPMAC.size();
		if (iSize < 252) {
			stuTemp.iIndex = iSize + 2;
			g_mapIPMAC.push_back(stuTemp);
			return stuTemp.iIndex;
		}
		else {
			return -1;
		}
	}
}

mydhcp.h:

#pragma once

enum PORTS {
	BOOTPS = 67,
	BOOTPC = 68
};

enum OP_TYPES {
	BOOTREQUEST = 1,
	BOOTREPLY = 2
};

enum HARDWARE_ADDRESS_TYPES {
	ETHERNET = 0x01,
	ETHERNET_LEN = 0x06
};

enum DHCP_MESSAGE_TYPE {
	DHCP_DISCOVER = 1,
	DHCP_OFFER    = 2,
	DHCP_REQUEST  = 3,
	DHCP_DECLINE  = 4,
	DHCP_ACK      = 5,
	DHCP_NAK      = 6,
	DHCP_RELEASE  = 7,
	DHCP_INFORM   = 8
};

enum {

	/* RFC 1497 Vendor Extensions */
	PAD = 0,
	END = 255,

	SUBNET_MASK = 1,
	TIME_OFFSET = 2,
	ROUTER = 3,
	TIME_SERVER = 4,
	NAME_SERVER = 5,
	DOMAIN_NAME_SERVER = 6,
	LOG_SERVER = 7,
	COOKIE_SERVER = 8,
	LPR_SERVER = 9,
	IMPRESS_SERVER = 10,
	RESOURCE_LOCATION_SERVER = 11,
	HOST_NAME = 12,
	BOOT_FILE_SIZE = 13,
	MERIT_DUMP_FILE = 14,
	DOMAIN_NAME = 15,
	SWAP_SERVER = 16,
	ROOT_PATH = 17,
	EXTENSIONS_PATH = 18,

	/* IP Layer Parameters per Host */
	IP_FORWARDING = 19,
	NON_LOCAL_SOURCE_ROUTING = 20,
	POLICY_FILTER = 21,
	MAXIMUM_DATAGRAM_REASSEMBLY_SIZE = 22,
	DEFAULT_IP_TIME_TO_LIVE = 23,
	PATH_MTU_AGING_TIMEOUT = 24,
	PATH_MTU_PLATEAU_TABLE = 25,

	/* IP Layer Parameters per Interface */
	INTERFACE_MTU = 26,
	ALL_SUBNETS_ARE_LOCAL = 27,
	BROADCAST_ADDRESS = 28,
	PERFORM_MASK_DISCOVERY = 29,
	MASK_SUPPLIER = 30,
	PERFORM_ROUTER_DISCOVERY = 31,
	ROUTER_SOLICITATION_ADDRESS = 32,
	STATIC_ROUTE = 33,

	/* Link Layer Parameters per Interface */
	TRAILER_ENCAPSULATION = 34,
	ARP_CACHE_TIMEOUT = 35,
	ETHERNET_ENCAPSULATION = 36,

	/* TCP Parameters */
	TCP_DEFAULT_TTL = 37,
	TCP_KEEPALIVE_INTERVAL = 38,
	TCP_KEEPALIVE_GARBAGE = 39,

	/* Application and Service Parameters */
	NETWORK_INFORMATION_SERVICE_DOMAIN = 40,
	NETWORK_INFORMATION_SERVERS = 41,
	NETWORK_TIME_PROTOCOL_SERVERS = 42,
	VENDOR_SPECIFIC_INFORMATION = 43,
	NETBIOS_OVER_TCP_IP_NAME_SERVER = 44,
	NETBIOS_OVER_TCP_IP_DATAGRAM_DISTRIBUTION_SERVER = 4,
	NETBIOS_OVER_TCP_IP_NODE_TYPE = 46,
	NETBIOS_OVER_TCP_IP_SCOPE = 47,
	X_WINDOW_SYSTEM_FONT_SERVER = 48,
	X_WINDOW_SYSTEM_DISPLAY_MANAGER = 49,
	NETWORK_INFORMATION_SERVICE_PLUS_DOMAIN = 64,
	NETWORK_INFORMATION_SERVICE_PLUS_SERVERS = 65,
	MOBILE_IP_HOME_AGENT = 68,
	SMTP_SERVER = 69,
	POP3_SERVER = 70,
	NNTP_SERVER = 71,
	DEFAULT_WWW_SERVER = 72,
	DEFAULT_FINGER_SERVER = 73,
	DEFAULT_IRC_SERVER = 74,
	STREETTALK_SERVER = 75,
	STREETTALK_DIRECTORY_ASSISTANCE_SERVER = 76,

	/* DHCP Extensions */
	REQUESTED_IP_ADDRESS = 50,
	IP_ADDRESS_LEASE_TIME = 51,
	OPTION_OVERLOAD = 52,
	TFTP_SERVER_NAME = 66,
	BOOTFILE_NAME = 67,
	DHCP_MESSAGE_TYPE = 53,
	SERVER_IDENTIFIER = 54,
	PARAMETER_REQUEST_LIST = 55,
	MESSAGE = 56,
	MAXIMUM_DHCP_MESSAGE_SIZE = 57,
	RENEWAL_T1_TIME_VALUE = 58,
	REBINDING_T2_TIME_VALUE = 59,
	VENDOR_CLASS_IDENTIFIER = 60,
	CLIENT_IDENTIFIER = 61

};

enum {
	DHCP_HEADER_SIZE = 240
};

struct  dhcp_message {
	UINT8 MessageType;
	UINT8 HardwareType;
	UINT8 HardwareAddressLength;
	UINT8 Hops;
	UINT32 TransactionID;
	UINT16 SecondsElapsed;
	UINT16 BootpFlags;
	UINT32 ClientIPAdress;
	UINT8 YourClientIPAdress[4];
	UINT32 NextServerIPAddress;
	UINT32 RelayAgentIPAddress;
	UINT8 ClienthardwareAddress[16];
	UINT8 ServerHostName[64];
	UINT8 BootFileName[128];
	UINT8 MagicCookie[4];
	UINT8 Options[312];
};
typedef  struct dhcp_message DHCP_MESSAGE;

struct  dhcp_options {
	UINT8 id;
	UINT8 len;
	UINT8 data[256];
};
typedef  struct dhcp_options DHCP_OPTIONS;

extern HANDLE g_hDispatcher;
extern SOCKET g_ServerSocket;

class mydhcp
{
public:
	
	mydhcp::mydhcp();
	mydhcp::~mydhcp();
	int mydhcp::StartmyDHCPServer(void);
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章