dhcpv4.rs 48 KB

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