ip.rs 32 KB

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