ip.rs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. use core::convert::From;
  2. use core::fmt;
  3. use crate::phy::ChecksumCapabilities;
  4. #[cfg(feature = "proto-ipv4")]
  5. use crate::wire::{Ipv4Address, Ipv4Cidr, Ipv4Packet, Ipv4Repr};
  6. #[cfg(feature = "proto-ipv6")]
  7. use crate::wire::{Ipv6Address, Ipv6Cidr, Ipv6Packet, Ipv6Repr};
  8. use crate::{Error, Result};
  9. /// Internet protocol version.
  10. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
  11. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  12. #[non_exhaustive]
  13. pub enum Version {
  14. Unspecified,
  15. #[cfg(feature = "proto-ipv4")]
  16. Ipv4,
  17. #[cfg(feature = "proto-ipv6")]
  18. Ipv6,
  19. }
  20. impl Version {
  21. /// Return the version of an IP packet stored in the provided buffer.
  22. ///
  23. /// This function never returns `Ok(IpVersion::Unspecified)`; instead,
  24. /// unknown versions result in `Err(Error::Unrecognized)`.
  25. pub fn of_packet(data: &[u8]) -> Result<Version> {
  26. match data[0] >> 4 {
  27. #[cfg(feature = "proto-ipv4")]
  28. 4 => Ok(Version::Ipv4),
  29. #[cfg(feature = "proto-ipv6")]
  30. 6 => Ok(Version::Ipv6),
  31. _ => Err(Error::Unrecognized),
  32. }
  33. }
  34. }
  35. impl fmt::Display for Version {
  36. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  37. match *self {
  38. Version::Unspecified => write!(f, "IPv?"),
  39. #[cfg(feature = "proto-ipv4")]
  40. Version::Ipv4 => write!(f, "IPv4"),
  41. #[cfg(feature = "proto-ipv6")]
  42. Version::Ipv6 => write!(f, "IPv6"),
  43. }
  44. }
  45. }
  46. enum_with_unknown! {
  47. /// IP datagram encapsulated protocol.
  48. pub enum Protocol(u8) {
  49. HopByHop = 0x00,
  50. Icmp = 0x01,
  51. Igmp = 0x02,
  52. Tcp = 0x06,
  53. Udp = 0x11,
  54. Ipv6Route = 0x2b,
  55. Ipv6Frag = 0x2c,
  56. Icmpv6 = 0x3a,
  57. Ipv6NoNxt = 0x3b,
  58. Ipv6Opts = 0x3c
  59. }
  60. }
  61. impl fmt::Display for Protocol {
  62. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  63. match *self {
  64. Protocol::HopByHop => write!(f, "Hop-by-Hop"),
  65. Protocol::Icmp => write!(f, "ICMP"),
  66. Protocol::Igmp => write!(f, "IGMP"),
  67. Protocol::Tcp => write!(f, "TCP"),
  68. Protocol::Udp => write!(f, "UDP"),
  69. Protocol::Ipv6Route => write!(f, "IPv6-Route"),
  70. Protocol::Ipv6Frag => write!(f, "IPv6-Frag"),
  71. Protocol::Icmpv6 => write!(f, "ICMPv6"),
  72. Protocol::Ipv6NoNxt => write!(f, "IPv6-NoNxt"),
  73. Protocol::Ipv6Opts => write!(f, "IPv6-Opts"),
  74. Protocol::Unknown(id) => write!(f, "0x{:02x}", id),
  75. }
  76. }
  77. }
  78. /// An internetworking address.
  79. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
  80. #[non_exhaustive]
  81. pub enum Address {
  82. /// An unspecified address.
  83. /// May be used as a placeholder for storage where the address is not assigned yet.
  84. Unspecified,
  85. /// An IPv4 address.
  86. #[cfg(feature = "proto-ipv4")]
  87. Ipv4(Ipv4Address),
  88. /// An IPv6 address.
  89. #[cfg(feature = "proto-ipv6")]
  90. Ipv6(Ipv6Address),
  91. }
  92. impl Address {
  93. /// Create an address wrapping an IPv4 address with the given octets.
  94. #[cfg(feature = "proto-ipv4")]
  95. pub fn v4(a0: u8, a1: u8, a2: u8, a3: u8) -> Address {
  96. Address::Ipv4(Ipv4Address::new(a0, a1, a2, a3))
  97. }
  98. /// Create an address wrapping an IPv6 address with the given octets.
  99. #[cfg(feature = "proto-ipv6")]
  100. #[allow(clippy::too_many_arguments)]
  101. pub fn v6(a0: u16, a1: u16, a2: u16, a3: u16, a4: u16, a5: u16, a6: u16, a7: u16) -> Address {
  102. Address::Ipv6(Ipv6Address::new(a0, a1, a2, a3, a4, a5, a6, a7))
  103. }
  104. /// Return the protocol version.
  105. pub fn version(&self) -> Option<Version> {
  106. match self {
  107. Address::Unspecified => None,
  108. #[cfg(feature = "proto-ipv4")]
  109. Address::Ipv4(_) => Some(Version::Ipv4),
  110. #[cfg(feature = "proto-ipv6")]
  111. Address::Ipv6(_) => Some(Version::Ipv6),
  112. }
  113. }
  114. /// Return an address as a sequence of octets, in big-endian.
  115. pub fn as_bytes(&self) -> &[u8] {
  116. match *self {
  117. Address::Unspecified => &[],
  118. #[cfg(feature = "proto-ipv4")]
  119. Address::Ipv4(ref addr) => addr.as_bytes(),
  120. #[cfg(feature = "proto-ipv6")]
  121. Address::Ipv6(ref addr) => addr.as_bytes(),
  122. }
  123. }
  124. /// Query whether the address is a valid unicast address.
  125. pub fn is_unicast(&self) -> bool {
  126. match *self {
  127. Address::Unspecified => false,
  128. #[cfg(feature = "proto-ipv4")]
  129. Address::Ipv4(addr) => addr.is_unicast(),
  130. #[cfg(feature = "proto-ipv6")]
  131. Address::Ipv6(addr) => addr.is_unicast(),
  132. }
  133. }
  134. /// Query whether the address is a valid multicast address.
  135. pub fn is_multicast(&self) -> bool {
  136. match *self {
  137. Address::Unspecified => false,
  138. #[cfg(feature = "proto-ipv4")]
  139. Address::Ipv4(addr) => addr.is_multicast(),
  140. #[cfg(feature = "proto-ipv6")]
  141. Address::Ipv6(addr) => addr.is_multicast(),
  142. }
  143. }
  144. /// Query whether the address is the broadcast address.
  145. pub fn is_broadcast(&self) -> bool {
  146. match *self {
  147. Address::Unspecified => false,
  148. #[cfg(feature = "proto-ipv4")]
  149. Address::Ipv4(addr) => addr.is_broadcast(),
  150. #[cfg(feature = "proto-ipv6")]
  151. Address::Ipv6(_) => false,
  152. }
  153. }
  154. /// Query whether the address falls into the "unspecified" range.
  155. pub fn is_unspecified(&self) -> bool {
  156. match *self {
  157. Address::Unspecified => true,
  158. #[cfg(feature = "proto-ipv4")]
  159. Address::Ipv4(addr) => addr.is_unspecified(),
  160. #[cfg(feature = "proto-ipv6")]
  161. Address::Ipv6(addr) => addr.is_unspecified(),
  162. }
  163. }
  164. /// Return an unspecified address that has the same IP version as `self`.
  165. pub fn as_unspecified(&self) -> Address {
  166. match *self {
  167. Address::Unspecified => Address::Unspecified,
  168. #[cfg(feature = "proto-ipv4")]
  169. Address::Ipv4(_) => Address::Ipv4(Ipv4Address::UNSPECIFIED),
  170. #[cfg(feature = "proto-ipv6")]
  171. Address::Ipv6(_) => Address::Ipv6(Ipv6Address::UNSPECIFIED),
  172. }
  173. }
  174. /// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
  175. /// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
  176. pub fn prefix_len(&self) -> Option<u8> {
  177. let mut ones = true;
  178. let mut prefix_len = 0;
  179. for byte in self.as_bytes() {
  180. let mut mask = 0x80;
  181. for _ in 0..8 {
  182. let one = *byte & mask != 0;
  183. if ones {
  184. // Expect 1s until first 0
  185. if one {
  186. prefix_len += 1;
  187. } else {
  188. ones = false;
  189. }
  190. } else if one {
  191. // 1 where 0 was expected
  192. return None;
  193. }
  194. mask >>= 1;
  195. }
  196. }
  197. Some(prefix_len)
  198. }
  199. }
  200. #[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
  201. impl From<::std::net::IpAddr> for Address {
  202. fn from(x: ::std::net::IpAddr) -> Address {
  203. match x {
  204. ::std::net::IpAddr::V4(ipv4) => Address::Ipv4(ipv4.into()),
  205. ::std::net::IpAddr::V6(ipv6) => Address::Ipv6(ipv6.into()),
  206. }
  207. }
  208. }
  209. #[cfg(feature = "std")]
  210. impl From<Address> for ::std::net::IpAddr {
  211. fn from(x: Address) -> ::std::net::IpAddr {
  212. match x {
  213. #[cfg(feature = "proto-ipv4")]
  214. Address::Ipv4(ipv4) => ::std::net::IpAddr::V4(ipv4.into()),
  215. #[cfg(feature = "proto-ipv6")]
  216. Address::Ipv6(ipv6) => ::std::net::IpAddr::V6(ipv6.into()),
  217. _ => unreachable!(),
  218. }
  219. }
  220. }
  221. #[cfg(all(feature = "std", feature = "proto-ipv4"))]
  222. impl From<::std::net::Ipv4Addr> for Address {
  223. fn from(ipv4: ::std::net::Ipv4Addr) -> Address {
  224. Address::Ipv4(ipv4.into())
  225. }
  226. }
  227. #[cfg(all(feature = "std", feature = "proto-ipv6"))]
  228. impl From<::std::net::Ipv6Addr> for Address {
  229. fn from(ipv6: ::std::net::Ipv6Addr) -> Address {
  230. Address::Ipv6(ipv6.into())
  231. }
  232. }
  233. impl Default for Address {
  234. fn default() -> Address {
  235. Address::Unspecified
  236. }
  237. }
  238. #[cfg(feature = "proto-ipv4")]
  239. impl From<Ipv4Address> for Address {
  240. fn from(addr: Ipv4Address) -> Self {
  241. Address::Ipv4(addr)
  242. }
  243. }
  244. #[cfg(feature = "proto-ipv6")]
  245. impl From<Ipv6Address> for Address {
  246. fn from(addr: Ipv6Address) -> Self {
  247. Address::Ipv6(addr)
  248. }
  249. }
  250. impl fmt::Display for Address {
  251. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  252. match *self {
  253. Address::Unspecified => write!(f, "*"),
  254. #[cfg(feature = "proto-ipv4")]
  255. Address::Ipv4(addr) => write!(f, "{}", addr),
  256. #[cfg(feature = "proto-ipv6")]
  257. Address::Ipv6(addr) => write!(f, "{}", addr),
  258. }
  259. }
  260. }
  261. #[cfg(feature = "defmt")]
  262. impl defmt::Format for Address {
  263. fn format(&self, f: defmt::Formatter) {
  264. match self {
  265. &Address::Unspecified => defmt::write!(f, "{:?}", "*"),
  266. #[cfg(feature = "proto-ipv4")]
  267. &Address::Ipv4(addr) => defmt::write!(f, "{:?}", addr),
  268. #[cfg(feature = "proto-ipv6")]
  269. &Address::Ipv6(addr) => defmt::write!(f, "{:?}", addr),
  270. }
  271. }
  272. }
  273. /// A specification of a CIDR block, containing an address and a variable-length
  274. /// subnet masking prefix length.
  275. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
  276. #[non_exhaustive]
  277. pub enum Cidr {
  278. #[cfg(feature = "proto-ipv4")]
  279. Ipv4(Ipv4Cidr),
  280. #[cfg(feature = "proto-ipv6")]
  281. Ipv6(Ipv6Cidr),
  282. }
  283. impl Cidr {
  284. /// Create a CIDR block from the given address and prefix length.
  285. ///
  286. /// # Panics
  287. /// This function panics if the given address is unspecified, or
  288. /// the given prefix length is invalid for the given address.
  289. pub fn new(addr: Address, prefix_len: u8) -> Cidr {
  290. match addr {
  291. #[cfg(feature = "proto-ipv4")]
  292. Address::Ipv4(addr) => Cidr::Ipv4(Ipv4Cidr::new(addr, prefix_len)),
  293. #[cfg(feature = "proto-ipv6")]
  294. Address::Ipv6(addr) => Cidr::Ipv6(Ipv6Cidr::new(addr, prefix_len)),
  295. Address::Unspecified => {
  296. panic!("a CIDR block cannot be based on an unspecified address")
  297. }
  298. }
  299. }
  300. /// Return the IP address of this CIDR block.
  301. pub fn address(&self) -> Address {
  302. match *self {
  303. #[cfg(feature = "proto-ipv4")]
  304. Cidr::Ipv4(cidr) => Address::Ipv4(cidr.address()),
  305. #[cfg(feature = "proto-ipv6")]
  306. Cidr::Ipv6(cidr) => Address::Ipv6(cidr.address()),
  307. }
  308. }
  309. /// Return the prefix length of this CIDR block.
  310. pub fn prefix_len(&self) -> u8 {
  311. match *self {
  312. #[cfg(feature = "proto-ipv4")]
  313. Cidr::Ipv4(cidr) => cidr.prefix_len(),
  314. #[cfg(feature = "proto-ipv6")]
  315. Cidr::Ipv6(cidr) => cidr.prefix_len(),
  316. }
  317. }
  318. /// Query whether the subnetwork described by this CIDR block contains
  319. /// the given address.
  320. pub fn contains_addr(&self, addr: &Address) -> bool {
  321. match (self, addr) {
  322. #[cfg(feature = "proto-ipv4")]
  323. (&Cidr::Ipv4(ref cidr), &Address::Ipv4(ref addr)) => cidr.contains_addr(addr),
  324. #[cfg(feature = "proto-ipv6")]
  325. (&Cidr::Ipv6(ref cidr), &Address::Ipv6(ref addr)) => cidr.contains_addr(addr),
  326. #[cfg(all(feature = "proto-ipv6", feature = "proto-ipv4"))]
  327. (&Cidr::Ipv4(_), &Address::Ipv6(_)) | (&Cidr::Ipv6(_), &Address::Ipv4(_)) => false,
  328. (_, &Address::Unspecified) =>
  329. // a fully unspecified address covers both IPv4 and IPv6,
  330. // and no CIDR block can do that.
  331. {
  332. false
  333. }
  334. }
  335. }
  336. /// Query whether the subnetwork described by this CIDR block contains
  337. /// the subnetwork described by the given CIDR block.
  338. pub fn contains_subnet(&self, subnet: &Cidr) -> bool {
  339. match (self, subnet) {
  340. #[cfg(feature = "proto-ipv4")]
  341. (&Cidr::Ipv4(ref cidr), &Cidr::Ipv4(ref other)) => cidr.contains_subnet(other),
  342. #[cfg(feature = "proto-ipv6")]
  343. (&Cidr::Ipv6(ref cidr), &Cidr::Ipv6(ref other)) => cidr.contains_subnet(other),
  344. #[cfg(all(feature = "proto-ipv6", feature = "proto-ipv4"))]
  345. (&Cidr::Ipv4(_), &Cidr::Ipv6(_)) | (&Cidr::Ipv6(_), &Cidr::Ipv4(_)) => false,
  346. }
  347. }
  348. }
  349. #[cfg(feature = "proto-ipv4")]
  350. impl From<Ipv4Cidr> for Cidr {
  351. fn from(addr: Ipv4Cidr) -> Self {
  352. Cidr::Ipv4(addr)
  353. }
  354. }
  355. #[cfg(feature = "proto-ipv6")]
  356. impl From<Ipv6Cidr> for Cidr {
  357. fn from(addr: Ipv6Cidr) -> Self {
  358. Cidr::Ipv6(addr)
  359. }
  360. }
  361. impl fmt::Display for Cidr {
  362. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  363. match *self {
  364. #[cfg(feature = "proto-ipv4")]
  365. Cidr::Ipv4(cidr) => write!(f, "{}", cidr),
  366. #[cfg(feature = "proto-ipv6")]
  367. Cidr::Ipv6(cidr) => write!(f, "{}", cidr),
  368. }
  369. }
  370. }
  371. #[cfg(feature = "defmt")]
  372. impl defmt::Format for Cidr {
  373. fn format(&self, f: defmt::Formatter) {
  374. match self {
  375. #[cfg(feature = "proto-ipv4")]
  376. &Cidr::Ipv4(cidr) => defmt::write!(f, "{:?}", cidr),
  377. #[cfg(feature = "proto-ipv6")]
  378. &Cidr::Ipv6(cidr) => defmt::write!(f, "{:?}", cidr),
  379. }
  380. }
  381. }
  382. /// An internet endpoint address.
  383. ///
  384. /// An endpoint can be constructed from a port, in which case the address is unspecified.
  385. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
  386. pub struct Endpoint {
  387. pub addr: Address,
  388. pub port: u16,
  389. }
  390. impl Endpoint {
  391. /// An endpoint with unspecified address and port.
  392. pub const UNSPECIFIED: Endpoint = Endpoint {
  393. addr: Address::Unspecified,
  394. port: 0,
  395. };
  396. /// Create an endpoint address from given address and port.
  397. pub fn new(addr: Address, port: u16) -> Endpoint {
  398. Endpoint { addr, port }
  399. }
  400. /// Query whether the endpoint has a specified address and port.
  401. pub fn is_specified(&self) -> bool {
  402. !self.addr.is_unspecified() && self.port != 0
  403. }
  404. }
  405. #[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
  406. impl From<::std::net::SocketAddr> for Endpoint {
  407. fn from(x: ::std::net::SocketAddr) -> Endpoint {
  408. Endpoint {
  409. addr: x.ip().into(),
  410. port: x.port(),
  411. }
  412. }
  413. }
  414. #[cfg(all(feature = "std", feature = "proto-ipv4"))]
  415. impl From<::std::net::SocketAddrV4> for Endpoint {
  416. fn from(x: ::std::net::SocketAddrV4) -> Endpoint {
  417. Endpoint {
  418. addr: (*x.ip()).into(),
  419. port: x.port(),
  420. }
  421. }
  422. }
  423. #[cfg(all(feature = "std", feature = "proto-ipv6"))]
  424. impl From<::std::net::SocketAddrV6> for Endpoint {
  425. fn from(x: ::std::net::SocketAddrV6) -> Endpoint {
  426. Endpoint {
  427. addr: (*x.ip()).into(),
  428. port: x.port(),
  429. }
  430. }
  431. }
  432. impl fmt::Display for Endpoint {
  433. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  434. write!(f, "{}:{}", self.addr, self.port)
  435. }
  436. }
  437. #[cfg(feature = "defmt")]
  438. impl defmt::Format for Endpoint {
  439. fn format(&self, f: defmt::Formatter) {
  440. defmt::write!(f, "{:?}:{=u16}", self.addr, self.port);
  441. }
  442. }
  443. impl From<u16> for Endpoint {
  444. fn from(port: u16) -> Endpoint {
  445. Endpoint {
  446. addr: Address::Unspecified,
  447. port,
  448. }
  449. }
  450. }
  451. impl<T: Into<Address>> From<(T, u16)> for Endpoint {
  452. fn from((addr, port): (T, u16)) -> Endpoint {
  453. Endpoint {
  454. addr: addr.into(),
  455. port,
  456. }
  457. }
  458. }
  459. /// An IP packet representation.
  460. ///
  461. /// This enum abstracts the various versions of IP packets. It either contains an IPv4
  462. /// or IPv6 concrete high-level representation.
  463. #[derive(Debug, Clone, PartialEq, Eq)]
  464. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  465. #[non_exhaustive]
  466. pub enum Repr {
  467. #[cfg(feature = "proto-ipv4")]
  468. Ipv4(Ipv4Repr),
  469. #[cfg(feature = "proto-ipv6")]
  470. Ipv6(Ipv6Repr),
  471. }
  472. #[cfg(feature = "proto-ipv4")]
  473. impl From<Ipv4Repr> for Repr {
  474. fn from(repr: Ipv4Repr) -> Repr {
  475. Repr::Ipv4(repr)
  476. }
  477. }
  478. #[cfg(feature = "proto-ipv6")]
  479. impl From<Ipv6Repr> for Repr {
  480. fn from(repr: Ipv6Repr) -> Repr {
  481. Repr::Ipv6(repr)
  482. }
  483. }
  484. impl Repr {
  485. /// Create a new IpRepr, choosing the right IP version for the src/dst addrs.
  486. ///
  487. /// # Panics
  488. ///
  489. /// Panics if `src_addr` and `dst_addr` are different IP version.
  490. pub fn new(
  491. src_addr: Address,
  492. dst_addr: Address,
  493. next_header: Protocol,
  494. payload_len: usize,
  495. hop_limit: u8,
  496. ) -> Self {
  497. match (src_addr, dst_addr) {
  498. #[cfg(feature = "proto-ipv4")]
  499. (Address::Ipv4(src_addr), Address::Ipv4(dst_addr)) => Self::Ipv4(Ipv4Repr {
  500. src_addr,
  501. dst_addr,
  502. next_header,
  503. payload_len,
  504. hop_limit,
  505. }),
  506. #[cfg(feature = "proto-ipv6")]
  507. (Address::Ipv6(src_addr), Address::Ipv6(dst_addr)) => Self::Ipv6(Ipv6Repr {
  508. src_addr,
  509. dst_addr,
  510. next_header,
  511. payload_len,
  512. hop_limit,
  513. }),
  514. _ => panic!("IP version mismatch: src={:?} dst={:?}", src_addr, dst_addr),
  515. }
  516. }
  517. /// Return the protocol version.
  518. pub fn version(&self) -> Version {
  519. match *self {
  520. #[cfg(feature = "proto-ipv4")]
  521. Repr::Ipv4(_) => Version::Ipv4,
  522. #[cfg(feature = "proto-ipv6")]
  523. Repr::Ipv6(_) => Version::Ipv6,
  524. }
  525. }
  526. /// Return the source address.
  527. pub fn src_addr(&self) -> Address {
  528. match *self {
  529. #[cfg(feature = "proto-ipv4")]
  530. Repr::Ipv4(repr) => Address::Ipv4(repr.src_addr),
  531. #[cfg(feature = "proto-ipv6")]
  532. Repr::Ipv6(repr) => Address::Ipv6(repr.src_addr),
  533. }
  534. }
  535. /// Return the destination address.
  536. pub fn dst_addr(&self) -> Address {
  537. match *self {
  538. #[cfg(feature = "proto-ipv4")]
  539. Repr::Ipv4(repr) => Address::Ipv4(repr.dst_addr),
  540. #[cfg(feature = "proto-ipv6")]
  541. Repr::Ipv6(repr) => Address::Ipv6(repr.dst_addr),
  542. }
  543. }
  544. /// Return the next header (protocol).
  545. pub fn next_header(&self) -> Protocol {
  546. match *self {
  547. #[cfg(feature = "proto-ipv4")]
  548. Repr::Ipv4(repr) => repr.next_header,
  549. #[cfg(feature = "proto-ipv6")]
  550. Repr::Ipv6(repr) => repr.next_header,
  551. }
  552. }
  553. /// Return the payload length.
  554. pub fn payload_len(&self) -> usize {
  555. match *self {
  556. #[cfg(feature = "proto-ipv4")]
  557. Repr::Ipv4(repr) => repr.payload_len,
  558. #[cfg(feature = "proto-ipv6")]
  559. Repr::Ipv6(repr) => repr.payload_len,
  560. }
  561. }
  562. /// Set the payload length.
  563. pub fn set_payload_len(&mut self, length: usize) {
  564. match *self {
  565. #[cfg(feature = "proto-ipv4")]
  566. Repr::Ipv4(Ipv4Repr {
  567. ref mut payload_len,
  568. ..
  569. }) => *payload_len = length,
  570. #[cfg(feature = "proto-ipv6")]
  571. Repr::Ipv6(Ipv6Repr {
  572. ref mut payload_len,
  573. ..
  574. }) => *payload_len = length,
  575. }
  576. }
  577. /// Return the TTL value.
  578. pub fn hop_limit(&self) -> u8 {
  579. match *self {
  580. #[cfg(feature = "proto-ipv4")]
  581. Repr::Ipv4(Ipv4Repr { hop_limit, .. }) => hop_limit,
  582. #[cfg(feature = "proto-ipv6")]
  583. Repr::Ipv6(Ipv6Repr { hop_limit, .. }) => hop_limit,
  584. }
  585. }
  586. /// Return the length of a header that will be emitted from this high-level representation.
  587. pub fn buffer_len(&self) -> usize {
  588. match *self {
  589. #[cfg(feature = "proto-ipv4")]
  590. Repr::Ipv4(repr) => repr.buffer_len(),
  591. #[cfg(feature = "proto-ipv6")]
  592. Repr::Ipv6(repr) => repr.buffer_len(),
  593. }
  594. }
  595. /// Emit this high-level representation into a buffer.
  596. pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(
  597. &self,
  598. buffer: T,
  599. _checksum_caps: &ChecksumCapabilities,
  600. ) {
  601. match *self {
  602. #[cfg(feature = "proto-ipv4")]
  603. Repr::Ipv4(repr) => repr.emit(&mut Ipv4Packet::new_unchecked(buffer), _checksum_caps),
  604. #[cfg(feature = "proto-ipv6")]
  605. Repr::Ipv6(repr) => repr.emit(&mut Ipv6Packet::new_unchecked(buffer)),
  606. }
  607. }
  608. /// Return the total length of a packet that will be emitted from this
  609. /// high-level representation.
  610. ///
  611. /// This is the same as `repr.buffer_len() + repr.payload_len()`.
  612. pub fn total_len(&self) -> usize {
  613. self.buffer_len() + self.payload_len()
  614. }
  615. }
  616. pub mod checksum {
  617. use byteorder::{ByteOrder, NetworkEndian};
  618. use super::*;
  619. fn propagate_carries(word: u32) -> u16 {
  620. let sum = (word >> 16) + (word & 0xffff);
  621. ((sum >> 16) as u16) + (sum as u16)
  622. }
  623. /// Compute an RFC 1071 compliant checksum (without the final complement).
  624. pub fn data(mut data: &[u8]) -> u16 {
  625. let mut accum = 0;
  626. // For each 32-byte chunk...
  627. const CHUNK_SIZE: usize = 32;
  628. while data.len() >= CHUNK_SIZE {
  629. let mut d = &data[..CHUNK_SIZE];
  630. // ... take by 2 bytes and sum them.
  631. while d.len() >= 2 {
  632. accum += NetworkEndian::read_u16(d) as u32;
  633. d = &d[2..];
  634. }
  635. data = &data[CHUNK_SIZE..];
  636. }
  637. // Sum the rest that does not fit the last 32-byte chunk,
  638. // taking by 2 bytes.
  639. while data.len() >= 2 {
  640. accum += NetworkEndian::read_u16(data) as u32;
  641. data = &data[2..];
  642. }
  643. // Add the last remaining odd byte, if any.
  644. if let Some(&value) = data.first() {
  645. accum += (value as u32) << 8;
  646. }
  647. propagate_carries(accum)
  648. }
  649. /// Combine several RFC 1071 compliant checksums.
  650. pub fn combine(checksums: &[u16]) -> u16 {
  651. let mut accum: u32 = 0;
  652. for &word in checksums {
  653. accum += word as u32;
  654. }
  655. propagate_carries(accum)
  656. }
  657. /// Compute an IP pseudo header checksum.
  658. pub fn pseudo_header(
  659. src_addr: &Address,
  660. dst_addr: &Address,
  661. next_header: Protocol,
  662. length: u32,
  663. ) -> u16 {
  664. match (src_addr, dst_addr) {
  665. #[cfg(feature = "proto-ipv4")]
  666. (&Address::Ipv4(src_addr), &Address::Ipv4(dst_addr)) => {
  667. let mut proto_len = [0u8; 4];
  668. proto_len[1] = next_header.into();
  669. NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
  670. combine(&[
  671. data(src_addr.as_bytes()),
  672. data(dst_addr.as_bytes()),
  673. data(&proto_len[..]),
  674. ])
  675. }
  676. #[cfg(feature = "proto-ipv6")]
  677. (&Address::Ipv6(src_addr), &Address::Ipv6(dst_addr)) => {
  678. let mut proto_len = [0u8; 8];
  679. proto_len[7] = next_header.into();
  680. NetworkEndian::write_u32(&mut proto_len[0..4], length);
  681. combine(&[
  682. data(src_addr.as_bytes()),
  683. data(dst_addr.as_bytes()),
  684. data(&proto_len[..]),
  685. ])
  686. }
  687. _ => panic!(
  688. "Unexpected pseudo header addresses: {}, {}",
  689. src_addr, dst_addr
  690. ),
  691. }
  692. }
  693. // We use this in pretty printer implementations.
  694. pub(crate) fn format_checksum(f: &mut fmt::Formatter, correct: bool) -> fmt::Result {
  695. if !correct {
  696. write!(f, " (checksum incorrect)")
  697. } else {
  698. Ok(())
  699. }
  700. }
  701. }
  702. use crate::wire::pretty_print::PrettyIndent;
  703. pub fn pretty_print_ip_payload<T: Into<Repr>>(
  704. f: &mut fmt::Formatter,
  705. indent: &mut PrettyIndent,
  706. ip_repr: T,
  707. payload: &[u8],
  708. ) -> fmt::Result {
  709. #[cfg(feature = "proto-ipv4")]
  710. use super::pretty_print::PrettyPrint;
  711. use crate::wire::ip::checksum::format_checksum;
  712. #[cfg(feature = "proto-ipv4")]
  713. use crate::wire::Icmpv4Packet;
  714. use crate::wire::{TcpPacket, TcpRepr, UdpPacket, UdpRepr};
  715. let checksum_caps = ChecksumCapabilities::ignored();
  716. let repr = ip_repr.into();
  717. match repr.next_header() {
  718. #[cfg(feature = "proto-ipv4")]
  719. Protocol::Icmp => {
  720. indent.increase(f)?;
  721. Icmpv4Packet::<&[u8]>::pretty_print(&payload, f, indent)
  722. }
  723. Protocol::Udp => {
  724. indent.increase(f)?;
  725. match UdpPacket::<&[u8]>::new_checked(payload) {
  726. Err(err) => write!(f, "{}({})", indent, err),
  727. Ok(udp_packet) => {
  728. match UdpRepr::parse(
  729. &udp_packet,
  730. &repr.src_addr(),
  731. &repr.dst_addr(),
  732. &checksum_caps,
  733. ) {
  734. Err(err) => write!(f, "{}{} ({})", indent, udp_packet, err),
  735. Ok(udp_repr) => {
  736. write!(
  737. f,
  738. "{}{} len={}",
  739. indent,
  740. udp_repr,
  741. udp_packet.payload().len()
  742. )?;
  743. let valid =
  744. udp_packet.verify_checksum(&repr.src_addr(), &repr.dst_addr());
  745. format_checksum(f, valid)
  746. }
  747. }
  748. }
  749. }
  750. }
  751. Protocol::Tcp => {
  752. indent.increase(f)?;
  753. match TcpPacket::<&[u8]>::new_checked(payload) {
  754. Err(err) => write!(f, "{}({})", indent, err),
  755. Ok(tcp_packet) => {
  756. match TcpRepr::parse(
  757. &tcp_packet,
  758. &repr.src_addr(),
  759. &repr.dst_addr(),
  760. &checksum_caps,
  761. ) {
  762. Err(err) => write!(f, "{}{} ({})", indent, tcp_packet, err),
  763. Ok(tcp_repr) => {
  764. write!(f, "{}{}", indent, tcp_repr)?;
  765. let valid =
  766. tcp_packet.verify_checksum(&repr.src_addr(), &repr.dst_addr());
  767. format_checksum(f, valid)
  768. }
  769. }
  770. }
  771. }
  772. }
  773. _ => Ok(()),
  774. }
  775. }
  776. #[cfg(test)]
  777. pub(crate) mod test {
  778. #![allow(unused)]
  779. #[cfg(feature = "proto-ipv6")]
  780. pub(crate) const MOCK_IP_ADDR_1: IpAddress = IpAddress::Ipv6(Ipv6Address([
  781. 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
  782. ]));
  783. #[cfg(feature = "proto-ipv6")]
  784. pub(crate) const MOCK_IP_ADDR_2: IpAddress = IpAddress::Ipv6(Ipv6Address([
  785. 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
  786. ]));
  787. #[cfg(feature = "proto-ipv6")]
  788. pub(crate) const MOCK_IP_ADDR_3: IpAddress = IpAddress::Ipv6(Ipv6Address([
  789. 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
  790. ]));
  791. #[cfg(feature = "proto-ipv6")]
  792. pub(crate) const MOCK_IP_ADDR_4: IpAddress = IpAddress::Ipv6(Ipv6Address([
  793. 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
  794. ]));
  795. #[cfg(feature = "proto-ipv6")]
  796. pub(crate) const MOCK_UNSPECIFIED: IpAddress = IpAddress::Ipv6(Ipv6Address::UNSPECIFIED);
  797. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  798. pub(crate) const MOCK_IP_ADDR_1: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 1]));
  799. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  800. pub(crate) const MOCK_IP_ADDR_2: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 2]));
  801. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  802. pub(crate) const MOCK_IP_ADDR_3: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 3]));
  803. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  804. pub(crate) const MOCK_IP_ADDR_4: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 4]));
  805. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  806. pub(crate) const MOCK_UNSPECIFIED: IpAddress = IpAddress::Ipv4(Ipv4Address::UNSPECIFIED);
  807. use super::*;
  808. use crate::wire::{IpAddress, IpCidr, IpProtocol};
  809. #[cfg(feature = "proto-ipv4")]
  810. use crate::wire::{Ipv4Address, Ipv4Repr};
  811. #[test]
  812. fn endpoint_unspecified() {
  813. assert!(!Endpoint::UNSPECIFIED.is_specified());
  814. }
  815. #[test]
  816. #[cfg(feature = "proto-ipv4")]
  817. fn to_prefix_len_ipv4() {
  818. fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
  819. assert_eq!(Some(prefix_len), mask.into().prefix_len());
  820. }
  821. test_eq(0, Ipv4Address::new(0, 0, 0, 0));
  822. test_eq(1, Ipv4Address::new(128, 0, 0, 0));
  823. test_eq(2, Ipv4Address::new(192, 0, 0, 0));
  824. test_eq(3, Ipv4Address::new(224, 0, 0, 0));
  825. test_eq(4, Ipv4Address::new(240, 0, 0, 0));
  826. test_eq(5, Ipv4Address::new(248, 0, 0, 0));
  827. test_eq(6, Ipv4Address::new(252, 0, 0, 0));
  828. test_eq(7, Ipv4Address::new(254, 0, 0, 0));
  829. test_eq(8, Ipv4Address::new(255, 0, 0, 0));
  830. test_eq(9, Ipv4Address::new(255, 128, 0, 0));
  831. test_eq(10, Ipv4Address::new(255, 192, 0, 0));
  832. test_eq(11, Ipv4Address::new(255, 224, 0, 0));
  833. test_eq(12, Ipv4Address::new(255, 240, 0, 0));
  834. test_eq(13, Ipv4Address::new(255, 248, 0, 0));
  835. test_eq(14, Ipv4Address::new(255, 252, 0, 0));
  836. test_eq(15, Ipv4Address::new(255, 254, 0, 0));
  837. test_eq(16, Ipv4Address::new(255, 255, 0, 0));
  838. test_eq(17, Ipv4Address::new(255, 255, 128, 0));
  839. test_eq(18, Ipv4Address::new(255, 255, 192, 0));
  840. test_eq(19, Ipv4Address::new(255, 255, 224, 0));
  841. test_eq(20, Ipv4Address::new(255, 255, 240, 0));
  842. test_eq(21, Ipv4Address::new(255, 255, 248, 0));
  843. test_eq(22, Ipv4Address::new(255, 255, 252, 0));
  844. test_eq(23, Ipv4Address::new(255, 255, 254, 0));
  845. test_eq(24, Ipv4Address::new(255, 255, 255, 0));
  846. test_eq(25, Ipv4Address::new(255, 255, 255, 128));
  847. test_eq(26, Ipv4Address::new(255, 255, 255, 192));
  848. test_eq(27, Ipv4Address::new(255, 255, 255, 224));
  849. test_eq(28, Ipv4Address::new(255, 255, 255, 240));
  850. test_eq(29, Ipv4Address::new(255, 255, 255, 248));
  851. test_eq(30, Ipv4Address::new(255, 255, 255, 252));
  852. test_eq(31, Ipv4Address::new(255, 255, 255, 254));
  853. test_eq(32, Ipv4Address::new(255, 255, 255, 255));
  854. }
  855. #[cfg(feature = "proto-ipv4")]
  856. fn to_prefix_len_ipv4_error() {
  857. assert_eq!(
  858. None,
  859. IpAddress::from(Ipv4Address::new(255, 255, 255, 1)).prefix_len()
  860. );
  861. }
  862. #[test]
  863. #[cfg(feature = "proto-ipv6")]
  864. fn to_prefix_len_ipv6() {
  865. fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
  866. assert_eq!(Some(prefix_len), mask.into().prefix_len());
  867. }
  868. test_eq(0, Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 0));
  869. test_eq(
  870. 128,
  871. Ipv6Address::new(
  872. 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
  873. ),
  874. );
  875. }
  876. #[cfg(feature = "proto-ipv6")]
  877. fn to_prefix_len_ipv6_error() {
  878. assert_eq!(
  879. None,
  880. IpAddress::from(Ipv6Address::new(
  881. 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0, 1
  882. ))
  883. .prefix_len()
  884. );
  885. }
  886. }