1use std::net::IpAddr;
8
9use ipnetwork::IpNetwork;
10
11use crate::{ClientIpsFilterConfig, FilterStatKey};
12
13fn matches<It, S>(client_ip: Option<IpAddr>, blacklisted_ips: It) -> bool
19where
20 It: IntoIterator<Item = S>,
21 S: AsRef<str>,
22{
23 let client_ip = match client_ip {
24 Some(client_ip) => client_ip,
25 None => return false,
26 };
27
28 for blacklisted_ip in blacklisted_ips {
29 if let Ok(blacklisted_network) = blacklisted_ip.as_ref().parse::<IpNetwork>() {
30 if blacklisted_network.contains(client_ip) {
31 return true;
32 }
33 }
34 }
35 false
36}
37
38pub fn should_filter(
44 client_ip: Option<IpAddr>,
45 config: &ClientIpsFilterConfig,
46) -> Result<(), FilterStatKey> {
47 let blacklisted_ips = &config.blacklisted_ips;
48
49 if matches(client_ip, blacklisted_ips) {
50 return Err(FilterStatKey::IpAddress);
51 }
52
53 Ok(())
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn test_should_filter_blacklisted_ips() {
62 let examples = &[
63 ("1.2.3.4", &[][..], false),
65 ("122.33.230.14", &["122.33.230.14"], true),
66 ("122.33.230.14", &["112.133.110.33", "122.33.230.14"], true),
67 ("aaaa:bbbb::cccc", &["aaaa:bbbb::cccc"], true),
69 (
70 "aaaa:bbbb::cccc",
71 &["121.121.12.121", "aaaa:bbbb::cccc"],
72 true,
73 ),
74 ("aaaa:bbbb::ccce", &["aaaa:bbbb::cccc"], false),
75 ("122.33.230.1", &["122.33.230.0/30"], true),
77 ("122.33.230.2", &["122.33.230.0/30"], true),
78 ("122.33.230.4", &["122.33.230.0/30"], false),
79 ("122.33.230.5", &["122.33.230.4/30"], true),
80 ("a:b:c::1", &["a:b:c::0/126"], true),
82 ("a:b:c::2", &["a:b:c::0/126"], true),
83 ("a:b:c::4", &["a:b:c::0/126"], false),
84 ("a:b:c::5", &["a:b:c::4/126"], true),
85 ("127.0.0.1", &[][..], false),
87 (
88 "127.0.0.1",
89 &["0.0.0.0", "192.168.1.1", "10.0.0.0/8"],
90 false,
91 ),
92 ("127.0.0.1", &["127.0.0.1"], true),
93 ("127.0.0.1", &["0.0.0.0", "127.0.0.1", "192.168.1.1"], true),
94 ("127.0.0.1", &["127.0.0.0/8"], true),
95 (
96 "127.0.0.1",
97 &["0.0.0.0", "127.0.0.0/8", "192.168.1.0/8"],
98 true,
99 ),
100 ("127.0.0.1", &["lol/bar"], false),
101 ];
102
103 for &(ip_addr, blacklisted_ips, expected) in examples {
104 let ip_addr = ip_addr.parse::<IpAddr>().ok();
105 let config = ClientIpsFilterConfig {
106 blacklisted_ips: blacklisted_ips.iter().map(|&ip| ip.to_string()).collect(),
107 };
108
109 let actual = should_filter(ip_addr, &config) != Ok(());
110
111 assert_eq!(
112 actual,
113 expected,
114 "Address {} should have {} been filtered by {:?}",
115 ip_addr.unwrap(),
116 if expected { "" } else { "not" },
117 blacklisted_ips
118 );
119 }
120 }
121}