parsers.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. #![cfg_attr(not(all(feature = "proto-ipv6", feature = "proto-ipv4")), allow(dead_code))]
  2. use core::str::FromStr;
  3. use core::result;
  4. use wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint};
  5. #[cfg(feature = "proto-ipv4")]
  6. use wire::{Ipv4Address, Ipv4Cidr};
  7. #[cfg(feature = "proto-ipv6")]
  8. use wire::{Ipv6Address, Ipv6Cidr};
  9. type Result<T> = result::Result<T, ()>;
  10. struct Parser<'a> {
  11. data: &'a [u8],
  12. pos: usize
  13. }
  14. impl<'a> Parser<'a> {
  15. fn new(data: &'a str) -> Parser<'a> {
  16. Parser {
  17. data: data.as_bytes(),
  18. pos: 0
  19. }
  20. }
  21. fn lookahead_char(&self, ch: u8) -> bool {
  22. if self.pos < self.data.len() {
  23. self.data[self.pos] == ch
  24. } else {
  25. false
  26. }
  27. }
  28. fn advance(&mut self) -> Result<u8> {
  29. match self.data.get(self.pos) {
  30. Some(&chr) => {
  31. self.pos += 1;
  32. Ok(chr)
  33. }
  34. None => Err(())
  35. }
  36. }
  37. fn try<F, T>(&mut self, f: F) -> Option<T>
  38. where F: FnOnce(&mut Parser<'a>) -> Result<T> {
  39. let pos = self.pos;
  40. match f(self) {
  41. Ok(res) => Some(res),
  42. Err(()) => {
  43. self.pos = pos;
  44. None
  45. }
  46. }
  47. }
  48. fn accept_eof(&mut self) -> Result<()> {
  49. if self.data.len() == self.pos {
  50. Ok(())
  51. } else {
  52. Err(())
  53. }
  54. }
  55. fn until_eof<F, T>(&mut self, f: F) -> Result<T>
  56. where F: FnOnce(&mut Parser<'a>) -> Result<T> {
  57. let res = f(self)?;
  58. self.accept_eof()?;
  59. Ok(res)
  60. }
  61. fn accept_char(&mut self, chr: u8) -> Result<()> {
  62. if self.advance()? == chr {
  63. Ok(())
  64. } else {
  65. Err(())
  66. }
  67. }
  68. fn accept_str(&mut self, string: &[u8]) -> Result<()> {
  69. for byte in string.iter() {
  70. self.accept_char(*byte)?;
  71. }
  72. Ok(())
  73. }
  74. fn accept_digit(&mut self, hex: bool) -> Result<u8> {
  75. let digit = self.advance()?;
  76. if digit >= b'0' && digit <= b'9' {
  77. Ok(digit - b'0')
  78. } else if hex && digit >= b'a' && digit <= b'f' {
  79. Ok(digit - b'a' + 10)
  80. } else if hex && digit >= b'A' && digit <= b'F' {
  81. Ok(digit - b'A' + 10)
  82. } else {
  83. Err(())
  84. }
  85. }
  86. fn accept_number(&mut self, max_digits: usize, max_value: u32,
  87. hex: bool) -> Result<u32> {
  88. let mut value = self.accept_digit(hex)? as u32;
  89. for _ in 1..max_digits {
  90. match self.try(|p| p.accept_digit(hex)) {
  91. Some(digit) => {
  92. value *= if hex { 16 } else { 10 };
  93. value += digit as u32;
  94. }
  95. None => break
  96. }
  97. }
  98. if value < max_value {
  99. Ok(value)
  100. } else {
  101. Err(())
  102. }
  103. }
  104. fn accept_mac_joined_with(&mut self, separator: u8) -> Result<EthernetAddress> {
  105. let mut octets = [0u8; 6];
  106. for n in 0..6 {
  107. octets[n] = self.accept_number(2, 0x100, true)? as u8;
  108. if n != 5 {
  109. self.accept_char(separator)?;
  110. }
  111. }
  112. Ok(EthernetAddress(octets))
  113. }
  114. fn accept_mac(&mut self) -> Result<EthernetAddress> {
  115. if let Some(mac) = self.try(|p| p.accept_mac_joined_with(b'-')) {
  116. return Ok(mac)
  117. }
  118. if let Some(mac) = self.try(|p| p.accept_mac_joined_with(b':')) {
  119. return Ok(mac)
  120. }
  121. Err(())
  122. }
  123. #[cfg(feature = "proto-ipv6")]
  124. fn accept_ipv4_mapped_ipv6_part(&mut self, parts: &mut [u16], idx: &mut usize) -> Result<()> {
  125. let octets = self.accept_ipv4_octets()?;
  126. parts[*idx] = ((octets[0] as u16) << 8) | (octets[1] as u16);
  127. *idx += 1;
  128. parts[*idx] = ((octets[2] as u16) << 8) | (octets[3] as u16);
  129. *idx += 1;
  130. Ok(())
  131. }
  132. #[cfg(feature = "proto-ipv6")]
  133. fn accept_ipv6_part(&mut self, (head, tail): (&mut [u16; 8], &mut [u16; 6]),
  134. (head_idx, tail_idx): (&mut usize, &mut usize),
  135. mut use_tail: bool, is_cidr: bool) -> Result<()> {
  136. let double_colon = match self.try(|p| p.accept_str(b"::")) {
  137. Some(_) if !use_tail && *head_idx < 7 => {
  138. // Found a double colon. Start filling out the
  139. // tail and set the double colon flag in case
  140. // this is the last character we can parse.
  141. use_tail = true;
  142. true
  143. },
  144. Some(_) => {
  145. // This is a bad address. Only one double colon is
  146. // allowed and an address is only 128 bits.
  147. return Err(());
  148. }
  149. None => {
  150. if *head_idx != 0 || use_tail && *tail_idx != 0 {
  151. // If this is not the first number or the position following
  152. // a double colon, we expect there to be a single colon.
  153. self.accept_char(b':')?;
  154. }
  155. false
  156. }
  157. };
  158. match self.try(|p| p.accept_number(4, 0x10000, true)) {
  159. Some(part) if !use_tail && *head_idx < 8 => {
  160. // Valid u16 to be added to the address
  161. head[*head_idx] = part as u16;
  162. *head_idx += 1;
  163. if *head_idx == 6 && head[0..*head_idx] == [0, 0, 0, 0, 0, 0xffff] {
  164. self.try(|p| {
  165. p.accept_char(b':')?;
  166. p.accept_ipv4_mapped_ipv6_part(head, head_idx)
  167. });
  168. }
  169. Ok(())
  170. },
  171. Some(part) if *tail_idx < 6 => {
  172. // Valid u16 to be added to the address
  173. tail[*tail_idx] = part as u16;
  174. *tail_idx += 1;
  175. if *tail_idx == 1 && tail[0] == 0xffff
  176. && head[0..8] == [0, 0, 0, 0, 0, 0, 0, 0] {
  177. self.try(|p| {
  178. p.accept_char(b':')?;
  179. p.accept_ipv4_mapped_ipv6_part(tail, tail_idx)
  180. });
  181. }
  182. Ok(())
  183. },
  184. Some(_) => {
  185. // Tail or head section is too long
  186. Err(())
  187. }
  188. None if double_colon && (is_cidr || self.pos == self.data.len()) => {
  189. // The address ends with "::". E.g. 1234:: or ::
  190. Ok(())
  191. }
  192. None => {
  193. // Invalid address
  194. Err(())
  195. }
  196. }?;
  197. if *head_idx + *tail_idx > 8 {
  198. // The head and tail indexes add up to a bad address length.
  199. Err(())
  200. } else if !self.lookahead_char(b':') {
  201. if *head_idx < 8 && !use_tail {
  202. // There was no double colon found, and the head is too short
  203. return Err(());
  204. }
  205. Ok(())
  206. } else {
  207. // Continue recursing
  208. self.accept_ipv6_part((head, tail), (head_idx, tail_idx), use_tail, is_cidr)
  209. }
  210. }
  211. #[cfg(feature = "proto-ipv6")]
  212. fn accept_ipv6(&mut self, is_cidr: bool) -> Result<Ipv6Address> {
  213. // IPv6 addresses may contain a "::" to indicate a series of
  214. // 16 bit sections that evaluate to 0. E.g.
  215. //
  216. // fe80:0000:0000:0000:0000:0000:0000:0001
  217. //
  218. // May be written as
  219. //
  220. // fe80::1
  221. //
  222. // As a result, we need to find the first section of colon
  223. // delimited u16's before a possible "::", then the
  224. // possible second section after the "::", and finally
  225. // combine the second optional section to the end of the
  226. // final address.
  227. //
  228. // See https://tools.ietf.org/html/rfc4291#section-2.2
  229. // for details.
  230. let (mut addr, mut tail) = ([0u16; 8], [0u16; 6]);
  231. let (mut head_idx, mut tail_idx) = (0, 0);
  232. self.accept_ipv6_part((&mut addr, &mut tail), (&mut head_idx, &mut tail_idx), false, is_cidr)?;
  233. // We need to copy the tail portion (the portion following the "::") to the
  234. // end of the address.
  235. addr[8 - tail_idx..].copy_from_slice(&tail[..tail_idx]);
  236. Ok(Ipv6Address::from_parts(&addr))
  237. }
  238. fn accept_ipv4_octets(&mut self) -> Result<[u8; 4]> {
  239. let mut octets = [0u8; 4];
  240. for n in 0..4 {
  241. octets[n] = self.accept_number(3, 0x100, false)? as u8;
  242. if n != 3 {
  243. self.accept_char(b'.')?;
  244. }
  245. }
  246. Ok(octets)
  247. }
  248. #[cfg(feature = "proto-ipv4")]
  249. fn accept_ipv4(&mut self) -> Result<Ipv4Address> {
  250. let octets = self.accept_ipv4_octets()?;
  251. Ok(Ipv4Address(octets))
  252. }
  253. fn accept_ip(&mut self) -> Result<IpAddress> {
  254. #[cfg(feature = "proto-ipv4")]
  255. match self.try(|p| p.accept_ipv4()) {
  256. Some(ipv4) => return Ok(IpAddress::Ipv4(ipv4)),
  257. None => ()
  258. }
  259. #[cfg(feature = "proto-ipv6")]
  260. match self.try(|p| p.accept_ipv6(false)) {
  261. Some(ipv6) => return Ok(IpAddress::Ipv6(ipv6)),
  262. None => ()
  263. }
  264. Err(())
  265. }
  266. #[cfg(feature = "proto-ipv4")]
  267. fn accept_ipv4_endpoint(&mut self) -> Result<IpEndpoint> {
  268. let ip = self.accept_ipv4()?;
  269. let port = if self.accept_eof().is_ok() {
  270. 0
  271. } else {
  272. self.accept_char(b':')?;
  273. self.accept_number(5, 65535, false)?
  274. };
  275. Ok(IpEndpoint { addr: IpAddress::Ipv4(ip), port: port as u16 })
  276. }
  277. #[cfg(feature = "proto-ipv6")]
  278. fn accept_ipv6_endpoint(&mut self) -> Result<IpEndpoint> {
  279. if self.lookahead_char(b'[') {
  280. self.accept_char(b'[')?;
  281. let ip = self.accept_ipv6(false)?;
  282. self.accept_char(b']')?;
  283. self.accept_char(b':')?;
  284. let port = self.accept_number(5, 65535, false)?;
  285. Ok(IpEndpoint { addr: IpAddress::Ipv6(ip), port: port as u16 })
  286. } else {
  287. let ip = self.accept_ipv6(false)?;
  288. Ok(IpEndpoint { addr: IpAddress::Ipv6(ip), port: 0 })
  289. }
  290. }
  291. fn accept_ip_endpoint(&mut self) -> Result<IpEndpoint> {
  292. #[cfg(feature = "proto-ipv4")]
  293. match self.try(|p| p.accept_ipv4_endpoint()) {
  294. Some(ipv4) => return Ok(ipv4),
  295. None => ()
  296. }
  297. #[cfg(feature = "proto-ipv6")]
  298. match self.try(|p| p.accept_ipv6_endpoint()) {
  299. Some(ipv6) => return Ok(ipv6),
  300. None => ()
  301. }
  302. Err(())
  303. }
  304. }
  305. impl FromStr for EthernetAddress {
  306. type Err = ();
  307. /// Parse a string representation of an Ethernet address.
  308. fn from_str(s: &str) -> Result<EthernetAddress> {
  309. Parser::new(s).until_eof(|p| p.accept_mac())
  310. }
  311. }
  312. #[cfg(feature = "proto-ipv4")]
  313. impl FromStr for Ipv4Address {
  314. type Err = ();
  315. /// Parse a string representation of an IPv4 address.
  316. fn from_str(s: &str) -> Result<Ipv4Address> {
  317. Parser::new(s).until_eof(|p| p.accept_ipv4())
  318. }
  319. }
  320. #[cfg(feature = "proto-ipv6")]
  321. impl FromStr for Ipv6Address {
  322. type Err = ();
  323. /// Parse a string representation of an IPv6 address.
  324. fn from_str(s: &str) -> Result<Ipv6Address> {
  325. Parser::new(s).until_eof(|p| p.accept_ipv6(false))
  326. }
  327. }
  328. impl FromStr for IpAddress {
  329. type Err = ();
  330. /// Parse a string representation of an IP address.
  331. fn from_str(s: &str) -> Result<IpAddress> {
  332. Parser::new(s).until_eof(|p| p.accept_ip())
  333. }
  334. }
  335. #[cfg(feature = "proto-ipv4")]
  336. impl FromStr for Ipv4Cidr {
  337. type Err = ();
  338. /// Parse a string representation of an IPv4 CIDR.
  339. fn from_str(s: &str) -> Result<Ipv4Cidr> {
  340. Parser::new(s).until_eof(|p| {
  341. let ip = p.accept_ipv4()?;
  342. p.accept_char(b'/')?;
  343. let prefix_len = p.accept_number(2, 33, false)? as u8;
  344. Ok(Ipv4Cidr::new(ip, prefix_len))
  345. })
  346. }
  347. }
  348. #[cfg(feature = "proto-ipv6")]
  349. impl FromStr for Ipv6Cidr {
  350. type Err = ();
  351. /// Parse a string representation of an IPv6 CIDR.
  352. fn from_str(s: &str) -> Result<Ipv6Cidr> {
  353. // https://tools.ietf.org/html/rfc4291#section-2.3
  354. Parser::new(s).until_eof(|p| {
  355. let ip = p.accept_ipv6(true)?;
  356. p.accept_char(b'/')?;
  357. let prefix_len = p.accept_number(3, 129, false)? as u8;
  358. Ok(Ipv6Cidr::new(ip, prefix_len))
  359. })
  360. }
  361. }
  362. impl FromStr for IpCidr {
  363. type Err = ();
  364. /// Parse a string representation of an IP CIDR.
  365. fn from_str(s: &str) -> Result<IpCidr> {
  366. #[cfg(feature = "proto-ipv4")]
  367. match Ipv4Cidr::from_str(s) {
  368. Ok(cidr) => return Ok(IpCidr::Ipv4(cidr)),
  369. Err(_) => ()
  370. }
  371. #[cfg(feature = "proto-ipv6")]
  372. match Ipv6Cidr::from_str(s) {
  373. Ok(cidr) => return Ok(IpCidr::Ipv6(cidr)),
  374. Err(_) => ()
  375. }
  376. Err(())
  377. }
  378. }
  379. impl FromStr for IpEndpoint {
  380. type Err = ();
  381. fn from_str(s: &str) -> Result<IpEndpoint> {
  382. Parser::new(s).until_eof(|p| Ok(p.accept_ip_endpoint()?))
  383. }
  384. }
  385. #[cfg(test)]
  386. mod test {
  387. use super::*;
  388. macro_rules! check_cidr_test_array {
  389. ($tests:expr, $from_str:path, $variant:path) => {
  390. for &(s, cidr) in &$tests {
  391. assert_eq!($from_str(s), cidr);
  392. assert_eq!(IpCidr::from_str(s), cidr.map($variant));
  393. if let Ok(cidr) = cidr {
  394. assert_eq!($from_str(&format!("{}", cidr)), Ok(cidr));
  395. assert_eq!(IpCidr::from_str(&format!("{}", cidr)),
  396. Ok($variant(cidr)));
  397. }
  398. }
  399. }
  400. }
  401. #[test]
  402. #[cfg(feature = "proto-ipv4")]
  403. fn test_mac() {
  404. assert_eq!(EthernetAddress::from_str(""), Err(()));
  405. assert_eq!(EthernetAddress::from_str("02:00:00:00:00:00"),
  406. Ok(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x00])));
  407. assert_eq!(EthernetAddress::from_str("01:23:45:67:89:ab"),
  408. Ok(EthernetAddress([0x01, 0x23, 0x45, 0x67, 0x89, 0xab])));
  409. assert_eq!(EthernetAddress::from_str("cd:ef:10:00:00:00"),
  410. Ok(EthernetAddress([0xcd, 0xef, 0x10, 0x00, 0x00, 0x00])));
  411. assert_eq!(EthernetAddress::from_str("00:00:00:ab:cd:ef"),
  412. Ok(EthernetAddress([0x00, 0x00, 0x00, 0xab, 0xcd, 0xef])));
  413. assert_eq!(EthernetAddress::from_str("00-00-00-ab-cd-ef"),
  414. Ok(EthernetAddress([0x00, 0x00, 0x00, 0xab, 0xcd, 0xef])));
  415. assert_eq!(EthernetAddress::from_str("AB-CD-EF-00-00-00"),
  416. Ok(EthernetAddress([0xab, 0xcd, 0xef, 0x00, 0x00, 0x00])));
  417. assert_eq!(EthernetAddress::from_str("100:00:00:00:00:00"), Err(()));
  418. assert_eq!(EthernetAddress::from_str("002:00:00:00:00:00"), Err(()));
  419. assert_eq!(EthernetAddress::from_str("02:00:00:00:00:000"), Err(()));
  420. assert_eq!(EthernetAddress::from_str("02:00:00:00:00:0x"), Err(()));
  421. }
  422. #[test]
  423. #[cfg(feature = "proto-ipv4")]
  424. fn test_ipv4() {
  425. assert_eq!(Ipv4Address::from_str(""), Err(()));
  426. assert_eq!(Ipv4Address::from_str("1.2.3.4"),
  427. Ok(Ipv4Address([1, 2, 3, 4])));
  428. assert_eq!(Ipv4Address::from_str("001.2.3.4"),
  429. Ok(Ipv4Address([1, 2, 3, 4])));
  430. assert_eq!(Ipv4Address::from_str("0001.2.3.4"), Err(()));
  431. assert_eq!(Ipv4Address::from_str("999.2.3.4"), Err(()));
  432. assert_eq!(Ipv4Address::from_str("1.2.3.4.5"), Err(()));
  433. assert_eq!(Ipv4Address::from_str("1.2.3"), Err(()));
  434. assert_eq!(Ipv4Address::from_str("1.2.3."), Err(()));
  435. assert_eq!(Ipv4Address::from_str("1.2.3.4."), Err(()));
  436. }
  437. #[test]
  438. #[cfg(feature = "proto-ipv6")]
  439. fn test_ipv6() {
  440. // Obviously not valid
  441. assert_eq!(Ipv6Address::from_str(""), Err(()));
  442. assert_eq!(Ipv6Address::from_str("fe80:0:0:0:0:0:0:1"),
  443. Ok(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1)));
  444. assert_eq!(Ipv6Address::from_str("::1"),
  445. Ok(Ipv6Address::LOOPBACK));
  446. assert_eq!(Ipv6Address::from_str("::"),
  447. Ok(Ipv6Address::UNSPECIFIED));
  448. assert_eq!(Ipv6Address::from_str("fe80::1"),
  449. Ok(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1)));
  450. assert_eq!(Ipv6Address::from_str("1234:5678::"),
  451. Ok(Ipv6Address::new(0x1234, 0x5678, 0, 0, 0, 0, 0, 0)));
  452. assert_eq!(Ipv6Address::from_str("1234:5678::8765:4321"),
  453. Ok(Ipv6Address::new(0x1234, 0x5678, 0, 0, 0, 0, 0x8765, 0x4321)));
  454. // Two double colons in address
  455. assert_eq!(Ipv6Address::from_str("1234:5678::1::1"),
  456. Err(()));
  457. assert_eq!(Ipv6Address::from_str("4444:333:22:1::4"),
  458. Ok(Ipv6Address::new(0x4444, 0x0333, 0x0022, 0x0001, 0, 0, 0, 4)));
  459. assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1::"),
  460. Ok(Ipv6Address::new(1, 1, 1, 1, 1, 1, 0, 0)));
  461. assert_eq!(Ipv6Address::from_str("::1:1:1:1:1:1"),
  462. Ok(Ipv6Address::new(0, 0, 1, 1, 1, 1, 1, 1)));
  463. assert_eq!(Ipv6Address::from_str("::1:1:1:1:1:1:1"),
  464. Err(()));
  465. // Double colon appears too late indicating an address that is too long
  466. assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1:1::"),
  467. Err(()));
  468. // Section after double colon is too long for a valid address
  469. assert_eq!(Ipv6Address::from_str("::1:1:1:1:1:1:1"),
  470. Err(()));
  471. // Obviously too long
  472. assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1:1:1:1"),
  473. Err(()));
  474. // Address is too short
  475. assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1:1"),
  476. Err(()));
  477. // Long number
  478. assert_eq!(Ipv6Address::from_str("::000001"),
  479. Err(()));
  480. // IPv4-Mapped address
  481. assert_eq!(Ipv6Address::from_str("::ffff:192.168.1.1"),
  482. Ok(Ipv6Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1])));
  483. assert_eq!(Ipv6Address::from_str("0:0:0:0:0:ffff:192.168.1.1"),
  484. Ok(Ipv6Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1])));
  485. assert_eq!(Ipv6Address::from_str("0::ffff:192.168.1.1"),
  486. Ok(Ipv6Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1])));
  487. // Only ffff is allowed in position 6 when IPv4 mapped
  488. assert_eq!(Ipv6Address::from_str("0:0:0:0:0:eeee:192.168.1.1"),
  489. Err(()));
  490. // Positions 1-5 must be 0 when IPv4 mapped
  491. assert_eq!(Ipv6Address::from_str("0:0:0:0:1:ffff:192.168.1.1"),
  492. Err(()));
  493. assert_eq!(Ipv6Address::from_str("1::ffff:192.168.1.1"),
  494. Err(()));
  495. // Out of range ipv4 octet
  496. assert_eq!(Ipv6Address::from_str("0:0:0:0:0:ffff:256.168.1.1"),
  497. Err(()));
  498. // Invalid hex in ipv4 octet
  499. assert_eq!(Ipv6Address::from_str("0:0:0:0:0:ffff:c0.168.1.1"),
  500. Err(()));
  501. }
  502. #[test]
  503. #[cfg(feature = "proto-ipv4")]
  504. fn test_ip_ipv4() {
  505. assert_eq!(IpAddress::from_str(""), Err(()));
  506. assert_eq!(IpAddress::from_str("1.2.3.4"),
  507. Ok(IpAddress::Ipv4(Ipv4Address([1, 2, 3, 4]))));
  508. assert_eq!(IpAddress::from_str("x"), Err(()));
  509. }
  510. #[test]
  511. #[cfg(feature = "proto-ipv6")]
  512. fn test_ip_ipv6() {
  513. assert_eq!(IpAddress::from_str(""), Err(()));
  514. assert_eq!(IpAddress::from_str("fe80::1"),
  515. Ok(IpAddress::Ipv6(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1))));
  516. assert_eq!(IpAddress::from_str("x"), Err(()));
  517. }
  518. #[test]
  519. #[cfg(feature = "proto-ipv4")]
  520. fn test_cidr_ipv4() {
  521. let tests = [
  522. ("127.0.0.1/8",
  523. Ok(Ipv4Cidr::new(Ipv4Address([127, 0, 0, 1]), 8u8))),
  524. ("192.168.1.1/24",
  525. Ok(Ipv4Cidr::new(Ipv4Address([192, 168, 1, 1]), 24u8))),
  526. ("8.8.8.8/32",
  527. Ok(Ipv4Cidr::new(Ipv4Address([8, 8, 8, 8]), 32u8))),
  528. ("8.8.8.8/0",
  529. Ok(Ipv4Cidr::new(Ipv4Address([8, 8, 8, 8]), 0u8))),
  530. ("", Err(())),
  531. ("1", Err(())),
  532. ("127.0.0.1", Err(())),
  533. ("127.0.0.1/", Err(())),
  534. ("127.0.0.1/33", Err(())),
  535. ("127.0.0.1/111", Err(())),
  536. ("/32", Err(())),
  537. ];
  538. check_cidr_test_array!(tests, Ipv4Cidr::from_str, IpCidr::Ipv4);
  539. }
  540. #[test]
  541. #[cfg(feature = "proto-ipv6")]
  542. fn test_cidr_ipv6() {
  543. let tests = [
  544. ("fe80::1/64",
  545. Ok(Ipv6Cidr::new(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64u8))),
  546. ("fe80::/64",
  547. Ok(Ipv6Cidr::new(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0), 64u8))),
  548. ("::1/128",
  549. Ok(Ipv6Cidr::new(Ipv6Address::LOOPBACK, 128u8))),
  550. ("::/128",
  551. Ok(Ipv6Cidr::new(Ipv6Address::UNSPECIFIED, 128u8))),
  552. ("fe80:0:0:0:0:0:0:1/64",
  553. Ok(Ipv6Cidr::new(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64u8))),
  554. ("fe80:0:0:0:0:0:0:1|64",
  555. Err(())),
  556. ("fe80::|64",
  557. Err(())),
  558. ("fe80::1::/64",
  559. Err(()))
  560. ];
  561. check_cidr_test_array!(tests, Ipv6Cidr::from_str, IpCidr::Ipv6);
  562. }
  563. #[test]
  564. #[cfg(feature = "proto-ipv4")]
  565. fn test_endpoint_ipv4() {
  566. assert_eq!(IpEndpoint::from_str(""), Err(()));
  567. assert_eq!(IpEndpoint::from_str("x"), Err(()));
  568. assert_eq!(
  569. IpEndpoint::from_str("127.0.0.1"),
  570. Ok(IpEndpoint { addr: IpAddress::v4(127, 0, 0, 1), port: 0 })
  571. );
  572. assert_eq!(
  573. IpEndpoint::from_str("127.0.0.1:12345"),
  574. Ok(IpEndpoint { addr: IpAddress::v4(127, 0, 0, 1), port: 12345 })
  575. );
  576. }
  577. #[test]
  578. #[cfg(feature = "proto-ipv6")]
  579. fn test_endpoint_ipv6() {
  580. assert_eq!(IpEndpoint::from_str(""), Err(()));
  581. assert_eq!(IpEndpoint::from_str("x"), Err(()));
  582. assert_eq!(
  583. IpEndpoint::from_str("fe80::1"),
  584. Ok(IpEndpoint { addr: IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), port: 0 })
  585. );
  586. assert_eq!(
  587. IpEndpoint::from_str("[fe80::1]:12345"),
  588. Ok(IpEndpoint { addr: IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), port: 12345 })
  589. );
  590. }
  591. }