DhcpPacket.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Net;
  5. using System.Text;
  6. using Utils;
  7. namespace DhcpServer
  8. {
  9. public partial class DhcpPacket
  10. {
  11. public DhcpOpCode OpCode { get; set; }
  12. public DhcpHardwareType HardwareType { get; set; }
  13. public byte Hops { get; set; }
  14. public int TransactionId { get; set; }
  15. public short SecondsElapsed { get; set; }
  16. public DhcpBootpFlag BootpFlags { get; set; }
  17. public IPAddress ClientIpAddress { get; set; }
  18. public IPAddress YourIpAddress { get; set; }
  19. public IPAddress NextServerIpAddress { get; set; }
  20. public IPAddress RelayAgentIpAddress { get; set; }
  21. public byte[] ClientMacAddress { get; set; }
  22. public string ServerHostName { get; set; }
  23. public string BootFileName { get; set; }
  24. public int MagicCookie { get; set; } = 0x63825363;
  25. public Dictionary<DhcpOption, byte[]> Options { get; set; } = new Dictionary<DhcpOption, byte[]>();
  26. public DhcpMessageType MessageType
  27. {
  28. get => Options.MapValue(DhcpOption.DhcpMessageType, value => (DhcpMessageType)value[0]);
  29. set => Options[DhcpOption.DhcpMessageType] = new[] { (byte)value };
  30. }
  31. public IPAddress SubNetMask
  32. {
  33. get => Options.MapValue(DhcpOption.SubNetMask, value => new IPAddress(value));
  34. set => Options[DhcpOption.SubNetMask] = value.GetAddressBytes();
  35. }
  36. public IPAddress Router
  37. {
  38. get => Options.MapValue(DhcpOption.Router, value => new IPAddress(value));
  39. set => Options[DhcpOption.Router] = value.GetAddressBytes();
  40. }
  41. public IPAddress DnsServer
  42. {
  43. get => Options.MapValue(DhcpOption.DnsServer, value => new IPAddress(value));
  44. set => Options[DhcpOption.DnsServer] = value.GetAddressBytes();
  45. }
  46. public string TftpServer
  47. {
  48. get => Options.MapValue(DhcpOption.TftpServer, value => Encoding.ASCII.GetString(value));
  49. set => Options[DhcpOption.TftpServer] = Encoding.ASCII.GetBytes(value);
  50. }
  51. public IPAddress BroadcastAddress
  52. {
  53. get => Options.MapValue(DhcpOption.BroadcastAddress, value => new IPAddress(value));
  54. set => Options[DhcpOption.BroadcastAddress] = value.GetAddressBytes();
  55. }
  56. public IPAddress ServerIdentifier
  57. {
  58. get => Options.MapValue(DhcpOption.ServerIdentifier, value => new IPAddress(value));
  59. set => Options[DhcpOption.ServerIdentifier] = value.GetAddressBytes();
  60. }
  61. public IPAddress DhcpServerIdentifier
  62. {
  63. get => Options.MapValue(DhcpOption.DhcpServerIdentifier, value => new IPAddress(value));
  64. set => Options[DhcpOption.DhcpServerIdentifier] = value.GetAddressBytes();
  65. }
  66. public string UserClass
  67. {
  68. get => Options.MapValue(DhcpOption.UserClass, value => Encoding.ASCII.GetString(value))?.Trim().Trim('\0');
  69. set => Options[DhcpOption.UserClass] = Encoding.ASCII.GetBytes(value);
  70. }
  71. public string HostName => Options.MapValue(DhcpOption.HostName, v => Encoding.ASCII.GetString(v))?.Trim().Trim('\0');
  72. public string Vendor => Options.MapValue(DhcpOption.Vendor, v => Encoding.ASCII.GetString(v))?.Trim().Trim('\0');
  73. public TimeSpan LeaseTime
  74. {
  75. get => Options.MapValue(DhcpOption.LeaseTime, p => TimeSpan.FromSeconds(ToBeUint(p)));
  76. set => Options[DhcpOption.LeaseTime] = ToBytes((uint)value.TotalSeconds);
  77. }
  78. public TimeSpan RenewalTime
  79. {
  80. get => Options.MapValue(DhcpOption.RenewalTime, p => TimeSpan.FromSeconds(ToBeUint(p)));
  81. set => Options[DhcpOption.RenewalTime] = ToBytes((uint)value.TotalSeconds);
  82. }
  83. public TimeSpan RebindingTime
  84. {
  85. get => Options.MapValue(DhcpOption.RebindingTime, p => TimeSpan.FromSeconds(ToBeUint(p)));
  86. set => Options[DhcpOption.RebindingTime] = ToBytes((uint)value.TotalSeconds);
  87. }
  88. public byte[] ClientIdentifier
  89. {
  90. get => Options.MapValue(DhcpOption.ClientIdentifier, p => p);
  91. set => Options[DhcpOption.ClientIdentifier] = value;
  92. }
  93. public DhcpPacket(byte[] buffer)
  94. {
  95. using var stream = new MemoryStream(buffer);
  96. using var reader = new BinaryReader(stream);
  97. OpCode = (DhcpOpCode)reader.ReadByte();
  98. HardwareType = (DhcpHardwareType)reader.ReadByte();
  99. var hardwareAddressLength = reader.ReadByte();
  100. Hops = reader.ReadByte();
  101. TransactionId = reader.ReadInt32();
  102. SecondsElapsed = IPAddress.NetworkToHostOrder(reader.ReadInt16());
  103. BootpFlags = (DhcpBootpFlag)IPAddress.NetworkToHostOrder(reader.ReadInt16());
  104. ClientIpAddress = new IPAddress(reader.ReadBytes(4));
  105. YourIpAddress = new IPAddress(reader.ReadBytes(4));
  106. NextServerIpAddress = new IPAddress(reader.ReadBytes(4));
  107. RelayAgentIpAddress = new IPAddress(reader.ReadBytes(4));
  108. ClientMacAddress = reader.ReadBytes(hardwareAddressLength);
  109. stream.Position += 16 - hardwareAddressLength; // Skip padding bytes
  110. ServerHostName = Encoding.ASCII.GetString(reader.ReadBytes(64)).Trim('\0');
  111. BootFileName = Encoding.ASCII.GetString(reader.ReadBytes(128)).Trim('\0');
  112. MagicCookie = reader.ReadInt32();
  113. do
  114. {
  115. var option = reader.ReadByte();
  116. if (option == 0xFF) break;
  117. Options[(DhcpOption)option] = reader.ReadBytes(reader.ReadByte());
  118. } while (true);
  119. }
  120. public int WriteToBuffer(byte[] buffer)
  121. {
  122. using var stream = new MemoryStream(buffer);
  123. using var writer = new BinaryWriter(stream);
  124. writer.Write((byte)OpCode);
  125. writer.Write((byte)HardwareType);
  126. writer.Write((byte)ClientMacAddress.Length);
  127. writer.Write(Hops);
  128. writer.Write(TransactionId);
  129. writer.Write(IPAddress.HostToNetworkOrder(SecondsElapsed));
  130. writer.Write(IPAddress.HostToNetworkOrder((short)BootpFlags));
  131. writer.Write(ClientIpAddress.GetAddressBytes());
  132. writer.Write(YourIpAddress.GetAddressBytes());
  133. writer.Write(NextServerIpAddress.GetAddressBytes());
  134. writer.Write(RelayAgentIpAddress.GetAddressBytes());
  135. writer.Write(ClientMacAddress);
  136. stream.Position += 16 - ClientMacAddress.Length;
  137. var buf = Encoding.ASCII.GetBytes(ServerHostName);
  138. writer.Write(buf);
  139. stream.Position += 64 - buf.Length;
  140. buf = Encoding.ASCII.GetBytes(BootFileName);
  141. writer.Write(buf);
  142. stream.Position += 128 - buf.Length;
  143. writer.Write(MagicCookie);
  144. foreach (var option in Options)
  145. {
  146. writer.Write((byte)option.Key);
  147. writer.Write((byte)option.Value.Length);
  148. writer.Write(option.Value);
  149. }
  150. writer.Write((byte)0xFF);
  151. return (int)(stream.Position);
  152. }
  153. public DhcpPacket()
  154. {
  155. }
  156. private static uint ToBeUint(byte[] buf)
  157. {
  158. return (uint)buf[0] << 24 |
  159. (uint)buf[1] << 16 |
  160. (uint)buf[2] << 8 |
  161. (uint)buf[3];
  162. }
  163. private static byte[] ToBytes(uint value)
  164. {
  165. var buf = new byte[4];
  166. buf[0] = (byte)(value >> 24);
  167. buf[1] = (byte)(value >> 16);
  168. buf[2] = (byte)(value >> 8);
  169. buf[3] = (byte)(value);
  170. return buf;
  171. }
  172. }
  173. }