dhcpv4.rs 49 KB

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