1#[cfg(feature = "std")]
16use core::fmt::Write;
17
18use crate::Error;
19
20#[cfg(feature = "alloc")]
21use alloc::string::String;
22
23const VALID_IP_BY_CONSTRUCTION: &str = "IP address is a valid string by construction";
24
25#[cfg(feature = "alloc")]
27#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
28#[derive(Clone, Debug, Eq, PartialEq, Hash)]
29pub enum IpAddr {
30 V4(String, [u8; 4]),
32 V6(String, [u8; 16]),
34}
35
36#[cfg(feature = "alloc")]
37#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
38impl AsRef<str> for IpAddr {
39 fn as_ref(&self) -> &str {
40 match self {
41 IpAddr::V4(ip_address, _) | IpAddr::V6(ip_address, _) => ip_address.as_str(),
42 }
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum IpAddrRef<'a> {
49 V4(&'a [u8], [u8; 4]),
51 V6(&'a [u8], [u8; 16]),
53}
54
55#[cfg(feature = "alloc")]
56#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
57impl<'a> From<IpAddrRef<'a>> for IpAddr {
58 fn from(ip_address: IpAddrRef<'a>) -> IpAddr {
59 match ip_address {
60 IpAddrRef::V4(ip_address, ip_address_octets) => IpAddr::V4(
61 String::from_utf8(ip_address.to_vec()).expect(VALID_IP_BY_CONSTRUCTION),
62 ip_address_octets,
63 ),
64 IpAddrRef::V6(ip_address, ip_address_octets) => IpAddr::V6(
65 String::from_utf8(ip_address.to_vec()).expect(VALID_IP_BY_CONSTRUCTION),
66 ip_address_octets,
67 ),
68 }
69 }
70}
71
72#[cfg(feature = "alloc")]
73#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
74impl<'a> From<&'a IpAddr> for IpAddrRef<'a> {
75 fn from(ip_address: &'a IpAddr) -> IpAddrRef<'a> {
76 match ip_address {
77 IpAddr::V4(ip_address, ip_address_octets) => {
78 IpAddrRef::V4(ip_address.as_bytes(), *ip_address_octets)
79 }
80 IpAddr::V6(ip_address, ip_address_octets) => {
81 IpAddrRef::V6(ip_address.as_bytes(), *ip_address_octets)
82 }
83 }
84 }
85}
86
87#[derive(Clone, Copy, Debug, Eq, PartialEq)]
90pub struct AddrParseError;
91
92impl core::fmt::Display for AddrParseError {
93 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
94 write!(f, "{:?}", self)
95 }
96}
97
98#[cfg(feature = "std")]
99#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
100impl ::std::error::Error for AddrParseError {}
101
102impl<'a> IpAddrRef<'a> {
103 pub fn try_from_ascii(ip_address: &'a [u8]) -> Result<Self, AddrParseError> {
106 if let Ok(ip_address) = parse_ipv4_address(ip_address) {
107 Ok(ip_address)
108 } else if let Ok(ip_address) = parse_ipv6_address(ip_address) {
109 Ok(ip_address)
110 } else {
111 Err(AddrParseError)
112 }
113 }
114
115 pub fn try_from_ascii_str(ip_address: &'a str) -> Result<Self, AddrParseError> {
118 Self::try_from_ascii(ip_address.as_bytes())
119 }
120
121 #[cfg(feature = "alloc")]
123 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
124 pub fn to_owned(&self) -> IpAddr {
125 match self {
126 IpAddrRef::V4(ip_address, ip_address_octets) => IpAddr::V4(
127 String::from_utf8(ip_address.to_vec()).expect(VALID_IP_BY_CONSTRUCTION),
128 *ip_address_octets,
129 ),
130 IpAddrRef::V6(ip_address, ip_address_octets) => IpAddr::V6(
131 String::from_utf8(ip_address.to_vec()).expect(VALID_IP_BY_CONSTRUCTION),
132 *ip_address_octets,
133 ),
134 }
135 }
136}
137
138#[cfg(feature = "std")]
139fn ipv6_to_uncompressed_string(octets: [u8; 16]) -> String {
140 let mut result = String::with_capacity(39);
141 for i in 0..7 {
142 result
143 .write_fmt(format_args!(
144 "{:02x?}{:02x?}:",
145 octets[i * 2],
146 octets[(i * 2) + 1]
147 ))
148 .expect("unexpected error while formatting IPv6 address");
149 }
150 result
151 .write_fmt(format_args!("{:02x?}{:02x?}", octets[14], octets[15]))
152 .expect("unexpected error while formatting IPv6 address");
153
154 result
155}
156
157#[cfg(feature = "std")]
158#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
159impl From<std::net::IpAddr> for IpAddr {
160 fn from(ip_address: std::net::IpAddr) -> IpAddr {
161 match ip_address {
162 std::net::IpAddr::V4(ip_address) => {
163 IpAddr::V4(ip_address.to_string(), ip_address.octets())
164 }
165 std::net::IpAddr::V6(ip_address) => IpAddr::V6(
166 ipv6_to_uncompressed_string(ip_address.octets()),
174 ip_address.octets(),
175 ),
176 }
177 }
178}
179
180impl<'a> From<IpAddrRef<'a>> for &'a str {
181 fn from(ip_address: IpAddrRef<'a>) -> &'a str {
182 match ip_address {
183 IpAddrRef::V4(ip_address, _) | IpAddrRef::V6(ip_address, _) => {
184 core::str::from_utf8(ip_address).expect(VALID_IP_BY_CONSTRUCTION)
185 }
186 }
187 }
188}
189
190impl<'a> From<IpAddrRef<'a>> for &'a [u8] {
191 fn from(ip_address: IpAddrRef<'a>) -> &'a [u8] {
192 match ip_address {
193 IpAddrRef::V4(ip_address, _) | IpAddrRef::V6(ip_address, _) => ip_address,
194 }
195 }
196}
197
198pub(super) fn presented_id_matches_reference_id(
207 presented_id: untrusted::Input,
208 reference_id: untrusted::Input,
209) -> bool {
210 match (presented_id.len(), reference_id.len()) {
211 (4, 4) => (),
212 (16, 16) => (),
213 _ => {
214 return false;
215 }
216 };
217
218 let mut presented_ip_address = untrusted::Reader::new(presented_id);
219 let mut reference_ip_address = untrusted::Reader::new(reference_id);
220 while !presented_ip_address.at_end() {
221 let presented_ip_address_byte = presented_ip_address.read_byte().unwrap();
222 let reference_ip_address_byte = reference_ip_address.read_byte().unwrap();
223 if presented_ip_address_byte != reference_ip_address_byte {
224 return false;
225 }
226 }
227
228 true
229}
230
231pub(super) fn presented_id_matches_constraint(
241 name: untrusted::Input,
242 constraint: untrusted::Input,
243) -> Result<bool, Error> {
244 match (name.len(), constraint.len()) {
245 (4, 8) => (),
246 (16, 32) => (),
247
248 (4, 32) | (16, 8) => {
250 return Ok(false);
251 }
252
253 (4, _) | (16, _) => {
255 return Err(Error::InvalidNetworkMaskConstraint);
256 }
257
258 _ => {
260 return Err(Error::BadDer);
261 }
262 };
263
264 let (constraint_address, constraint_mask) = constraint.read_all(Error::BadDer, |value| {
265 let address = value.read_bytes(constraint.len() / 2).unwrap();
266 let mask = value.read_bytes(constraint.len() / 2).unwrap();
267 Ok((address, mask))
268 })?;
269
270 let mut name = untrusted::Reader::new(name);
271 let mut constraint_address = untrusted::Reader::new(constraint_address);
272 let mut constraint_mask = untrusted::Reader::new(constraint_mask);
273 let mut seen_zero_bit = false;
274
275 loop {
276 let name_byte = name.read_byte().unwrap();
279 let constraint_address_byte = constraint_address.read_byte().unwrap();
280 let constraint_mask_byte = constraint_mask.read_byte().unwrap();
281
282 let leading = constraint_mask_byte.leading_ones();
286 let trailing = constraint_mask_byte.trailing_zeros();
287
288 if leading + trailing != 8 {
292 return Err(Error::InvalidNetworkMaskConstraint);
293 }
294
295 if seen_zero_bit && constraint_mask_byte != 0x00 {
297 return Err(Error::InvalidNetworkMaskConstraint);
298 }
299
300 if constraint_mask_byte != 0xff {
302 seen_zero_bit = true;
303 }
304
305 if ((name_byte ^ constraint_address_byte) & constraint_mask_byte) != 0 {
306 return Ok(false);
307 }
308 if name.at_end() {
309 break;
310 }
311 }
312
313 Ok(true)
314}
315
316pub(crate) fn parse_ipv4_address(ip_address_: &[u8]) -> Result<IpAddrRef, AddrParseError> {
317 let mut ip_address = untrusted::Reader::new(untrusted::Input::from(ip_address_));
318 let mut is_first_byte = true;
319 let mut current_octet: [u8; 3] = [0, 0, 0];
320 let mut current_size = 0;
321 let mut dot_count = 0;
322
323 let mut octet = 0;
324 let mut octets: [u8; 4] = [0, 0, 0, 0];
325
326 fn radix10_to_octet(textual_octets: &[u8]) -> u32 {
329 let mut result: u32 = 0;
330 for digit in textual_octets.iter() {
331 result *= 10;
332 result += u32::from(*digit);
333 }
334 result
335 }
336
337 loop {
338 match ip_address.read_byte() {
339 Ok(b'.') => {
340 if is_first_byte {
341 return Err(AddrParseError);
343 }
344 if ip_address.at_end() {
345 return Err(AddrParseError);
347 }
348 if dot_count == 3 {
349 return Err(AddrParseError);
351 }
352 dot_count += 1;
353 if current_size == 0 {
354 return Err(AddrParseError);
356 }
357 let current_raw_octet = radix10_to_octet(¤t_octet[..current_size]);
358 if current_raw_octet > 255 {
359 return Err(AddrParseError);
361 }
362 octets[octet] =
363 TryInto::<u8>::try_into(current_raw_octet).expect("invalid character");
364 octet += 1;
365 current_octet = [0, 0, 0];
367 current_size = 0;
368 }
369 Ok(number @ b'0'..=b'9') => {
370 if number == b'0'
371 && current_size == 0
372 && !ip_address.peek(b'.')
373 && !ip_address.at_end()
374 {
375 return Err(AddrParseError);
377 }
378 if current_size >= current_octet.len() {
379 return Err(AddrParseError);
381 }
382 current_octet[current_size] = number - b'0';
383 current_size += 1;
384 }
385 _ => {
386 return Err(AddrParseError);
387 }
388 }
389 is_first_byte = false;
390
391 if ip_address.at_end() {
392 let last_octet = radix10_to_octet(¤t_octet[..current_size]);
393 if current_size > 0 && last_octet > 255 {
394 return Err(AddrParseError);
396 }
397 octets[octet] = TryInto::<u8>::try_into(last_octet).expect("invalid character");
398 break;
399 }
400 }
401 if dot_count != 3 {
402 return Err(AddrParseError);
403 }
404 Ok(IpAddrRef::V4(ip_address_, octets))
405}
406
407pub(crate) fn parse_ipv6_address(ip_address_: &[u8]) -> Result<IpAddrRef, AddrParseError> {
408 if ip_address_.len() != 39 {
412 return Err(AddrParseError);
413 }
414
415 let mut ip_address = untrusted::Reader::new(untrusted::Input::from(ip_address_));
416 let mut is_first_byte = true;
417 let mut current_textual_block_size = 0;
418 let mut colon_count = 0;
419
420 let mut octet = 0;
421 let mut previous_character = None;
422 let mut octets: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
423
424 loop {
425 match ip_address.read_byte() {
426 Ok(b':') => {
427 if is_first_byte {
428 return Err(AddrParseError);
430 }
431 if ip_address.at_end() {
432 return Err(AddrParseError);
434 }
435 if colon_count == 7 {
436 return Err(AddrParseError);
438 }
439 colon_count += 1;
440 if current_textual_block_size == 0 {
441 return Err(AddrParseError);
443 }
444 if current_textual_block_size != 4 {
445 return Err(AddrParseError);
447 }
448 current_textual_block_size = 0;
450 previous_character = None;
451 }
452 Ok(character @ b'0'..=b'9')
453 | Ok(character @ b'a'..=b'f')
454 | Ok(character @ b'A'..=b'F') => {
455 if current_textual_block_size == 4 {
456 return Err(AddrParseError);
458 }
459 if let Some(previous_character_) = previous_character {
460 octets[octet] = (TryInto::<u8>::try_into(
461 TryInto::<u8>::try_into(
462 (TryInto::<char>::try_into(previous_character_)
463 .expect("invalid character"))
464 .to_digit(16)
465 .unwrap(),
467 )
468 .expect("invalid character"),
469 )
470 .expect("invalid character")
471 << 4)
472 | (TryInto::<u8>::try_into(
473 TryInto::<char>::try_into(character)
474 .expect("invalid character")
475 .to_digit(16)
476 .unwrap(),
478 )
479 .expect("invalid character"));
480 previous_character = None;
481 octet += 1;
482 } else {
483 previous_character = Some(character);
484 }
485 current_textual_block_size += 1;
486 }
487 _ => {
488 return Err(AddrParseError);
489 }
490 }
491 is_first_byte = false;
492
493 if ip_address.at_end() {
494 break;
495 }
496 }
497 if colon_count != 7 {
498 return Err(AddrParseError);
499 }
500 Ok(IpAddrRef::V6(ip_address_, octets))
501}
502
503#[cfg(test)]
504mod tests {
505 use super::*;
506
507 const fn ipv4_address(
508 ip_address: &[u8],
509 octets: [u8; 4],
510 ) -> (&[u8], Result<IpAddrRef, AddrParseError>) {
511 (ip_address, Ok(IpAddrRef::V4(ip_address, octets)))
512 }
513
514 const IPV4_ADDRESSES: &[(&[u8], Result<IpAddrRef, AddrParseError>)] = &[
515 ipv4_address(b"0.0.0.0", [0, 0, 0, 0]),
517 ipv4_address(b"1.1.1.1", [1, 1, 1, 1]),
518 ipv4_address(b"205.0.0.0", [205, 0, 0, 0]),
519 ipv4_address(b"0.205.0.0", [0, 205, 0, 0]),
520 ipv4_address(b"0.0.205.0", [0, 0, 205, 0]),
521 ipv4_address(b"0.0.0.205", [0, 0, 0, 205]),
522 ipv4_address(b"0.0.0.20", [0, 0, 0, 20]),
523 (b"", Err(AddrParseError)),
525 (b"...", Err(AddrParseError)),
526 (b".0.0.0.0", Err(AddrParseError)),
527 (b"0.0.0.0.", Err(AddrParseError)),
528 (b"0.0.0", Err(AddrParseError)),
529 (b"0.0.0.", Err(AddrParseError)),
530 (b"256.0.0.0", Err(AddrParseError)),
531 (b"0.256.0.0", Err(AddrParseError)),
532 (b"0.0.256.0", Err(AddrParseError)),
533 (b"0.0.0.256", Err(AddrParseError)),
534 (b"1..1.1.1", Err(AddrParseError)),
535 (b"1.1..1.1", Err(AddrParseError)),
536 (b"1.1.1..1", Err(AddrParseError)),
537 (b"025.0.0.0", Err(AddrParseError)),
538 (b"0.025.0.0", Err(AddrParseError)),
539 (b"0.0.025.0", Err(AddrParseError)),
540 (b"0.0.0.025", Err(AddrParseError)),
541 (b"1234.0.0.0", Err(AddrParseError)),
542 (b"0.1234.0.0", Err(AddrParseError)),
543 (b"0.0.1234.0", Err(AddrParseError)),
544 (b"0.0.0.1234", Err(AddrParseError)),
545 ];
546
547 #[test]
548 fn parse_ipv4_address_test() {
549 for &(ip_address, expected_result) in IPV4_ADDRESSES {
550 assert_eq!(parse_ipv4_address(ip_address), expected_result,);
551 }
552 }
553
554 const fn ipv6_address(
555 ip_address: &[u8],
556 octets: [u8; 16],
557 ) -> (&[u8], Result<IpAddrRef, AddrParseError>) {
558 (ip_address, Ok(IpAddrRef::V6(ip_address, octets)))
559 }
560
561 const IPV6_ADDRESSES: &[(&[u8], Result<IpAddrRef, AddrParseError>)] = &[
562 ipv6_address(
564 b"2a05:d018:076c:b685:e8ab:afd3:af51:3aed",
565 [
566 0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
567 0x3a, 0xed,
568 ],
569 ),
570 ipv6_address(
571 b"2A05:D018:076C:B685:E8AB:AFD3:AF51:3AED",
572 [
573 0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
574 0x3a, 0xed,
575 ],
576 ),
577 ipv6_address(
578 b"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
579 [
580 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
581 0xff, 0xff,
582 ],
583 ),
584 ipv6_address(
585 b"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF",
586 [
587 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
588 0xff, 0xff,
589 ],
590 ),
591 ipv6_address(
592 b"FFFF:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
593 [
594 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
595 0xff, 0xff,
596 ],
597 ),
598 (
601 b"aaa:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
602 Err(AddrParseError),
603 ),
604 (
605 b"ffff:aaa:ffff:ffff:ffff:ffff:ffff:ffff",
606 Err(AddrParseError),
607 ),
608 (
609 b"ffff:ffff:aaa:ffff:ffff:ffff:ffff:ffff",
610 Err(AddrParseError),
611 ),
612 (
613 b"ffff:ffff:ffff:aaa:ffff:ffff:ffff:ffff",
614 Err(AddrParseError),
615 ),
616 (
617 b"ffff:ffff:ffff:ffff:aaa:ffff:ffff:ffff",
618 Err(AddrParseError),
619 ),
620 (
621 b"ffff:ffff:ffff:ffff:ffff:aaa:ffff:ffff",
622 Err(AddrParseError),
623 ),
624 (
625 b"ffff:ffff:ffff:ffff:ffff:ffff:aaa:ffff",
626 Err(AddrParseError),
627 ),
628 (
629 b"ffff:ffff:ffff:ffff:ffff:ffff:ffff:aaa",
630 Err(AddrParseError),
631 ),
632 (
634 b"ffgf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
635 Err(AddrParseError),
636 ),
637 (
638 b"ffff:gfff:ffff:ffff:ffff:ffff:ffff:ffff",
639 Err(AddrParseError),
640 ),
641 (
642 b"ffff:ffff:fffg:ffff:ffff:ffff:ffff:ffff",
643 Err(AddrParseError),
644 ),
645 (
646 b"ffff:ffff:ffff:ffgf:ffff:ffff:ffff:ffff",
647 Err(AddrParseError),
648 ),
649 (
650 b"ffff:ffff:ffff:ffff:gfff:ffff:ffff:ffff",
651 Err(AddrParseError),
652 ),
653 (
654 b"ffff:ffff:ffff:ffff:ffff:fgff:ffff:ffff",
655 Err(AddrParseError),
656 ),
657 (
658 b"ffff:ffff:ffff:ffff:ffff:ffff:ffgf:ffff",
659 Err(AddrParseError),
660 ),
661 (
662 b"ffff:ffff:ffff:ffff:ffff:ffff:ffgf:fffg",
663 Err(AddrParseError),
664 ),
665 (
667 b":ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
668 Err(AddrParseError),
669 ),
670 (
671 b"ffff::ffff:ffff:ffff:ffff:ffff:ffff:ffff",
672 Err(AddrParseError),
673 ),
674 (
675 b"ffff:ffff::ffff:ffff:ffff:ffff:ffff:ffff",
676 Err(AddrParseError),
677 ),
678 (
679 b"ffff:ffff:ffff::ffff:ffff:ffff:ffff:ffff",
680 Err(AddrParseError),
681 ),
682 (
683 b"ffff:ffff:ffff:ffff::ffff:ffff:ffff:ffff",
684 Err(AddrParseError),
685 ),
686 (
687 b"ffff:ffff:ffff:ffff:ffff::ffff:ffff:ffff",
688 Err(AddrParseError),
689 ),
690 (
691 b"ffff:ffff:ffff:ffff:ffff:ffff::ffff:ffff",
692 Err(AddrParseError),
693 ),
694 (
695 b"ffff:ffff:ffff:ffff:ffff:ffff:ffff::ffff",
696 Err(AddrParseError),
697 ),
698 (
700 b"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:",
701 Err(AddrParseError),
702 ),
703 (
704 b"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
705 Err(AddrParseError),
706 ),
707 (
709 b"\xc3\x28a05:d018:076c:b685:e8ab:afd3:af51:3aed",
710 Err(AddrParseError),
711 ),
712 (
714 b"ga05:d018:076c:b685:e8ab:afd3:af51:3aed",
715 Err(AddrParseError),
716 ),
717 (
719 b":a05:d018:076c:b685:e8ab:afd3:af51:3aed",
720 Err(AddrParseError),
721 ),
722 (
724 b"2a05:d018:076c:b685:e8ab:afd3:af51:3ae:",
725 Err(AddrParseError),
726 ),
727 (
729 b"2a05:d018:076c:b685:e8ab:afd3:af51:3a::",
730 Err(AddrParseError),
731 ),
732 (
734 b"2a05::018:076c:b685:e8ab:afd3:af51:3aed",
735 Err(AddrParseError),
736 ),
737 (
739 b"2a056:d018:076c:b685:e8ab:afd3:af51:3ae",
740 Err(AddrParseError),
741 ),
742 (
744 b"2a0:d018:076c:b685:e8ab:afd3:af51:3aed ",
745 Err(AddrParseError),
746 ),
747 (b"d018:076c:b685:e8ab:afd3:af51:3aed", Err(AddrParseError)),
749 (
751 b"2a05:d018:076c:b685:e8ab:afd3:af51:3aed3aed",
752 Err(AddrParseError),
753 ),
754 (b"0:0:0:0:0:0:0:1", Err(AddrParseError)),
756 (
757 b"2a05:d018:76c:b685:e8ab:afd3:af51:3aed",
758 Err(AddrParseError),
759 ),
760 ];
761
762 #[test]
763 fn parse_ipv6_address_test() {
764 for &(ip_address, expected_result) in IPV6_ADDRESSES {
765 assert_eq!(parse_ipv6_address(ip_address), expected_result,);
766 }
767 }
768
769 #[test]
770 fn try_from_ascii_ip_address_test() {
771 const IP_ADDRESSES: &[(&[u8], Result<IpAddrRef, AddrParseError>)] = &[
772 (
774 b"127.0.0.1",
775 Ok(IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1])),
776 ),
777 (
779 b"127.0.0.",
781 Err(AddrParseError),
782 ),
783 (
785 b"0000:0000:0000:0000:0000:0000:0000:0001",
786 Ok(IpAddrRef::V6(
787 b"0000:0000:0000:0000:0000:0000:0000:0001",
788 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
789 )),
790 ),
791 (
793 b"0:0:0:0:0:0:0:1",
795 Err(AddrParseError),
796 ),
797 (
799 b"example.com",
801 Err(AddrParseError),
802 ),
803 ];
804 for &(ip_address, expected_result) in IP_ADDRESSES {
805 assert_eq!(IpAddrRef::try_from_ascii(ip_address), expected_result)
806 }
807 }
808
809 #[test]
810 fn try_from_ascii_str_ip_address_test() {
811 const IP_ADDRESSES: &[(&str, Result<IpAddrRef, AddrParseError>)] = &[
812 ("127.0.0.1", Ok(IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]))),
814 (
816 "127.0.0.",
818 Err(AddrParseError),
819 ),
820 (
822 "0000:0000:0000:0000:0000:0000:0000:0001",
823 Ok(IpAddrRef::V6(
824 b"0000:0000:0000:0000:0000:0000:0000:0001",
825 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
826 )),
827 ),
828 (
830 "0:0:0:0:0:0:0:1",
832 Err(AddrParseError),
833 ),
834 (
836 "example.com",
838 Err(AddrParseError),
839 ),
840 ];
841 for &(ip_address, expected_result) in IP_ADDRESSES {
842 assert_eq!(IpAddrRef::try_from_ascii_str(ip_address), expected_result)
843 }
844 }
845
846 #[test]
847 fn str_from_ip_address_ref_test() {
848 let ip_addresses = vec![
849 (IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]), "127.0.0.1"),
851 (
853 IpAddrRef::V6(
854 b"0000:0000:0000:0000:0000:0000:0000:0001",
855 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
856 ),
857 "0000:0000:0000:0000:0000:0000:0000:0001",
858 ),
859 ];
860 for (ip_address, expected_ip_address) in ip_addresses {
861 assert_eq!(Into::<&str>::into(ip_address), expected_ip_address,)
862 }
863 }
864
865 #[test]
866 fn u8_array_from_ip_address_ref_test() {
867 let ip_addresses = vec![
868 (IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]), "127.0.0.1"),
870 (
872 IpAddrRef::V6(
873 b"0000:0000:0000:0000:0000:0000:0000:0001",
874 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
875 ),
876 "0000:0000:0000:0000:0000:0000:0000:0001",
877 ),
878 ];
879 for (ip_address, expected_ip_address) in ip_addresses {
880 assert_eq!(
881 Into::<&[u8]>::into(ip_address),
882 expected_ip_address.as_bytes()
883 )
884 }
885 }
886
887 #[test]
888 fn presented_id_matches_constraint_ipv4_test() {
889 let names_and_constraints = vec![
890 (
891 [0xC0, 0x00, 0x02, 0x00],
893 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
894 Ok(true),
895 ),
896 (
897 [0xC0, 0x00, 0x02, 0x01],
899 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
900 Ok(true),
901 ),
902 (
903 [0xC0, 0x00, 0x02, 0xFF],
905 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
906 Ok(true),
907 ),
908 (
909 [0xC0, 0x00, 0x01, 0xFF],
911 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
912 Ok(false),
913 ),
914 (
915 [0xC0, 0x00, 0x03, 0x00],
917 [0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00],
918 Ok(false),
919 ),
920 ];
921 for (name, constraint, match_result) in names_and_constraints {
922 assert_eq!(
923 presented_id_matches_constraint(
924 untrusted::Input::from(&name),
925 untrusted::Input::from(&constraint),
926 ),
927 match_result
928 )
929 }
930
931 assert_eq!(
933 presented_id_matches_constraint(
934 untrusted::Input::from(&[0xC0, 0x00, 0x02]),
935 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00]),
936 ),
937 Err(Error::BadDer),
938 );
939
940 assert_eq!(
942 presented_id_matches_constraint(
943 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0x00]),
944 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00]),
945 ),
946 Err(Error::BadDer),
947 );
948
949 assert_eq!(
951 presented_id_matches_constraint(
952 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00]),
953 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF]),
954 ),
955 Err(Error::InvalidNetworkMaskConstraint),
956 );
957
958 assert_eq!(
960 presented_id_matches_constraint(
961 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00]),
962 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00]),
963 ),
964 Err(Error::InvalidNetworkMaskConstraint),
965 );
966
967 assert_eq!(
969 presented_id_matches_constraint(
970 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00]),
971 untrusted::Input::from(&[
972 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
973 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
974 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
975 ]),
976 ),
977 Ok(false),
978 );
979 }
980
981 #[test]
982 fn presented_id_matches_constraint_ipv6_test() {
983 let names_and_constraints = vec![
984 (
985 [
988 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
989 0x00, 0x00, 0x00,
990 ],
991 [
992 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
993 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
994 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
995 ],
996 Ok(true),
997 ),
998 (
999 [
1002 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1003 0x00, 0x00, 0x01,
1004 ],
1005 [
1006 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1007 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1009 ],
1010 Ok(true),
1011 ),
1012 (
1013 [
1016 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1017 0xFF, 0xFF, 0xFF,
1018 ],
1019 [
1020 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1021 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1022 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1023 ],
1024 Ok(true),
1025 ),
1026 (
1027 [
1030 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
1031 0x00, 0x00, 0x00,
1032 ],
1033 [
1034 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1035 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1037 ],
1038 Ok(false),
1039 ),
1040 (
1041 [
1044 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
1045 0x00, 0x00, 0x00,
1046 ],
1047 [
1048 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1049 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1050 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1051 ],
1052 Ok(false),
1053 ),
1054 ];
1055 for (name, constraint, match_result) in names_and_constraints {
1056 assert_eq!(
1057 presented_id_matches_constraint(
1058 untrusted::Input::from(&name),
1059 untrusted::Input::from(&constraint),
1060 ),
1061 match_result
1062 )
1063 }
1064
1065 assert_eq!(
1067 presented_id_matches_constraint(
1068 untrusted::Input::from(&[
1069 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1070 0x00, 0x00
1071 ]),
1072 untrusted::Input::from(&[
1073 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1074 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1075 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1076 ]),
1077 ),
1078 Err(Error::BadDer),
1079 );
1080
1081 assert_eq!(
1083 presented_id_matches_constraint(
1084 untrusted::Input::from(&[
1085 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1086 0x00, 0x00, 0x00, 0x00
1087 ]),
1088 untrusted::Input::from(&[
1089 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1090 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1092 ]),
1093 ),
1094 Err(Error::BadDer),
1095 );
1096
1097 assert_eq!(
1099 presented_id_matches_constraint(
1100 untrusted::Input::from(&[
1101 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1102 0x00, 0x00, 0x00,
1103 ]),
1104 untrusted::Input::from(&[
1105 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1106 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1107 0x00, 0x00, 0x00, 0x00, 0x00
1108 ]),
1109 ),
1110 Err(Error::InvalidNetworkMaskConstraint),
1111 );
1112
1113 assert_eq!(
1115 presented_id_matches_constraint(
1116 untrusted::Input::from(&[
1117 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1118 0x00, 0x00, 0x00,
1119 ]),
1120 untrusted::Input::from(&[
1121 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1122 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1124 ]),
1125 ),
1126 Err(Error::InvalidNetworkMaskConstraint),
1127 );
1128
1129 assert_eq!(
1131 presented_id_matches_constraint(
1132 untrusted::Input::from(&[
1133 0x20, 0x01, 0x0D, 0xB8, 0xAB, 0xCD, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
1134 0x00, 0x00, 0x00,
1135 ]),
1136 untrusted::Input::from(&[0xC0, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0x00]),
1137 ),
1138 Ok(false),
1139 );
1140 }
1141
1142 #[test]
1143 fn test_presented_id_matches_reference_id() {
1144 assert!(!presented_id_matches_reference_id(
1145 untrusted::Input::from(&[]),
1146 untrusted::Input::from(&[]),
1147 ));
1148
1149 assert!(!presented_id_matches_reference_id(
1150 untrusted::Input::from(&[0x01]),
1151 untrusted::Input::from(&[])
1152 ));
1153
1154 assert!(!presented_id_matches_reference_id(
1155 untrusted::Input::from(&[]),
1156 untrusted::Input::from(&[0x01])
1157 ));
1158
1159 assert!(presented_id_matches_reference_id(
1160 untrusted::Input::from(&[1, 2, 3, 4]),
1161 untrusted::Input::from(&[1, 2, 3, 4])
1162 ));
1163
1164 assert!(!presented_id_matches_reference_id(
1165 untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
1166 untrusted::Input::from(&[1, 2, 3, 4])
1167 ));
1168
1169 assert!(!presented_id_matches_reference_id(
1170 untrusted::Input::from(&[1, 2, 3, 4]),
1171 untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
1172 ));
1173
1174 assert!(presented_id_matches_reference_id(
1175 untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
1176 untrusted::Input::from(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
1177 ));
1178 }
1179
1180 #[test]
1181 fn presented_id_matches_constraint_rejects_incorrect_length_arguments() {
1182 assert_eq!(
1184 presented_id_matches_constraint(
1185 untrusted::Input::from(b"\x00\x00\x00"),
1186 untrusted::Input::from(b"")
1187 ),
1188 Err(Error::BadDer)
1189 );
1190 assert_eq!(
1191 presented_id_matches_constraint(
1192 untrusted::Input::from(b"\x00\x00\x00\x00\x00"),
1193 untrusted::Input::from(b"")
1194 ),
1195 Err(Error::BadDer)
1196 );
1197
1198 assert_eq!(
1199 presented_id_matches_constraint(
1200 untrusted::Input::from(
1201 b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
1202 ),
1203 untrusted::Input::from(b"")
1204 ),
1205 Err(Error::BadDer)
1206 );
1207 assert_eq!(
1208 presented_id_matches_constraint(
1209 untrusted::Input::from(
1210 b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
1211 ),
1212 untrusted::Input::from(b"")
1213 ),
1214 Err(Error::BadDer)
1215 );
1216
1217 assert_eq!(
1219 presented_id_matches_constraint(
1220 untrusted::Input::from(b"\x00\x00\x00\x00"),
1221 untrusted::Input::from(b"\x00\x00\x00\x00\xff\xff\xff")
1222 ),
1223 Err(Error::InvalidNetworkMaskConstraint)
1224 );
1225 assert_eq!(
1226 presented_id_matches_constraint(
1227 untrusted::Input::from(b"\x00\x00\x00\x00"),
1228 untrusted::Input::from(b"\x00\x00\x00\x00\xff\xff\xff\xff\x00")
1229 ),
1230 Err(Error::InvalidNetworkMaskConstraint)
1231 );
1232 assert_eq!(
1233 presented_id_matches_constraint(untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
1234 untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
1235 \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
1236 Err(Error::InvalidNetworkMaskConstraint)
1237 );
1238 assert_eq!(
1239 presented_id_matches_constraint(untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
1240 untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
1241 \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
1242 Err(Error::InvalidNetworkMaskConstraint)
1243 );
1244
1245 assert_eq!(
1247 presented_id_matches_constraint(untrusted::Input::from(b"\x00\x00\x00\x00"),
1248 untrusted::Input::from(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
1249 \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")),
1250 Ok(false)
1251 );
1252 assert_eq!(
1253 presented_id_matches_constraint(
1254 untrusted::Input::from(
1255 b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
1256 ),
1257 untrusted::Input::from(b"\x00\x00\x00\x00\xff\xff\xff\xff")
1258 ),
1259 Ok(false)
1260 );
1261 }
1262}
1263
1264#[cfg(all(test, feature = "alloc"))]
1265mod alloc_tests {
1266 use super::*;
1267
1268 #[test]
1269 fn as_ref_ip_address_test() {
1270 assert_eq!(
1271 IpAddr::V4(String::from("127.0.0.1"), [127, 0, 0, 1]).as_ref(),
1272 "127.0.0.1",
1273 );
1274 assert_eq!(
1275 IpAddr::V6(
1276 String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
1277 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
1278 )
1279 .as_ref(),
1280 "0000:0000:0000:0000:0000:0000:0000:0001",
1281 );
1282 }
1283
1284 #[test]
1285 fn from_ip_address_ref_for_ip_address_test() {
1286 {
1287 let (ip_address, ip_address_octets) = ("127.0.0.1", [127, 0, 0, 1]);
1288 assert_eq!(
1289 IpAddr::from(IpAddrRef::V4(ip_address.as_bytes(), ip_address_octets)),
1290 IpAddr::V4(String::from(ip_address), ip_address_octets),
1291 )
1292 }
1293 {
1294 let (ip_address, ip_address_octets) = (
1295 "0000:0000:0000:0000:0000:0000:0000:0001",
1296 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
1297 );
1298 assert_eq!(
1299 IpAddr::from(IpAddrRef::V6(ip_address.as_bytes(), ip_address_octets)),
1300 IpAddr::V6(String::from(ip_address), ip_address_octets),
1301 )
1302 }
1303 }
1304
1305 #[test]
1306 fn from_ip_address_for_ip_address_ref_test() {
1307 {
1308 let ip_address = IpAddr::V4(String::from("127.0.0.1"), [127, 0, 0, 1]);
1309 assert_eq!(
1310 IpAddrRef::from(&ip_address),
1311 IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]),
1312 )
1313 }
1314 {
1315 let ip_address = IpAddr::V6(
1316 String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
1317 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
1318 );
1319 assert_eq!(
1320 IpAddrRef::from(&ip_address),
1321 IpAddrRef::V6(
1322 b"0000:0000:0000:0000:0000:0000:0000:0001",
1323 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
1324 ),
1325 )
1326 }
1327 }
1328
1329 #[test]
1330 fn display_invalid_ip_address_error_test() {
1331 assert_eq!(AddrParseError.to_string(), String::from("AddrParseError"),)
1332 }
1333
1334 #[test]
1335 fn ip_address_ref_to_owned_test() {
1336 {
1337 assert_eq!(
1338 IpAddrRef::V4(b"127.0.0.1", [127, 0, 0, 1]).to_owned(),
1339 IpAddr::V4(String::from("127.0.0.1"), [127, 0, 0, 1]),
1340 )
1341 }
1342 {
1343 assert_eq!(
1344 IpAddrRef::V6(
1345 b"0000:0000:0000:0000:0000:0000:0000:0001",
1346 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
1347 )
1348 .to_owned(),
1349 IpAddr::V6(
1350 String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
1351 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
1352 ),
1353 )
1354 }
1355 }
1356
1357 #[test]
1358 fn ip_address_from_std_net_ipaddr_test() {
1359 let ip_addresses = vec![
1360 (
1361 std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)),
1362 IpAddr::V4(String::from("127.0.0.1"), [127, 0, 0, 1]),
1363 ),
1364 (
1365 std::net::IpAddr::V6(std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)),
1366 IpAddr::V6(
1367 String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
1368 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
1369 ),
1370 ),
1371 ];
1372 for (ip_address, expected_ip_address) in ip_addresses {
1373 assert_eq!(IpAddr::from(ip_address), expected_ip_address,)
1374 }
1375 }
1376
1377 #[test]
1378 fn ipv6_to_uncompressed_string_test() {
1379 let ip_addresses = vec![
1380 (
1381 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
1382 String::from("0000:0000:0000:0000:0000:0000:0000:0001"),
1383 ),
1384 (
1385 [
1386 0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x84, 0x8e, 0x48, 0x47, 0xc9, 0x84,
1387 0xaa, 0xb3, 0x4d,
1388 ],
1389 String::from("2a05:d018:076c:b684:8e48:47c9:84aa:b34d"),
1390 ),
1391 ];
1392 for (ip_address_octets, expected_result) in ip_addresses {
1393 assert_eq!(
1394 ipv6_to_uncompressed_string(ip_address_octets),
1395 expected_result,
1396 )
1397 }
1398 }
1399
1400 const PRESENTED_MATCHES_CONSTRAINT: &[(&str, &str, &str, Result<bool, Error>)] = &[
1402 ("2001:db8::", "8.8.8.8", "255.255.255.255", Ok(false)),
1404 ("8.8.8.8", "2001:db8::", "ffff::", Ok(false)),
1405 (
1407 "8.8.8.8",
1408 "8.8.8.8",
1409 "255.255.255.1",
1410 Err(Error::InvalidNetworkMaskConstraint),
1411 ),
1412 (
1413 "8.8.8.8",
1414 "8.8.8.8",
1415 "255.255.0.255",
1416 Err(Error::InvalidNetworkMaskConstraint),
1417 ),
1418 (
1419 "8.8.8.8",
1420 "8.8.8.8",
1421 "255.0.255.255",
1422 Err(Error::InvalidNetworkMaskConstraint),
1423 ),
1424 (
1425 "8.8.8.8",
1426 "8.8.8.8",
1427 "0.255.255.255",
1428 Err(Error::InvalidNetworkMaskConstraint),
1429 ),
1430 (
1431 "8.8.8.8",
1432 "8.8.8.8",
1433 "1.255.255.255",
1434 Err(Error::InvalidNetworkMaskConstraint),
1435 ),
1436 (
1437 "8.8.8.8",
1438 "8.8.8.8",
1439 "128.128.128.128",
1440 Err(Error::InvalidNetworkMaskConstraint),
1441 ),
1442 ("8.8.8.8", "8.8.8.8", "255.255.255.255", Ok(true)),
1444 ("8.8.8.9", "8.8.8.8", "255.255.255.255", Ok(false)),
1445 ("8.8.8.9", "8.8.8.8", "255.255.255.254", Ok(true)),
1446 ("8.8.8.10", "8.8.8.8", "255.255.255.254", Ok(false)),
1447 ("8.8.8.10", "8.8.8.8", "255.255.255.0", Ok(true)),
1448 ("8.8.15.10", "8.8.8.8", "255.255.248.0", Ok(true)),
1449 ("8.8.16.10", "8.8.8.8", "255.255.248.0", Ok(false)),
1450 ("8.8.16.10", "8.8.8.8", "255.255.0.0", Ok(true)),
1451 ("8.31.16.10", "8.8.8.8", "255.224.0.0", Ok(true)),
1452 ("8.32.16.10", "8.8.8.8", "255.224.0.0", Ok(false)),
1453 ("8.32.16.10", "8.8.8.8", "255.0.0.0", Ok(true)),
1454 ("63.32.16.10", "8.8.8.8", "192.0.0.0", Ok(true)),
1455 ("64.32.16.10", "8.8.8.8", "192.0.0.0", Ok(false)),
1456 ("64.32.16.10", "8.8.8.8", "0.0.0.0", Ok(true)),
1457 (
1459 "2001:db8::",
1460 "2001:db8::",
1461 "fffe:ffff::",
1462 Err(Error::InvalidNetworkMaskConstraint),
1463 ),
1464 (
1465 "2001:db8::",
1466 "2001:db8::",
1467 "ffff:fdff::",
1468 Err(Error::InvalidNetworkMaskConstraint),
1469 ),
1470 (
1471 "2001:db8::",
1472 "2001:db8::",
1473 "ffff:feff::",
1474 Err(Error::InvalidNetworkMaskConstraint),
1475 ),
1476 (
1477 "2001:db8::",
1478 "2001:db8::",
1479 "ffff:fcff::",
1480 Err(Error::InvalidNetworkMaskConstraint),
1481 ),
1482 (
1483 "2001:db8::",
1484 "2001:db8::",
1485 "7fff:ffff::",
1486 Err(Error::InvalidNetworkMaskConstraint),
1487 ),
1488 ("2001:db8::", "2001:db8::", "ffff:ffff::", Ok(true)),
1490 ("2001:db9::", "2001:db8::", "ffff:ffff::", Ok(false)),
1491 ("2001:db9::", "2001:db8::", "ffff:fffe::", Ok(true)),
1492 ("2001:dba::", "2001:db8::", "ffff:fffe::", Ok(false)),
1493 ("2001:dba::", "2001:db8::", "ffff:ff00::", Ok(true)),
1494 ("2001:dca::", "2001:db8::", "ffff:fe00::", Ok(true)),
1495 ("2001:fca::", "2001:db8::", "ffff:fe00::", Ok(false)),
1496 ("2001:fca::", "2001:db8::", "ffff:0000::", Ok(true)),
1497 ("2000:fca::", "2001:db8::", "fffe:0000::", Ok(true)),
1498 ("2003:fca::", "2001:db8::", "fffe:0000::", Ok(false)),
1499 ("2003:fca::", "2001:db8::", "ff00:0000::", Ok(true)),
1500 ("1003:fca::", "2001:db8::", "e000:0000::", Ok(false)),
1501 ("1003:fca::", "2001:db8::", "0000:0000::", Ok(true)),
1502 ];
1503
1504 #[cfg(feature = "std")]
1505 #[test]
1506 fn presented_matches_constraint_test() {
1507 use std::boxed::Box;
1508 use std::net::IpAddr;
1509
1510 for &(presented, constraint_address, constraint_mask, expected_result) in
1511 PRESENTED_MATCHES_CONSTRAINT
1512 {
1513 let presented_bytes: Box<[u8]> = match presented.parse::<IpAddr>().unwrap() {
1514 IpAddr::V4(p) => Box::new(p.octets()),
1515 IpAddr::V6(p) => Box::new(p.octets()),
1516 };
1517 let ca_bytes: Box<[u8]> = match constraint_address.parse::<IpAddr>().unwrap() {
1518 IpAddr::V4(ca) => Box::new(ca.octets()),
1519 IpAddr::V6(ca) => Box::new(ca.octets()),
1520 };
1521 let cm_bytes: Box<[u8]> = match constraint_mask.parse::<IpAddr>().unwrap() {
1522 IpAddr::V4(cm) => Box::new(cm.octets()),
1523 IpAddr::V6(cm) => Box::new(cm.octets()),
1524 };
1525 let constraint_bytes = [ca_bytes, cm_bytes].concat();
1526 let actual_result = presented_id_matches_constraint(
1527 untrusted::Input::from(&presented_bytes),
1528 untrusted::Input::from(&constraint_bytes),
1529 );
1530 assert_eq!(
1531 actual_result, expected_result,
1532 "presented_id_matches_constraint(\"{:?}\", \"{:?}\")",
1533 presented_bytes, constraint_bytes
1534 );
1535 }
1536 }
1537}