ip.rs 43 KB

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