active_call/
locator.rs

1use crate::config::RewriteRule;
2use async_trait::async_trait;
3use regex::Regex;
4use rsipstack::Result;
5use rsipstack::transaction::endpoint::TargetLocator;
6use rsipstack::transport::SipAddr;
7
8pub struct RewriteTargetLocator {
9    rules: Vec<(Regex, String)>,
10}
11
12impl RewriteTargetLocator {
13    pub fn new(rules: Vec<RewriteRule>) -> Self {
14        let rules = rules
15            .into_iter()
16            .filter_map(|rule| match Regex::new(&rule.r#match) {
17                Ok(re) => Some((re, rule.rewrite)),
18                Err(e) => {
19                    tracing::error!("Invalid rewrite rule pattern '{}': {}", rule.r#match, e);
20                    None
21                }
22            })
23            .collect();
24        Self { rules }
25    }
26}
27
28#[async_trait]
29impl TargetLocator for RewriteTargetLocator {
30    async fn locate(&self, uri: &rsip::Uri) -> Result<SipAddr> {
31        let mut target_uri_str = uri.to_string();
32        let mut matched = false;
33
34        for (re, replacement) in &self.rules {
35            if re.is_match(&target_uri_str) {
36                let new_uri = re
37                    .replace_all(&target_uri_str, replacement.as_str())
38                    .to_string();
39                tracing::debug!("Rewrite URI: {} -> {}", target_uri_str, new_uri);
40                target_uri_str = new_uri;
41                matched = true;
42            }
43        }
44
45        if matched {
46            let target_uri = rsip::Uri::try_from(target_uri_str.as_str())
47                .map_err(|e| rsipstack::Error::Error(format!("Invalid rewritten URI: {}", e)))?;
48
49            SipAddr::try_from(&target_uri)
50        } else {
51            SipAddr::try_from(uri)
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use rsip::Uri;
60
61    #[tokio::test]
62    async fn test_rewrite_ip() {
63        let rules = vec![RewriteRule {
64            r#match: "116.116.116.116".to_string(),
65            rewrite: "172.25.25.2".to_string(),
66        }];
67        let locator = RewriteTargetLocator::new(rules);
68
69        let uri = Uri::try_from("sip:1001@116.116.116.116:5060").unwrap();
70        let addr = locator.locate(&uri).await.unwrap();
71
72        assert_eq!(addr.addr.to_string(), "172.25.25.2:5060");
73    }
74
75    #[tokio::test]
76    async fn test_rewrite_regex() {
77        let rules = vec![RewriteRule {
78            r#match: "sip:(\\d+)@.*".to_string(),
79            rewrite: "sip:$1@internal.net".to_string(),
80        }];
81        let locator = RewriteTargetLocator::new(rules);
82
83        let uri = Uri::try_from("sip:12345@external.com").unwrap();
84        let addr = locator.locate(&uri).await.unwrap();
85
86        assert_eq!(addr.addr.to_string(), "internal.net");
87    }
88
89    #[tokio::test]
90    async fn test_no_match() {
91        let rules = vec![RewriteRule {
92            r#match: "nomatch".to_string(),
93            rewrite: "whatever".to_string(),
94        }];
95        let locator = RewriteTargetLocator::new(rules);
96
97        let uri = Uri::try_from("sip:1001@116.62.75.161:5060").unwrap();
98        let addr = locator.locate(&uri).await.unwrap();
99
100        assert_eq!(addr.addr.to_string(), "116.62.75.161:5060");
101    }
102
103    #[tokio::test]
104    async fn test_multiple_rules() {
105        let rules = vec![
106            RewriteRule {
107                r#match: "116.62.75.161".to_string(),
108                rewrite: "172.25.225.2".to_string(),
109            },
110            RewriteRule {
111                r#match: "172.25.225.2".to_string(),
112                rewrite: "10.0.0.1".to_string(),
113            },
114        ];
115        let locator = RewriteTargetLocator::new(rules);
116
117        let uri = Uri::try_from("sip:1001@116.62.75.161:5060").unwrap();
118        let addr = locator.locate(&uri).await.unwrap();
119
120        assert_eq!(addr.addr.to_string(), "10.0.0.1:5060");
121    }
122}