本节开始,我们代码实现DHCP的协议流程。其本质上是在相应的阶段,构造相应的数据包进行发送和接收,总体而言,DHCP数据包的格式如下:
它最复杂的其实是填写options字段,该字段种类及其繁杂,我们根据不同协议的不同阶段去搞清楚options字段的内容。根据我们前面描述,DHCP协议启动时,第一步是客户端在子网内广播dhcp discover消息,然后子网内相应的dhcp服务器回发dhcp offer消息,因此我们的代码先完成这一步骤。
首先我们要解析DHCP DISCOVER数据包结构。如果使用的是mac系统,在命令行控制台中输入命令:
sudo ipconfig set en0 DHCP
如果使用的是windows,那么在控制台中输入命令:
ipconfig renew
然后按照上一节使用wireshark抓包,我们就可以抓取DHCP DISCOVER消息:
点击打开该消息后,我们可以看到消息的字段结构:
这里我们需要把握几个option结构,第一个是option 53,它用来表明该数据包的类型,它的code值是53,数据长度1个字节,一般取值为1,数据内容用于表明数据包的类型,取值1表示消息类型为DHCPDISCOVERY,2为DHCPOFFER等,具体内容如下:
第2个option的code值为55,data_length 占据的字节数可变,数据区用于表明设备想从服务器获得哪些消息,从我抓包的情况看,它包含如下信息如下:
从上图看,我的设备向服务器请求一系列数据,例如子网掩码,路由器,域名服务器等,这些请求各自使用不同的数值来表示,例如数值1表示请求子网掩码,数值3请求路由器IP等。
第3个option的code值是57,data_length字节数是2,它用来确定相互交互的DHCP数据包的最大长度,数据区的内容是长度值。
第4个option的code值是61,它用来表示设备的身份标识,data_length的值根据具体情况而定,通常情况下它是1字节,在我们抓包中它取值7,数据区第一个字节表示硬件类型,接下来6个字节存储设备的mac地址。
第5个option的code值是51,它用来表示ip的租借时长。它的data_length字段占据4个字节,数据区存储的是一个数值,用于表示租借时长的秒数。
第6个option的code值是12,它用来表示设备名称,一般来说是你的主机名称,data_length占据长度根据名字长度而定,数据区存储的是设备名称字符串。
第7个option的code值是255,它表示结束,它只包含1个字节。
接下来我们看看如何使用代码组装该数据包:
package Application;
import java.nio.ByteBuffer;
import java.util.Random;
import datalinklayer.DataLinkLayer;
import protocol.ProtocolManager;
public class DHCPApplication extends Application{
private static byte HARDWARE_TYPE = 1;
private static byte HARDWARE_ADDR_LENGTH = 6;
private static byte DHCP_HOPS = 0;
private static byte MESSAGE_TYPE_REQUEST = 1;
private short secs_elapsed = 0;
private short bootp_flags = 0;
private byte[] client_ip_address = new byte[4];
private byte[] your_ip_address = new byte[4];
private byte[] next_server_ip_add