ip.rs 30 KB

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