shadowsocks_service/local/
context.rs

1//! Shadowsocks Local Server Context
2
3use std::sync::Arc;
4#[cfg(feature = "local-dns")]
5use std::{net::IpAddr, time::Duration};
6
7#[cfg(feature = "local-dns")]
8use lru_time_cache::LruCache;
9use shadowsocks::{
10    config::ServerType,
11    context::{Context, SharedContext},
12    dns_resolver::DnsResolver,
13    net::{AcceptOpts, ConnectOpts},
14    relay::Address,
15};
16#[cfg(feature = "local-dns")]
17use tokio::sync::Mutex;
18#[cfg(feature = "local-fake-dns")]
19use tokio::sync::RwLock;
20
21use crate::{acl::AccessControl, config::SecurityConfig, net::FlowStat};
22
23#[cfg(feature = "local-fake-dns")]
24use super::fake_dns::manager::FakeDnsManager;
25
26/// Local Service Context
27#[derive(Clone)]
28pub struct ServiceContext {
29    context: SharedContext,
30    connect_opts: ConnectOpts,
31    accept_opts: AcceptOpts,
32
33    // Access Control
34    acl: Option<Arc<AccessControl>>,
35
36    // Flow statistic report
37    flow_stat: Arc<FlowStat>,
38
39    // For DNS relay's ACL domain name reverse lookup -- whether the IP shall be forwarded
40    #[cfg(feature = "local-dns")]
41    reverse_lookup_cache: Arc<Mutex<LruCache<IpAddr, bool>>>,
42
43    #[cfg(feature = "local-fake-dns")]
44    fake_dns_manager: Arc<RwLock<Vec<Arc<FakeDnsManager>>>>,
45}
46
47impl Default for ServiceContext {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53impl ServiceContext {
54    /// Create a new `ServiceContext`
55    pub fn new() -> Self {
56        Self {
57            context: Context::new_shared(ServerType::Local),
58            connect_opts: ConnectOpts::default(),
59            accept_opts: AcceptOpts::default(),
60            acl: None,
61            flow_stat: Arc::new(FlowStat::new()),
62            #[cfg(feature = "local-dns")]
63            reverse_lookup_cache: Arc::new(Mutex::new(LruCache::with_expiry_duration_and_capacity(
64                Duration::from_secs(3 * 24 * 60 * 60),
65                10240, // XXX: It should be enough for a normal user.
66            ))),
67            #[cfg(feature = "local-fake-dns")]
68            fake_dns_manager: Arc::new(RwLock::new(Vec::new())),
69        }
70    }
71
72    /// Get cloned `shadowsocks` Context
73    pub fn context(&self) -> SharedContext {
74        self.context.clone()
75    }
76
77    /// Get `shadowsocks` Context reference
78    pub fn context_ref(&self) -> &Context {
79        self.context.as_ref()
80    }
81
82    /// Set `ConnectOpts`
83    pub fn set_connect_opts(&mut self, connect_opts: ConnectOpts) {
84        self.connect_opts = connect_opts;
85    }
86
87    /// Get `ConnectOpts` reference
88    pub fn connect_opts_ref(&self) -> &ConnectOpts {
89        &self.connect_opts
90    }
91
92    /// Set `AcceptOpts`
93    pub fn set_accept_opts(&mut self, accept_opts: AcceptOpts) {
94        self.accept_opts = accept_opts;
95    }
96
97    /// Get `AcceptOpts` cloned
98    pub fn accept_opts(&self) -> AcceptOpts {
99        self.accept_opts.clone()
100    }
101
102    /// Set Access Control List
103    pub fn set_acl(&mut self, acl: Arc<AccessControl>) {
104        self.acl = Some(acl);
105    }
106
107    /// Get Access Control List reference
108    pub fn acl(&self) -> Option<&AccessControl> {
109        self.acl.as_deref()
110    }
111
112    /// Get cloned flow statistic
113    pub fn flow_stat(&self) -> Arc<FlowStat> {
114        self.flow_stat.clone()
115    }
116
117    /// Get flow statistic reference
118    pub fn flow_stat_ref(&self) -> &FlowStat {
119        self.flow_stat.as_ref()
120    }
121
122    /// Set customized DNS resolver
123    pub fn set_dns_resolver(&mut self, resolver: Arc<DnsResolver>) {
124        let context = Arc::get_mut(&mut self.context).expect("cannot set DNS resolver on a shared context");
125        context.set_dns_resolver(resolver)
126    }
127
128    /// Get reference of DNS resolver
129    pub fn dns_resolver(&self) -> &DnsResolver {
130        self.context.dns_resolver()
131    }
132
133    /// Check if target should be bypassed
134    pub async fn check_target_bypassed(&self, addr: &Address) -> bool {
135        match self.acl {
136            None => false,
137            Some(ref acl) => {
138                #[cfg(feature = "local-dns")]
139                {
140                    if let Address::SocketAddress(saddr) = addr {
141                        // do the reverse lookup in our local cache
142                        let mut reverse_lookup_cache = self.reverse_lookup_cache.lock().await;
143                        // if a qname is found
144                        if let Some(forward) = reverse_lookup_cache.get(&saddr.ip()) {
145                            return !*forward;
146                        }
147                    }
148                }
149
150                acl.check_target_bypassed(&self.context, addr).await
151            }
152        }
153    }
154
155    /// Add a record to the reverse lookup cache
156    #[cfg(feature = "local-dns")]
157    pub async fn add_to_reverse_lookup_cache(&self, addr: IpAddr, forward: bool) {
158        let is_exception = forward
159            != match self.acl {
160                // Proxy everything by default
161                None => true,
162                Some(ref a) => a.check_ip_in_proxy_list(&addr),
163            };
164        let mut reverse_lookup_cache = self.reverse_lookup_cache.lock().await;
165        match reverse_lookup_cache.get_mut(&addr) {
166            Some(value) => {
167                if is_exception {
168                    *value = forward;
169                } else {
170                    // we do not need to remember the entry if it is already matched correctly
171                    reverse_lookup_cache.remove(&addr);
172                }
173            }
174            None => {
175                if is_exception {
176                    reverse_lookup_cache.insert(addr, forward);
177                }
178            }
179        }
180    }
181
182    /// Try to connect IPv6 addresses first if hostname could be resolved to both IPv4 and IPv6
183    pub fn set_ipv6_first(&mut self, ipv6_first: bool) {
184        let context = Arc::get_mut(&mut self.context).expect("cannot set ipv6_first on a shared context");
185        context.set_ipv6_first(ipv6_first);
186    }
187
188    /// Set security config
189    pub fn set_security_config(&mut self, security: &SecurityConfig) {
190        let context = Arc::get_mut(&mut self.context).expect("cannot set security on a shared context");
191        context.set_replay_attack_policy(security.replay_attack.policy);
192    }
193
194    /// Set Fake DNS manager
195    #[cfg(feature = "local-fake-dns")]
196    pub async fn add_fake_dns_manager(&self, manager: Arc<FakeDnsManager>) {
197        let mut managers = self.fake_dns_manager.write().await;
198        managers.push(manager);
199    }
200
201    /// Fake DNS maps IP to Domain
202    #[cfg(feature = "local-fake-dns")]
203    pub async fn try_map_fake_address(&self, addr: &Address) -> Option<Address> {
204        let socket_addr = match addr {
205            Address::DomainNameAddress(..) => return None,
206            Address::SocketAddress(socket_addr) => socket_addr,
207        };
208        let ip_addr = socket_addr.ip();
209
210        for mgr in self.fake_dns_manager.read().await.iter() {
211            if let Ok(Some(name)) = mgr.map_ip_domain(ip_addr).await {
212                let new_addr = Address::DomainNameAddress(name.to_string(), socket_addr.port());
213                log::trace!("fakedns mapped {} -> {}", addr, new_addr);
214                return Some(new_addr);
215            }
216        }
217
218        None
219    }
220}