dhcpv4.rs 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  1. // See https://tools.ietf.org/html/rfc2131 for the DHCP specification.
  2. use byteorder::{ByteOrder, NetworkEndian};
  3. use crate::{Error, Result};
  4. use crate::wire::{EthernetAddress, Ipv4Address};
  5. use crate::wire::arp::Hardware;
  6. pub const SERVER_PORT: u16 = 67;
  7. pub const CLIENT_PORT: u16 = 68;
  8. pub const MAX_DNS_SERVER_COUNT: usize = 3;
  9. const DHCP_MAGIC_NUMBER: u32 = 0x63825363;
  10. enum_with_unknown! {
  11. /// The possible opcodes of a DHCP packet.
  12. pub enum OpCode(u8) {
  13. Request = 1,
  14. Reply = 2,
  15. }
  16. }
  17. enum_with_unknown! {
  18. /// The possible message types of a DHCP packet.
  19. pub enum MessageType(u8) {
  20. Discover = 1,
  21. Offer = 2,
  22. Request = 3,
  23. Decline = 4,
  24. Ack = 5,
  25. Nak = 6,
  26. Release = 7,
  27. Inform = 8,
  28. }
  29. }
  30. impl MessageType {
  31. fn opcode(&self) -> OpCode {
  32. match *self {
  33. MessageType::Discover | MessageType::Inform | MessageType::Request |
  34. MessageType::Decline | MessageType::Release => OpCode::Request,
  35. MessageType::Offer | MessageType::Ack | MessageType::Nak => OpCode::Reply,
  36. MessageType::Unknown(_) => OpCode::Unknown(0),
  37. }
  38. }
  39. }
  40. /// A representation of a single DHCP option.
  41. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  42. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  43. pub enum DhcpOption<'a> {
  44. EndOfList,
  45. Pad,
  46. MessageType(MessageType),
  47. RequestedIp(Ipv4Address),
  48. ClientIdentifier(EthernetAddress),
  49. ServerIdentifier(Ipv4Address),
  50. IpLeaseTime(u32),
  51. Router(Ipv4Address),
  52. SubnetMask(Ipv4Address),
  53. MaximumDhcpMessageSize(u16),
  54. Other { kind: u8, data: &'a [u8] }
  55. }
  56. impl<'a> DhcpOption<'a> {
  57. pub fn parse(buffer: &'a [u8]) -> Result<(&'a [u8], DhcpOption<'a>)> {
  58. // See https://tools.ietf.org/html/rfc2132 for all possible DHCP options.
  59. let (skip_len, option);
  60. match *buffer.get(0).ok_or(Error::Truncated)? {
  61. field::OPT_END => {
  62. skip_len = 1;
  63. option = DhcpOption::EndOfList;
  64. }
  65. field::OPT_PAD => {
  66. skip_len = 1;
  67. option = DhcpOption::Pad;
  68. }
  69. kind => {
  70. let length = *buffer.get(1).ok_or(Error::Truncated)? as usize;
  71. skip_len = length + 2;
  72. let data = buffer.get(2..skip_len).ok_or(Error::Truncated)?;
  73. match (kind, length) {
  74. (field::OPT_END, _) |
  75. (field::OPT_PAD, _) =>
  76. unreachable!(),
  77. (field::OPT_DHCP_MESSAGE_TYPE, 1) => {
  78. option = DhcpOption::MessageType(MessageType::from(data[0]));
  79. },
  80. (field::OPT_REQUESTED_IP, 4) => {
  81. option = DhcpOption::RequestedIp(Ipv4Address::from_bytes(data));
  82. }
  83. (field::OPT_CLIENT_ID, 7) => {
  84. let hardware_type = Hardware::from(u16::from(data[0]));
  85. if hardware_type != Hardware::Ethernet {
  86. return Err(Error::Unrecognized);
  87. }
  88. option = DhcpOption::ClientIdentifier(EthernetAddress::from_bytes(&data[1..]));
  89. }
  90. (field::OPT_SERVER_IDENTIFIER, 4) => {
  91. option = DhcpOption::ServerIdentifier(Ipv4Address::from_bytes(data));
  92. }
  93. (field::OPT_ROUTER, 4) => {
  94. option = DhcpOption::Router(Ipv4Address::from_bytes(data));
  95. }
  96. (field::OPT_SUBNET_MASK, 4) => {
  97. option = DhcpOption::SubnetMask(Ipv4Address::from_bytes(data));
  98. }
  99. (field::OPT_MAX_DHCP_MESSAGE_SIZE, 2) => {
  100. option = DhcpOption::MaximumDhcpMessageSize(u16::from_be_bytes([data[0], data[1]]));
  101. }
  102. (field::OPT_IP_LEASE_TIME, 4) => {
  103. option = DhcpOption::IpLeaseTime(u32::from_be_bytes([data[0], data[1], data[2], data[3]]))
  104. }
  105. (_, _) => {
  106. option = DhcpOption::Other { kind: kind, data: data };
  107. }
  108. }
  109. }
  110. }
  111. Ok((&buffer[skip_len..], option))
  112. }
  113. pub fn buffer_len(&self) -> usize {
  114. match self {
  115. &DhcpOption::EndOfList => 1,
  116. &DhcpOption::Pad => 1,
  117. &DhcpOption::MessageType(_) => 3,
  118. &DhcpOption::ClientIdentifier(eth_addr) => {
  119. 3 + eth_addr.as_bytes().len()
  120. }
  121. &DhcpOption::RequestedIp(ip) |
  122. &DhcpOption::ServerIdentifier(ip) |
  123. &DhcpOption::Router(ip) |
  124. &DhcpOption::SubnetMask(ip) => {
  125. 2 + ip.as_bytes().len()
  126. },
  127. &DhcpOption::MaximumDhcpMessageSize(_) => {
  128. 4
  129. }
  130. &DhcpOption::IpLeaseTime(_) => 6,
  131. &DhcpOption::Other { data, .. } => 2 + data.len()
  132. }
  133. }
  134. pub fn emit<'b>(&self, buffer: &'b mut [u8]) -> &'b mut [u8] {
  135. let skip_length;
  136. match *self {
  137. DhcpOption::EndOfList => {
  138. skip_length = 1;
  139. buffer[0] = field::OPT_END;
  140. }
  141. DhcpOption::Pad => {
  142. skip_length = 1;
  143. buffer[0] = field::OPT_PAD;
  144. }
  145. _ => {
  146. skip_length = self.buffer_len();
  147. buffer[1] = (skip_length - 2) as u8;
  148. match *self {
  149. DhcpOption::EndOfList | DhcpOption::Pad => unreachable!(),
  150. DhcpOption::MessageType(value) => {
  151. buffer[0] = field::OPT_DHCP_MESSAGE_TYPE;
  152. buffer[2] = value.into();
  153. }
  154. DhcpOption::ClientIdentifier(eth_addr) => {
  155. buffer[0] = field::OPT_CLIENT_ID;
  156. buffer[2] = u16::from(Hardware::Ethernet) as u8;
  157. buffer[3..9].copy_from_slice(eth_addr.as_bytes());
  158. }
  159. DhcpOption::RequestedIp(ip) => {
  160. buffer[0] = field::OPT_REQUESTED_IP;
  161. buffer[2..6].copy_from_slice(ip.as_bytes());
  162. }
  163. DhcpOption::ServerIdentifier(ip) => {
  164. buffer[0] = field::OPT_SERVER_IDENTIFIER;
  165. buffer[2..6].copy_from_slice(ip.as_bytes());
  166. }
  167. DhcpOption::Router(ip) => {
  168. buffer[0] = field::OPT_ROUTER;
  169. buffer[2..6].copy_from_slice(ip.as_bytes());
  170. }
  171. DhcpOption::SubnetMask(mask) => {
  172. buffer[0] = field::OPT_SUBNET_MASK;
  173. buffer[2..6].copy_from_slice(mask.as_bytes());
  174. }
  175. DhcpOption::MaximumDhcpMessageSize(size) => {
  176. buffer[0] = field::OPT_MAX_DHCP_MESSAGE_SIZE;
  177. buffer[2..4].copy_from_slice(&size.to_be_bytes()[..]);
  178. }
  179. DhcpOption::IpLeaseTime(lease_time) => {
  180. buffer[0] = field::OPT_IP_LEASE_TIME;
  181. buffer[2..6].copy_from_slice(&lease_time.to_be_bytes()[..]);
  182. }
  183. DhcpOption::Other { kind, data: provided } => {
  184. buffer[0] = kind;
  185. buffer[2..skip_length].copy_from_slice(provided);
  186. }
  187. }
  188. }
  189. }
  190. &mut buffer[skip_length..]
  191. }
  192. }
  193. /// A read/write wrapper around a Dynamic Host Configuration Protocol packet buffer.
  194. #[derive(Debug, PartialEq)]
  195. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  196. pub struct Packet<T: AsRef<[u8]>> {
  197. buffer: T
  198. }
  199. pub(crate) mod field {
  200. #![allow(non_snake_case)]
  201. #![allow(unused)]
  202. use crate::wire::field::*;
  203. pub const OP: usize = 0;
  204. pub const HTYPE: usize = 1;
  205. pub const HLEN: usize = 2;
  206. pub const HOPS: usize = 3;
  207. pub const XID: Field = 4..8;
  208. pub const SECS: Field = 8..10;
  209. pub const FLAGS: Field = 10..12;
  210. pub const CIADDR: Field = 12..16;
  211. pub const YIADDR: Field = 16..20;
  212. pub const SIADDR: Field = 20..24;
  213. pub const GIADDR: Field = 24..28;
  214. pub const CHADDR: Field = 28..34;
  215. pub const SNAME: Field = 34..108;
  216. pub const FILE: Field = 108..236;
  217. pub const MAGIC_NUMBER: Field = 236..240;
  218. pub const OPTIONS: Rest = 240..;
  219. // Vendor Extensions
  220. pub const OPT_END: u8 = 255;
  221. pub const OPT_PAD: u8 = 0;
  222. pub const OPT_SUBNET_MASK: u8 = 1;
  223. pub const OPT_TIME_OFFSET: u8 = 2;
  224. pub const OPT_ROUTER: u8 = 3;
  225. pub const OPT_TIME_SERVER: u8 = 4;
  226. pub const OPT_NAME_SERVER: u8 = 5;
  227. pub const OPT_DOMAIN_NAME_SERVER: u8 = 6;
  228. pub const OPT_LOG_SERVER: u8 = 7;
  229. pub const OPT_COOKIE_SERVER: u8 = 8;
  230. pub const OPT_LPR_SERVER: u8 = 9;
  231. pub const OPT_IMPRESS_SERVER: u8 = 10;
  232. pub const OPT_RESOURCE_LOCATION_SERVER: u8 = 11;
  233. pub const OPT_HOST_NAME: u8 = 12;
  234. pub const OPT_BOOT_FILE_SIZE: u8 = 13;
  235. pub const OPT_MERIT_DUMP: u8 = 14;
  236. pub const OPT_DOMAIN_NAME: u8 = 15;
  237. pub const OPT_SWAP_SERVER: u8 = 16;
  238. pub const OPT_ROOT_PATH: u8 = 17;
  239. pub const OPT_EXTENSIONS_PATH: u8 = 18;
  240. // IP Layer Parameters per Host
  241. pub const OPT_IP_FORWARDING: u8 = 19;
  242. pub const OPT_NON_LOCAL_SOURCE_ROUTING: u8 = 20;
  243. pub const OPT_POLICY_FILTER: u8 = 21;
  244. pub const OPT_MAX_DATAGRAM_REASSEMBLY_SIZE: u8 = 22;
  245. pub const OPT_DEFAULT_TTL: u8 = 23;
  246. pub const OPT_PATH_MTU_AGING_TIMEOUT: u8 = 24;
  247. pub const OPT_PATH_MTU_PLATEU_TABLE: u8 = 25;
  248. // IP Layer Parameters per Interface
  249. pub const OPT_INTERFACE_MTU: u8 = 26;
  250. pub const OPT_ALL_SUBNETS_ARE_LOCAL: u8 = 27;
  251. pub const OPT_BROADCAST_ADDRESS: u8 = 28;
  252. pub const OPT_PERFORM_MASK_DISCOVERY: u8 = 29;
  253. pub const OPT_MASK_SUPPLIER: u8 = 30;
  254. pub const OPT_PERFORM_ROUTER_DISCOVERY: u8 = 31;
  255. pub const OPT_ROUTER_SOLICITATION_ADDRESS: u8 = 32;
  256. pub const OPT_STATIC_ROUTE: u8 = 33;
  257. // Link Layer Parameters per Interface
  258. pub const OPT_TRAILER_ENCAPSULATION: u8 = 34;
  259. pub const OPT_ARP_CACHE_TIMEOUT: u8 = 35;
  260. pub const OPT_ETHERNET_ENCAPSULATION: u8 = 36;
  261. // TCP Parameters
  262. pub const OPT_TCP_DEFAULT_TTL: u8 = 37;
  263. pub const OPT_TCP_KEEPALIVE_INTERVAL: u8 = 38;
  264. pub const OPT_TCP_KEEPALIVE_GARBAGE: u8 = 39;
  265. // Application and Service Parameters
  266. pub const OPT_NIS_DOMAIN: u8 = 40;
  267. pub const OPT_NIS_SERVERS: u8 = 41;
  268. pub const OPT_NTP_SERVERS: u8 = 42;
  269. pub const OPT_VENDOR_SPECIFIC_INFO: u8 = 43;
  270. pub const OPT_NETBIOS_NAME_SERVER: u8 = 44;
  271. pub const OPT_NETBIOS_DISTRIBUTION_SERVER: u8 = 45;
  272. pub const OPT_NETBIOS_NODE_TYPE: u8 = 46;
  273. pub const OPT_NETBIOS_SCOPE: u8 = 47;
  274. pub const OPT_X_WINDOW_FONT_SERVER: u8 = 48;
  275. pub const OPT_X_WINDOW_DISPLAY_MANAGER: u8 = 49;
  276. pub const OPT_NIS_PLUS_DOMAIN: u8 = 64;
  277. pub const OPT_NIS_PLUS_SERVERS: u8 = 65;
  278. pub const OPT_MOBILE_IP_HOME_AGENT: u8 = 68;
  279. pub const OPT_SMTP_SERVER: u8 = 69;
  280. pub const OPT_POP3_SERVER: u8 = 70;
  281. pub const OPT_NNTP_SERVER: u8 = 71;
  282. pub const OPT_WWW_SERVER: u8 = 72;
  283. pub const OPT_FINGER_SERVER: u8 = 73;
  284. pub const OPT_IRC_SERVER: u8 = 74;
  285. pub const OPT_STREETTALK_SERVER: u8 = 75;
  286. pub const OPT_STDA_SERVER: u8 = 76;
  287. // DHCP Extensions
  288. pub const OPT_REQUESTED_IP: u8 = 50;
  289. pub const OPT_IP_LEASE_TIME: u8 = 51;
  290. pub const OPT_OPTION_OVERLOAD: u8 = 52;
  291. pub const OPT_TFTP_SERVER_NAME: u8 = 66;
  292. pub const OPT_BOOTFILE_NAME: u8 = 67;
  293. pub const OPT_DHCP_MESSAGE_TYPE: u8 = 53;
  294. pub const OPT_SERVER_IDENTIFIER: u8 = 54;
  295. pub const OPT_PARAMETER_REQUEST_LIST: u8 = 55;
  296. pub const OPT_MESSAGE: u8 = 56;
  297. pub const OPT_MAX_DHCP_MESSAGE_SIZE: u8 = 57;
  298. pub const OPT_RENEWAL_TIME_VALUE: u8 = 58;
  299. pub const OPT_REBINDING_TIME_VALUE: u8 = 59;
  300. pub const OPT_VENDOR_CLASS_ID: u8 = 60;
  301. pub const OPT_CLIENT_ID: u8 = 61;
  302. }
  303. impl<T: AsRef<[u8]>> Packet<T> {
  304. /// Imbue a raw octet buffer with DHCP packet structure.
  305. pub fn new_unchecked(buffer: T) -> Packet<T> {
  306. Packet { buffer }
  307. }
  308. /// Shorthand for a combination of [new_unchecked] and [check_len].
  309. ///
  310. /// [new_unchecked]: #method.new_unchecked
  311. /// [check_len]: #method.check_len
  312. pub fn new_checked(buffer: T) -> Result<Packet<T>> {
  313. let packet = Self::new_unchecked(buffer);
  314. packet.check_len()?;
  315. Ok(packet)
  316. }
  317. /// Ensure that no accessor method will panic if called.
  318. /// Returns `Err(Error::Truncated)` if the buffer is too short.
  319. ///
  320. /// [set_header_len]: #method.set_header_len
  321. pub fn check_len(&self) -> Result<()> {
  322. let len = self.buffer.as_ref().len();
  323. if len < field::MAGIC_NUMBER.end {
  324. Err(Error::Truncated)
  325. } else {
  326. Ok(())
  327. }
  328. }
  329. /// Consume the packet, returning the underlying buffer.
  330. pub fn into_inner(self) -> T {
  331. self.buffer
  332. }
  333. /// Returns the operation code of this packet.
  334. pub fn opcode(&self) -> OpCode {
  335. let data = self.buffer.as_ref();
  336. OpCode::from(data[field::OP])
  337. }
  338. /// Returns the hardware protocol type (e.g. ethernet).
  339. pub fn hardware_type(&self) -> Hardware {
  340. let data = self.buffer.as_ref();
  341. Hardware::from(u16::from(data[field::HTYPE]))
  342. }
  343. /// Returns the length of a hardware address in bytes (e.g. 6 for ethernet).
  344. pub fn hardware_len(&self) -> u8 {
  345. self.buffer.as_ref()[field::HLEN]
  346. }
  347. /// Returns the transaction ID.
  348. ///
  349. /// The transaction ID (called `xid` in the specification) is a random number used to
  350. /// associate messages and responses between client and server. The number is chosen by
  351. /// the client.
  352. pub fn transaction_id(&self) -> u32 {
  353. let field = &self.buffer.as_ref()[field::XID];
  354. NetworkEndian::read_u32(field)
  355. }
  356. /// Returns the hardware address of the client (called `chaddr` in the specification).
  357. ///
  358. /// Only ethernet is supported by `smoltcp`, so this functions returns
  359. /// an `EthernetAddress`.
  360. pub fn client_hardware_address(&self) -> EthernetAddress {
  361. let field = &self.buffer.as_ref()[field::CHADDR];
  362. EthernetAddress::from_bytes(field)
  363. }
  364. /// Returns the value of the `hops` field.
  365. ///
  366. /// The `hops` field is set to zero by clients and optionally used by relay agents.
  367. pub fn hops(&self) -> u8 {
  368. self.buffer.as_ref()[field::HOPS]
  369. }
  370. /// Returns the value of the `secs` field.
  371. ///
  372. /// The secs field is filled by clients and describes the number of seconds elapsed
  373. /// since client began process.
  374. pub fn secs(&self) -> u16 {
  375. let field = &self.buffer.as_ref()[field::SECS];
  376. NetworkEndian::read_u16(field)
  377. }
  378. /// Returns the value of the `magic cookie` field in the DHCP options.
  379. ///
  380. /// This field should be always be `0x63825363`.
  381. pub fn magic_number(&self) -> u32 {
  382. let field = &self.buffer.as_ref()[field::MAGIC_NUMBER];
  383. NetworkEndian::read_u32(field)
  384. }
  385. /// Returns the Ipv4 address of the client, zero if not set.
  386. ///
  387. /// This corresponds to the `ciaddr` field in the DHCP specification. According to it,
  388. /// this field is “only filled in if client is in `BOUND`, `RENEW` or `REBINDING` state
  389. /// and can respond to ARP requests”.
  390. pub fn client_ip(&self) -> Ipv4Address {
  391. let field = &self.buffer.as_ref()[field::CIADDR];
  392. Ipv4Address::from_bytes(field)
  393. }
  394. /// Returns the value of the `yiaddr` field, zero if not set.
  395. pub fn your_ip(&self) -> Ipv4Address {
  396. let field = &self.buffer.as_ref()[field::YIADDR];
  397. Ipv4Address::from_bytes(field)
  398. }
  399. /// Returns the value of the `siaddr` field, zero if not set.
  400. pub fn server_ip(&self) -> Ipv4Address {
  401. let field = &self.buffer.as_ref()[field::SIADDR];
  402. Ipv4Address::from_bytes(field)
  403. }
  404. /// Returns the value of the `giaddr` field, zero if not set.
  405. pub fn relay_agent_ip(&self) -> Ipv4Address {
  406. let field = &self.buffer.as_ref()[field::GIADDR];
  407. Ipv4Address::from_bytes(field)
  408. }
  409. /// Returns true if the broadcast flag is set.
  410. pub fn broadcast_flag(&self) -> bool {
  411. let field = &self.buffer.as_ref()[field::FLAGS];
  412. NetworkEndian::read_u16(field) & 0b1 == 0b1
  413. }
  414. }
  415. impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
  416. /// Return a pointer to the options.
  417. #[inline]
  418. pub fn options(&self) -> Result<&'a [u8]> {
  419. let data = self.buffer.as_ref();
  420. data.get(field::OPTIONS).ok_or(Error::Malformed)
  421. }
  422. }
  423. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  424. /// Sets the optional `sname` (“server name”) and `file` (“boot file name”) fields to zero.
  425. ///
  426. /// The fields are not commonly used, so we set their value always to zero. **This method
  427. /// must be called when creating a packet, otherwise the emitted values for these fields
  428. /// are undefined!**
  429. pub fn set_sname_and_boot_file_to_zero(&mut self) {
  430. let data = self.buffer.as_mut();
  431. for byte in &mut data[field::SNAME] {
  432. *byte = 0;
  433. }
  434. for byte in &mut data[field::FILE] {
  435. *byte = 0;
  436. }
  437. }
  438. /// Sets the `OpCode` for the packet.
  439. pub fn set_opcode(&mut self, value: OpCode) {
  440. let data = self.buffer.as_mut();
  441. data[field::OP] = value.into();
  442. }
  443. /// Sets the hardware address type (only ethernet is supported).
  444. pub fn set_hardware_type(&mut self, value: Hardware) {
  445. let data = self.buffer.as_mut();
  446. let number: u16 = value.into();
  447. assert!(number <= u16::from(u8::max_value())); // TODO: Replace with TryFrom when it's stable
  448. data[field::HTYPE] = number as u8;
  449. }
  450. /// Sets the hardware address length.
  451. ///
  452. /// Only ethernet is supported, so this field should be set to the value `6`.
  453. pub fn set_hardware_len(&mut self, value: u8) {
  454. self.buffer.as_mut()[field::HLEN] = value;
  455. }
  456. /// Sets the transaction ID.
  457. ///
  458. /// The transaction ID (called `xid` in the specification) is a random number used to
  459. /// associate messages and responses between client and server. The number is chosen by
  460. /// the client.
  461. pub fn set_transaction_id(&mut self, value: u32) {
  462. let field = &mut self.buffer.as_mut()[field::XID];
  463. NetworkEndian::write_u32(field, value)
  464. }
  465. /// Sets the ethernet address of the client.
  466. ///
  467. /// Sets the `chaddr` field.
  468. pub fn set_client_hardware_address(&mut self, value: EthernetAddress) {
  469. let field = &mut self.buffer.as_mut()[field::CHADDR];
  470. field.copy_from_slice(value.as_bytes());
  471. }
  472. /// Sets the hops field.
  473. ///
  474. /// The `hops` field is set to zero by clients and optionally used by relay agents.
  475. pub fn set_hops(&mut self, value: u8) {
  476. self.buffer.as_mut()[field::HOPS] = value;
  477. }
  478. /// Sets the `secs` field.
  479. ///
  480. /// The secs field is filled by clients and describes the number of seconds elapsed
  481. /// since client began process.
  482. pub fn set_secs(&mut self, value: u16) {
  483. let field = &mut self.buffer.as_mut()[field::SECS];
  484. NetworkEndian::write_u16(field, value);
  485. }
  486. /// Sets the value of the `magic cookie` field in the DHCP options.
  487. ///
  488. /// This field should be always be `0x63825363`.
  489. pub fn set_magic_number(&mut self, value: u32) {
  490. let field = &mut self.buffer.as_mut()[field::MAGIC_NUMBER];
  491. NetworkEndian::write_u32(field, value);
  492. }
  493. /// Sets the Ipv4 address of the client.
  494. ///
  495. /// This corresponds to the `ciaddr` field in the DHCP specification. According to it,
  496. /// this field is “only filled in if client is in `BOUND`, `RENEW` or `REBINDING` state
  497. /// and can respond to ARP requests”.
  498. pub fn set_client_ip(&mut self, value: Ipv4Address) {
  499. let field = &mut self.buffer.as_mut()[field::CIADDR];
  500. field.copy_from_slice(value.as_bytes());
  501. }
  502. /// Sets the value of the `yiaddr` field.
  503. pub fn set_your_ip(&mut self, value: Ipv4Address) {
  504. let field = &mut self.buffer.as_mut()[field::YIADDR];
  505. field.copy_from_slice(value.as_bytes());
  506. }
  507. /// Sets the value of the `siaddr` field.
  508. pub fn set_server_ip(&mut self, value: Ipv4Address) {
  509. let field = &mut self.buffer.as_mut()[field::SIADDR];
  510. field.copy_from_slice(value.as_bytes());
  511. }
  512. /// Sets the value of the `giaddr` field.
  513. pub fn set_relay_agent_ip(&mut self, value: Ipv4Address) {
  514. let field = &mut self.buffer.as_mut()[field::GIADDR];
  515. field.copy_from_slice(value.as_bytes());
  516. }
  517. /// Sets the broadcast flag to the specified value.
  518. pub fn set_broadcast_flag(&mut self, value: bool) {
  519. let field = &mut self.buffer.as_mut()[field::FLAGS];
  520. NetworkEndian::write_u16(field, if value { 1 } else { 0 });
  521. }
  522. }
  523. impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
  524. /// Return a pointer to the options.
  525. #[inline]
  526. pub fn options_mut(&mut self) -> Result<&mut [u8]> {
  527. let data = self.buffer.as_mut();
  528. data.get_mut(field::OPTIONS).ok_or(Error::Truncated)
  529. }
  530. }
  531. /// A high-level representation of a Dynamic Host Configuration Protocol packet.
  532. ///
  533. /// DHCP messages have the following layout (see [RFC 2131](https://tools.ietf.org/html/rfc2131)
  534. /// for details):
  535. ///
  536. /// ```no_rust
  537. /// 0 1 2 3
  538. /// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  539. /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  540. /// | message_type | htype (N/A) | hlen (N/A) | hops |
  541. /// +---------------+---------------+---------------+---------------+
  542. /// | transaction_id |
  543. /// +-------------------------------+-------------------------------+
  544. /// | secs | flags |
  545. /// +-------------------------------+-------------------------------+
  546. /// | client_ip |
  547. /// +---------------------------------------------------------------+
  548. /// | your_ip |
  549. /// +---------------------------------------------------------------+
  550. /// | server_ip |
  551. /// +---------------------------------------------------------------+
  552. /// | relay_agent_ip |
  553. /// +---------------------------------------------------------------+
  554. /// | |
  555. /// | client_hardware_address |
  556. /// | |
  557. /// | |
  558. /// +---------------------------------------------------------------+
  559. /// | |
  560. /// | sname (N/A) |
  561. /// +---------------------------------------------------------------+
  562. /// | |
  563. /// | file (N/A) |
  564. /// +---------------------------------------------------------------+
  565. /// | |
  566. /// | options |
  567. /// +---------------------------------------------------------------+
  568. /// ```
  569. ///
  570. /// It is assumed that the access layer is Ethernet, so `htype` (the field representing the
  571. /// hardware address type) is always set to `1`, and `hlen` (which represents the hardware address
  572. /// length) is set to `6`.
  573. ///
  574. /// The `options` field has a variable length.
  575. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  576. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  577. pub struct Repr<'a> {
  578. /// This field is also known as `op` in the RFC. It indicates the type of DHCP message this
  579. /// packet represents.
  580. pub message_type: MessageType,
  581. /// This field is also known as `xid` in the RFC. It is a random number chosen by the client,
  582. /// used by the client and server to associate messages and responses between a client and a
  583. /// server.
  584. pub transaction_id: u32,
  585. /// This field is also known as `chaddr` in the RFC and for networks where the access layer is
  586. /// ethernet, it is the client MAC address.
  587. pub client_hardware_address: EthernetAddress,
  588. /// This field is also known as `ciaddr` in the RFC. It is only filled in if client is in
  589. /// BOUND, RENEW or REBINDING state and can respond to ARP requests.
  590. pub client_ip: Ipv4Address,
  591. /// This field is also known as `yiaddr` in the RFC.
  592. pub your_ip: Ipv4Address,
  593. /// This field is also known as `siaddr` in the RFC. It may be set by the server in DHCPOFFER
  594. /// and DHCPACK messages, and represent the address of the next server to use in bootstrap.
  595. pub server_ip: Ipv4Address,
  596. /// Default gateway
  597. pub router: Option<Ipv4Address>,
  598. /// This field comes from a corresponding DhcpOption.
  599. pub subnet_mask: Option<Ipv4Address>,
  600. /// This field is also known as `giaddr` in the RFC. In order to allow DHCP clients on subnets
  601. /// not directly served by DHCP servers to communicate with DHCP servers, DHCP relay agents can
  602. /// be installed on these subnets. The DHCP client broadcasts on the local link; the relay
  603. /// agent receives the broadcast and transmits it to one or more DHCP servers using unicast.
  604. /// The relay agent stores its own IP address in the `relay_agent_ip` field of the DHCP packet.
  605. /// The DHCP server uses the `relay_agent_ip` to determine the subnet on which the relay agent
  606. /// received the broadcast, and allocates an IP address on that subnet. When the DHCP server
  607. /// replies to the client, it sends the reply to the `relay_agent_ip` address, again using
  608. /// unicast. The relay agent then retransmits the response on the local network
  609. pub relay_agent_ip: Ipv4Address,
  610. /// Broadcast flags. It can be set in DHCPDISCOVER, DHCPINFORM and DHCPREQUEST message if the
  611. /// client requires the response to be broadcasted.
  612. pub broadcast: bool,
  613. /// The "requested IP address" option. It can be used by clients in DHCPREQUEST or DHCPDISCOVER
  614. /// messages, or by servers in DHCPDECLINE messages.
  615. pub requested_ip: Option<Ipv4Address>,
  616. /// The "client identifier" option.
  617. ///
  618. /// The 'client identifier' is an opaque key, not to be interpreted by the server; for example,
  619. /// the 'client identifier' may contain a hardware address, identical to the contents of the
  620. /// 'chaddr' field, or it may contain another type of identifier, such as a DNS name. The
  621. /// 'client identifier' chosen by a DHCP client MUST be unique to that client within the subnet
  622. /// to which the client is attached. If the client uses a 'client identifier' in one message,
  623. /// it MUST use that same identifier in all subsequent messages, to ensure that all servers
  624. /// correctly identify the client.
  625. pub client_identifier: Option<EthernetAddress>,
  626. /// The "server identifier" option. It is used both to identify a DHCP server
  627. /// in a DHCP message and as a destination address from clients to servers.
  628. pub server_identifier: Option<Ipv4Address>,
  629. /// The parameter request list informs the server about which configuration parameters
  630. /// the client is interested in.
  631. pub parameter_request_list: Option<&'a [u8]>,
  632. /// DNS servers
  633. pub dns_servers: Option<[Option<Ipv4Address>; MAX_DNS_SERVER_COUNT]>,
  634. /// The maximum size dhcp packet the interface can receive
  635. pub max_size: Option<u16>,
  636. /// The DHCP IP lease duration, specified in seconds.
  637. pub lease_duration: Option<u32>
  638. }
  639. impl<'a> Repr<'a> {
  640. /// Return the length of a packet that will be emitted from this high-level representation.
  641. pub fn buffer_len(&self) -> usize {
  642. let mut len = field::OPTIONS.start;
  643. // message type and end-of-options options
  644. len += 3 + 1;
  645. if self.requested_ip.is_some() { len += 6; }
  646. if self.client_identifier.is_some() { len += 9; }
  647. if self.server_identifier.is_some() { len += 6; }
  648. if self.max_size.is_some() { len += 4; }
  649. if self.router.is_some() { len += 6; }
  650. if self.subnet_mask.is_some() { len += 6; }
  651. if self.lease_duration.is_some() { len += 6; }
  652. if let Some(list) = self.parameter_request_list { len += list.len() + 2; }
  653. len
  654. }
  655. /// Parse a DHCP packet and return a high-level representation.
  656. pub fn parse<T>(packet: &Packet<&'a T>) -> Result<Self>
  657. where T: AsRef<[u8]> + ?Sized {
  658. let transaction_id = packet.transaction_id();
  659. let client_hardware_address = packet.client_hardware_address();
  660. let client_ip = packet.client_ip();
  661. let your_ip = packet.your_ip();
  662. let server_ip = packet.server_ip();
  663. let relay_agent_ip = packet.relay_agent_ip();
  664. // only ethernet is supported right now
  665. match packet.hardware_type() {
  666. Hardware::Ethernet => {
  667. if packet.hardware_len() != 6 {
  668. return Err(Error::Malformed);
  669. }
  670. }
  671. Hardware::Unknown(_) => return Err(Error::Unrecognized), // unimplemented
  672. }
  673. if packet.magic_number() != DHCP_MAGIC_NUMBER {
  674. return Err(Error::Malformed);
  675. }
  676. let mut message_type = Err(Error::Malformed);
  677. let mut requested_ip = None;
  678. let mut client_identifier = None;
  679. let mut server_identifier = None;
  680. let mut router = None;
  681. let mut subnet_mask = None;
  682. let mut parameter_request_list = None;
  683. let mut dns_servers = None;
  684. let mut max_size = None;
  685. let mut lease_duration = None;
  686. let mut options = packet.options()?;
  687. while !options.is_empty() {
  688. let (next_options, option) = DhcpOption::parse(options)?;
  689. match option {
  690. DhcpOption::EndOfList => break,
  691. DhcpOption::Pad => {},
  692. DhcpOption::MessageType(value) => {
  693. if value.opcode() == packet.opcode() {
  694. message_type = Ok(value);
  695. }
  696. },
  697. DhcpOption::RequestedIp(ip) => {
  698. requested_ip = Some(ip);
  699. }
  700. DhcpOption::ClientIdentifier(eth_addr) => {
  701. client_identifier = Some(eth_addr);
  702. }
  703. DhcpOption::ServerIdentifier(ip) => {
  704. server_identifier = Some(ip);
  705. }
  706. DhcpOption::Router(ip) => {
  707. router = Some(ip);
  708. }
  709. DhcpOption::SubnetMask(mask) => {
  710. subnet_mask = Some(mask);
  711. },
  712. DhcpOption::MaximumDhcpMessageSize(size) => {
  713. max_size = Some(size);
  714. }
  715. DhcpOption::IpLeaseTime(duration) => {
  716. lease_duration = Some(duration);
  717. }
  718. DhcpOption::Other {kind: field::OPT_PARAMETER_REQUEST_LIST, data} => {
  719. parameter_request_list = Some(data);
  720. }
  721. DhcpOption::Other {kind: field::OPT_DOMAIN_NAME_SERVER, data} => {
  722. let mut servers = [None; MAX_DNS_SERVER_COUNT];
  723. for (server, chunk) in servers.iter_mut().zip(data.chunks(4)) {
  724. *server = Some(Ipv4Address::from_bytes(chunk));
  725. }
  726. dns_servers = Some(servers);
  727. }
  728. DhcpOption::Other {..} => {}
  729. }
  730. options = next_options;
  731. }
  732. let broadcast = packet.broadcast_flag();
  733. Ok(Repr {
  734. transaction_id, client_hardware_address, client_ip, your_ip, server_ip, relay_agent_ip,
  735. broadcast, requested_ip, server_identifier, router,
  736. subnet_mask, client_identifier, parameter_request_list, dns_servers, max_size,
  737. lease_duration,
  738. message_type: message_type?,
  739. })
  740. }
  741. /// Emit a high-level representation into a Dynamic Host
  742. /// Configuration Protocol packet.
  743. pub fn emit<T>(&self, packet: &mut Packet<&mut T>) -> Result<()>
  744. where T: AsRef<[u8]> + AsMut<[u8]> + ?Sized {
  745. packet.set_sname_and_boot_file_to_zero();
  746. packet.set_opcode(self.message_type.opcode());
  747. packet.set_hardware_type(Hardware::Ethernet);
  748. packet.set_hardware_len(6);
  749. packet.set_transaction_id(self.transaction_id);
  750. packet.set_client_hardware_address(self.client_hardware_address);
  751. packet.set_hops(0);
  752. packet.set_secs(0); // TODO
  753. packet.set_magic_number(0x63825363);
  754. packet.set_client_ip(self.client_ip);
  755. packet.set_your_ip(self.your_ip);
  756. packet.set_server_ip(self.server_ip);
  757. packet.set_relay_agent_ip(self.relay_agent_ip);
  758. packet.set_broadcast_flag(self.broadcast);
  759. {
  760. let mut options = packet.options_mut()?;
  761. options = DhcpOption::MessageType(self.message_type).emit(options);
  762. if let Some(eth_addr) = self.client_identifier {
  763. options = DhcpOption::ClientIdentifier(eth_addr).emit(options);
  764. }
  765. if let Some(ip) = self.server_identifier {
  766. options = DhcpOption::ServerIdentifier(ip).emit(options);
  767. }
  768. if let Some(ip) = self.router {
  769. options = DhcpOption::Router(ip).emit(options);
  770. }
  771. if let Some(ip) = self.subnet_mask {
  772. options = DhcpOption::SubnetMask(ip).emit(options);
  773. }
  774. if let Some(ip) = self.requested_ip {
  775. options = DhcpOption::RequestedIp(ip).emit(options);
  776. }
  777. if let Some(size) = self.max_size {
  778. options = DhcpOption::MaximumDhcpMessageSize(size).emit(options);
  779. }
  780. if let Some(duration) = self.lease_duration {
  781. options = DhcpOption::IpLeaseTime(duration).emit(options);
  782. }
  783. if let Some(list) = self.parameter_request_list {
  784. options = DhcpOption::Other{ kind: field::OPT_PARAMETER_REQUEST_LIST, data: list }.emit(options);
  785. }
  786. DhcpOption::EndOfList.emit(options);
  787. }
  788. Ok(())
  789. }
  790. }
  791. #[cfg(test)]
  792. mod test {
  793. use crate::wire::Ipv4Address;
  794. use super::*;
  795. const MAGIC_COOKIE: u32 = 0x63825363;
  796. static DISCOVER_BYTES: &[u8] = &[
  797. 0x01, 0x01, 0x06, 0x00, 0x00, 0x00, 0x3d, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  798. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x82, 0x01,
  799. 0xfc, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  800. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  801. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  802. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  803. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  804. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  805. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  806. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  807. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  808. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  809. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  810. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  811. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63,
  812. 0x35, 0x01, 0x01, 0x3d, 0x07, 0x01, 0x00, 0x0b, 0x82, 0x01, 0xfc, 0x42, 0x32, 0x04, 0x00, 0x00,
  813. 0x00, 0x00, 0x39, 0x2, 0x5, 0xdc, 0x37, 0x04, 0x01, 0x03, 0x06, 0x2a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  814. ];
  815. static ACK_DNS_SERVER_BYTES: &[u8] = &[
  816. 0x02, 0x01, 0x06, 0x00, 0xcc, 0x34, 0x75, 0xab, 0x00, 0x00, 0x80, 0x00, 0x0a, 0xff, 0x06, 0x91,
  817. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xff, 0x06, 0xfe, 0x34, 0x17, 0xeb, 0xc9,
  818. 0xaa, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  819. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  820. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  821. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  822. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  823. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  824. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  825. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  826. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  827. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  828. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  829. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  830. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63,
  831. 0x35, 0x01, 0x05, 0x36, 0x04, 0xa3, 0x01, 0x4a, 0x16, 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, 0x2b,
  832. 0x05, 0xdc, 0x03, 0x4e, 0x41, 0x50, 0x0f, 0x15, 0x6e, 0x61, 0x74, 0x2e, 0x70, 0x68, 0x79, 0x73,
  833. 0x69, 0x63, 0x73, 0x2e, 0x6f, 0x78, 0x2e, 0x61, 0x63, 0x2e, 0x75, 0x6b, 0x00, 0x03, 0x04, 0x0a,
  834. 0xff, 0x06, 0xfe, 0x06, 0x10, 0xa3, 0x01, 0x4a, 0x06, 0xa3, 0x01, 0x4a, 0x07, 0xa3, 0x01, 0x4a,
  835. 0x03, 0xa3, 0x01, 0x4a, 0x04, 0x2c, 0x10, 0xa3, 0x01, 0x4a, 0x03, 0xa3, 0x01, 0x4a, 0x04, 0xa3,
  836. 0x01, 0x4a, 0x06, 0xa3, 0x01, 0x4a, 0x07, 0x2e, 0x01, 0x08, 0xff
  837. ];
  838. static ACK_LEASE_TIME_BYTES: &[u8] = &[
  839. 0x02, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  840. 0x0a, 0x22, 0x10, 0x0b, 0x0a, 0x22, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x04, 0x91, 0x62, 0xd2,
  841. 0xa8, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  842. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  843. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  844. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  845. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  846. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  847. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  848. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  849. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  850. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  851. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  852. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  853. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63,
  854. 0x35, 0x01, 0x05, 0x36, 0x04, 0x0a, 0x22, 0x10, 0x0a, 0x33, 0x04, 0x00, 0x00, 0x02, 0x56, 0x01,
  855. 0x04, 0xff, 0xff, 0xff, 0x00, 0x03, 0x04, 0x0a, 0x22, 0x10, 0x0a, 0xff, 0x00, 0x00, 0x00, 0x00,
  856. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  857. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  858. ];
  859. const IP_NULL: Ipv4Address = Ipv4Address([0, 0, 0, 0]);
  860. const CLIENT_MAC: EthernetAddress = EthernetAddress([0x0, 0x0b, 0x82, 0x01, 0xfc, 0x42]);
  861. const DHCP_SIZE: u16 = 1500;
  862. #[test]
  863. fn test_deconstruct_discover() {
  864. let packet = Packet::new_unchecked(DISCOVER_BYTES);
  865. assert_eq!(packet.magic_number(), MAGIC_COOKIE);
  866. assert_eq!(packet.opcode(), OpCode::Request);
  867. assert_eq!(packet.hardware_type(), Hardware::Ethernet);
  868. assert_eq!(packet.hardware_len(), 6);
  869. assert_eq!(packet.hops(), 0);
  870. assert_eq!(packet.transaction_id(), 0x3d1d);
  871. assert_eq!(packet.secs(), 0);
  872. assert_eq!(packet.client_ip(), IP_NULL);
  873. assert_eq!(packet.your_ip(), IP_NULL);
  874. assert_eq!(packet.server_ip(), IP_NULL);
  875. assert_eq!(packet.relay_agent_ip(), IP_NULL);
  876. assert_eq!(packet.client_hardware_address(), CLIENT_MAC);
  877. let options = packet.options().unwrap();
  878. assert_eq!(options.len(), 3 + 9 + 6 + 4 + 6 + 1 + 7);
  879. let (options, message_type) = DhcpOption::parse(options).unwrap();
  880. assert_eq!(message_type, DhcpOption::MessageType(MessageType::Discover));
  881. assert_eq!(options.len(), 9 + 6 + 4 + 6 + 1 + 7);
  882. let (options, client_id) = DhcpOption::parse(options).unwrap();
  883. assert_eq!(client_id, DhcpOption::ClientIdentifier(CLIENT_MAC));
  884. assert_eq!(options.len(), 6 + 4 + 6 + 1 + 7);
  885. let (options, client_id) = DhcpOption::parse(options).unwrap();
  886. assert_eq!(client_id, DhcpOption::RequestedIp(IP_NULL));
  887. assert_eq!(options.len(), 4 + 6 + 1 + 7);
  888. let (options, msg_size) = DhcpOption::parse(options).unwrap();
  889. assert_eq!(msg_size, DhcpOption::MaximumDhcpMessageSize(DHCP_SIZE));
  890. assert_eq!(options.len(), 6 + 1 + 7);
  891. let (options, client_id) = DhcpOption::parse(options).unwrap();
  892. assert_eq!(client_id, DhcpOption::Other {
  893. kind: field::OPT_PARAMETER_REQUEST_LIST, data: &[1, 3, 6, 42]
  894. });
  895. assert_eq!(options.len(), 1 + 7);
  896. let (options, client_id) = DhcpOption::parse(options).unwrap();
  897. assert_eq!(client_id, DhcpOption::EndOfList);
  898. assert_eq!(options.len(), 7); // padding
  899. }
  900. #[test]
  901. fn test_construct_discover() {
  902. let mut bytes = vec![0xa5; 276];
  903. let mut packet = Packet::new_unchecked(&mut bytes);
  904. packet.set_magic_number(MAGIC_COOKIE);
  905. packet.set_sname_and_boot_file_to_zero();
  906. packet.set_opcode(OpCode::Request);
  907. packet.set_hardware_type(Hardware::Ethernet);
  908. packet.set_hardware_len(6);
  909. packet.set_hops(0);
  910. packet.set_transaction_id(0x3d1d);
  911. packet.set_secs(0);
  912. packet.set_broadcast_flag(false);
  913. packet.set_client_ip(IP_NULL);
  914. packet.set_your_ip(IP_NULL);
  915. packet.set_server_ip(IP_NULL);
  916. packet.set_relay_agent_ip(IP_NULL);
  917. packet.set_client_hardware_address(CLIENT_MAC);
  918. {
  919. let mut options = packet.options_mut().unwrap();
  920. options = DhcpOption::MessageType(MessageType::Discover).emit(options);
  921. options = DhcpOption::ClientIdentifier(CLIENT_MAC).emit(options);
  922. options = DhcpOption::RequestedIp(IP_NULL).emit(options);
  923. options = DhcpOption::MaximumDhcpMessageSize(DHCP_SIZE).emit(options);
  924. let option = DhcpOption::Other {
  925. kind: field::OPT_PARAMETER_REQUEST_LIST, data: &[1, 3, 6, 42],
  926. };
  927. options = option.emit(options);
  928. DhcpOption::EndOfList.emit(options);
  929. }
  930. let packet = &mut packet.into_inner()[..];
  931. for byte in &mut packet[269..276] {
  932. *byte = 0; // padding bytes
  933. }
  934. assert_eq!(packet, DISCOVER_BYTES);
  935. }
  936. fn offer_repr() -> Repr<'static> {
  937. Repr {
  938. message_type: MessageType::Offer,
  939. transaction_id: 0x3d1d,
  940. client_hardware_address: CLIENT_MAC,
  941. client_ip: IP_NULL,
  942. your_ip: IP_NULL,
  943. server_ip: IP_NULL,
  944. router: Some(IP_NULL),
  945. subnet_mask: Some(IP_NULL),
  946. relay_agent_ip: IP_NULL,
  947. broadcast: false,
  948. requested_ip: None,
  949. client_identifier: Some(CLIENT_MAC),
  950. server_identifier: None,
  951. parameter_request_list: None,
  952. dns_servers: None,
  953. max_size: None,
  954. lease_duration: Some(0xffff_ffff), // Infinite lease
  955. }
  956. }
  957. fn discover_repr() -> Repr<'static> {
  958. Repr {
  959. message_type: MessageType::Discover,
  960. transaction_id: 0x3d1d,
  961. client_hardware_address: CLIENT_MAC,
  962. client_ip: IP_NULL,
  963. your_ip: IP_NULL,
  964. server_ip: IP_NULL,
  965. router: None,
  966. subnet_mask: None,
  967. relay_agent_ip: IP_NULL,
  968. broadcast: false,
  969. max_size: Some(DHCP_SIZE),
  970. lease_duration: None,
  971. requested_ip: Some(IP_NULL),
  972. client_identifier: Some(CLIENT_MAC),
  973. server_identifier: None,
  974. parameter_request_list: Some(&[1, 3, 6, 42]),
  975. dns_servers: None,
  976. }
  977. }
  978. #[test]
  979. fn test_parse_discover() {
  980. let packet = Packet::new_unchecked(DISCOVER_BYTES);
  981. let repr = Repr::parse(&packet).unwrap();
  982. assert_eq!(repr, discover_repr());
  983. }
  984. #[test]
  985. fn test_emit_discover() {
  986. let repr = discover_repr();
  987. let mut bytes = vec![0xa5; repr.buffer_len()];
  988. let mut packet = Packet::new_unchecked(&mut bytes);
  989. repr.emit(&mut packet).unwrap();
  990. let packet = &packet.into_inner()[..];
  991. let packet_len = packet.len();
  992. assert_eq!(packet, &DISCOVER_BYTES[..packet_len]);
  993. for byte in &DISCOVER_BYTES[packet_len..] {
  994. assert_eq!(*byte, 0); // padding bytes
  995. }
  996. }
  997. #[test]
  998. fn test_emit_offer() {
  999. let repr = offer_repr();
  1000. let mut bytes = vec![0xa5; repr.buffer_len()];
  1001. let mut packet = Packet::new_unchecked(&mut bytes);
  1002. repr.emit(&mut packet).unwrap();
  1003. }
  1004. #[test]
  1005. fn test_emit_dhcp_option() {
  1006. static DATA: &[u8] = &[1, 3, 6];
  1007. let mut bytes = vec![0xa5; 5];
  1008. let dhcp_option = DhcpOption::Other {
  1009. kind: field::OPT_PARAMETER_REQUEST_LIST,
  1010. data: DATA,
  1011. };
  1012. {
  1013. let rest = dhcp_option.emit(&mut bytes);
  1014. assert_eq!(rest.len(), 0);
  1015. }
  1016. assert_eq!(&bytes[0..2], &[field::OPT_PARAMETER_REQUEST_LIST, DATA.len() as u8]);
  1017. assert_eq!(&bytes[2..], DATA);
  1018. }
  1019. #[test]
  1020. fn test_parse_ack_dns_servers() {
  1021. let packet = Packet::new_unchecked(ACK_DNS_SERVER_BYTES);
  1022. let repr = Repr::parse(&packet).unwrap();
  1023. // The packet described by ACK_BYTES advertises 4 DNS servers
  1024. // Here we ensure that we correctly parse the first 3 into our fixed
  1025. // length-3 array (see issue #305)
  1026. assert_eq!(repr.dns_servers, Some([
  1027. Some(Ipv4Address([163, 1, 74, 6])),
  1028. Some(Ipv4Address([163, 1, 74, 7])),
  1029. Some(Ipv4Address([163, 1, 74, 3]))]));
  1030. }
  1031. #[test]
  1032. fn test_parse_ack_lease_duration() {
  1033. let packet = Packet::new_unchecked(ACK_LEASE_TIME_BYTES);
  1034. let repr = Repr::parse(&packet).unwrap();
  1035. // Verify that the lease time in the ACK is properly parsed. The packet contains a lease
  1036. // duration of 598s.
  1037. assert_eq!(repr.lease_duration, Some(598));
  1038. }
  1039. }