1use fancy_regex::Regex;
14
15#[derive(Default, Clone)]
16struct Options {
17 exact: bool,
19 include_boundaries: bool,
21}
22
23enum RegexType {
24 V4,
25 V6,
26 V4V6,
27}
28
29fn get_regex(regex_type: &RegexType, options: Option<&Options>) -> String {
30 let options = options.cloned().unwrap_or_default();
31
32 assert!(
34 !(options.exact && options.include_boundaries),
35 "Cannot set both exact and include_boundaries options to true"
36 );
37
38 let word = "[a-fA-F\\d:]";
39
40 let boundary = if options.include_boundaries {
41 format!("(?:(?<=\\s|^)(?={word})|(?<={word})(?=\\s|$))")
42 } else {
43 String::new()
44 };
45
46 let v4 = "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}";
47
48 let v6segment = "[a-fA-F\\d]{1,4}";
49
50 let v6 = format!(
51 r"
52(?:
53(?:{v6segment}:){{7}}(?:{v6segment}|:)|
54 // 1:2:3:4:5:6:7:: 1:2:3:4:5:6:7:8
55(?:{v6segment}:){{6}}(?:{v4}|:{v6segment}|:)|
56 // 1:2:3:4:5:6:: 1:2:3:4:5:6::8 1:2:3:4:5:6::8 1:2:3:4:5:6::1.2.3.4
57(?:{v6segment}:){{5}}(?::{v4}|(?::{v6segment}){{1,2}}|:)|
58 // 1:2:3:4:5:: 1:2:3:4:5::7:8 1:2:3:4:5::8 1:2:3:4:5::7:1.2.3.4
59(?:{v6segment}:){{4}}(?:(?::{v6segment}){{0,1}}:{v4}|(?::{v6segment}){{1,3}}|:)|
60 // 1:2:3:4:: 1:2:3:4::6:7:8 1:2:3:4::8 1:2:3:4::6:7:1.2.3.4
61(?:{v6segment}:){{3}}(?:(?::{v6segment}){{0,2}}:{v4}|(?::{v6segment}){{1,4}}|:)|
62 // 1:2:3:: 1:2:3::5:6:7:8 1:2:3::8 1:2:3::5:6:7:1.2.3.4
63(?:{v6segment}:){{2}}(?:(?::{v6segment}){{0,3}}:{v4}|(?::{v6segment}){{1,5}}|:)|
64 // 1:2:: 1:2::4:5:6:7:8 1:2::8 1:2::4:5:6:7:1.2.3.4
65(?:{v6segment}:){{1}}(?:(?::{v6segment}){{0,4}}:{v4}|(?::{v6segment}){{1,6}}|:)|
66 // 1:: 1::3:4:5:6:7:8 1::8 1::3:4:5:6:7:1.2.3.4
67(?::(?:(?::{v6segment}){{0,5}}:{v4}|(?::{v6segment}){{1,7}}|:))
68 // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::1.2.3.4
69)(?:%[0-9a-zA-Z]{{1,}})?
70 // %eth0 %1
71"
72 );
73 let v6 = normalize_v6(&v6);
74
75 let v46_exact = format!(r"(?:^{v4}$)|(?:^{v6}$)");
77 let v4_exact = format!(r"^{v4}$");
78 let v6_exact = format!(r"^{v6}$");
79
80 let is_exact = options.exact;
81
82 let ip_regex = if is_exact {
83 v46_exact
84 } else {
85 format!(r"(?:{boundary}{v4}{boundary})|(?:{boundary}{v6}{boundary})")
86 };
87
88 let ip_regex_v4 = if is_exact {
89 v4_exact
90 } else {
91 format!(r"{boundary}{v4}{boundary}")
92 };
93 let ip_regex_v6 = if is_exact {
94 v6_exact
95 } else {
96 format!(r"{boundary}{v6}{boundary}")
97 };
98
99 match regex_type {
100 RegexType::V4 => ip_regex_v4,
101 RegexType::V6 => ip_regex_v6,
102 RegexType::V4V6 => ip_regex,
103 }
104}
105
106fn normalize_v6(v6: &str) -> String {
107 let re_comments = Regex::new(r"(?m)\s*//.*$").expect("invalid regex");
109 let v6 = re_comments.replace_all(v6, "").to_string();
110 let re_newline = Regex::new(r"\n").expect("invalid regex");
112 let v6 = re_newline.replace_all(&v6, "").to_string();
113 v6.trim().to_string()
115}
116
117pub fn get_regex_ipv4_ipv6_exact() -> String {
121 get_regex(
122 &RegexType::V4V6,
123 Some(&Options {
124 exact: true,
125 include_boundaries: false,
126 }),
127 )
128}
129
130#[cfg(test)]
133#[allow(clippy::unwrap_in_result, clippy::panic_in_result_fn)]
134mod tests {
135 use once_cell::sync::Lazy;
136
137 use super::*;
138 use std::collections::HashMap;
139 use std::sync::RwLock;
140
141 fn build_regex_rt(rt: &RegexType, options: Option<&Options>) -> Regex {
142 let pat = get_regex(rt, options);
143
144 {
146 let cache = REGEX_CACHE.read().unwrap();
147 if let Some(re) = cache.get(&pat) {
148 return re.clone();
149 }
150 }
151
152 let invalid_msg = format!("invalid regex {pat}");
155 let compiled = Regex::new(&pat).expect(&invalid_msg);
156
157 let mut cache = REGEX_CACHE.write().unwrap();
159 let entry = cache.entry(pat).or_insert_with(|| compiled.clone());
160 entry.clone()
161 }
162
163 #[crate::ctb_test]
164 fn test_get_regex_ipv4_ipv6() {
165 let regex_str = get_regex_ipv4_ipv6_exact();
166 let regex = fancy_regex::Regex::new(®ex_str).unwrap();
167
168 let valid_ipv4 = vec![
170 "127.0.0.1",
171 "0.0.0.0",
172 "255.255.255.255",
173 "192.168.1.1",
174 "1.2.3.4",
175 "10.0.0.1",
176 ];
177 for ip in valid_ipv4 {
178 assert!(
179 regex.is_match(ip).expect("Error"),
180 "expected '{}' to match IPv4 with regex '{}'",
181 ip,
182 regex.as_str()
183 );
184 }
185
186 let valid_ipv6 = vec![
188 "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
189 "2001:db8::1",
190 "::1",
191 "fe80::1ff:fe23:4567:890a",
192 "2001:db8:85a3::8a2e:370:7334",
193 "2001:0db8:0000:0000:0000:0000:1428:57ab",
194 "::ffff:192.0.2.128",
195 ];
196 for ip in valid_ipv6 {
197 assert!(
198 regex.is_match(ip).expect("Error"),
199 "expected '{}' to match IPv6 with regex '{}'",
200 ip,
201 regex.as_str()
202 );
203 }
204
205 let invalid = vec![
207 "256.256.256.256",
208 "256.1.1.1",
209 "123.456.78.90",
210 "1.2.3",
211 "1.2.3.4.5",
212 "gibberish",
213 "2001::85a3::7334",
214 "2001:db8:85a3:8a2e:370:7334:1",
215 "",
216 ":",
217 ":::",
218 ];
219 for ip in invalid {
220 assert!(
221 !regex.is_match(ip).expect("Error"),
222 "expected '{}' to NOT match with regex '{}'",
223 ip,
224 regex.as_str()
225 );
226 }
227 }
228
229 static REGEX_CACHE: Lazy<RwLock<HashMap<String, Regex>>> =
231 Lazy::new(|| RwLock::new(HashMap::new()));
232
233 #[test]
234 #[allow(clippy::too_many_lines)]
235 fn test_ip() {
236 let v4 = v4();
237 let v6 = v6();
238 let v4not = v4not();
239 let v6not = v6not();
240 let mut v6boundaries: HashMap<&str, Vec<&str>> = HashMap::new();
243 v6boundaries.insert(
244 "02001:0000:1234:0000:0000:C1C0:ABCD:0876",
245 vec!["2001:0000:1234:0000:0000:C1C0:ABCD:0876"],
246 );
247 v6boundaries.insert(
248 "fe80:0000:0000:0000:0204:61ff:fe9d:f156245",
249 vec!["fe80:0000:0000:0000:0204:61ff:fe9d:f156"],
250 );
251
252 let mut v6extract: HashMap<&str, Vec<&str>> = HashMap::new();
253 v6extract.insert("::1, ::2, ::3-::5", vec!["::1", "::2", "::3", "::5"]);
254 v6extract
255 .insert("::1 ::2 ::3 - ::5", vec!["::1", "::2", "::3", "::5"]);
256 v6extract.insert(
257 "::ffff:192.168.1.1 1::1.2.3.4",
258 vec!["::ffff:192.168.1.1", "1::1.2.3.4"],
259 );
260 v6extract.insert(
261 "02001:0000:1234:0000:0000:C1C0:ABCD:0876 a::xyz",
262 vec!["2001:0000:1234:0000:0000:C1C0:ABCD:0876", "a::"],
263 );
264
265 let mut v4boundaries: HashMap<&str, Vec<&str>> = HashMap::new();
266 v4boundaries.insert("0000000192.168.0.200", vec!["192.168.0.200"]);
267 v4boundaries.insert("192.168.0.2000000000", vec!["192.168.0.200"]);
268
269 let mut v4extract: HashMap<&str, Vec<&str>> = HashMap::new();
270 v4extract.insert(
271 "255.255.255.255 0.0.0.0",
272 vec!["255.255.255.255", "0.0.0.0"],
273 );
274 v4extract.insert(
275 "1.2.3.4, 6.7.8.9, 1.2.3.4-5.6.7.8",
276 vec!["1.2.3.4", "6.7.8.9", "1.2.3.4", "5.6.7.8"],
277 );
278 v4extract.insert(
279 "1.2.3.4 6.7.8.9 1.2.3.4 - 5.6.7.8",
280 vec!["1.2.3.4", "6.7.8.9", "1.2.3.4", "5.6.7.8"],
281 );
282 v4extract.insert("192.168.0.2000000000", vec!["192.168.0.200"]);
283
284 for fixture in &v4 {
286 let re = build_regex_rt(
287 &RegexType::V4V6,
288 Some(&Options {
289 exact: true,
290 include_boundaries: false,
291 }),
292 );
293 assert!(
294 re.is_match(fixture).expect("Error"),
295 "Expected to match '{}' with regex '{}'",
296 fixture,
297 re.as_str()
298 );
299 }
300
301 for fixture in &v4 {
303 let re = build_regex_rt(&RegexType::V4V6, None);
304 let haystack = format!("foo {fixture} bar");
305 let caps = re.find(&haystack).expect("Error");
306 assert_eq!(
307 caps.map(|m| m.as_str()),
308 Some(fixture.as_str()),
309 "Expected to match '{}' with regex '{}'",
310 fixture,
311 re.as_str()
312 );
313 }
314
315 for fixture in &v4 {
317 let re = build_regex_rt(&RegexType::V4V6, None);
318 assert!(re.is_match(&format!("foo{fixture}bar")).expect("Error"));
319
320 let re_bound = build_regex_rt(
321 &RegexType::V4V6,
322 Some(&Options {
323 exact: false,
324 include_boundaries: true,
325 }),
326 );
327 assert!(
328 !re_bound
329 .is_match(&format!("foo{fixture}bar"))
330 .expect("Error"),
331 "Expected to NOT match '{}' with regex '{}'",
332 fixture,
333 re_bound.as_str()
334 );
335 }
336
337 for fixture in &v4not {
339 let re = build_regex_rt(
340 &RegexType::V4V6,
341 Some(&Options {
342 exact: true,
343 include_boundaries: false,
344 }),
345 );
346 assert!(
347 !re.is_match(fixture).expect("Error"),
348 "Expected to NOT match '{}' with regex '{}'",
349 fixture,
350 re.as_str()
351 );
352 }
353
354 for fixture in &v6 {
356 let re = build_regex_rt(
357 &RegexType::V4V6,
358 Some(&Options {
359 exact: true,
360 include_boundaries: false,
361 }),
362 );
363 assert!(
364 re.is_match(fixture).expect("Error"),
365 "Expected to match '{}' with regex '{}'",
366 fixture,
367 re.as_str()
368 );
369 }
370
371 for fixture in &v6 {
373 let re = build_regex_rt(&RegexType::V4V6, None);
374 let haystack = format!("foo {fixture} bar");
375 let caps = re.find(&haystack).expect("Error");
376 assert_eq!(
377 caps.map(|m| m.as_str()),
378 Some(fixture.as_str()),
379 "Expected to match '{}' with regex '{}'",
380 fixture,
381 re.as_str()
382 );
383 }
384
385 for fixture in &v6 {
387 let re = build_regex_rt(&RegexType::V4V6, None);
388 assert!(
389 re.is_match(&format!("foo{fixture}bar")).expect("Error"),
390 "Expected to match '{}' with regex '{}'",
391 fixture,
392 re.as_str()
393 );
394
395 let re_bound = build_regex_rt(
396 &RegexType::V4V6,
397 Some(&Options {
398 exact: false,
399 include_boundaries: true,
400 }),
401 );
402 assert!(
403 !re_bound
404 .is_match(&format!("foo{fixture}bar"))
405 .expect("Error"),
406 "Expected to NOT match '{}' with regex '{}'",
407 fixture,
408 re.as_str()
409 );
410 }
411
412 for fixture in &v6not {
414 let re = build_regex_rt(
415 &RegexType::V4V6,
416 Some(&Options {
417 exact: true,
418 include_boundaries: false,
419 }),
420 );
421 assert!(
422 !re.is_match(fixture).expect("Error"),
423 "Expected to NOT match '{}' with regex '{}'",
424 fixture,
425 re.as_str()
426 );
427 }
428
429 for (fixture, expected) in &v4boundaries {
431 let re = build_regex_rt(&RegexType::V4, None);
432 assert!(
433 re.is_match(fixture).expect("Error"),
434 "Expected to match '{}' with regex '{}'",
435 fixture,
436 re.as_str()
437 );
438
439 let matches: Vec<&str> = re
441 .find(fixture)
442 .expect("Error")
443 .map(|m| m.as_str())
444 .into_iter()
445 .collect();
446 assert_eq!(
447 &matches,
448 expected,
449 "Expected to match '{}' with regex '{}'",
450 fixture,
451 re.as_str()
452 );
453
454 let re_bound = build_regex_rt(
455 &RegexType::V4,
456 Some(&Options {
457 exact: false,
458 include_boundaries: true,
459 }),
460 );
461 assert!(!re_bound.is_match(fixture).expect("Error"));
462 let matches2: Vec<&str> = re_bound
463 .find(fixture)
464 .expect("Error")
465 .map(|m| m.as_str())
466 .into_iter()
467 .collect();
468 assert!(
469 matches2.is_empty(),
470 "Expected to find no matches for '{}' with regex '{}'",
471 fixture,
472 re_bound.as_str()
473 );
474 }
475
476 for (fixture, expected) in &v4extract {
477 let re = build_regex_rt(&RegexType::V4, None);
478 let matches: Vec<&str> = re
479 .find_iter(fixture)
480 .map(|m| m.expect("Error").as_str())
481 .collect();
482 assert_eq!(
483 &matches,
484 expected,
485 "Expected to match '{}' with regex '{}'",
486 fixture,
487 re.as_str()
488 );
489 }
490
491 for (fixture, expected) in &v6boundaries {
493 let re = build_regex_rt(&RegexType::V6, None);
494 assert!(re.is_match(fixture).expect("Error"));
495 let matches: Vec<&str> = re
496 .find(fixture)
497 .expect("Error")
498 .map(|m| m.as_str())
499 .into_iter()
500 .collect();
501 assert_eq!(
502 &matches,
503 expected,
504 "Expected to match '{}' with regex '{}'",
505 fixture,
506 re.as_str()
507 );
508
509 let re_bound = build_regex_rt(
510 &RegexType::V6,
511 Some(&Options {
512 exact: false,
513 include_boundaries: true,
514 }),
515 );
516 assert!(
517 !re_bound.is_match(fixture).expect("Error"),
518 "Expected to NOT match '{}' with regex '{}'",
519 fixture,
520 re_bound.as_str()
521 );
522 let matches2: Vec<&str> = re_bound
523 .find(fixture)
524 .expect("Error")
525 .map(|m| m.as_str())
526 .into_iter()
527 .collect();
528 assert!(
529 matches2.is_empty(),
530 "Expected to find no matches for '{}' with regex '{}'",
531 fixture,
532 re_bound.as_str()
533 );
534 }
535
536 for (fixture, expected) in &v6extract {
537 let re = build_regex_rt(&RegexType::V6, None);
538 let matches: Vec<&str> = re
539 .find_iter(fixture)
540 .map(|m| m.expect("Error").as_str())
541 .collect();
542 assert_eq!(
543 &matches,
544 expected,
545 "Expected to match '{}' with regex '{}'",
546 fixture,
547 re.as_str()
548 );
549 }
550 }
551
552 #[test]
553 #[allow(clippy::too_many_lines)]
554 fn test_ip_v4() {
555 let v4 = v4();
556 let v4not = v4not();
557 for fixture in &v4 {
559 let re = build_regex_rt(
560 &RegexType::V4,
561 Some(&Options {
562 exact: true,
563 include_boundaries: false,
564 }),
565 );
566 assert!(re.is_match(fixture).expect("Error"));
567 }
568
569 for fixture in &v4 {
570 let re = build_regex_rt(&RegexType::V4, None);
571 let haystack = format!("foo {fixture} bar");
572 let caps = re.find(&haystack).expect("Error");
573 assert_eq!(
574 caps.map(|m| m.as_str()),
575 Some(fixture.as_str()),
576 "Expected to match '{}' with regex '{}'",
577 fixture,
578 re.as_str()
579 );
580 }
581
582 for fixture in &v4 {
583 let re = build_regex_rt(&RegexType::V4, None);
584 assert!(
585 re.is_match(&format!("foo{fixture}bar")).expect("Error"),
586 "Expected to match '{}' with regex '{}'",
587 fixture,
588 re.as_str()
589 );
590
591 let re_bound = build_regex_rt(
592 &RegexType::V4,
593 Some(&Options {
594 exact: false,
595 include_boundaries: true,
596 }),
597 );
598 assert!(
599 !re_bound
600 .is_match(&format!("foo{fixture}bar"))
601 .expect("Error"),
602 "Expected to match '{}' with regex '{}'",
603 fixture,
604 re.as_str()
605 );
606 }
607
608 for fixture in &v4not {
609 let re = build_regex_rt(
610 &RegexType::V4,
611 Some(&Options {
612 exact: true,
613 include_boundaries: false,
614 }),
615 );
616 assert!(!re.is_match(fixture).expect("Error"));
617 }
618
619 let mut v4boundaries: HashMap<&str, Vec<&str>> = HashMap::new();
621 v4boundaries.insert("0000000192.168.0.200", vec!["192.168.0.200"]);
622 v4boundaries.insert("192.168.0.2000000000", vec!["192.168.0.200"]);
623
624 let mut v4extract: HashMap<&str, Vec<&str>> = HashMap::new();
625 v4extract.insert(
626 "255.255.255.255 0.0.0.0",
627 vec!["255.255.255.255", "0.0.0.0"],
628 );
629 v4extract.insert(
630 "1.2.3.4, 6.7.8.9, 1.2.3.4-5.6.7.8",
631 vec!["1.2.3.4", "6.7.8.9", "1.2.3.4", "5.6.7.8"],
632 );
633 v4extract.insert(
634 "1.2.3.4 6.7.8.9 1.2.3.4 - 5.6.7.8",
635 vec!["1.2.3.4", "6.7.8.9", "1.2.3.4", "5.6.7.8"],
636 );
637 v4extract.insert("192.168.0.2000000000", vec!["192.168.0.200"]);
638
639 for (fixture, expected) in &v4boundaries {
640 let re = build_regex_rt(&RegexType::V4, None);
641 assert!(re.is_match(fixture).expect("Error"));
642 let matches: Vec<&str> = re
643 .find(fixture)
644 .expect("Error")
645 .map(|m| m.as_str())
646 .into_iter()
647 .collect();
648 assert_eq!(&matches, expected);
649
650 let re_bound = build_regex_rt(
651 &RegexType::V4,
652 Some(&Options {
653 exact: false,
654 include_boundaries: true,
655 }),
656 );
657 assert!(!re_bound.is_match(fixture).expect("Error"));
658 let matches2: Vec<&str> = re_bound
659 .find(fixture)
660 .expect("Error")
661 .map(|m| m.as_str())
662 .into_iter()
663 .collect();
664 assert!(matches2.is_empty());
665 }
666
667 for (fixture, expected) in &v4extract {
668 let re = build_regex_rt(&RegexType::V4, None);
669 let matches: Vec<&str> = re
670 .find_iter(fixture)
671 .map(|m| m.expect("Error").as_str())
672 .collect();
673 assert_eq!(&matches, expected);
674 }
675 }
676
677 #[test]
678 #[allow(clippy::too_many_lines)]
679 fn test_ip_v6() {
680 let v6 = v6();
681 let v6not = v6not();
682 for fixture in &v6 {
684 let re = build_regex_rt(
685 &RegexType::V6,
686 Some(&Options {
687 exact: true,
688 include_boundaries: false,
689 }),
690 );
691 assert!(re.is_match(fixture).expect("Error"));
692 }
693
694 for fixture in &v6 {
695 let re = build_regex_rt(&RegexType::V6, None);
696 let haystack = format!("foo {fixture} bar");
697 let caps = re.find(&haystack).expect("Error");
698 assert_eq!(caps.map(|m| m.as_str()), Some(fixture.as_str()));
699 }
700
701 for fixture in &v6 {
702 let re = build_regex_rt(&RegexType::V6, None);
703 assert!(re.is_match(&format!("foo{fixture}bar")).expect("Error"));
704
705 let re_bound = build_regex_rt(
706 &RegexType::V6,
707 Some(&Options {
708 exact: false,
709 include_boundaries: true,
710 }),
711 );
712 assert!(
713 !re_bound
714 .is_match(&format!("foo{fixture}bar"))
715 .expect("Error")
716 );
717 }
718
719 for fixture in &v6not {
720 let re = build_regex_rt(
721 &RegexType::V6,
722 Some(&Options {
723 exact: true,
724 include_boundaries: false,
725 }),
726 );
727 assert!(!re.is_match(fixture).expect("Error"));
728 }
729
730 let mut v6boundaries: HashMap<&str, Vec<&str>> = HashMap::new();
732 v6boundaries.insert(
733 "02001:0000:1234:0000:0000:C1C0:ABCD:0876",
734 vec!["2001:0000:1234:0000:0000:C1C0:ABCD:0876"],
735 );
736 v6boundaries.insert(
737 "fe80:0000:0000:0000:0204:61ff:fe9d:f156245",
738 vec!["fe80:0000:0000:0000:0204:61ff:fe9d:f156"],
739 );
740
741 let mut v6extract: HashMap<&str, Vec<&str>> = HashMap::new();
742 v6extract.insert("::1, ::2, ::3-::5", vec!["::1", "::2", "::3", "::5"]);
743 v6extract
744 .insert("::1 ::2 ::3 - ::5", vec!["::1", "::2", "::3", "::5"]);
745 v6extract.insert(
746 "::ffff:192.168.1.1 1::1.2.3.4",
747 vec!["::ffff:192.168.1.1", "1::1.2.3.4"],
748 );
749 v6extract.insert(
750 "02001:0000:1234:0000:0000:C1C0:ABCD:0876 a::xyz",
751 vec!["2001:0000:1234:0000:0000:C1C0:ABCD:0876", "a::"],
752 );
753
754 for (fixture, expected) in &v6boundaries {
755 let re = build_regex_rt(&RegexType::V6, None);
756 assert!(re.is_match(fixture).expect("Error"));
757 let matches: Vec<&str> = re
758 .find(fixture)
759 .expect("Error")
760 .map(|m| m.as_str())
761 .into_iter()
762 .collect();
763 assert_eq!(
764 &matches,
765 expected,
766 "Expected to match '{}' with regex '{}'",
767 fixture,
768 re.as_str()
769 );
770
771 let re_bound = build_regex_rt(
772 &RegexType::V6,
773 Some(&Options {
774 exact: false,
775 include_boundaries: true,
776 }),
777 );
778 assert!(
779 !re_bound.is_match(fixture).expect("Error"),
780 "Expected to NOT match '{}' with regex '{}'",
781 fixture,
782 re_bound.as_str()
783 );
784 let matches2: Vec<&str> = re_bound
785 .find(fixture)
786 .expect("Error")
787 .map(|m| m.as_str())
788 .into_iter()
789 .collect();
790 assert!(
791 matches2.is_empty(),
792 "Expected to find no matches for '{}' with regex '{}'",
793 fixture,
794 re_bound.as_str()
795 );
796 }
797
798 for (fixture, expected) in &v6extract {
799 let re = build_regex_rt(&RegexType::V6, None);
800 let matches: Vec<&str> = re
801 .find_iter(fixture)
802 .map(|m| m.expect("Error").as_str())
803 .collect();
804 assert_eq!(
805 &matches,
806 expected,
807 "Expected to match '{}' with regex '{}'",
808 fixture,
809 re.as_str()
810 );
811 }
812 }
813
814 #[crate::ctb_test]
815 #[should_panic(
816 expected = "Cannot set both exact and include_boundaries options to true"
817 )]
818 fn test_disallows_both_options() {
819 get_regex(
820 &RegexType::V4V6,
821 Some(&Options {
822 exact: true,
823 include_boundaries: true,
824 }),
825 );
826 }
827
828 #[crate::ctb_test]
829 fn test_compatible() {
830 let inexact_no_boundaries = Some(&Options {
832 exact: false,
833 include_boundaries: false,
834 });
835 let inexact_boundaries = Some(&Options {
836 exact: false,
837 include_boundaries: true,
838 });
839 let exact_no_boundaries = Some(&Options {
840 exact: true,
841 include_boundaries: false,
842 });
843
844 let both_inexact_no_boundaries =
845 get_regex(&RegexType::V4V6, inexact_no_boundaries);
846 let expected = "(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3})|(?:(?:(?:[a-fA-F\\d]{1,4}:){7}(?:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,2}|:)|(?:[a-fA-F\\d]{1,4}:){4}(?:(?::[a-fA-F\\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,3}|:)|(?:[a-fA-F\\d]{1,4}:){3}(?:(?::[a-fA-F\\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,4}|:)|(?:[a-fA-F\\d]{1,4}:){2}(?:(?::[a-fA-F\\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,5}|:)|(?:[a-fA-F\\d]{1,4}:){1}(?:(?::[a-fA-F\\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?)";
847 assert_eq!(both_inexact_no_boundaries, expected);
848
849 let both_inexact_boundaries =
850 get_regex(&RegexType::V4V6, inexact_boundaries);
851 let expected = "(?:(?:(?<=\\s|^)(?=[a-fA-F\\d:])|(?<=[a-fA-F\\d:])(?=\\s|$))(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}(?:(?<=\\s|^)(?=[a-fA-F\\d:])|(?<=[a-fA-F\\d:])(?=\\s|$)))|(?:(?:(?<=\\s|^)(?=[a-fA-F\\d:])|(?<=[a-fA-F\\d:])(?=\\s|$))(?:(?:[a-fA-F\\d]{1,4}:){7}(?:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,2}|:)|(?:[a-fA-F\\d]{1,4}:){4}(?:(?::[a-fA-F\\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,3}|:)|(?:[a-fA-F\\d]{1,4}:){3}(?:(?::[a-fA-F\\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,4}|:)|(?:[a-fA-F\\d]{1,4}:){2}(?:(?::[a-fA-F\\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,5}|:)|(?:[a-fA-F\\d]{1,4}:){1}(?:(?::[a-fA-F\\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?(?:(?<=\\s|^)(?=[a-fA-F\\d:])|(?<=[a-fA-F\\d:])(?=\\s|$)))";
852 assert_eq!(both_inexact_boundaries, expected);
853
854 let both_exact_no_boundaries =
855 get_regex(&RegexType::V4V6, exact_no_boundaries);
856 let expected = "(?:^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$)|(?:^(?:(?:[a-fA-F\\d]{1,4}:){7}(?:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,2}|:)|(?:[a-fA-F\\d]{1,4}:){4}(?:(?::[a-fA-F\\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,3}|:)|(?:[a-fA-F\\d]{1,4}:){3}(?:(?::[a-fA-F\\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,4}|:)|(?:[a-fA-F\\d]{1,4}:){2}(?:(?::[a-fA-F\\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,5}|:)|(?:[a-fA-F\\d]{1,4}:){1}(?:(?::[a-fA-F\\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$)";
857 assert_eq!(both_exact_no_boundaries, expected);
858
859 let v4_inexact_no_boundaries =
860 get_regex(&RegexType::V4, inexact_no_boundaries);
861 let expected = "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}";
862 assert_eq!(v4_inexact_no_boundaries, expected);
863
864 let v4_inexact_boundaries =
865 get_regex(&RegexType::V4, inexact_boundaries);
866 let expected = "(?:(?<=\\s|^)(?=[a-fA-F\\d:])|(?<=[a-fA-F\\d:])(?=\\s|$))(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}(?:(?<=\\s|^)(?=[a-fA-F\\d:])|(?<=[a-fA-F\\d:])(?=\\s|$))";
867 assert_eq!(v4_inexact_boundaries, expected);
868
869 let v4_exact_no_boundaries =
870 get_regex(&RegexType::V4, exact_no_boundaries);
871 let expected = "^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$";
872 assert_eq!(v4_exact_no_boundaries, expected);
873
874 let v6_inexact_no_boundaries =
875 get_regex(&RegexType::V6, inexact_no_boundaries);
876 let expected = "(?:(?:[a-fA-F\\d]{1,4}:){7}(?:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,2}|:)|(?:[a-fA-F\\d]{1,4}:){4}(?:(?::[a-fA-F\\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,3}|:)|(?:[a-fA-F\\d]{1,4}:){3}(?:(?::[a-fA-F\\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,4}|:)|(?:[a-fA-F\\d]{1,4}:){2}(?:(?::[a-fA-F\\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,5}|:)|(?:[a-fA-F\\d]{1,4}:){1}(?:(?::[a-fA-F\\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?";
877 assert_eq!(v6_inexact_no_boundaries, expected);
878
879 let v6_inexact_boundaries =
880 get_regex(&RegexType::V6, inexact_boundaries);
881 let expected = "(?:(?<=\\s|^)(?=[a-fA-F\\d:])|(?<=[a-fA-F\\d:])(?=\\s|$))(?:(?:[a-fA-F\\d]{1,4}:){7}(?:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,2}|:)|(?:[a-fA-F\\d]{1,4}:){4}(?:(?::[a-fA-F\\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,3}|:)|(?:[a-fA-F\\d]{1,4}:){3}(?:(?::[a-fA-F\\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,4}|:)|(?:[a-fA-F\\d]{1,4}:){2}(?:(?::[a-fA-F\\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,5}|:)|(?:[a-fA-F\\d]{1,4}:){1}(?:(?::[a-fA-F\\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?(?:(?<=\\s|^)(?=[a-fA-F\\d:])|(?<=[a-fA-F\\d:])(?=\\s|$))";
882 assert_eq!(v6_inexact_boundaries, expected);
883
884 let v6_exact_no_boundaries =
885 get_regex(&RegexType::V6, exact_no_boundaries);
886 let expected = "^(?:(?:[a-fA-F\\d]{1,4}:){7}(?:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|:[a-fA-F\\d]{1,4}|:)|(?:[a-fA-F\\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,2}|:)|(?:[a-fA-F\\d]{1,4}:){4}(?:(?::[a-fA-F\\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,3}|:)|(?:[a-fA-F\\d]{1,4}:){3}(?:(?::[a-fA-F\\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,4}|:)|(?:[a-fA-F\\d]{1,4}:){2}(?:(?::[a-fA-F\\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,5}|:)|(?:[a-fA-F\\d]{1,4}:){1}(?:(?::[a-fA-F\\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$";
887 assert_eq!(v6_exact_no_boundaries, expected);
888 }
889
890 fn v4() -> Vec<String> {
891 let vec = vec![
892 "0.0.0.0",
893 "8.8.8.8",
894 "127.0.0.1",
895 "100.100.100.100",
896 "192.168.0.1",
897 "18.101.25.153",
898 "123.23.34.2",
899 "172.26.168.134",
900 "212.58.241.131",
901 "128.0.0.0",
902 "23.71.254.72",
903 "223.255.255.255",
904 "192.0.2.235",
905 "99.198.122.146",
906 "46.51.197.88",
907 "173.194.34.134",
908 ];
909
910 vec.into_iter().map(String::from).collect()
911 }
912
913 fn v4not() -> Vec<String> {
914 let vec = vec![
915 ".100.100.100.100",
916 "100..100.100.100.",
917 "100.100.100.100.",
918 "999.999.999.999",
919 "256.256.256.256",
920 "256.100.100.100.100",
921 "123.123.123",
922 "http://123.123.123",
923 "1000.2.3.4",
924 "999.2.3.4",
925 ];
926
927 vec.into_iter().map(String::from).collect()
928 }
929
930 #[allow(clippy::too_many_lines)]
931 fn v6() -> Vec<String> {
932 let vec = vec![
933 "::",
934 "1::",
935 "::1",
936 "1::8",
937 "1::7:8",
938 "1:2:3:4:5:6:7:8",
939 "1:2:3:4:5:6::8",
940 "1:2:3:4:5:6:7::",
941 "1:2:3:4:5::7:8",
942 "1:2:3:4:5::8",
943 "1:2:3::8",
944 "1::4:5:6:7:8",
945 "1::6:7:8",
946 "1::3:4:5:6:7:8",
947 "1:2:3:4::6:7:8",
948 "1:2::4:5:6:7:8",
949 "::2:3:4:5:6:7:8",
950 "1:2::8",
951 "2001:0000:1234:0000:0000:C1C0:ABCD:0876",
952 "3ffe:0b00:0000:0000:0001:0000:0000:000a",
953 "FF02:0000:0000:0000:0000:0000:0000:0001",
954 "0000:0000:0000:0000:0000:0000:0000:0001",
955 "0000:0000:0000:0000:0000:0000:0000:0000",
956 "::ffff:192.168.1.26",
957 "2::10",
958 "ff02::1",
959 "fe80::",
960 "2002::",
961 "2001:db8::",
962 "2001:0db8:1234::",
963 "::ffff:0:0",
964 "::ffff:192.168.1.1",
965 "1:2:3:4::8",
966 "1::2:3:4:5:6:7",
967 "1::2:3:4:5:6",
968 "1::2:3:4:5",
969 "1::2:3:4",
970 "1::2:3",
971 "::2:3:4:5:6:7",
972 "::2:3:4:5:6",
973 "::2:3:4:5",
974 "::2:3:4",
975 "::2:3",
976 "::8",
977 "1:2:3:4:5:6::",
978 "1:2:3:4:5::",
979 "1:2:3:4::",
980 "1:2:3::",
981 "1:2::",
982 "1:2:3:4::7:8",
983 "1:2:3::7:8",
984 "1:2::7:8",
985 "1:2:3:4:5:6:1.2.3.4",
986 "1:2:3:4:5::1.2.3.4",
987 "1:2:3:4::1.2.3.4",
988 "1:2:3::1.2.3.4",
989 "1:2::1.2.3.4",
990 "1::1.2.3.4",
991 "1:2:3:4::5:1.2.3.4",
992 "1:2:3::5:1.2.3.4",
993 "1:2::5:1.2.3.4",
994 "1::5:1.2.3.4",
995 "1::5:11.22.33.44",
996 "fe80::217:f2ff:254.7.237.98",
997 "fe80::217:f2ff:fe07:ed62",
998 "2001:DB8:0:0:8:800:200C:417A",
999 "FF01:0:0:0:0:0:0:101",
1000 "0:0:0:0:0:0:0:1",
1001 "0:0:0:0:0:0:0:0",
1002 "2001:DB8::8:800:200C:417A",
1003 "FF01::101",
1004 "0:0:0:0:0:0:13.1.68.3",
1005 "0:0:0:0:0:FFFF:129.144.52.38",
1006 "::13.1.68.3",
1007 "::FFFF:129.144.52.38",
1008 "fe80:0000:0000:0000:0204:61ff:fe9d:f156",
1009 "fe80:0:0:0:204:61ff:fe9d:f156",
1010 "fe80::204:61ff:fe9d:f156",
1011 "fe80:0:0:0:204:61ff:254.157.241.86",
1012 "fe80::204:61ff:254.157.241.86",
1013 "fe80::1",
1014 "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
1015 "2001:db8:85a3:0:0:8a2e:370:7334",
1016 "2001:db8:85a3::8a2e:370:7334",
1017 "2001:0db8:0000:0000:0000:0000:1428:57ab",
1018 "2001:0db8:0000:0000:0000::1428:57ab",
1019 "2001:0db8:0:0:0:0:1428:57ab",
1020 "2001:0db8:0:0::1428:57ab",
1021 "2001:0db8::1428:57ab",
1022 "2001:db8::1428:57ab",
1023 "::ffff:12.34.56.78",
1024 "::ffff:0c22:384e",
1025 "2001:0db8:1234:0000:0000:0000:0000:0000",
1026 "2001:0db8:1234:ffff:ffff:ffff:ffff:ffff",
1027 "2001:db8:a::123",
1028 "::ffff:192.0.2.128",
1029 "::ffff:c000:280",
1030 "a:b:c:d:e:f:f1:f2",
1031 "a:b:c::d:e:f:f1",
1032 "a:b:c::d:e:f",
1033 "a:b:c::d:e",
1034 "a:b:c::d",
1035 "::a",
1036 "::a:b:c",
1037 "::a:b:c:d:e:f:f1",
1038 "a::",
1039 "a:b:c::",
1040 "a:b:c:d:e:f:f1::",
1041 "a:bb:ccc:dddd:000e:00f:0f::",
1042 "0:a:0:a:0:0:0:a",
1043 "0:a:0:0:a:0:0:a",
1044 "2001:db8:1:1:1:1:0:0",
1045 "2001:db8:1:1:1:0:0:0",
1046 "2001:db8:1:1:0:0:0:0",
1047 "2001:db8:1:0:0:0:0:0",
1048 "2001:db8:0:0:0:0:0:0",
1049 "2001:0:0:0:0:0:0:0",
1050 "A:BB:CCC:DDDD:000E:00F:0F::",
1051 "0:0:0:0:0:0:0:a",
1052 "0:0:0:0:a:0:0:0",
1053 "0:0:0:a:0:0:0:0",
1054 "a:0:0:a:0:0:a:a",
1055 "a:0:0:a:0:0:0:a",
1056 "a:0:0:0:a:0:0:a",
1057 "a:0:0:0:a:0:0:0",
1058 "a:0:0:0:0:0:0:0",
1059 "fe80::7:8%eth0",
1060 "fe80::7:8%1",
1061 ];
1062
1063 vec.into_iter().map(String::from).collect()
1064 }
1065
1066 fn v6not() -> Vec<String> {
1067 let vec = vec![
1068 "",
1069 "1:",
1070 ":1",
1071 "11:36:12",
1072 "02001:0000:1234:0000:0000:C1C0:ABCD:0876",
1073 "2001:0000:1234:0000:00001:C1C0:ABCD:0876",
1074 "2001:0000:1234: 0000:0000:C1C0:ABCD:0876",
1075 "2001:1:1:1:1:1:255Z255X255Y255",
1076 "3ffe:0b00:0000:0001:0000:0000:000a",
1077 "FF02:0000:0000:0000:0000:0000:0000:0000:0001",
1078 "3ffe:b00::1::a",
1079 "::1111:2222:3333:4444:5555:6666::",
1080 "1:2:3::4:5::7:8",
1081 "12345::6:7:8",
1082 "1::5:400.2.3.4",
1083 "1::5:260.2.3.4",
1084 "1::5:256.2.3.4",
1085 "1::5:1.256.3.4",
1086 "1::5:1.2.256.4",
1087 "1::5:1.2.3.256",
1088 "1::5:300.2.3.4",
1089 "1::5:1.300.3.4",
1090 "1::5:1.2.300.4",
1091 "1::5:1.2.3.300",
1092 "1::5:900.2.3.4",
1093 "1::5:1.900.3.4",
1094 "1::5:1.2.900.4",
1095 "1::5:1.2.3.900",
1096 "1::5:300.300.300.300",
1097 "1::5:3000.30.30.30",
1098 "1::400.2.3.4",
1099 "1::260.2.3.4",
1100 "1::256.2.3.4",
1101 "1::1.256.3.4",
1102 "1::1.2.256.4",
1103 "1::1.2.3.256",
1104 "1::300.2.3.4",
1105 "1::1.300.3.4",
1106 "1::1.2.300.4",
1107 "1::1.2.3.300",
1108 "1::900.2.3.4",
1109 "1::1.900.3.4",
1110 "1::1.2.900.4",
1111 "1::1.2.3.900",
1112 "1::300.300.300.300",
1113 "1::3000.30.30.30",
1114 "::400.2.3.4",
1115 "::260.2.3.4",
1116 "::256.2.3.4",
1117 "::1.256.3.4",
1118 "::1.2.256.4",
1119 "::1.2.3.256",
1120 "::300.2.3.4",
1121 "::1.300.3.4",
1122 "::1.2.300.4",
1123 "::1.2.3.300",
1124 "::900.2.3.4",
1125 "::1.900.3.4",
1126 "::1.2.900.4",
1127 "::1.2.3.900",
1128 "::300.300.300.300",
1129 "::3000.30.30.30",
1130 "2001:DB8:0:0:8:800:200C:417A:221",
1131 "FF01::101::2",
1132 "1111:2222:3333:4444::5555:",
1133 "1111:2222:3333::5555:",
1134 "1111:2222::5555:",
1135 "1111::5555:",
1136 "::5555:",
1137 ":::",
1138 "1111:",
1139 ":",
1140 ":1111:2222:3333:4444::5555",
1141 ":1111:2222:3333::5555",
1142 ":1111:2222::5555",
1143 ":1111::5555",
1144 ":::5555",
1145 "1.2.3.4:1111:2222:3333:4444::5555",
1146 "1.2.3.4:1111:2222:3333::5555",
1147 "1.2.3.4:1111:2222::5555",
1148 "1.2.3.4:1111::5555",
1149 "1.2.3.4::5555",
1150 "1.2.3.4::",
1151 "fe80:0000:0000:0000:0204:61ff:254.157.241.086",
1152 "123",
1153 "ldkfj",
1154 "2001::FFD3::57ab",
1155 "2001:db8:85a3::8a2e:37023:7334",
1156 "2001:db8:85a3::8a2e:370k:7334",
1157 "1:2:3:4:5:6:7:8:9",
1158 "1::2::3",
1159 "1:::3:4:5",
1160 "1:2:3::4:5:6:7:8:9",
1161 "::ffff:2.3.4",
1162 "::ffff:257.1.2.3",
1163 "::ffff:12345678901234567890.1.26",
1164 ];
1165
1166 vec.into_iter().map(String::from).collect()
1167 }
1168}