1use crate::models::*;
116use crate::parser::ComparableRegex;
117use crate::ParserError;
118use crate::ParserError::FilterError;
119use ipnet::IpNet;
120use std::net::IpAddr;
121use std::str::FromStr;
122
123#[derive(Debug, Clone, PartialEq)]
144pub enum Filter {
145 OriginAsn(u32),
146 OriginAsns(Vec<u32>),
147 Prefix(IpNet, PrefixMatchType),
148 Prefixes(Vec<IpNet>, PrefixMatchType),
149 PeerIp(IpAddr),
150 PeerIps(Vec<IpAddr>),
151 PeerAsn(u32),
152 PeerAsns(Vec<u32>),
153 Type(ElemType),
154 IpVersion(IpVersion),
155 TsStart(f64),
156 TsEnd(f64),
157 AsPath(ComparableRegex),
158 Community(ComparableRegex),
159 Negated(Box<Filter>),
161}
162
163#[derive(Debug, Clone, PartialEq, Eq)]
164pub enum IpVersion {
165 Ipv4,
166 Ipv6,
167}
168
169#[derive(Debug, Clone, PartialEq, Eq)]
170pub enum PrefixMatchType {
171 Exact,
172 IncludeSuper,
173 IncludeSub,
174 IncludeSuperSub,
175}
176
177fn parse_time_str(time_str: &str) -> Option<chrono::NaiveDateTime> {
178 if let Ok(t) = time_str.parse::<f64>() {
179 return chrono::DateTime::from_timestamp(t as i64, 0).map(|t| t.naive_utc());
180 }
181 if let Ok(t) = chrono::DateTime::parse_from_rfc3339(time_str) {
182 return Some(t.naive_utc());
183 }
184 None
185}
186
187fn parse_asn_list(filter_value: &str) -> Result<(Vec<u32>, bool), ParserError> {
188 let mut asns = vec![];
189 let mut all_negated: Option<bool> = None;
190
191 for asn_str in filter_value.replace(' ', "").split(',') {
192 if asn_str.is_empty() {
194 continue;
195 }
196
197 let (is_negated, actual_value) = if let Some(stripped) = asn_str.strip_prefix('!') {
198 (true, stripped)
199 } else {
200 (false, asn_str)
201 };
202
203 match all_negated {
205 None => all_negated = Some(is_negated),
206 Some(prev) if prev != is_negated => {
207 return Err(FilterError(
208 "cannot mix positive and negative values in the same filter".to_string(),
209 ));
210 }
211 _ => {}
212 }
213
214 match u32::from_str(actual_value) {
215 Ok(v) => asns.push(v),
216 Err(_) => return Err(FilterError(format!("cannot parse ASN from {actual_value}"))),
217 }
218 }
219 if asns.is_empty() {
221 return Err(FilterError(
222 "ASN list filter requires at least one ASN".to_string(),
223 ));
224 }
225 Ok((asns, all_negated.unwrap_or(false)))
226}
227
228fn parse_prefix_list(filter_value: &str) -> Result<(Vec<IpNet>, bool), ParserError> {
229 let mut prefixes = vec![];
230 let mut all_negated: Option<bool> = None;
231
232 for prefix_str in filter_value.replace(' ', "").split(',') {
233 if prefix_str.is_empty() {
235 continue;
236 }
237
238 let (is_negated, actual_value) = if let Some(stripped) = prefix_str.strip_prefix('!') {
239 (true, stripped)
240 } else {
241 (false, prefix_str)
242 };
243
244 match all_negated {
246 None => all_negated = Some(is_negated),
247 Some(prev) if prev != is_negated => {
248 return Err(FilterError(
249 "cannot mix positive and negative values in the same filter".to_string(),
250 ));
251 }
252 _ => {}
253 }
254
255 match IpNet::from_str(actual_value) {
256 Ok(v) => prefixes.push(v),
257 Err(_) => {
258 return Err(FilterError(format!(
259 "cannot parse prefix from {actual_value}"
260 )))
261 }
262 }
263 }
264 if prefixes.is_empty() {
266 return Err(FilterError(
267 "prefix list filter requires at least one prefix".to_string(),
268 ));
269 }
270 Ok((prefixes, all_negated.unwrap_or(false)))
271}
272
273fn parse_ip_list(filter_value: &str) -> Result<(Vec<IpAddr>, bool), ParserError> {
274 let mut ips = vec![];
275 let mut all_negated: Option<bool> = None;
276
277 for ip_str in filter_value.replace(' ', "").split(',') {
278 if ip_str.is_empty() {
280 continue;
281 }
282
283 let (is_negated, actual_value) = if let Some(stripped) = ip_str.strip_prefix('!') {
284 (true, stripped)
285 } else {
286 (false, ip_str)
287 };
288
289 match all_negated {
291 None => all_negated = Some(is_negated),
292 Some(prev) if prev != is_negated => {
293 return Err(FilterError(
294 "cannot mix positive and negative values in the same filter".to_string(),
295 ));
296 }
297 _ => {}
298 }
299
300 match IpAddr::from_str(actual_value) {
301 Ok(v) => ips.push(v),
302 Err(_) => {
303 return Err(FilterError(format!(
304 "cannot parse IP address from {actual_value}"
305 )))
306 }
307 }
308 }
309 if ips.is_empty() {
311 return Err(FilterError(
312 "IP list filter requires at least one IP address".to_string(),
313 ));
314 }
315 Ok((ips, all_negated.unwrap_or(false)))
316}
317
318impl Filter {
319 pub fn new(filter_type: &str, filter_value: &str) -> Result<Filter, ParserError> {
320 let multi_value_filters = [
323 "origin_asns",
324 "prefixes",
325 "prefixes_super",
326 "prefixes_sub",
327 "prefixes_super_sub",
328 "peer_ips",
329 "peer_asns",
330 ];
331
332 if multi_value_filters.contains(&filter_type) {
333 return Self::new_base(filter_type, filter_value);
335 }
336
337 let (negated, actual_value) = if let Some(stripped) = filter_value.strip_prefix('!') {
339 if stripped.starts_with('!') {
341 return Err(FilterError(format!(
342 "invalid filter value '{}': double negation is not allowed",
343 filter_value
344 )));
345 }
346 (true, stripped)
347 } else {
348 (false, filter_value)
349 };
350
351 if negated
353 && (filter_type == "ts_start"
354 || filter_type == "start_ts"
355 || filter_type == "ts_end"
356 || filter_type == "end_ts")
357 {
358 return Err(FilterError(format!(
359 "timestamp filter '{}' does not support negation",
360 filter_type
361 )));
362 }
363
364 let base_filter = Self::new_base(filter_type, actual_value)?;
365
366 if negated {
367 Ok(Filter::Negated(Box::new(base_filter)))
368 } else {
369 Ok(base_filter)
370 }
371 }
372
373 fn new_base(filter_type: &str, filter_value: &str) -> Result<Filter, ParserError> {
374 match filter_type {
375 "origin_asn" => match u32::from_str(filter_value) {
376 Ok(v) => Ok(Filter::OriginAsn(v)),
377 Err(_) => Err(FilterError(format!(
378 "cannot parse origin asn from {filter_value}"
379 ))),
380 },
381 "origin_asns" => {
382 let (asns, negated) = parse_asn_list(filter_value)?;
383 let filter = Filter::OriginAsns(asns);
384 if negated {
385 Ok(Filter::Negated(Box::new(filter)))
386 } else {
387 Ok(filter)
388 }
389 }
390 "prefix" => match IpNet::from_str(filter_value) {
391 Ok(v) => Ok(Filter::Prefix(v, PrefixMatchType::Exact)),
392 Err(_) => Err(FilterError(format!(
393 "cannot parse prefix from {filter_value}"
394 ))),
395 },
396 "prefix_super" => match IpNet::from_str(filter_value) {
397 Ok(v) => Ok(Filter::Prefix(v, PrefixMatchType::IncludeSuper)),
398 Err(_) => Err(FilterError(format!(
399 "cannot parse prefix from {filter_value}"
400 ))),
401 },
402 "prefix_sub" => match IpNet::from_str(filter_value) {
403 Ok(v) => Ok(Filter::Prefix(v, PrefixMatchType::IncludeSub)),
404 Err(_) => Err(FilterError(format!(
405 "cannot parse prefix from {filter_value}"
406 ))),
407 },
408 "prefix_super_sub" => match IpNet::from_str(filter_value) {
409 Ok(v) => Ok(Filter::Prefix(v, PrefixMatchType::IncludeSuperSub)),
410 Err(_) => Err(FilterError(format!(
411 "cannot parse prefix from {filter_value}"
412 ))),
413 },
414 "prefixes" => {
415 let (prefixes, negated) = parse_prefix_list(filter_value)?;
416 let filter = Filter::Prefixes(prefixes, PrefixMatchType::Exact);
417 if negated {
418 Ok(Filter::Negated(Box::new(filter)))
419 } else {
420 Ok(filter)
421 }
422 }
423 "prefixes_super" => {
424 let (prefixes, negated) = parse_prefix_list(filter_value)?;
425 let filter = Filter::Prefixes(prefixes, PrefixMatchType::IncludeSuper);
426 if negated {
427 Ok(Filter::Negated(Box::new(filter)))
428 } else {
429 Ok(filter)
430 }
431 }
432 "prefixes_sub" => {
433 let (prefixes, negated) = parse_prefix_list(filter_value)?;
434 let filter = Filter::Prefixes(prefixes, PrefixMatchType::IncludeSub);
435 if negated {
436 Ok(Filter::Negated(Box::new(filter)))
437 } else {
438 Ok(filter)
439 }
440 }
441 "prefixes_super_sub" => {
442 let (prefixes, negated) = parse_prefix_list(filter_value)?;
443 let filter = Filter::Prefixes(prefixes, PrefixMatchType::IncludeSuperSub);
444 if negated {
445 Ok(Filter::Negated(Box::new(filter)))
446 } else {
447 Ok(filter)
448 }
449 }
450 "peer_ip" => match IpAddr::from_str(filter_value) {
451 Ok(v) => Ok(Filter::PeerIp(v)),
452 Err(_) => Err(FilterError(format!(
453 "cannot parse peer IP from {filter_value}"
454 ))),
455 },
456 "peer_ips" => {
457 let (ips, negated) = parse_ip_list(filter_value)?;
458 let filter = Filter::PeerIps(ips);
459 if negated {
460 Ok(Filter::Negated(Box::new(filter)))
461 } else {
462 Ok(filter)
463 }
464 }
465 "peer_asn" => match u32::from_str(filter_value) {
466 Ok(v) => Ok(Filter::PeerAsn(v)),
467 Err(_) => Err(FilterError(format!(
468 "cannot parse peer asn from {filter_value}"
469 ))),
470 },
471 "peer_asns" => {
472 let (asns, negated) = parse_asn_list(filter_value)?;
473 let filter = Filter::PeerAsns(asns);
474 if negated {
475 Ok(Filter::Negated(Box::new(filter)))
476 } else {
477 Ok(filter)
478 }
479 }
480 "type" => match filter_value {
481 "w" | "withdraw" | "withdrawal" => Ok(Filter::Type(ElemType::WITHDRAW)),
482 "a" | "announce" | "announcement" => Ok(Filter::Type(ElemType::ANNOUNCE)),
483 _ => Err(FilterError(format!(
484 "cannot parse elem type from {filter_value}"
485 ))),
486 },
487 "ts_start" | "start_ts" => match parse_time_str(filter_value) {
488 Some(t) => Ok(Filter::TsStart(t.and_utc().timestamp() as f64)),
489 None => Err(FilterError(format!(
490 "cannot parse TsStart filter from {filter_value}"
491 ))),
492 },
493 "ts_end" | "end_ts" => match parse_time_str(filter_value) {
494 Some(t) => Ok(Filter::TsEnd(t.and_utc().timestamp() as f64)),
495 None => Err(FilterError(format!(
496 "cannot parse TsEnd filter from {filter_value}"
497 ))),
498 },
499 "as_path" => match ComparableRegex::new(filter_value) {
500 Ok(v) => Ok(Filter::AsPath(v)),
501 Err(_) => Err(FilterError(format!(
502 "cannot parse AS path regex from {filter_value}"
503 ))),
504 },
505 "community" => match ComparableRegex::new(filter_value) {
506 Ok(v) => Ok(Filter::Community(v)),
507 Err(_) => Err(FilterError(format!(
508 "cannot parse Community regex from {filter_value}"
509 ))),
510 },
511 "ip_version" | "ip" => match filter_value {
512 "4" | "v4" | "ipv4" => Ok(Filter::IpVersion(IpVersion::Ipv4)),
513 "6" | "v6" | "ipv6" => Ok(Filter::IpVersion(IpVersion::Ipv6)),
514 _ => Err(FilterError(format!(
515 "cannot parse IP version from {filter_value}"
516 ))),
517 },
518 _ => Err(FilterError(format!("unknown filter type: {filter_type}"))),
519 }
520 }
521}
522
523pub trait Filterable {
524 fn match_filter(&self, filter: &Filter) -> bool;
525 fn match_filters(&self, filters: &[Filter]) -> bool;
526}
527
528const fn same_family(prefix_1: &IpNet, prefix_2: &IpNet) -> bool {
529 matches!(
530 (prefix_1, prefix_2),
531 (IpNet::V4(_), IpNet::V4(_)) | (IpNet::V6(_), IpNet::V6(_))
532 )
533}
534
535fn prefix_match(match_prefix: &IpNet, input_prefix: &IpNet, t: &PrefixMatchType) -> bool {
536 let exact = input_prefix.eq(match_prefix);
537 match t {
538 PrefixMatchType::Exact => exact,
539 PrefixMatchType::IncludeSuper => {
540 if exact {
541 exact
542 } else if !same_family(match_prefix, input_prefix) {
543 false
545 } else {
546 match_prefix.addr() >= input_prefix.addr()
548 && match_prefix.broadcast() <= input_prefix.broadcast()
549 }
550 }
551 PrefixMatchType::IncludeSub => {
552 if exact {
553 exact
554 } else if !same_family(match_prefix, input_prefix) {
555 false
557 } else {
558 match_prefix.addr() <= input_prefix.addr()
560 && match_prefix.broadcast() >= input_prefix.broadcast()
561 }
562 }
563 PrefixMatchType::IncludeSuperSub => {
564 if exact {
565 exact
566 } else if !same_family(match_prefix, input_prefix) {
567 false
569 } else {
570 (match_prefix.addr() >= input_prefix.addr()
572 && match_prefix.broadcast() <= input_prefix.broadcast())
573 || (match_prefix.addr() <= input_prefix.addr()
574 && match_prefix.broadcast() >= input_prefix.broadcast())
575 }
576 }
577 }
578}
579
580impl Filterable for BgpElem {
581 fn match_filter(&self, filter: &Filter) -> bool {
582 match filter {
583 Filter::Negated(inner) => !self.match_filter(inner),
584 Filter::OriginAsn(v) => {
585 let asn: Asn = (*v).into();
586 if let Some(origins) = &self.origin_asns {
587 origins.contains(&asn)
588 } else {
589 false
590 }
591 }
592 Filter::OriginAsns(v) => {
593 if let Some(origins) = &self.origin_asns {
594 v.iter().any(|asn| {
595 let asn_obj: Asn = (*asn).into();
596 origins.contains(&asn_obj)
597 })
598 } else {
599 false
600 }
601 }
602 Filter::Prefix(v, t) => prefix_match(v, &self.prefix.prefix, t),
603 Filter::Prefixes(v, t) => v
604 .iter()
605 .any(|prefix| prefix_match(prefix, &self.prefix.prefix, t)),
606 Filter::PeerIp(v) => self.peer_ip == *v,
607 Filter::PeerIps(v) => v.contains(&self.peer_ip),
608 Filter::PeerAsn(v) => self.peer_asn.eq(v),
609 Filter::PeerAsns(v) => v.iter().any(|asn| self.peer_asn.eq(asn)),
610 Filter::Type(v) => self.elem_type.eq(v),
611 Filter::TsStart(v) => self.timestamp >= *v,
612 Filter::TsEnd(v) => self.timestamp <= *v,
613 Filter::AsPath(v) => {
614 if let Some(path) = &self.as_path {
615 v.is_match(path.to_string().as_str())
616 } else {
617 false
618 }
619 }
620 Filter::Community(r) => {
621 if let Some(communities) = &self.communities {
622 communities.iter().any(|c| r.is_match(c.to_string()))
623 } else {
624 false
625 }
626 }
627 Filter::IpVersion(version) => match version {
628 IpVersion::Ipv4 => self.prefix.prefix.addr().is_ipv4(),
629 IpVersion::Ipv6 => self.prefix.prefix.addr().is_ipv6(),
630 },
631 }
632 }
633
634 fn match_filters(&self, filters: &[Filter]) -> bool {
635 filters.iter().all(|f| self.match_filter(f))
636 }
637}
638
639#[cfg(test)]
640mod tests {
641 use super::*;
642 use crate::BgpkitParser;
643 use anyhow::Result;
644 use std::str::FromStr;
645
646 #[test]
647 fn test_filters_on_mrt_file() {
648 let url = "https://spaces.bgpkit.org/parser/update-example.gz";
649 let parser = BgpkitParser::new(url).unwrap();
650 let elems = parser.into_elem_iter().collect::<Vec<BgpElem>>();
651
652 let filters = vec![Filter::PeerIp(IpAddr::from_str("185.1.8.65").unwrap())];
653 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
654 assert_eq!(count, 3393);
655
656 let filters = vec![
657 Filter::PeerIp(IpAddr::from_str("185.1.8.65").unwrap()),
658 Filter::Prefix(
659 IpNet::from_str("190.115.192.0/22").unwrap(),
660 PrefixMatchType::Exact,
661 ),
662 ];
663 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
664 assert_eq!(count, 5);
665
666 let filters = vec![Filter::Prefix(
667 IpNet::from_str("190.115.192.0/24").unwrap(),
668 PrefixMatchType::IncludeSuper,
669 )];
670 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
671 assert_eq!(count, 18);
672
673 let filters = vec![Filter::Prefix(
674 IpNet::from_str("190.115.192.0/22").unwrap(),
675 PrefixMatchType::IncludeSub,
676 )];
677 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
678 assert_eq!(count, 42);
679
680 let filters = vec![Filter::Prefix(
681 IpNet::from_str("190.115.192.0/23").unwrap(),
682 PrefixMatchType::IncludeSuperSub,
683 )];
684 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
685 assert_eq!(count, 24);
686
687 let filters = vec![Filter::new("as_path", r" ?174 1916 52888$").unwrap()];
688 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
689 assert_eq!(count, 12);
690
691 let filters = vec![Filter::new("community", r"60924:.*").unwrap()];
693 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
694 assert_eq!(count, 4243);
695
696 let filters = vec![Filter::new("community", r".+:784$").unwrap()];
698 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
699 assert_eq!(count, 107);
700
701 let filters = vec![Filter::new("community", r"\d+:\d+:\d+$").unwrap()];
703 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
704 assert_eq!(count, 4397);
705
706 let filters = vec![
707 Filter::TsStart(1637437798_f64),
708 Filter::TsEnd(1637437798_f64),
709 ];
710 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
711 assert_eq!(count, 13);
712
713 let filters = vec![Filter::Type(ElemType::WITHDRAW)];
714 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
715 assert_eq!(count, 379);
716
717 let filters = vec![
718 Filter::Type(ElemType::WITHDRAW),
719 Filter::Prefix(
720 IpNet::from_str("2804:100::/32").unwrap(),
721 PrefixMatchType::Exact,
722 ),
723 ];
724 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
725 assert_eq!(count, 1);
726
727 let filters = vec![Filter::PeerIps(vec![
738 IpAddr::from_str("185.1.8.65").unwrap(),
739 IpAddr::from_str("2001:7f8:73:0:3:fa4:0:1").unwrap(),
740 ])];
741 let count = elems.iter().filter(|e| e.match_filters(&filters)).count();
742 assert_eq!(count, 3393 + 834);
743 }
744
745 #[test]
746 fn test_filter_incorrect_filters() {
747 let incorrect_filters = [
749 Filter::new("community", r"[abc"),
750 Filter::new("as_path", r"[0-9"),
751 Filter::new("prefix_super_sub", "-192.-168.-1.1/24"),
752 ];
753 assert!(incorrect_filters
754 .iter()
755 .all(|f| matches!(f, Err(FilterError(_)))));
756 }
757
758 #[test]
759 fn test_parsing_time_str() {
760 let ts = chrono::NaiveDateTime::from_str("2021-11-20T19:49:58").unwrap();
761 assert_eq!(parse_time_str("1637437798"), Some(ts));
762 assert_eq!(parse_time_str("2021-11-20T19:49:58Z"), Some(ts));
763 assert_eq!(parse_time_str("2021-11-20T19:49:58+00:00"), Some(ts));
764
765 assert_eq!(parse_time_str("2021-11-20T19:49:58"), None);
766 assert_eq!(parse_time_str("2021-11-20T19:49:58ZDXV"), None);
767 assert_eq!(parse_time_str("2021-11-20 19:49:58"), None);
768 assert_eq!(parse_time_str("2021-11-20"), None);
769 }
770
771 #[test]
772 fn test_filter_iter() -> Result<()> {
773 let url = "https://spaces.bgpkit.org/parser/update-example.gz";
774 let parser = BgpkitParser::new(url)?
775 .add_filter("peer_ip", "185.1.8.50")?
776 .add_filter("type", "w")?;
777 let count = parser.into_elem_iter().count();
778 assert_eq!(count, 39);
779
780 let parser = BgpkitParser::new(url)?
781 .add_filter("ts_start", "1637437798")?
782 .add_filter("ts_end", "2021-11-20T19:49:58Z")?;
783 let count = parser.into_elem_iter().count();
784 assert_eq!(count, 13);
785 Ok(())
786 }
787
788 #[test]
789 fn test_filter_iter_with_negation() -> Result<()> {
790 let url = "https://spaces.bgpkit.org/parser/update-example.gz";
791
792 let parser = BgpkitParser::new(url)?.add_filter("peer_ip", "!185.1.8.65")?;
795 let count = parser.into_elem_iter().count();
796 assert_eq!(count, 8160 - 3393);
797
798 let parser = BgpkitParser::new(url)?.add_filter("type", "!w")?;
801 let count = parser.into_elem_iter().count();
802 assert_eq!(count, 8160 - 379);
803
804 let parser = BgpkitParser::new(url)?
807 .add_filter("peer_ip", "185.1.8.50")?
808 .add_filter("type", "!w")?;
809 let count = parser.into_elem_iter().count();
810 assert_eq!(count, 1563 - 39);
812
813 Ok(())
814 }
815
816 #[test]
817 fn test_filter_iter_multi_peers() {
818 let url = "https://spaces.bgpkit.org/parser/update-example.gz";
819 let parser = BgpkitParser::new(url)
820 .unwrap()
821 .add_filter("peer_ips", "185.1.8.65, 2001:7f8:73:0:3:fa4:0:1")
822 .unwrap();
823 let count = parser.into_elem_iter().count();
824 assert_eq!(count, 3393 + 834);
825 }
826
827 #[test]
828 fn test_prefix_match() {
829 let p1 = IpNet::from_str("10.1.1.0/24").unwrap();
831 let p1_exact = IpNet::from_str("10.1.1.0/24").unwrap();
832 let p1_super = IpNet::from_str("10.1.0.0/16").unwrap();
833 let p1_sub = IpNet::from_str("10.1.1.0/25").unwrap();
834
835 let p2 = IpNet::from_str("2001:0DB8:0000:000b::/64").unwrap();
836
837 assert!(prefix_match(&p1, &p1_exact, &PrefixMatchType::Exact));
839 assert!(!prefix_match(&p1, &p1_sub, &PrefixMatchType::Exact));
840 assert!(!prefix_match(&p1, &p1_super, &PrefixMatchType::Exact));
841 assert!(!prefix_match(&p1, &p2, &PrefixMatchType::Exact));
842
843 assert!(prefix_match(&p1, &p1_exact, &PrefixMatchType::IncludeSuper));
845 assert!(!prefix_match(&p1, &p1_sub, &PrefixMatchType::IncludeSuper));
846 assert!(prefix_match(&p1, &p1_super, &PrefixMatchType::IncludeSuper));
847 assert!(!prefix_match(&p1, &p2, &PrefixMatchType::IncludeSuper));
848
849 assert!(prefix_match(&p1, &p1_exact, &PrefixMatchType::IncludeSub));
851 assert!(prefix_match(&p1, &p1_sub, &PrefixMatchType::IncludeSub));
852 assert!(!prefix_match(&p1, &p1_super, &PrefixMatchType::IncludeSub));
853 assert!(!prefix_match(&p1, &p2, &PrefixMatchType::IncludeSub));
854
855 assert!(prefix_match(
857 &p1,
858 &p1_exact,
859 &PrefixMatchType::IncludeSuperSub
860 ));
861 assert!(prefix_match(
862 &p1,
863 &p1_sub,
864 &PrefixMatchType::IncludeSuperSub
865 ));
866 assert!(prefix_match(
867 &p1,
868 &p1_super,
869 &PrefixMatchType::IncludeSuperSub
870 ));
871 assert!(!prefix_match(&p1, &p2, &PrefixMatchType::IncludeSuperSub));
872 }
873
874 #[test]
875 fn test_filter_new() {
876 let filter = Filter::new("origin_asn", "12345").unwrap();
877 assert_eq!(filter, Filter::OriginAsn(12345));
878
879 let filter = Filter::new("origin_asn", "!12345").unwrap();
881 assert_eq!(filter, Filter::Negated(Box::new(Filter::OriginAsn(12345))));
882
883 let filter = Filter::new("prefix", "!192.168.1.0/24").unwrap();
884 assert_eq!(
885 filter,
886 Filter::Negated(Box::new(Filter::Prefix(
887 IpNet::from_str("192.168.1.0/24").unwrap(),
888 PrefixMatchType::Exact
889 )))
890 );
891
892 let filter = Filter::new("peer_ip", "!192.168.1.1").unwrap();
893 assert_eq!(
894 filter,
895 Filter::Negated(Box::new(Filter::PeerIp(
896 IpAddr::from_str("192.168.1.1").unwrap()
897 )))
898 );
899
900 let filter = Filter::new("peer_asn", "!12345").unwrap();
901 assert_eq!(filter, Filter::Negated(Box::new(Filter::PeerAsn(12345))));
902
903 let filter = Filter::new("type", "!w").unwrap();
904 assert_eq!(
905 filter,
906 Filter::Negated(Box::new(Filter::Type(ElemType::WITHDRAW)))
907 );
908
909 let filter = Filter::new("ip_version", "!4").unwrap();
910 assert_eq!(
911 filter,
912 Filter::Negated(Box::new(Filter::IpVersion(IpVersion::Ipv4)))
913 );
914
915 let filter = Filter::new("prefix", "192.168.1.0/24").unwrap();
916 assert_eq!(
917 filter,
918 Filter::Prefix(
919 IpNet::from_str("192.168.1.0/24").unwrap(),
920 PrefixMatchType::Exact
921 )
922 );
923 let filter = Filter::new("prefix_super", "192.168.1.0/24").unwrap();
924 assert_eq!(
925 filter,
926 Filter::Prefix(
927 IpNet::from_str("192.168.1.0/24").unwrap(),
928 PrefixMatchType::IncludeSuper
929 )
930 );
931 let filter = Filter::new("prefix_sub", "192.168.1.0/24").unwrap();
932 assert_eq!(
933 filter,
934 Filter::Prefix(
935 IpNet::from_str("192.168.1.0/24").unwrap(),
936 PrefixMatchType::IncludeSub
937 )
938 );
939 let filter = Filter::new("prefix_super_sub", "192.168.1.0/24").unwrap();
940 assert_eq!(
941 filter,
942 Filter::Prefix(
943 IpNet::from_str("192.168.1.0/24").unwrap(),
944 PrefixMatchType::IncludeSuperSub
945 )
946 );
947
948 let filter = Filter::new("peer_ip", "192.168.1.1").unwrap();
949 assert_eq!(
950 filter,
951 Filter::PeerIp(IpAddr::from_str("192.168.1.1").unwrap())
952 );
953
954 let filter = Filter::new("peer_asn", "12345").unwrap();
955 assert_eq!(filter, Filter::PeerAsn(12345));
956
957 let filter = Filter::new("type", "w").unwrap();
958 assert_eq!(filter, Filter::Type(ElemType::WITHDRAW));
959
960 let filter = Filter::new("ts_start", "1637437798").unwrap();
961 assert_eq!(filter, Filter::TsStart(1637437798_f64));
962
963 let filter = Filter::new("ts_end", "1637437798").unwrap();
964 assert_eq!(filter, Filter::TsEnd(1637437798_f64));
965
966 let filter = Filter::new("as_path", r" ?174 1916 52888$").unwrap();
967 assert_eq!(
968 filter,
969 Filter::AsPath(ComparableRegex::new(r" ?174 1916 52888$").unwrap())
970 );
971
972 assert!(Filter::new("origin_asn", "not a number").is_err());
973 assert!(Filter::new("peer_asn", "not a number").is_err());
974 assert!(Filter::new("ts_start", "not a number").is_err());
975 assert!(Filter::new("ts_end", "not a number").is_err());
976 assert!(Filter::new("prefix", "not a prefix").is_err());
977 assert!(Filter::new("prefix_super", "not a prefix").is_err());
978 assert!(Filter::new("prefix_sub", "not a prefix").is_err());
979 assert!(Filter::new("peer_ip", "not a IP").is_err());
980 assert!(Filter::new("peer_ips", "not,a,IP").is_err());
981 assert!(Filter::new("type", "not a type").is_err());
982 assert!(Filter::new("as_path", "[abc").is_err());
983 assert!(Filter::new("ip_version", "5").is_err());
984 assert!(Filter::new("unknown_filter", "some_value").is_err());
985 }
986
987 #[test]
988 fn test_filterable_match_filter() {
989 let elem = BgpElem {
990 timestamp: 1637437798_f64,
991 peer_ip: IpAddr::from_str("192.168.1.1").unwrap(),
992 peer_asn: Asn::new_32bit(12345),
993 prefix: NetworkPrefix::new(IpNet::from_str("192.168.1.0/24").unwrap(), None),
994 next_hop: None,
995 as_path: Some(AsPath::from_sequence(vec![174, 1916, 52888])),
996 origin_asns: Some(vec![Asn::new_16bit(12345)]),
997 origin: None,
998 local_pref: None,
999 med: None,
1000 communities: Some(vec![MetaCommunity::Large(LargeCommunity::new(
1001 12345,
1002 [678910, 111213],
1003 ))]),
1004 atomic: false,
1005 aggr_asn: None,
1006 aggr_ip: None,
1007 only_to_customer: None,
1008 unknown: None,
1009 elem_type: ElemType::ANNOUNCE,
1010 deprecated: None,
1011 };
1012
1013 let mut filters = vec![];
1014
1015 let filter = Filter::new("origin_asn", "12345").unwrap();
1016 filters.push(filter.clone());
1017 assert!(elem.match_filter(&filter));
1018
1019 let filter = Filter::new("origin_asn", "678910").unwrap();
1020 assert!(!elem.match_filter(&filter));
1021
1022 let filter = Filter::new("prefix", "192.168.1.0/24").unwrap();
1023 filters.push(filter.clone());
1024 assert!(elem.match_filter(&filter));
1025
1026 let filter = Filter::new("peer_ip", "192.168.1.1").unwrap();
1027 filters.push(filter.clone());
1028 assert!(elem.match_filter(&filter));
1029
1030 let filter = Filter::new("peer_asn", "12345").unwrap();
1031 filters.push(filter.clone());
1032 assert!(elem.match_filter(&filter));
1033
1034 let filter = Filter::new("type", "a").unwrap();
1035 filters.push(filter.clone());
1036 assert!(elem.match_filter(&filter));
1037
1038 let filter = Filter::new("ts_start", "1637437798").unwrap();
1039 filters.push(filter.clone());
1040 assert!(elem.match_filter(&filter));
1041
1042 let filter = Filter::new("ts_end", "1637437798").unwrap();
1043 filters.push(filter.clone());
1044 assert!(elem.match_filter(&filter));
1045
1046 let filter = Filter::new("as_path", r" ?174 1916 52888$").unwrap();
1047 filters.push(filter.clone());
1048 assert!(elem.match_filter(&filter));
1049
1050 let filter = Filter::new("ip_version", "4").unwrap();
1051 filters.push(filter.clone());
1052 assert!(elem.match_filter(&filter));
1053
1054 let filter = Filter::new("ip", "ipv6").unwrap();
1055 assert!(!elem.match_filter(&filter));
1056
1057 let filter = Filter::new("community", r"12345:678910:111213$").unwrap();
1058 filters.push(filter.clone());
1059 assert!(elem.match_filter(&filter));
1060
1061 assert!(elem.match_filters(&filters));
1062 }
1063
1064 #[test]
1065 fn test_negated_filters() {
1066 let elem = BgpElem {
1067 timestamp: 1637437798_f64,
1068 peer_ip: IpAddr::from_str("192.168.1.1").unwrap(),
1069 peer_asn: Asn::new_32bit(12345),
1070 prefix: NetworkPrefix::new(IpNet::from_str("192.168.1.0/24").unwrap(), None),
1071 next_hop: None,
1072 as_path: Some(AsPath::from_sequence(vec![174, 1916, 52888])),
1073 origin_asns: Some(vec![Asn::new_16bit(12345)]),
1074 origin: None,
1075 local_pref: None,
1076 med: None,
1077 communities: Some(vec![MetaCommunity::Large(LargeCommunity::new(
1078 12345,
1079 [678910, 111213],
1080 ))]),
1081 atomic: false,
1082 aggr_asn: None,
1083 aggr_ip: None,
1084 only_to_customer: None,
1085 unknown: None,
1086 elem_type: ElemType::ANNOUNCE,
1087 deprecated: None,
1088 };
1089
1090 let filter = Filter::new("origin_asn", "!12345").unwrap();
1093 assert!(!elem.match_filter(&filter));
1094
1095 let filter = Filter::new("origin_asn", "!99999").unwrap();
1097 assert!(elem.match_filter(&filter));
1098
1099 let filter = Filter::new("prefix", "!192.168.1.0/24").unwrap();
1102 assert!(!elem.match_filter(&filter));
1103
1104 let filter = Filter::new("prefix", "!10.0.0.0/8").unwrap();
1106 assert!(elem.match_filter(&filter));
1107
1108 let filter = Filter::new("peer_ip", "!192.168.1.1").unwrap();
1111 assert!(!elem.match_filter(&filter));
1112
1113 let filter = Filter::new("peer_ip", "!10.0.0.1").unwrap();
1115 assert!(elem.match_filter(&filter));
1116
1117 let filter = Filter::new("peer_asn", "!12345").unwrap();
1120 assert!(!elem.match_filter(&filter));
1121
1122 let filter = Filter::new("peer_asn", "!99999").unwrap();
1124 assert!(elem.match_filter(&filter));
1125
1126 let filter = Filter::new("type", "!a").unwrap();
1129 assert!(!elem.match_filter(&filter));
1130
1131 let filter = Filter::new("type", "!w").unwrap();
1133 assert!(elem.match_filter(&filter));
1134
1135 let filter = Filter::new("ip_version", "!4").unwrap();
1138 assert!(!elem.match_filter(&filter));
1139
1140 let filter = Filter::new("ip_version", "!6").unwrap();
1142 assert!(elem.match_filter(&filter));
1143
1144 let filter = Filter::new("as_path", r"!174 1916 52888$").unwrap();
1147 assert!(!elem.match_filter(&filter));
1148
1149 let filter = Filter::new("as_path", r"!99999$").unwrap();
1151 assert!(elem.match_filter(&filter));
1152
1153 let filter = Filter::new("community", r"!12345:678910:111213$").unwrap();
1155 assert!(!elem.match_filter(&filter));
1156
1157 let filter = Filter::new("community", r"!99999:99999$").unwrap();
1158 assert!(elem.match_filter(&filter));
1159
1160 let filter = Filter::new("peer_ips", "!192.168.1.1, !10.0.0.1").unwrap();
1162 assert!(!elem.match_filter(&filter)); let filter = Filter::new("peer_ips", "!10.0.0.1, !10.0.0.2").unwrap();
1165 assert!(elem.match_filter(&filter)); let filters = vec![
1169 Filter::new("origin_asn", "12345").unwrap(), Filter::new("peer_asn", "!99999").unwrap(), Filter::new("prefix", "!10.0.0.0/8").unwrap(), ];
1173 assert!(elem.match_filters(&filters));
1174
1175 let filters = vec![
1177 Filter::new("origin_asn", "12345").unwrap(), Filter::new("origin_asn", "!12345").unwrap(), ];
1180 assert!(!elem.match_filters(&filters));
1181 }
1182
1183 #[test]
1184 fn test_negated_filters_on_mrt_file() {
1185 let url = "https://spaces.bgpkit.org/parser/update-example.gz";
1186 let parser = BgpkitParser::new(url).unwrap();
1187 let elems = parser.into_elem_iter().collect::<Vec<BgpElem>>();
1188
1189 let filters = vec![Filter::PeerIp(IpAddr::from_str("185.1.8.65").unwrap())];
1191 let count_with_peer = elems.iter().filter(|e| e.match_filters(&filters)).count();
1192 assert_eq!(count_with_peer, 3393);
1193
1194 let filters = vec![Filter::new("peer_ip", "!185.1.8.65").unwrap()];
1196 let count_without_peer = elems.iter().filter(|e| e.match_filters(&filters)).count();
1197 assert_eq!(count_without_peer, elems.len() - 3393);
1198
1199 assert_eq!(count_with_peer + count_without_peer, elems.len());
1201
1202 let filters = vec![Filter::Type(ElemType::WITHDRAW)];
1204 let count_withdrawals = elems.iter().filter(|e| e.match_filters(&filters)).count();
1205 assert_eq!(count_withdrawals, 379);
1206
1207 let filters = vec![Filter::new("type", "!w").unwrap()];
1208 let count_not_withdrawals = elems.iter().filter(|e| e.match_filters(&filters)).count();
1209 assert_eq!(count_not_withdrawals, elems.len() - 379);
1210
1211 let filters = vec![Filter::Prefix(
1213 IpNet::from_str("190.115.192.0/22").unwrap(),
1214 PrefixMatchType::Exact,
1215 )];
1216 let count_with_prefix = elems.iter().filter(|e| e.match_filters(&filters)).count();
1217
1218 let filters = vec![Filter::new("prefix", "!190.115.192.0/22").unwrap()];
1219 let count_without_prefix = elems.iter().filter(|e| e.match_filters(&filters)).count();
1220 assert_eq!(count_with_prefix + count_without_prefix, elems.len());
1221
1222 let filters = vec![Filter::Prefix(
1224 IpNet::from_str("190.115.192.0/24").unwrap(),
1225 PrefixMatchType::IncludeSuper,
1226 )];
1227 let count_with_super = elems.iter().filter(|e| e.match_filters(&filters)).count();
1228
1229 let filters = vec![Filter::new("prefix_super", "!190.115.192.0/24").unwrap()];
1230 let count_without_super = elems.iter().filter(|e| e.match_filters(&filters)).count();
1231 assert_eq!(count_with_super + count_without_super, elems.len());
1232
1233 let filters = vec![Filter::Prefix(
1235 IpNet::from_str("190.115.192.0/22").unwrap(),
1236 PrefixMatchType::IncludeSub,
1237 )];
1238 let count_with_sub = elems.iter().filter(|e| e.match_filters(&filters)).count();
1239
1240 let filters = vec![Filter::new("prefix_sub", "!190.115.192.0/22").unwrap()];
1241 let count_without_sub = elems.iter().filter(|e| e.match_filters(&filters)).count();
1242 assert_eq!(count_with_sub + count_without_sub, elems.len());
1243
1244 let filters = vec![Filter::Prefix(
1246 IpNet::from_str("190.115.192.0/23").unwrap(),
1247 PrefixMatchType::IncludeSuperSub,
1248 )];
1249 let count_with_super_sub = elems.iter().filter(|e| e.match_filters(&filters)).count();
1250
1251 let filters = vec![Filter::new("prefix_super_sub", "!190.115.192.0/23").unwrap()];
1252 let count_without_super_sub = elems.iter().filter(|e| e.match_filters(&filters)).count();
1253 assert_eq!(count_with_super_sub + count_without_super_sub, elems.len());
1254 }
1255
1256 #[test]
1257 fn test_double_negation_rejected() {
1258 let result = Filter::new("origin_asn", "!!13335");
1261 assert!(result.is_err());
1262 let err = result.unwrap_err();
1263 assert!(err.to_string().contains("double negation"));
1264
1265 let result = Filter::new("prefix", "!!!10.0.0.0/8");
1266 assert!(result.is_err());
1267 let err = result.unwrap_err();
1268 assert!(err.to_string().contains("double negation"));
1269 }
1270
1271 #[test]
1272 fn test_timestamp_negation_rejected() {
1273 let result = Filter::new("ts_start", "!1637437798");
1275 assert!(result.is_err());
1276 let err = result.unwrap_err();
1277 assert!(err
1278 .to_string()
1279 .contains("timestamp filter 'ts_start' does not support negation"));
1280
1281 let result = Filter::new("ts_end", "!1637437798");
1282 assert!(result.is_err());
1283 let err = result.unwrap_err();
1284 assert!(err
1285 .to_string()
1286 .contains("timestamp filter 'ts_end' does not support negation"));
1287
1288 let result = Filter::new("start_ts", "!1637437798");
1289 assert!(result.is_err());
1290
1291 let result = Filter::new("end_ts", "!1637437798");
1292 assert!(result.is_err());
1293 }
1294
1295 #[test]
1296 fn test_multiple_origin_asns() -> Result<()> {
1297 let filter = Filter::new("origin_asns", "12345,67890,13335").unwrap();
1299 match filter {
1300 Filter::OriginAsns(asns) => {
1301 assert_eq!(asns.len(), 3);
1302 assert!(asns.contains(&12345));
1303 assert!(asns.contains(&67890));
1304 assert!(asns.contains(&13335));
1305 }
1306 _ => panic!("Expected OriginAsns filter"),
1307 }
1308
1309 let filter = Filter::new("origin_asns", "12345, 67890, 13335").unwrap();
1311 match filter {
1312 Filter::OriginAsns(asns) => {
1313 assert_eq!(asns.len(), 3);
1314 }
1315 _ => panic!("Expected OriginAsns filter"),
1316 }
1317
1318 Ok(())
1319 }
1320
1321 #[test]
1322 fn test_multiple_prefixes() -> Result<()> {
1323 let prefix1 = IpNet::from_str("190.115.192.0/22").unwrap();
1325 let prefix2 = IpNet::from_str("2804:100::/32").unwrap();
1326
1327 let filter = Filter::new("prefixes", "190.115.192.0/22,2804:100::/32").unwrap();
1328 match filter {
1329 Filter::Prefixes(prefixes, match_type) => {
1330 assert_eq!(prefixes.len(), 2);
1331 assert!(prefixes.contains(&prefix1));
1332 assert!(prefixes.contains(&prefix2));
1333 assert_eq!(match_type, PrefixMatchType::Exact);
1334 }
1335 _ => panic!("Expected Prefixes filter"),
1336 }
1337
1338 let filter = Filter::new("prefixes", "190.115.192.0/22, 2804:100::/32").unwrap();
1340 match filter {
1341 Filter::Prefixes(prefixes, _) => {
1342 assert_eq!(prefixes.len(), 2);
1343 }
1344 _ => panic!("Expected Prefixes filter"),
1345 }
1346
1347 Ok(())
1348 }
1349
1350 #[test]
1351 fn test_multiple_prefixes_with_match_types() -> Result<()> {
1352 let filter = Filter::new("prefixes_super", "190.115.192.0/24,2804:100::/32").unwrap();
1354 match filter {
1355 Filter::Prefixes(prefixes, match_type) => {
1356 assert_eq!(prefixes.len(), 2);
1357 assert_eq!(match_type, PrefixMatchType::IncludeSuper);
1358 }
1359 _ => panic!("Expected Prefixes filter with IncludeSuper"),
1360 }
1361
1362 let filter = Filter::new("prefixes_sub", "190.115.192.0/22,2804:100::/32").unwrap();
1364 match filter {
1365 Filter::Prefixes(prefixes, match_type) => {
1366 assert_eq!(prefixes.len(), 2);
1367 assert_eq!(match_type, PrefixMatchType::IncludeSub);
1368 }
1369 _ => panic!("Expected Prefixes filter with IncludeSub"),
1370 }
1371
1372 let filter = Filter::new("prefixes_super_sub", "190.115.192.0/23,2804:100::/32").unwrap();
1374 match filter {
1375 Filter::Prefixes(prefixes, match_type) => {
1376 assert_eq!(prefixes.len(), 2);
1377 assert_eq!(match_type, PrefixMatchType::IncludeSuperSub);
1378 }
1379 _ => panic!("Expected Prefixes filter with IncludeSuperSub"),
1380 }
1381
1382 Ok(())
1383 }
1384
1385 #[test]
1386 fn test_multiple_peer_asns() -> Result<()> {
1387 let filter = Filter::new("peer_asns", "12345,67890,13335").unwrap();
1389 match filter {
1390 Filter::PeerAsns(asns) => {
1391 assert_eq!(asns.len(), 3);
1392 assert!(asns.contains(&12345));
1393 assert!(asns.contains(&67890));
1394 assert!(asns.contains(&13335));
1395 }
1396 _ => panic!("Expected PeerAsns filter"),
1397 }
1398
1399 Ok(())
1400 }
1401
1402 #[test]
1403 fn test_negated_multiple_filters() -> Result<()> {
1404 let filter = Filter::new("origin_asns", "!13335,!15169").unwrap();
1406 assert!(matches!(filter, Filter::Negated(_)));
1407
1408 let filter = Filter::new("prefixes", "!1.1.1.0/24,!8.8.8.0/24").unwrap();
1410 assert!(matches!(filter, Filter::Negated(_)));
1411
1412 let filter = Filter::new("peer_asns", "!12345,!67890").unwrap();
1414 assert!(matches!(filter, Filter::Negated(_)));
1415
1416 Ok(())
1417 }
1418
1419 #[test]
1420 fn test_invalid_multiple_filters() {
1421 let result = Filter::new("origin_asns", "12345,not_a_number,67890");
1423 assert!(result.is_err());
1424
1425 let result = Filter::new("prefixes", "1.1.1.0/24,invalid_prefix");
1427 assert!(result.is_err());
1428
1429 let result = Filter::new("peer_asns", "12345,invalid,67890");
1431 assert!(result.is_err());
1432
1433 let result = Filter::new("peer_ips", "192.168.1.1,invalid_ip");
1435 assert!(result.is_err());
1436
1437 let result = Filter::new("origin_asns", "12345,!67890");
1439 assert!(result.is_err());
1440 assert!(result
1441 .unwrap_err()
1442 .to_string()
1443 .contains("cannot mix positive and negative values"));
1444
1445 let result = Filter::new("prefixes", "1.1.1.0/24,!8.8.8.0/24");
1446 assert!(result.is_err());
1447 assert!(result
1448 .unwrap_err()
1449 .to_string()
1450 .contains("cannot mix positive and negative values"));
1451
1452 let result = Filter::new("peer_ips", "192.168.1.1,!10.0.0.1");
1453 assert!(result.is_err());
1454 assert!(result
1455 .unwrap_err()
1456 .to_string()
1457 .contains("cannot mix positive and negative values"));
1458
1459 let result = Filter::new("peer_asns", "!12345,67890");
1460 assert!(result.is_err());
1461 assert!(result
1462 .unwrap_err()
1463 .to_string()
1464 .contains("cannot mix positive and negative values"));
1465
1466 let result = Filter::new("origin_asns", "");
1468 assert!(result.is_err());
1469 assert!(result.unwrap_err().to_string().contains("at least one ASN"));
1470
1471 let result = Filter::new("prefixes", "");
1473 assert!(result.is_err());
1474 assert!(result
1475 .unwrap_err()
1476 .to_string()
1477 .contains("at least one prefix"));
1478
1479 let result = Filter::new("peer_ips", "");
1481 assert!(result.is_err());
1482 assert!(result.unwrap_err().to_string().contains("at least one IP"));
1483
1484 let result = Filter::new("origin_asns", ",,,");
1486 assert!(result.is_err());
1487 assert!(result.unwrap_err().to_string().contains("at least one ASN"));
1488
1489 let result = Filter::new("prefixes", ",,,");
1491 assert!(result.is_err());
1492 assert!(result
1493 .unwrap_err()
1494 .to_string()
1495 .contains("at least one prefix"));
1496
1497 let result = Filter::new("peer_ips", ",,,");
1499 assert!(result.is_err());
1500 assert!(result.unwrap_err().to_string().contains("at least one IP"));
1501
1502 let result = Filter::new("origin_asns", "12345,67890,");
1504 assert!(result.is_ok());
1505
1506 let result = Filter::new("origin_asns", "12345,,67890");
1508 assert!(result.is_ok());
1509
1510 let result = Filter::new("peer_ips", "192.168.1.1,192.168.1.2,");
1512 assert!(result.is_ok());
1513 }
1514
1515 #[test]
1516 fn test_multiple_filters_or_logic_behavior() {
1517 let elem = BgpElem {
1519 timestamp: 1637437798_f64,
1520 peer_ip: IpAddr::from_str("192.168.1.1").unwrap(),
1521 peer_asn: Asn::new_32bit(12345),
1522 prefix: NetworkPrefix::new(IpNet::from_str("192.168.1.0/24").unwrap(), None),
1523 next_hop: None,
1524 as_path: Some(AsPath::from_sequence(vec![174, 1916, 52888])),
1525 origin_asns: Some(vec![Asn::new_16bit(12345)]),
1526 origin: None,
1527 local_pref: None,
1528 med: None,
1529 communities: None,
1530 atomic: false,
1531 aggr_asn: None,
1532 aggr_ip: None,
1533 only_to_customer: None,
1534 unknown: None,
1535 elem_type: ElemType::ANNOUNCE,
1536 deprecated: None,
1537 };
1538
1539 let filter = Filter::new("origin_asns", "12345,67890,99999").unwrap();
1541 assert!(elem.match_filter(&filter)); let filter = Filter::new("origin_asns", "67890,99999").unwrap();
1544 assert!(!elem.match_filter(&filter)); let filter = Filter::new("prefixes", "192.168.1.0/24,10.0.0.0/8,172.16.0.0/12").unwrap();
1548 assert!(elem.match_filter(&filter)); let filter = Filter::new("prefixes", "10.0.0.0/8,172.16.0.0/12").unwrap();
1551 assert!(!elem.match_filter(&filter)); let filter = Filter::new("peer_asns", "12345,67890").unwrap();
1555 assert!(elem.match_filter(&filter)); let filter = Filter::new("peer_asns", "67890,99999").unwrap();
1558 assert!(!elem.match_filter(&filter)); let filter = Filter::new("origin_asns", "!67890,!99999").unwrap();
1562 assert!(elem.match_filter(&filter)); let filter = Filter::new("origin_asns", "!12345,!67890").unwrap();
1565 assert!(!elem.match_filter(&filter)); }
1567}