Here is a class I wrote to generate a DHCP message. It’s primary purpose is to send a DHCP message, which can be useful for finding DHCP servers on a network
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net; using System.Globalization; using System.Text.RegularExpressions; namespace SigkillDHCP { public class DhcpMessage { private const UInt32 MagicNumber = 1666417251; //http://search.cpan.org/~shadinger/Net-DHCP-0.66/lib/Net/DHCP/Packet.pm //Declare Fields private DhcpOp _op; private DhcpHtype _htype; private byte _hlen; private byte _hops; private int _xid; private UInt16 _secs; private UInt16 _flags = 128; private string _ciaddr = "0.0.0.0"; private string _yiaddr = "0.0.0.0"; private string _siaddr = "0.0.0.0"; private string _giaddr = "0.0.0.0"; private string _chaddr; private byte[] _sname = new byte[64]; private byte[] _file = new byte[128]; //OPTIONS private byte[] _mcookie = new byte[4]; private Dictionary<dhcpoption, byte[]=""> _options = new Dictionary<dhcpoption, byte[]="">(); #region Constructors public DhcpMessage() { //Default Constructor Zero Fields } public DhcpMessage(byte[] data) { //Initiate DHCP Instance Fields When Reading Packet From DHCP Server int Offset = 0; byte[] tempip = new byte[4]; //MessageBox.Show("Op:" + BitConverter.ToString(data, Offset, 1).Replace("-", "")); this._op = (DhcpOp)data[Offset]; Offset++; this._htype = (DhcpHtype)data[Offset]; Offset++; this._hlen = data[Offset]; Offset++; this._hops = data[Offset]; Offset++; this._xid = BitConverter.ToInt32(data, Offset); Offset += 4; this._secs = BitConverter.ToUInt16(data, Offset); //Need to reverse Byte order??? Offset += 2; this._flags = BitConverter.ToUInt16(data, Offset); Offset += 2; Array.Copy(data, Offset, tempip, 0, 4); this._ciaddr = new IPAddress(tempip).ToString(); Offset += 4; Array.Copy(data, Offset, tempip, 0, 4); this._yiaddr = new IPAddress(tempip).ToString(); Offset += 4; Array.Copy(data, Offset, tempip, 0, 4); this._siaddr = new IPAddress(tempip).ToString(); Offset += 4; Array.Copy(data, Offset, tempip, 0, 4); this._giaddr = new IPAddress(tempip).ToString(); Offset += 4; this._chaddr = BitConverter.ToString(data, Offset, 6); Offset += 16; Array.Copy(data, Offset, this._sname, 0, 64); Offset += 64; Array.Copy(data, Offset, this._file, 0, 128); Offset += 128; //Check for DHCP Magic Cookie if (BitConverter.ToUInt32(data, Offset) == MagicNumber) { Offset += 4; Boolean end = false; //Loop Other DHCP Options while (!end && Offset < data.Length) { DhcpOption Option = (DhcpOption)data[Offset]; Offset++; int OptionLength; switch (Option) { case DhcpOption.Pad: continue; case DhcpOption.End: end = true; continue; default: OptionLength = (int)data[Offset]; Offset++; break; } byte[] OptionData = new byte[OptionLength]; Array.Copy(data, Offset, OptionData, 0, OptionLength); Offset += OptionLength; this._options.Add(Option, OptionData); } } } #endregion #region Properties public DhcpOp Op { get { return this._op; } set { this._op = value; } } public DhcpHtype Htype { get { return this._htype; } set { this._htype = value; } } public byte Hlen { get { return this._hlen; } set { this._hlen = value; } } public byte Hops { get { return this._hops; } set { this._hops = value; } } public int Xid { get { return this._xid; } set { this._xid = value; } } public UInt16 Secs { get { return this._secs; } set { this._secs = value; } } public UInt16 Flags { get { return this._flags; } set { this._flags = value; } } public string Ciaddr { get { return this._ciaddr; } set { if (ValidateIp(value) == false) { throw new Exception("Invalid IP Specified for Ciaddr"); } this._ciaddr = value; } } public string Yiaddr { get { return this._yiaddr; } set { if (ValidateIp(value) == false) { throw new Exception("Invalid IP Specified for Yiaddr"); } this._yiaddr = value; } } public string Siaddr { get { return this._siaddr; } set { if (ValidateIp(value) == false) { throw new Exception("Invalid IP Specified for Siaddr"); } this._siaddr = value; } } public string Giaddr { get { return this._giaddr; } set { if (ValidateIp(value) == false) { throw new Exception("Invalid IP Specified for Giaddr"); } this._giaddr = value; } } public string Chaddr { get { return this._chaddr; } set { if (ValidateMac(value) == false) { throw new Exception("Invalid MAC Specified for Chaddr"); } this._chaddr = value.Replace(":", "").Replace("-", "").Replace(".", ""); } } public byte[] Sname { get { return this._sname; } set { this._sname = value; } } public byte[] File { get { return this._file; } set { this._file = value; } } #endregion #region IP-Binary Conversions public string IpToBitString(string Address) { //Convert IP String to Octets byte[] IP = IPAddress.Parse(Address).GetAddressBytes(); string IPBits = ""; //Loop Octets and Convert to Binary for (int i = 0; i < IP.Length; i++) { IPBits += PadBinary(Convert.ToString(IP[i], 2), 8); } return IPBits; } public string PadBinary(string Bits, int TotalBits) { //Pad Bit Strings to Ensure Proper Length //ex: Decimal 4 converts to 100 as a Binary String // But We Want to Pad it to 8 bits as 00000100 string PadBits = ""; if (Bits.Length < TotalBits) { for (int i = 0; i < (TotalBits - Bits.Length); i++) { PadBits += "0"; } Bits = PadBits + Bits; } return Bits; } public string BitStringToIp(string Bits) { //Convert 32bit Binary to IP String string IP = ""; if (Bits.Length == 32) { IP = BinaryStringToInt(Bits.Substring(0, 8)).ToString() + "."; IP += BinaryStringToInt(Bits.Substring(8, 8)).ToString() + "."; IP += BinaryStringToInt(Bits.Substring(16, 8)).ToString() + "."; IP += BinaryStringToInt(Bits.Substring(24, 8)).ToString(); } else { IP = "127.0.0.1"; } return IP; } public int BinaryStringToInt(string Bits) { //Converts a Binary String to Integer Based on Most Significant Bit //ex: Binary 00000100 and Binary 100 Converts to Integer 4 int Number = 0; for (int i = 0, Exp = (Bits.Length - 1); i < Bits.Length; i++, Exp--) { if (Bits[i].ToString() == "1") { Number += (int)Math.Pow(2, Exp); } } return Number; } #endregion #region Subnet Calculations public int GetNetworkPrefix(string Mask) { //Convert Subnet Mask to Bit String Mask = IpToBitString(Mask); //Get Network Prefix int Prefix = 0; for (int i = 0; i < Mask.Length; i++) { if (Mask[i].ToString() == "1") { Prefix++; } } return Prefix; } public string GetSubnetNumber(string Address, string Mask) { //Convert IP and SubnetMask String to Octets byte[] IP = IPAddress.Parse(Address).GetAddressBytes(); byte[] SM = IPAddress.Parse(Mask).GetAddressBytes(); string SubnetNumber = ""; //Loop Octets Then Bitwise Boolean AND the IP and Subnet Mask for (int i = 0; i < IP.Length; i++) { if (i < (IP.Length - 1)) { SubnetNumber += (IP[i] & SM[i]).ToString() + "."; } else { SubnetNumber += (IP[i] & SM[i]).ToString(); } } return SubnetNumber; } public string GetSubnetBroadcast(string Mask, string SubnetNumber) { //Get Prefix int Prefix = GetNetworkPrefix(Mask); //Copy Network/Subnet Bits of SubnetNumber Then Replace Host Bits with 1's string SNBits = IpToBitString(SubnetNumber); string Broadcast = ""; for (int i = 0; i < SNBits.Length; i++) { if (i < Prefix) { Broadcast += SNBits[i]; } else { Broadcast += "1"; } } //Convert Broadcast From Binary to IP Broadcast = BitStringToIp(Broadcast); return Broadcast; } public string GetSubnetFirstAddress(string SubnetNumber) { //Convert Subnet Number String to Octets byte[] IP = IPAddress.Parse(SubnetNumber).GetAddressBytes(); string FirstAddress = ""; //First Address Equals Subnet Number Plus 1 in the Last Octet IP[IP.Length - 1] += 1; //Loop Octets to Build IP for (int i = 0; i < IP.Length; i++) { if (i < (IP.Length - 1)) { FirstAddress += IP[i].ToString() + "."; } else { FirstAddress += IP[i].ToString(); } } return FirstAddress; } public string GetSubnetLastAddress(string Broadcast) { //Convert Broadcast String to Octets byte[] IP = IPAddress.Parse(Broadcast).GetAddressBytes(); string LastAddress = ""; //Last Address Equals Broadcast Minus 1 in the Last Octet IP[IP.Length - 1] -= 1; //Loop Octets to Build IP for (int i = 0; i < IP.Length; i++) { if (i < (IP.Length - 1)) { LastAddress += IP[i].ToString() + "."; } else { LastAddress += IP[i].ToString(); } } return LastAddress; } public int GetNetworkBits(string Address) { //Convert IP String to Octets byte[] IP = IPAddress.Parse(Address).GetAddressBytes(); //Determine Network Bits Based on IP Class if ((IP[0] >= 1) && (IP[0] <= 126)) { //Class A 8 Network Bits return 8; } else if ((IP[0] >= 128) && (IP[0] <= 191)) { //Class B 16 Network Bits return 16; } else if ((IP[0] >= 192) && (IP[0] <= 223)) { //Class C 24 Network Bits return 24; } else { //Error Invalid return 0; } } public int GetHostBits(string Mask) { //Convert Subnet Mask to Binary string SM = IpToBitString(Mask); int HostBits = 0; for (int i = 0; i < SM.Length; i++) { if (SM[i].ToString() == "0") { HostBits++; } } return HostBits; } public int GetSubnetBits(int NetworkBits, int HostBits) { return (32 - (NetworkBits + HostBits)); } public int GetMaxSubnets(int SubnetBits, bool ClassfulProtocol) { //Determine Number of Subnets if (ClassfulProtocol == true) { //Use ((2^s)-2) When: //Classful routing protocol, Rip Ver 1 or IGRP protocol used, or no ip subnet zero command is configured //Subtract 2 because Subnet Zero and Broadcast Subnet are reserved return ((int)Math.Pow(2, SubnetBits) - 2); } else { //Use 2^s When: //Classless routing protocol, Rip Ver 2 EIGRP or OSPF protocol used, ip subnet zero is configured or omitted, VLSM used, no other clues //Subnet Zero and Broadcast Subnet are not reserved and can be used return (int)Math.Pow(2, SubnetBits); } } public int GetMaxHosts(int HostBits) { //Use ((2^h) - 2) Subtract 2 for the Subnet Number and Broadcast Address return ((int)Math.Pow(2, HostBits) - 2); } #endregion #region Methods public bool ValidateIp(string testip) { IPAddress ip; bool valid = false; if (string.IsNullOrEmpty(testip)) { valid = false; } else { valid = IPAddress.TryParse(testip, out ip); } return valid; } public bool ValidateMac(string testmac) { testmac = testmac.Replace(":", "").Replace("-", "").Replace(".", ""); bool valid = false; if (testmac.Length == 12) { Regex rx = new Regex("([0-9a-fA-F][0-9a-fA-F]){6}"); if (rx.IsMatch(testmac)) { valid = true; } } return valid; } public byte[] MacToByte(string mac) { byte[] macBytes = BitConverter.GetBytes(long.Parse(mac, NumberStyles.HexNumber)); byte[] macAddress = new byte[6]; if (BitConverter.IsLittleEndian) { Array.Reverse(macBytes); for (int i = 0; i <= 5; i++) { macAddress[i] = macBytes[i + 2]; } } return macAddress; } public byte[] GetOption(DhcpOption option) { if (this._options.ContainsKey(option)) { return this._options[option]; } else { return null; } } public void AddOption(DhcpOption option, params byte[] val) { byte[] data = new byte[1 + val.Length]; data[0] = (byte)val.Length; val.CopyTo(data, 1); this._options.Add(option, data); } public int SessionId() { return (int)DateTime.Now.Ticks; } public byte[] StringToByteArray(string str, EncodingType encodingType) { System.Text.Encoding encoding = null; switch (encodingType) { case EncodingType.ASCII: encoding = new System.Text.ASCIIEncoding(); break; case EncodingType.Unicode: encoding = new System.Text.UnicodeEncoding(); break; case EncodingType.UTF7: encoding = new System.Text.UTF7Encoding(); break; case EncodingType.UTF8: encoding = new System.Text.UTF8Encoding(); break; } return encoding.GetBytes(str); } public static string ByteArrayToString(byte[] bytes, EncodingType encodingType) { System.Text.Encoding encoding = null; switch (encodingType) { case EncodingType.ASCII: encoding = new System.Text.ASCIIEncoding(); break; case EncodingType.Unicode: encoding = new System.Text.UnicodeEncoding(); break; case EncodingType.UTF7: encoding = new System.Text.UTF7Encoding(); break; case EncodingType.UTF8: encoding = new System.Text.UTF8Encoding(); break; } return encoding.GetString(bytes); } public byte[] ClassToByteArray() { //Minimum DHCP Message Size + Magic Cookie + End int DhcpMsgSize = 236 + 4 + 1; foreach (KeyValuePair<dhcpoption, byte[]=""> pair in this._options) { DhcpMsgSize += 1 + pair.Value.Length; } byte[] data = new byte[DhcpMsgSize]; int Offset = 0; data[Offset] = (byte)this._op; Offset++; data[Offset] = (byte)this._htype; Offset++; data[Offset] = this._hlen; Offset++; data[Offset] = this._hops; Offset++; BitConverter.GetBytes(this._xid).CopyTo(data, Offset); Offset += 4; BitConverter.GetBytes(this._secs).CopyTo(data, Offset); //Need to reverse Byte order??? Offset += 2; BitConverter.GetBytes(this._flags).CopyTo(data, Offset); Offset += 2; IPAddress.Parse(this._ciaddr).GetAddressBytes().CopyTo(data, Offset); Offset += 4; IPAddress.Parse(this._yiaddr).GetAddressBytes().CopyTo(data, Offset); Offset += 4; IPAddress.Parse(this._siaddr).GetAddressBytes().CopyTo(data, Offset); Offset += 4; IPAddress.Parse(this._giaddr).GetAddressBytes().CopyTo(data, Offset); Offset += 4; MacToByte(this._chaddr).CopyTo(data, Offset); Offset += 16; this._sname.CopyTo(data, Offset); Offset += 64; this._file.CopyTo(data, Offset); Offset += 128; BitConverter.GetBytes(MagicNumber).CopyTo(data, Offset); Offset += 4; if (this._options.Count > 0) { foreach (DhcpOption option in this._options.Keys) { //Copy Option data[Offset] = (byte)option; Offset++; //Copy Option Data Array.Copy(this._options[option], 0, data, Offset, this._options[option].Length); Offset += this._options[option].Length; } } data[Offset] = (byte)DhcpOption.End; return data; } #endregion } #region Packet Examples //byte[] discoverMessage = { // /* Opt */0x01, // /* Htype */0x01, // /* Hlen */0x06, // /* Hops */0x00, // /* XID */0x00, 0x00, 0x00, 0x01, // /* Sec */0x00, 0x00, // /* Flags */0x80, 0x00, // /* Ciaddr */0x00, 0x00, 0x00, 0x00, // /* Yiaddr */0x00, 0x00, 0x00, 0x00, // /* Siaddr */0x00, 0x00, 0x00, 0x00, // /* Giaddr */0x00, 0x00, 0x00, 0x00, // /* Chaddr */0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // /* Sname */0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // /* File */0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // /* DHCP OPTIONS */ // /* Mcookie */0x63, 0x82, 0x53, 0x63, // /* ClientID */0x3d, 0x06, 0x00, 0x1f, 0x3b, 0x5b, 0xbd, 0xad, // /* Hostname */0x0c, 0x05, 0x52, 0x6f, 0x67, 0x75, 0x65, // /* DHCPDiscover */0x35, 0x01, 0x01, // /* ParamReqList */0x37, 0x01, 0x03, // /* EndOption */0xff // }; #endregion #region Enumerations public enum DhcpOp : byte { //Number Operation Code - RFC1700 BootRequest = 0x01, BootReply } public enum DhcpHtype : byte { //Number Hardware Type - RFC1700 Ethernet = 0x01, ExperimentalEthernet, AmateurRadio, ProteonTokenRing, Chaos, Ieee802Networks, Arcnet, Hyperchannel, Lanstar } public enum DhcpMsgType : byte { //DHCP Message Type - RFC2132, RFC4388 Discover = 0x01, Offer, Request, Decline, Ack, Nak, Release, Inform, ForceRenew, LeaseQuery, LeaseUnassigned, LeaseUnknown, LeaseActive } public enum DhcpOption : byte { //DHCP Options - RFC2132 Pad = 0x00, SubnetMask = 0x01, TimeOffset = 0x02, Router = 0x03, TimeServer = 0x04, NameServer = 0x05, DomainNameServer = 0x06, Hostname = 0x0C, DomainNameSuffix = 0x0F, AddressRequest = 0x32, AddressTime = 0x33, DhcpMessageType = 0x35, DhcpAddress = 0x36, ParameterList = 0x37, DhcpMessage = 0x38, DhcpMaxMessageSize = 0x39, ClassId = 0x3C, ClientId = 0x3D, AutoConfig = 0x74, End = 0xFF } public enum EncodingType { ASCII, Unicode, UTF7, UTF8 } #endregion }