我正在尝试使用 C++ 代码从我的一端模仿 DHCP 客户端。我的目标是从 DHCP 服务器获取一些免费/未使用的 IP,以将其分配给不同的设备 - 类似于 DHCP 中继,但在技术上并不相同。我CLIENT
在嵌入式 linux 平台上运行,并通过我们的内部网络与 DHCP 服务器通信。
根据 DHCP 协议,有一个正式的程序 ( DISCOVER
, OFFER
, REQUEST
, ACK/NAK
, RELEASE
) 与 DHCP 服务器通信。根据 RFC (2131),当我执行 a 时,我在 YIAddr 字段中DISCOVER
收到一个未使用的 IP 地址。我使用RFC 2132 中提到的选项 50OFFER
在我的消息中进一步使用此 IP 地址。REQUEST
我的主路由器 make-Edgewater(也是 DHCP 服务器)在发送DISCOVER
消息时,会在 YIAddr 字段中发回OFFER
一条带有未使用 IP 地址的消息(我在后续REQUEST
消息中使用了这个未使用的 IP),这是我的要求。我对其他几个路由器(NetGear、Dlink、Broadcom)做了同样的实验,发现该OFFER
消息将我发送回CLIENT
请求未使用 IP 的相同 IP 地址。我很想知道为什么会这样。据我了解,我正在按照 RFC2131/RFC2131/RFC4361 中提到的步骤来创建我的 DHCP 数据包格式。
是否有其他 DHCP 服务器/路由器期望提供未使用的 IP 的特定格式或特定选项?如 RFC4361 中所述,我在我的选项字段中使用了唯一的客户端标识符。
这是我正在创建 dhcp 数据包的部分的快照。
request_packet.m_OperationCode = 0x01;
request_packet.m_HwareType = 0x01;
request_packet.m_HwareLen = 0x06;
request_packet.m_Hops = 0x01;
request_packet.m_XID = htonl(XID[m_numberOfIPs]);
request_packet.m_Secs = htons(0x10);
request_packet.m_flags = htons(0x8000);
request_packet.m_CIAddr = 0x000000; //Client IP
request_packet.m_YIAddr = 0x000000; //Your IP
request_packet.m_SIAddr = 0x000000; //Server IP
request_packet.m_GIAddr = 0x000000;
request_packet.m_CHAddr[0] = MACADDRESS[m_numberOfIPs][0];
request_packet.m_CHAddr[1] = MACADDRESS[m_numberOfIPs][1];//[1];
request_packet.m_CHAddr[2] = MACADDRESS[m_numberOfIPs][2];//[2];
request_packet.m_CHAddr[3] = MACADDRESS[m_numberOfIPs][3];//[3];
request_packet.m_CHAddr[4] = MACADDRESS[m_numberOfIPs][4];//[4];
request_packet.m_CHAddr[5] = MACADDRESS[m_numberOfIPs][5];//[5];
memset(request_packet.m_CHAddr+6, 0, 10);
memset(request_packet.m_SName, 0, 64);
memset(request_packet.m_File, 0, 128);
request_packet.m_pOptions[0] = 99; //Start of magic cookie
request_packet.m_pOptions[1] = 130;
request_packet.m_pOptions[2] = 83;
request_packet.m_pOptions[3] = 99; //end of magic cookie
选项字段
发现消息
CID 和 DUID 是随机的唯一数字,用于创建唯一的客户端标识符
request_packet.m_pOptions[4] = 53; //DHCP MESSAGE TYPE OPTION CODE
request_packet.m_pOptions[5] = 1; //OPTION DATA LEN
request_packet.m_pOptions[6] = 1; //DHCP DISCOVER
request_packet.m_pOptions[7] = 55; //Parameter Request List
request_packet.m_pOptions[8] = 7; //Length
request_packet.m_pOptions[9] = 1; //Subnet Mask
request_packet.m_pOptions[10] = 3; //Router
request_packet.m_pOptions[11] = 6; //Domain Name Server
request_packet.m_pOptions[12] = 12; // Host Name
request_packet.m_pOptions[13] = 15; //Domain Name
request_packet.m_pOptions[14] = 28; //Broadcast Address
request_packet.m_pOptions[15] = 42; //NTP servers
request_packet.m_pOptions[16] = 51; //IP Address Lease Time
request_packet.m_pOptions[17] = 4;
request_packet.m_pOptions[18] = 0x00;
request_packet.m_pOptions[19] = 0x00;
request_packet.m_pOptions[20] = 0xFF;
request_packet.m_pOptions[21] = 0xFF;
request_packet.m_pOptions[22] = 61;//Client Identifier code
request_packet.m_pOptions[23] = 15;//Length
request_packet.m_pOptions[24] = 255;//IAID Type
printf("The CID generated inside REQUEST is %x\n", CID[m_numberOfIPs]);
request_packet.m_pOptions[25] = CID[m_numberOfIPs][0];
request_packet.m_pOptions[26] = CID[m_numberOfIPs][1];
request_packet.m_pOptions[27] = CID[m_numberOfIPs][2];
request_packet.m_pOptions[28] = CID[m_numberOfIPs][3];
request_packet.m_pOptions[29] = 0x00;//DUID Type
request_packet.m_pOptions[30] = 0x03;//DUID Type
request_packet.m_pOptions[31] = 0x00;//HW Type code - Ethernet
request_packet.m_pOptions[32] = 0x01;//HW Type code - Ethernet
request_packet.m_pOptions[33] = DUID[m_numberOfIPs][0];
request_packet.m_pOptions[34] = DUID[m_numberOfIPs][1];
request_packet.m_pOptions[35] = DUID[m_numberOfIPs][2];
request_packet.m_pOptions[36] = DUID[m_numberOfIPs][3];
request_packet.m_pOptions[37] = DUID[m_numberOfIPs][4];
request_packet.m_pOptions[38] = DUID[m_numberOfIPs][5];
request_packet.m_pOptions[39] = (0xff); // End option
请求消息
request_packet.m_pOptions[4] = 53; //DHCP MESSAGE TYPE OPTION CODE
request_packet.m_pOptions[5] = 1; //OPTION DATA LEN
request_packet.m_pOptions[6] = 3; //DHCP REQUEST
request_packet.m_pOptions[7] = 50; //DHCP REQUESTION OPTION
request_packet.m_pOptions[8] = 4; //OPTION DATA LEN
request_packet.m_pOptions[9] = (m_YourIP & 0xff000000)>>24; //first byte
request_packet.m_pOptions[10] = (m_YourIP & 0xff0000)>>16; //second byte
request_packet.m_pOptions[11] = (m_YourIP & 0xff00)>>8; //third byte
request_packet.m_pOptions[12] = (m_YourIP & 0xff); //fourth byte
/*- Added by JA. Refer 3.1.3 Section of RFC2131.txt - Server identifier option*/
request_packet.m_pOptions[13] = 54;
request_packet.m_pOptions[14] = 4;
request_packet.m_pOptions[15] = (m_ServerIP & 0xff000000) >> 24; //first byte
request_packet.m_pOptions[16] = (m_ServerIP & 0xff0000)>>16; //second byte
request_packet.m_pOptions[17] = (m_ServerIP & 0xff00)>>8; //third byte
request_packet.m_pOptions[18] = (m_ServerIP & 0xff); //fourth byte
request_packet.m_pOptions[19] = 55; //Parameter Request List
request_packet.m_pOptions[20] = 7; //Length
request_packet.m_pOptions[21] = 1; //Subnet Mask
request_packet.m_pOptions[22] = 3; //Router
request_packet.m_pOptions[23] = 6; //Domain Name Server
request_packet.m_pOptions[24] = 12; // Host Name
request_packet.m_pOptions[25] = 15; //Domain Name
request_packet.m_pOptions[26] = 28; //Broadcast Address
request_packet.m_pOptions[27] = 42; //NTP servers
request_packet.m_pOptions[28] = 51; //IP Address Lease Time
request_packet.m_pOptions[29] = 4;
request_packet.m_pOptions[30] = 0x00;
request_packet.m_pOptions[31] = 0x00;
request_packet.m_pOptions[32] = 0xFF;
request_packet.m_pOptions[33] = 0xFF;
/*- Added by JA. Refer 6.1 Section of RFC4361.txt - Client identifier option*/
request_packet.m_pOptions[34] = 61;//Client Identifier code
request_packet.m_pOptions[35] = 15;//Length
request_packet.m_pOptions[36] = 255;//IAID Type
printf("The CID generated inside REQUEST is %x\n", CID[m_numberOfIPs]);
request_packet.m_pOptions[37] = CID[m_numberOfIPs][0];
request_packet.m_pOptions[38] = CID[m_numberOfIPs][1];
request_packet.m_pOptions[39] = CID[m_numberOfIPs][2];
request_packet.m_pOptions[40] = CID[m_numberOfIPs][3];
request_packet.m_pOptions[41] = 0x00;//DUID Type
request_packet.m_pOptions[42] = 0x03;//DUID Type
request_packet.m_pOptions[43] = 0x00;//HW Type code - Ethernet
request_packet.m_pOptions[44] = 0x01;//HW Type code - Ethernet
request_packet.m_pOptions[45] = DUID[m_numberOfIPs][0];
request_packet.m_pOptions[46] = DUID[m_numberOfIPs][1];
request_packet.m_pOptions[47] = DUID[m_numberOfIPs][2];
request_packet.m_pOptions[48] = DUID[m_numberOfIPs][3];
request_packet.m_pOptions[49] = DUID[m_numberOfIPs][4];
request_packet.m_pOptions[50] = DUID[m_numberOfIPs][5];
request_packet.m_pOptions[51] = (0xff); // End option