ip.rs 38 KB

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