relay_filter/
client_ips.rs

1//! Implements event filtering based on the client ip address.
2//!
3//! A project may be configured with blacklisted ip addresses that will
4//! be banned from sending events (all events received from banned ip
5//! addresses will be filtered).
6
7use std::net::IpAddr;
8
9use ipnetwork::IpNetwork;
10
11use crate::{ClientIpsFilterConfig, FilterStatKey};
12
13/// Checks if the event is part of the blacklisted client IP ranges.
14///
15/// The client IP is the address of the originator of the event. If it was forwarded through
16/// multiple proxies, this address should be derived from the `X-Forwarded-For` header. Otherwise,
17/// it is the remote socket address.
18fn 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
38/// Filters events by blacklisted client IP ranges.
39///
40/// The client IP is the address of the originator of the event. If it was forwarded through
41/// multiple proxies, this address should be derived from the `X-Forwarded-For` header. Otherwise,
42/// it is the remote socket address.
43pub 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            //test matches ipv4
64            ("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            //test matches ipv6
68            ("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            //test network ipv4 matches
76            ("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            //test network ipv6 matches
81            ("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            //sentry compatibility tests
86            ("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}