ip.rs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. use core::fmt;
  2. use core::convert::From;
  3. use crate::{Error, Result};
  4. use crate::phy::ChecksumCapabilities;
  5. #[cfg(feature = "proto-ipv4")]
  6. use crate::wire::{Ipv4Address, Ipv4Packet, Ipv4Repr, Ipv4Cidr};
  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. 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. /// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
  173. /// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
  174. pub fn to_prefix_len(&self) -> Option<u8> {
  175. let mut ones = true;
  176. let mut prefix_len = 0;
  177. for byte in self.as_bytes() {
  178. let mut mask = 0x80;
  179. for _ in 0..8 {
  180. let one = *byte & mask != 0;
  181. if ones {
  182. // Expect 1s until first 0
  183. if one {
  184. prefix_len += 1;
  185. } else {
  186. ones = false;
  187. }
  188. } else if one {
  189. // 1 where 0 was expected
  190. return None
  191. }
  192. mask >>= 1;
  193. }
  194. }
  195. Some(prefix_len)
  196. }
  197. }
  198. #[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
  199. impl From<::std::net::IpAddr> for Address {
  200. fn from(x: ::std::net::IpAddr) -> Address {
  201. match x {
  202. ::std::net::IpAddr::V4(ipv4) => Address::Ipv4(ipv4.into()),
  203. ::std::net::IpAddr::V6(ipv6) => Address::Ipv6(ipv6.into()),
  204. }
  205. }
  206. }
  207. #[cfg(all(feature = "std", feature = "proto-ipv4"))]
  208. impl From<::std::net::Ipv4Addr> for Address {
  209. fn from(ipv4: ::std::net::Ipv4Addr) -> Address {
  210. Address::Ipv4(ipv4.into())
  211. }
  212. }
  213. #[cfg(all(feature = "std", feature = "proto-ipv6"))]
  214. impl From<::std::net::Ipv6Addr> for Address {
  215. fn from(ipv6: ::std::net::Ipv6Addr) -> Address {
  216. Address::Ipv6(ipv6.into())
  217. }
  218. }
  219. impl Default for Address {
  220. fn default() -> Address {
  221. Address::Unspecified
  222. }
  223. }
  224. #[cfg(feature = "proto-ipv4")]
  225. impl From<Ipv4Address> for Address {
  226. fn from(addr: Ipv4Address) -> Self {
  227. Address::Ipv4(addr)
  228. }
  229. }
  230. #[cfg(feature = "proto-ipv6")]
  231. impl From<Ipv6Address> for Address {
  232. fn from(addr: Ipv6Address) -> Self {
  233. Address::Ipv6(addr)
  234. }
  235. }
  236. impl fmt::Display for Address {
  237. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  238. match *self {
  239. Address::Unspecified => write!(f, "*"),
  240. #[cfg(feature = "proto-ipv4")]
  241. Address::Ipv4(addr) => write!(f, "{}", addr),
  242. #[cfg(feature = "proto-ipv6")]
  243. Address::Ipv6(addr) => write!(f, "{}", addr),
  244. Address::__Nonexhaustive => unreachable!()
  245. }
  246. }
  247. }
  248. /// A specification of a CIDR block, containing an address and a variable-length
  249. /// subnet masking prefix length.
  250. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
  251. pub enum Cidr {
  252. #[cfg(feature = "proto-ipv4")]
  253. Ipv4(Ipv4Cidr),
  254. #[cfg(feature = "proto-ipv6")]
  255. Ipv6(Ipv6Cidr),
  256. #[doc(hidden)]
  257. __Nonexhaustive,
  258. }
  259. impl Cidr {
  260. /// Create a CIDR block from the given address and prefix length.
  261. ///
  262. /// # Panics
  263. /// This function panics if the given address is unspecified, or
  264. /// the given prefix length is invalid for the given address.
  265. pub fn new(addr: Address, prefix_len: u8) -> Cidr {
  266. match addr {
  267. #[cfg(feature = "proto-ipv4")]
  268. Address::Ipv4(addr) => Cidr::Ipv4(Ipv4Cidr::new(addr, prefix_len)),
  269. #[cfg(feature = "proto-ipv6")]
  270. Address::Ipv6(addr) => Cidr::Ipv6(Ipv6Cidr::new(addr, prefix_len)),
  271. Address::Unspecified =>
  272. panic!("a CIDR block cannot be based on an unspecified address"),
  273. Address::__Nonexhaustive =>
  274. unreachable!()
  275. }
  276. }
  277. /// Return the IP address of this CIDR block.
  278. pub fn address(&self) -> Address {
  279. match *self {
  280. #[cfg(feature = "proto-ipv4")]
  281. Cidr::Ipv4(cidr) => Address::Ipv4(cidr.address()),
  282. #[cfg(feature = "proto-ipv6")]
  283. Cidr::Ipv6(cidr) => Address::Ipv6(cidr.address()),
  284. Cidr::__Nonexhaustive => unreachable!()
  285. }
  286. }
  287. /// Return the prefix length of this CIDR block.
  288. pub fn prefix_len(&self) -> u8 {
  289. match *self {
  290. #[cfg(feature = "proto-ipv4")]
  291. Cidr::Ipv4(cidr) => cidr.prefix_len(),
  292. #[cfg(feature = "proto-ipv6")]
  293. Cidr::Ipv6(cidr) => cidr.prefix_len(),
  294. Cidr::__Nonexhaustive => unreachable!()
  295. }
  296. }
  297. /// Query whether the subnetwork described by this CIDR block contains
  298. /// the given address.
  299. pub fn contains_addr(&self, addr: &Address) -> bool {
  300. match (self, addr) {
  301. #[cfg(feature = "proto-ipv4")]
  302. (&Cidr::Ipv4(ref cidr), &Address::Ipv4(ref addr)) =>
  303. cidr.contains_addr(addr),
  304. #[cfg(feature = "proto-ipv6")]
  305. (&Cidr::Ipv6(ref cidr), &Address::Ipv6(ref addr)) =>
  306. cidr.contains_addr(addr),
  307. #[cfg(all(feature = "proto-ipv6", feature = "proto-ipv4"))]
  308. (&Cidr::Ipv4(_), &Address::Ipv6(_)) | (&Cidr::Ipv6(_), &Address::Ipv4(_)) =>
  309. false,
  310. (_, &Address::Unspecified) =>
  311. // a fully unspecified address covers both IPv4 and IPv6,
  312. // and no CIDR block can do that.
  313. false,
  314. (&Cidr::__Nonexhaustive, _) |
  315. (_, &Address::__Nonexhaustive) =>
  316. unreachable!()
  317. }
  318. }
  319. /// Query whether the subnetwork described by this CIDR block contains
  320. /// the subnetwork described by the given CIDR block.
  321. pub fn contains_subnet(&self, subnet: &Cidr) -> bool {
  322. match (self, subnet) {
  323. #[cfg(feature = "proto-ipv4")]
  324. (&Cidr::Ipv4(ref cidr), &Cidr::Ipv4(ref other)) =>
  325. cidr.contains_subnet(other),
  326. #[cfg(feature = "proto-ipv6")]
  327. (&Cidr::Ipv6(ref cidr), &Cidr::Ipv6(ref other)) =>
  328. cidr.contains_subnet(other),
  329. #[cfg(all(feature = "proto-ipv6", feature = "proto-ipv4"))]
  330. (&Cidr::Ipv4(_), &Cidr::Ipv6(_)) | (&Cidr::Ipv6(_), &Cidr::Ipv4(_)) =>
  331. false,
  332. (&Cidr::__Nonexhaustive, _) |
  333. (_, &Cidr::__Nonexhaustive) =>
  334. unreachable!()
  335. }
  336. }
  337. }
  338. #[cfg(feature = "proto-ipv4")]
  339. impl From<Ipv4Cidr> for Cidr {
  340. fn from(addr: Ipv4Cidr) -> Self {
  341. Cidr::Ipv4(addr)
  342. }
  343. }
  344. #[cfg(feature = "proto-ipv6")]
  345. impl From<Ipv6Cidr> for Cidr {
  346. fn from(addr: Ipv6Cidr) -> Self {
  347. Cidr::Ipv6(addr)
  348. }
  349. }
  350. impl fmt::Display for Cidr {
  351. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  352. match *self {
  353. #[cfg(feature = "proto-ipv4")]
  354. Cidr::Ipv4(cidr) => write!(f, "{}", cidr),
  355. #[cfg(feature = "proto-ipv6")]
  356. Cidr::Ipv6(cidr) => write!(f, "{}", cidr),
  357. Cidr::__Nonexhaustive => unreachable!()
  358. }
  359. }
  360. }
  361. /// An internet endpoint address.
  362. ///
  363. /// An endpoint can be constructed from a port, in which case the address is unspecified.
  364. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
  365. pub struct Endpoint {
  366. pub addr: Address,
  367. pub port: u16
  368. }
  369. impl Endpoint {
  370. /// An endpoint with unspecified address and port.
  371. pub const UNSPECIFIED: Endpoint = Endpoint { addr: Address::Unspecified, port: 0 };
  372. /// Create an endpoint address from given address and port.
  373. pub fn new(addr: Address, port: u16) -> Endpoint {
  374. Endpoint { addr, port }
  375. }
  376. /// Query whether the endpoint has a specified address and port.
  377. pub fn is_specified(&self) -> bool {
  378. !self.addr.is_unspecified() && self.port != 0
  379. }
  380. }
  381. #[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
  382. impl From<::std::net::SocketAddr> for Endpoint {
  383. fn from(x: ::std::net::SocketAddr) -> Endpoint {
  384. Endpoint {
  385. addr: x.ip().into(),
  386. port: x.port(),
  387. }
  388. }
  389. }
  390. #[cfg(all(feature = "std", feature = "proto-ipv4"))]
  391. impl From<::std::net::SocketAddrV4> for Endpoint {
  392. fn from(x: ::std::net::SocketAddrV4) -> Endpoint {
  393. Endpoint {
  394. addr: x.ip().clone().into(),
  395. port: x.port(),
  396. }
  397. }
  398. }
  399. #[cfg(all(feature = "std", feature = "proto-ipv6"))]
  400. impl From<::std::net::SocketAddrV6> for Endpoint {
  401. fn from(x: ::std::net::SocketAddrV6) -> Endpoint {
  402. Endpoint {
  403. addr: x.ip().clone().into(),
  404. port: x.port(),
  405. }
  406. }
  407. }
  408. impl fmt::Display for Endpoint {
  409. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  410. write!(f, "{}:{}", self.addr, self.port)
  411. }
  412. }
  413. impl From<u16> for Endpoint {
  414. fn from(port: u16) -> Endpoint {
  415. Endpoint { addr: Address::Unspecified, port }
  416. }
  417. }
  418. impl<T: Into<Address>> From<(T, u16)> for Endpoint {
  419. fn from((addr, port): (T, u16)) -> Endpoint {
  420. Endpoint { addr: addr.into(), port }
  421. }
  422. }
  423. /// An IP packet representation.
  424. ///
  425. /// This enum abstracts the various versions of IP packets. It either contains a concrete
  426. /// high-level representation for some IP protocol version, or an unspecified representation,
  427. /// which permits the `IpAddress::Unspecified` addresses.
  428. #[derive(Debug, Clone, PartialEq, Eq)]
  429. pub enum Repr {
  430. Unspecified {
  431. src_addr: Address,
  432. dst_addr: Address,
  433. protocol: Protocol,
  434. payload_len: usize,
  435. hop_limit: u8
  436. },
  437. #[cfg(feature = "proto-ipv4")]
  438. Ipv4(Ipv4Repr),
  439. #[cfg(feature = "proto-ipv6")]
  440. Ipv6(Ipv6Repr),
  441. #[doc(hidden)]
  442. __Nonexhaustive
  443. }
  444. #[cfg(feature = "proto-ipv4")]
  445. impl From<Ipv4Repr> for Repr {
  446. fn from(repr: Ipv4Repr) -> Repr {
  447. Repr::Ipv4(repr)
  448. }
  449. }
  450. #[cfg(feature = "proto-ipv6")]
  451. impl From<Ipv6Repr> for Repr {
  452. fn from(repr: Ipv6Repr) -> Repr {
  453. Repr::Ipv6(repr)
  454. }
  455. }
  456. impl Repr {
  457. /// Return the protocol version.
  458. pub fn version(&self) -> Version {
  459. match *self {
  460. Repr::Unspecified { .. } => Version::Unspecified,
  461. #[cfg(feature = "proto-ipv4")]
  462. Repr::Ipv4(_) => Version::Ipv4,
  463. #[cfg(feature = "proto-ipv6")]
  464. Repr::Ipv6(_) => Version::Ipv6,
  465. Repr::__Nonexhaustive => unreachable!()
  466. }
  467. }
  468. /// Return the source address.
  469. pub fn src_addr(&self) -> Address {
  470. match *self {
  471. Repr::Unspecified { src_addr, .. } => src_addr,
  472. #[cfg(feature = "proto-ipv4")]
  473. Repr::Ipv4(repr) => Address::Ipv4(repr.src_addr),
  474. #[cfg(feature = "proto-ipv6")]
  475. Repr::Ipv6(repr) => Address::Ipv6(repr.src_addr),
  476. Repr::__Nonexhaustive => unreachable!()
  477. }
  478. }
  479. /// Return the destination address.
  480. pub fn dst_addr(&self) -> Address {
  481. match *self {
  482. Repr::Unspecified { dst_addr, .. } => dst_addr,
  483. #[cfg(feature = "proto-ipv4")]
  484. Repr::Ipv4(repr) => Address::Ipv4(repr.dst_addr),
  485. #[cfg(feature = "proto-ipv6")]
  486. Repr::Ipv6(repr) => Address::Ipv6(repr.dst_addr),
  487. Repr::__Nonexhaustive => unreachable!()
  488. }
  489. }
  490. /// Return the protocol.
  491. pub fn protocol(&self) -> Protocol {
  492. match *self {
  493. Repr::Unspecified { protocol, .. } => protocol,
  494. #[cfg(feature = "proto-ipv4")]
  495. Repr::Ipv4(repr) => repr.protocol,
  496. #[cfg(feature = "proto-ipv6")]
  497. Repr::Ipv6(repr) => repr.next_header,
  498. Repr::__Nonexhaustive => unreachable!()
  499. }
  500. }
  501. /// Return the payload length.
  502. pub fn payload_len(&self) -> usize {
  503. match *self {
  504. Repr::Unspecified { payload_len, .. } => payload_len,
  505. #[cfg(feature = "proto-ipv4")]
  506. Repr::Ipv4(repr) => repr.payload_len,
  507. #[cfg(feature = "proto-ipv6")]
  508. Repr::Ipv6(repr) => repr.payload_len,
  509. Repr::__Nonexhaustive => unreachable!()
  510. }
  511. }
  512. /// Set the payload length.
  513. pub fn set_payload_len(&mut self, length: usize) {
  514. match *self {
  515. Repr::Unspecified { ref mut payload_len, .. } =>
  516. *payload_len = length,
  517. #[cfg(feature = "proto-ipv4")]
  518. Repr::Ipv4(Ipv4Repr { ref mut payload_len, .. }) =>
  519. *payload_len = length,
  520. #[cfg(feature = "proto-ipv6")]
  521. Repr::Ipv6(Ipv6Repr { ref mut payload_len, .. }) =>
  522. *payload_len = length,
  523. Repr::__Nonexhaustive => unreachable!()
  524. }
  525. }
  526. /// Return the TTL value.
  527. pub fn hop_limit(&self) -> u8 {
  528. match *self {
  529. Repr::Unspecified { hop_limit, .. } => hop_limit,
  530. #[cfg(feature = "proto-ipv4")]
  531. Repr::Ipv4(Ipv4Repr { hop_limit, .. }) => hop_limit,
  532. #[cfg(feature = "proto-ipv6")]
  533. Repr::Ipv6(Ipv6Repr { hop_limit, ..}) => hop_limit,
  534. Repr::__Nonexhaustive => unreachable!()
  535. }
  536. }
  537. /// Convert an unspecified representation into a concrete one, or return
  538. /// `Err(Error::Unaddressable)` if not possible.
  539. ///
  540. /// # Panics
  541. /// This function panics if source and destination addresses belong to different families,
  542. /// or the destination address is unspecified, since this indicates a logic error.
  543. pub fn lower(&self, fallback_src_addrs: &[Cidr]) -> Result<Repr> {
  544. macro_rules! resolve_unspecified {
  545. ($reprty:path, $ipty:path, $iprepr:expr, $fallbacks:expr) => {
  546. if $iprepr.src_addr.is_unspecified() {
  547. for cidr in $fallbacks {
  548. match cidr.address() {
  549. $ipty(addr) => {
  550. $iprepr.src_addr = addr;
  551. return Ok($reprty($iprepr));
  552. },
  553. _ => ()
  554. }
  555. }
  556. Err(Error::Unaddressable)
  557. } else {
  558. Ok($reprty($iprepr))
  559. }
  560. }
  561. }
  562. match self {
  563. #[cfg(feature = "proto-ipv4")]
  564. &Repr::Unspecified {
  565. src_addr: src_addr @ Address::Unspecified,
  566. dst_addr: Address::Ipv4(dst_addr),
  567. protocol, payload_len, hop_limit
  568. } |
  569. &Repr::Unspecified {
  570. src_addr: src_addr @ Address::Ipv4(_),
  571. dst_addr: Address::Ipv4(dst_addr),
  572. protocol, payload_len, hop_limit
  573. } if src_addr.is_unspecified() => {
  574. let mut src_addr = if let Address::Ipv4(src_ipv4_addr) = src_addr {
  575. Some(src_ipv4_addr)
  576. } else {
  577. None
  578. };
  579. for cidr in fallback_src_addrs {
  580. if let Address::Ipv4(addr) = cidr.address() {
  581. src_addr = Some(addr);
  582. break;
  583. }
  584. }
  585. Ok(Repr::Ipv4(Ipv4Repr {
  586. src_addr: src_addr.ok_or(Error::Unaddressable)?,
  587. dst_addr, protocol, payload_len, hop_limit
  588. }))
  589. }
  590. #[cfg(feature = "proto-ipv6")]
  591. &Repr::Unspecified {
  592. src_addr: src_addr @ Address::Unspecified,
  593. dst_addr: Address::Ipv6(dst_addr),
  594. protocol, payload_len, hop_limit
  595. } |
  596. &Repr::Unspecified {
  597. src_addr: src_addr @ Address::Ipv6(_),
  598. dst_addr: Address::Ipv6(dst_addr),
  599. protocol, payload_len, hop_limit
  600. } if src_addr.is_unspecified() => {
  601. let mut src_addr = if let Address::Ipv6(src_ipv6_addr) = src_addr {
  602. Some(src_ipv6_addr)
  603. } else {
  604. None
  605. };
  606. for cidr in fallback_src_addrs {
  607. if let Address::Ipv6(addr) = cidr.address() {
  608. src_addr = Some(addr);
  609. break;
  610. }
  611. }
  612. Ok(Repr::Ipv6(Ipv6Repr {
  613. src_addr: src_addr.ok_or(Error::Unaddressable)?,
  614. next_header: protocol,
  615. dst_addr, payload_len, hop_limit
  616. }))
  617. }
  618. #[cfg(feature = "proto-ipv4")]
  619. &Repr::Unspecified {
  620. src_addr: Address::Ipv4(src_addr),
  621. dst_addr: Address::Ipv4(dst_addr),
  622. protocol, payload_len, hop_limit
  623. } => {
  624. Ok(Repr::Ipv4(Ipv4Repr {
  625. src_addr: src_addr,
  626. dst_addr: dst_addr,
  627. protocol: protocol,
  628. payload_len: payload_len, hop_limit
  629. }))
  630. }
  631. #[cfg(feature = "proto-ipv6")]
  632. &Repr::Unspecified {
  633. src_addr: Address::Ipv6(src_addr),
  634. dst_addr: Address::Ipv6(dst_addr),
  635. protocol, payload_len, hop_limit
  636. } => {
  637. Ok(Repr::Ipv6(Ipv6Repr {
  638. src_addr: src_addr,
  639. dst_addr: dst_addr,
  640. next_header: protocol,
  641. payload_len: payload_len,
  642. hop_limit: hop_limit
  643. }))
  644. }
  645. #[cfg(feature = "proto-ipv4")]
  646. &Repr::Ipv4(mut repr) =>
  647. resolve_unspecified!(Repr::Ipv4, Address::Ipv4, repr, fallback_src_addrs),
  648. #[cfg(feature = "proto-ipv6")]
  649. &Repr::Ipv6(mut repr) =>
  650. resolve_unspecified!(Repr::Ipv6, Address::Ipv6, repr, fallback_src_addrs),
  651. &Repr::Unspecified { .. } =>
  652. panic!("source and destination IP address families do not match"),
  653. &Repr::__Nonexhaustive => unreachable!()
  654. }
  655. }
  656. /// Return the length of a header that will be emitted from this high-level representation.
  657. ///
  658. /// # Panics
  659. /// This function panics if invoked on an unspecified representation.
  660. pub fn buffer_len(&self) -> usize {
  661. match *self {
  662. Repr::Unspecified { .. } =>
  663. panic!("unspecified IP representation"),
  664. #[cfg(feature = "proto-ipv4")]
  665. Repr::Ipv4(repr) =>
  666. repr.buffer_len(),
  667. #[cfg(feature = "proto-ipv6")]
  668. Repr::Ipv6(repr) =>
  669. repr.buffer_len(),
  670. Repr::__Nonexhaustive =>
  671. unreachable!()
  672. }
  673. }
  674. /// Emit this high-level representation into a buffer.
  675. ///
  676. /// # Panics
  677. /// This function panics if invoked on an unspecified representation.
  678. pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, buffer: T, _checksum_caps: &ChecksumCapabilities) {
  679. match *self {
  680. Repr::Unspecified { .. } =>
  681. panic!("unspecified IP representation"),
  682. #[cfg(feature = "proto-ipv4")]
  683. Repr::Ipv4(repr) =>
  684. repr.emit(&mut Ipv4Packet::new_unchecked(buffer), &_checksum_caps),
  685. #[cfg(feature = "proto-ipv6")]
  686. Repr::Ipv6(repr) =>
  687. repr.emit(&mut Ipv6Packet::new_unchecked(buffer)),
  688. Repr::__Nonexhaustive =>
  689. unreachable!()
  690. }
  691. }
  692. /// Return the total length of a packet that will be emitted from this
  693. /// high-level representation.
  694. ///
  695. /// This is the same as `repr.buffer_len() + repr.payload_len()`.
  696. ///
  697. /// # Panics
  698. /// This function panics if invoked on an unspecified representation.
  699. pub fn total_len(&self) -> usize {
  700. self.buffer_len() + self.payload_len()
  701. }
  702. }
  703. pub mod checksum {
  704. use byteorder::{ByteOrder, NetworkEndian};
  705. use super::*;
  706. fn propagate_carries(word: u32) -> u16 {
  707. let sum = (word >> 16) + (word & 0xffff);
  708. ((sum >> 16) as u16) + (sum as u16)
  709. }
  710. /// Compute an RFC 1071 compliant checksum (without the final complement).
  711. pub fn data(mut data: &[u8]) -> u16 {
  712. let mut accum = 0;
  713. // For each 32-byte chunk...
  714. const CHUNK_SIZE: usize = 32;
  715. while data.len() >= CHUNK_SIZE {
  716. let mut d = &data[..CHUNK_SIZE];
  717. // ... take by 2 bytes and sum them.
  718. while d.len() >= 2 {
  719. accum += NetworkEndian::read_u16(d) as u32;
  720. d = &d[2..];
  721. }
  722. data = &data[CHUNK_SIZE..];
  723. }
  724. // Sum the rest that does not fit the last 32-byte chunk,
  725. // taking by 2 bytes.
  726. while data.len() >= 2 {
  727. accum += NetworkEndian::read_u16(data) as u32;
  728. data = &data[2..];
  729. }
  730. // Add the last remaining odd byte, if any.
  731. if let Some(&value) = data.first() {
  732. accum += (value as u32) << 8;
  733. }
  734. propagate_carries(accum)
  735. }
  736. /// Combine several RFC 1071 compliant checksums.
  737. pub fn combine(checksums: &[u16]) -> u16 {
  738. let mut accum: u32 = 0;
  739. for &word in checksums {
  740. accum += word as u32;
  741. }
  742. propagate_carries(accum)
  743. }
  744. /// Compute an IP pseudo header checksum.
  745. pub fn pseudo_header(src_addr: &Address, dst_addr: &Address,
  746. protocol: Protocol, length: u32) -> u16 {
  747. match (src_addr, dst_addr) {
  748. #[cfg(feature = "proto-ipv4")]
  749. (&Address::Ipv4(src_addr), &Address::Ipv4(dst_addr)) => {
  750. let mut proto_len = [0u8; 4];
  751. proto_len[1] = protocol.into();
  752. NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
  753. combine(&[
  754. data(src_addr.as_bytes()),
  755. data(dst_addr.as_bytes()),
  756. data(&proto_len[..])
  757. ])
  758. },
  759. #[cfg(feature = "proto-ipv6")]
  760. (&Address::Ipv6(src_addr), &Address::Ipv6(dst_addr)) => {
  761. let mut proto_len = [0u8; 8];
  762. proto_len[7] = protocol.into();
  763. NetworkEndian::write_u32(&mut proto_len[0..4], length);
  764. combine(&[
  765. data(src_addr.as_bytes()),
  766. data(dst_addr.as_bytes()),
  767. data(&proto_len[..])
  768. ])
  769. }
  770. _ => panic!("Unexpected pseudo header addresses: {}, {}",
  771. src_addr, dst_addr)
  772. }
  773. }
  774. // We use this in pretty printer implementations.
  775. pub(crate) fn format_checksum(f: &mut fmt::Formatter, correct: bool) -> fmt::Result {
  776. if !correct {
  777. write!(f, " (checksum incorrect)")
  778. } else {
  779. Ok(())
  780. }
  781. }
  782. }
  783. use crate::wire::pretty_print::PrettyIndent;
  784. pub fn pretty_print_ip_payload<T: Into<Repr>>(f: &mut fmt::Formatter, indent: &mut PrettyIndent,
  785. ip_repr: T, payload: &[u8]) -> fmt::Result {
  786. #[cfg(feature = "proto-ipv4")]
  787. use crate::wire::Icmpv4Packet;
  788. #[cfg(feature = "proto-ipv4")]
  789. use super::pretty_print::PrettyPrint;
  790. use crate::wire::{TcpPacket, TcpRepr, UdpPacket, UdpRepr};
  791. use crate::wire::ip::checksum::format_checksum;
  792. let checksum_caps = ChecksumCapabilities::ignored();
  793. let repr = ip_repr.into();
  794. match repr.protocol() {
  795. #[cfg(feature = "proto-ipv4")]
  796. Protocol::Icmp => {
  797. indent.increase(f)?;
  798. Icmpv4Packet::<&[u8]>::pretty_print(&payload, f, indent)
  799. }
  800. Protocol::Udp => {
  801. indent.increase(f)?;
  802. match UdpPacket::<&[u8]>::new_checked(payload) {
  803. Err(err) => write!(f, "{}({})", indent, err),
  804. Ok(udp_packet) => {
  805. match UdpRepr::parse(&udp_packet, &repr.src_addr(),
  806. &repr.dst_addr(), &checksum_caps) {
  807. Err(err) => write!(f, "{}{} ({})", indent, udp_packet, err),
  808. Ok(udp_repr) => {
  809. write!(f, "{}{}", indent, udp_repr)?;
  810. let valid = udp_packet.verify_checksum(&repr.src_addr(),
  811. &repr.dst_addr());
  812. format_checksum(f, valid)
  813. }
  814. }
  815. }
  816. }
  817. }
  818. Protocol::Tcp => {
  819. indent.increase(f)?;
  820. match TcpPacket::<&[u8]>::new_checked(payload) {
  821. Err(err) => write!(f, "{}({})", indent, err),
  822. Ok(tcp_packet) => {
  823. match TcpRepr::parse(&tcp_packet, &repr.src_addr(),
  824. &repr.dst_addr(), &checksum_caps) {
  825. Err(err) => write!(f, "{}{} ({})", indent, tcp_packet, err),
  826. Ok(tcp_repr) => {
  827. write!(f, "{}{}", indent, tcp_repr)?;
  828. let valid = tcp_packet.verify_checksum(&repr.src_addr(),
  829. &repr.dst_addr());
  830. format_checksum(f, valid)
  831. }
  832. }
  833. }
  834. }
  835. }
  836. _ => Ok(())
  837. }
  838. }
  839. #[cfg(test)]
  840. pub(crate) mod test {
  841. #![allow(unused)]
  842. #[cfg(feature = "proto-ipv6")]
  843. pub(crate) const MOCK_IP_ADDR_1: IpAddress = IpAddress::Ipv6(Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0,
  844. 0, 0, 0, 0, 0, 0, 0, 1]));
  845. #[cfg(feature = "proto-ipv6")]
  846. pub(crate) const MOCK_IP_ADDR_2: IpAddress = IpAddress::Ipv6(Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0,
  847. 0, 0, 0, 0, 0, 0, 0, 2]));
  848. #[cfg(feature = "proto-ipv6")]
  849. pub(crate) const MOCK_IP_ADDR_3: IpAddress = IpAddress::Ipv6(Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0,
  850. 0, 0, 0, 0, 0, 0, 0, 3]));
  851. #[cfg(feature = "proto-ipv6")]
  852. pub(crate) const MOCK_IP_ADDR_4: IpAddress = IpAddress::Ipv6(Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0,
  853. 0, 0, 0, 0, 0, 0, 0, 4]));
  854. #[cfg(feature = "proto-ipv6")]
  855. pub(crate) const MOCK_UNSPECIFIED: IpAddress = IpAddress::Ipv6(Ipv6Address::UNSPECIFIED);
  856. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  857. pub(crate) const MOCK_IP_ADDR_1: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 1]));
  858. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  859. pub(crate) const MOCK_IP_ADDR_2: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 2]));
  860. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  861. pub(crate) const MOCK_IP_ADDR_3: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 3]));
  862. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  863. pub(crate) const MOCK_IP_ADDR_4: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 4]));
  864. #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
  865. pub(crate) const MOCK_UNSPECIFIED: IpAddress = IpAddress::Ipv4(Ipv4Address::UNSPECIFIED);
  866. use super::*;
  867. use crate::wire::{IpAddress, IpProtocol,IpCidr};
  868. #[cfg(feature = "proto-ipv4")]
  869. use crate::wire::{Ipv4Address, Ipv4Repr};
  870. macro_rules! generate_common_tests {
  871. ($name:ident, $repr:ident, $ip_repr:path, $ip_addr:path,
  872. $addr_from:path, $nxthdr:ident, $bytes_a:expr, $bytes_b:expr,
  873. $unspecified:expr) => {
  874. mod $name {
  875. use super::*;
  876. #[test]
  877. fn test_ip_repr_lower() {
  878. let ip_addr_a = $addr_from(&$bytes_a);
  879. let ip_addr_b = $addr_from(&$bytes_b);
  880. let proto = IpProtocol::Icmp;
  881. let payload_len = 10;
  882. assert_eq!(
  883. Repr::Unspecified{
  884. src_addr: $ip_addr(ip_addr_a),
  885. dst_addr: $ip_addr(ip_addr_b),
  886. protocol: proto,
  887. hop_limit: 0x2a,
  888. payload_len,
  889. }.lower(&[]),
  890. Ok($ip_repr($repr{
  891. src_addr: ip_addr_a,
  892. dst_addr: ip_addr_b,
  893. $nxthdr: proto,
  894. hop_limit: 0x2a,
  895. payload_len
  896. }))
  897. );
  898. assert_eq!(
  899. Repr::Unspecified{
  900. src_addr: IpAddress::Unspecified,
  901. dst_addr: $ip_addr(ip_addr_b),
  902. protocol: proto,
  903. hop_limit: 64,
  904. payload_len
  905. }.lower(&[]),
  906. Err(Error::Unaddressable)
  907. );
  908. assert_eq!(
  909. Repr::Unspecified{
  910. src_addr: IpAddress::Unspecified,
  911. dst_addr: $ip_addr(ip_addr_b),
  912. protocol: proto,
  913. hop_limit: 64,
  914. payload_len
  915. }.lower(&[IpCidr::new($ip_addr(ip_addr_a), 24)]),
  916. Ok($ip_repr($repr{
  917. src_addr: ip_addr_a,
  918. dst_addr: ip_addr_b,
  919. $nxthdr: proto,
  920. hop_limit: 64,
  921. payload_len
  922. }))
  923. );
  924. assert_eq!(
  925. Repr::Unspecified{
  926. src_addr: $ip_addr($unspecified),
  927. dst_addr: $ip_addr(ip_addr_b),
  928. protocol: proto,
  929. hop_limit: 64,
  930. payload_len
  931. }.lower(&[IpCidr::new($ip_addr(ip_addr_a), 24)]),
  932. Ok($ip_repr($repr{
  933. src_addr: ip_addr_a,
  934. dst_addr: ip_addr_b,
  935. $nxthdr: proto,
  936. hop_limit: 64,
  937. payload_len
  938. }))
  939. );
  940. assert_eq!(
  941. Repr::Unspecified{
  942. src_addr: $ip_addr($unspecified),
  943. dst_addr: $ip_addr(ip_addr_b),
  944. protocol: proto,
  945. hop_limit: 64,
  946. payload_len
  947. }.lower(&[]),
  948. Ok($ip_repr($repr{
  949. src_addr: $unspecified,
  950. dst_addr: ip_addr_b,
  951. $nxthdr: proto,
  952. hop_limit: 64,
  953. payload_len
  954. }))
  955. );
  956. assert_eq!(
  957. $ip_repr($repr{
  958. src_addr: ip_addr_a,
  959. dst_addr: ip_addr_b,
  960. $nxthdr: proto,
  961. hop_limit: 255,
  962. payload_len
  963. }).lower(&[]),
  964. Ok($ip_repr($repr{
  965. src_addr: ip_addr_a,
  966. dst_addr: ip_addr_b,
  967. $nxthdr: proto,
  968. hop_limit: 255,
  969. payload_len
  970. }))
  971. );
  972. assert_eq!(
  973. $ip_repr($repr{
  974. src_addr: $unspecified,
  975. dst_addr: ip_addr_b,
  976. $nxthdr: proto,
  977. hop_limit: 255,
  978. payload_len
  979. }).lower(&[]),
  980. Err(Error::Unaddressable)
  981. );
  982. assert_eq!(
  983. $ip_repr($repr{
  984. src_addr: $unspecified,
  985. dst_addr: ip_addr_b,
  986. $nxthdr: proto,
  987. hop_limit: 64,
  988. payload_len
  989. }).lower(&[IpCidr::new($ip_addr(ip_addr_a), 24)]),
  990. Ok($ip_repr($repr{
  991. src_addr: ip_addr_a,
  992. dst_addr: ip_addr_b,
  993. $nxthdr: proto,
  994. hop_limit: 64,
  995. payload_len
  996. }))
  997. );
  998. }
  999. }
  1000. };
  1001. (ipv4 $addr_bytes_a:expr, $addr_bytes_b:expr) => {
  1002. generate_common_tests!(ipv4, Ipv4Repr, Repr::Ipv4, IpAddress::Ipv4,
  1003. Ipv4Address::from_bytes, protocol, $addr_bytes_a,
  1004. $addr_bytes_b, Ipv4Address::UNSPECIFIED);
  1005. };
  1006. (ipv6 $addr_bytes_a:expr, $addr_bytes_b:expr) => {
  1007. generate_common_tests!(ipv6, Ipv6Repr, Repr::Ipv6, IpAddress::Ipv6,
  1008. Ipv6Address::from_bytes, next_header, $addr_bytes_a,
  1009. $addr_bytes_b, Ipv6Address::UNSPECIFIED);
  1010. }
  1011. }
  1012. #[cfg(feature = "proto-ipv4")]
  1013. generate_common_tests!(ipv4
  1014. [1, 2, 3, 4],
  1015. [5, 6, 7, 8]);
  1016. #[cfg(feature = "proto-ipv6")]
  1017. generate_common_tests!(ipv6
  1018. [0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  1019. [0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
  1020. #[test]
  1021. #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
  1022. #[should_panic(expected = "source and destination IP address families do not match")]
  1023. fn test_lower_between_families() {
  1024. Repr::Unspecified {
  1025. src_addr: Address::Ipv6(Ipv6Address::UNSPECIFIED),
  1026. dst_addr: Address::Ipv4(Ipv4Address::UNSPECIFIED),
  1027. protocol: IpProtocol::Icmpv6,
  1028. hop_limit: 0xff,
  1029. payload_len: 0
  1030. }.lower(&[]);
  1031. }
  1032. #[test]
  1033. fn endpoint_unspecified() {
  1034. assert!(!Endpoint::UNSPECIFIED.is_specified());
  1035. }
  1036. #[test]
  1037. #[cfg(feature = "proto-ipv4")]
  1038. fn to_prefix_len_ipv4() {
  1039. fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
  1040. assert_eq!(
  1041. Some(prefix_len),
  1042. mask.into().to_prefix_len()
  1043. );
  1044. }
  1045. test_eq(0, Ipv4Address::new(0, 0, 0, 0));
  1046. test_eq(1, Ipv4Address::new(128, 0, 0, 0));
  1047. test_eq(2, Ipv4Address::new(192, 0, 0, 0));
  1048. test_eq(3, Ipv4Address::new(224, 0, 0, 0));
  1049. test_eq(4, Ipv4Address::new(240, 0, 0, 0));
  1050. test_eq(5, Ipv4Address::new(248, 0, 0, 0));
  1051. test_eq(6, Ipv4Address::new(252, 0, 0, 0));
  1052. test_eq(7, Ipv4Address::new(254, 0, 0, 0));
  1053. test_eq(8, Ipv4Address::new(255, 0, 0, 0));
  1054. test_eq(9, Ipv4Address::new(255, 128, 0, 0));
  1055. test_eq(10, Ipv4Address::new(255, 192, 0, 0));
  1056. test_eq(11, Ipv4Address::new(255, 224, 0, 0));
  1057. test_eq(12, Ipv4Address::new(255, 240, 0, 0));
  1058. test_eq(13, Ipv4Address::new(255, 248, 0, 0));
  1059. test_eq(14, Ipv4Address::new(255, 252, 0, 0));
  1060. test_eq(15, Ipv4Address::new(255, 254, 0, 0));
  1061. test_eq(16, Ipv4Address::new(255, 255, 0, 0));
  1062. test_eq(17, Ipv4Address::new(255, 255, 128, 0));
  1063. test_eq(18, Ipv4Address::new(255, 255, 192, 0));
  1064. test_eq(19, Ipv4Address::new(255, 255, 224, 0));
  1065. test_eq(20, Ipv4Address::new(255, 255, 240, 0));
  1066. test_eq(21, Ipv4Address::new(255, 255, 248, 0));
  1067. test_eq(22, Ipv4Address::new(255, 255, 252, 0));
  1068. test_eq(23, Ipv4Address::new(255, 255, 254, 0));
  1069. test_eq(24, Ipv4Address::new(255, 255, 255, 0));
  1070. test_eq(25, Ipv4Address::new(255, 255, 255, 128));
  1071. test_eq(26, Ipv4Address::new(255, 255, 255, 192));
  1072. test_eq(27, Ipv4Address::new(255, 255, 255, 224));
  1073. test_eq(28, Ipv4Address::new(255, 255, 255, 240));
  1074. test_eq(29, Ipv4Address::new(255, 255, 255, 248));
  1075. test_eq(30, Ipv4Address::new(255, 255, 255, 252));
  1076. test_eq(31, Ipv4Address::new(255, 255, 255, 254));
  1077. test_eq(32, Ipv4Address::new(255, 255, 255, 255));
  1078. }
  1079. #[cfg(feature = "proto-ipv4")]
  1080. fn to_prefix_len_ipv4_error() {
  1081. assert_eq!(None, IpAddress::from(Ipv4Address::new(255,255,255,1)).to_prefix_len());
  1082. }
  1083. #[test]
  1084. #[cfg(feature = "proto-ipv6")]
  1085. fn to_prefix_len_ipv6() {
  1086. fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
  1087. assert_eq!(
  1088. Some(prefix_len),
  1089. mask.into().to_prefix_len()
  1090. );
  1091. }
  1092. test_eq(0, Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 0));
  1093. test_eq(128, Ipv6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff));
  1094. }
  1095. #[cfg(feature = "proto-ipv6")]
  1096. fn to_prefix_len_ipv6_error() {
  1097. assert_eq!(None, IpAddress::from(Ipv6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0, 1)).to_prefix_len());
  1098. }
  1099. }