1use std::{
2 collections::HashMap,
3 convert::From,
4};
5
6use url::Url;
7
8use super::{
9 common::ProxyProto,
10 Policy,
11};
12#[allow(unused_imports)]
14use crate::config::{
15 ForwarderBuilder,
16 TunnelBuilder,
17};
18use crate::{
19 config::common::{
20 default_forwards_to,
21 Binding,
22 CommonOpts,
23 TunnelConfig,
24 },
25 internals::proto::{
26 self,
27 BindExtra,
28 BindOpts,
29 },
30 tunnel::TcpTunnel,
31 Session,
32};
33
34#[derive(Default, Clone)]
36struct TcpOptions {
37 pub(crate) common_opts: CommonOpts,
38 pub(crate) remote_addr: Option<String>,
39 pub(crate) bindings: Vec<String>,
40}
41
42impl TunnelConfig for TcpOptions {
43 fn forwards_to(&self) -> String {
44 self.common_opts
45 .forwards_to
46 .clone()
47 .unwrap_or(default_forwards_to().into())
48 }
49 fn extra(&self) -> BindExtra {
50 BindExtra {
51 token: Default::default(),
52 ip_policy_ref: Default::default(),
53 metadata: self.common_opts.metadata.clone().unwrap_or_default(),
54 bindings: self.bindings.clone(),
55 pooling_enabled: self.common_opts.pooling_enabled.unwrap_or(false),
56 }
57 }
58 fn proto(&self) -> String {
59 "tcp".into()
60 }
61
62 fn forwards_proto(&self) -> String {
63 String::new()
65 }
66
67 fn verify_upstream_tls(&self) -> bool {
68 self.common_opts.verify_upstream_tls()
69 }
70
71 fn opts(&self) -> Option<BindOpts> {
72 let mut tcp_endpoint = proto::TcpEndpoint::default();
74
75 if let Some(remote_addr) = self.remote_addr.as_ref() {
76 tcp_endpoint.addr = remote_addr.clone();
77 }
78 tcp_endpoint.proxy_proto = self.common_opts.proxy_proto;
79
80 tcp_endpoint.ip_restriction = self.common_opts.ip_restriction();
81
82 tcp_endpoint.traffic_policy = if self.common_opts.traffic_policy.is_some() {
83 self.common_opts.traffic_policy.clone().map(From::from)
84 } else if self.common_opts.policy.is_some() {
85 self.common_opts.policy.clone().map(From::from)
86 } else {
87 None
88 };
89 Some(BindOpts::Tcp(tcp_endpoint))
90 }
91 fn labels(&self) -> HashMap<String, String> {
92 HashMap::new()
93 }
94}
95
96impl_builder! {
97 TcpTunnelBuilder, TcpOptions, TcpTunnel, endpoint
101}
102
103impl TcpTunnelBuilder {
105 pub fn allow_cidr(&mut self, cidr: impl Into<String>) -> &mut Self {
109 self.options.common_opts.cidr_restrictions.allow(cidr);
110 self
111 }
112 pub fn deny_cidr(&mut self, cidr: impl Into<String>) -> &mut Self {
116 self.options.common_opts.cidr_restrictions.deny(cidr);
117 self
118 }
119 pub fn proxy_proto(&mut self, proxy_proto: ProxyProto) -> &mut Self {
121 self.options.common_opts.proxy_proto = proxy_proto;
122 self
123 }
124 pub fn metadata(&mut self, metadata: impl Into<String>) -> &mut Self {
128 self.options.common_opts.metadata = Some(metadata.into());
129 self
130 }
131
132 pub fn binding(&mut self, binding: impl Into<String>) -> &mut Self {
163 if !self.options.bindings.is_empty() {
164 panic!("binding() can only be called once");
165 }
166 let binding_str = binding.into();
167 if let Err(e) = Binding::validate(&binding_str) {
168 panic!("{}", e);
169 }
170 self.options.bindings.push(binding_str);
171 self
172 }
173 pub fn forwards_to(&mut self, forwards_to: impl Into<String>) -> &mut Self {
182 self.options.common_opts.forwards_to = Some(forwards_to.into());
183 self
184 }
185
186 pub fn verify_upstream_tls(&mut self, verify_upstream_tls: bool) -> &mut Self {
188 self.options
189 .common_opts
190 .set_verify_upstream_tls(verify_upstream_tls);
191 self
192 }
193
194 pub fn remote_addr(&mut self, remote_addr: impl Into<String>) -> &mut Self {
198 self.options.remote_addr = Some(remote_addr.into());
199 self
200 }
201
202 pub fn policy<S>(&mut self, s: S) -> Result<&mut Self, S::Error>
204 where
205 S: TryInto<Policy>,
206 {
207 self.options.common_opts.policy = Some(s.try_into()?);
208 Ok(self)
209 }
210
211 pub fn traffic_policy(&mut self, policy_str: impl Into<String>) -> &mut Self {
213 self.options.common_opts.traffic_policy = Some(policy_str.into());
214 self
215 }
216
217 pub(crate) async fn for_forwarding_to(&mut self, to_url: &Url) -> &mut Self {
218 self.options.common_opts.for_forwarding_to(to_url);
219 self
220 }
221
222 pub fn pooling_enabled(&mut self, pooling_enabled: impl Into<bool>) -> &mut Self {
224 self.options.common_opts.pooling_enabled = Some(pooling_enabled.into());
225 self
226 }
227}
228
229#[cfg(test)]
230mod test {
231 use super::*;
232 use crate::config::policies::test::POLICY_JSON;
233 const METADATA: &str = "testmeta";
234 const TEST_FORWARD: &str = "testforward";
235 const REMOTE_ADDR: &str = "4.tcp.ngrok.io:1337";
236 const ALLOW_CIDR: &str = "0.0.0.0/0";
237 const DENY_CIDR: &str = "10.1.1.1/32";
238
239 #[test]
240 fn test_interface_to_proto() {
241 tunnel_test(
244 &TcpTunnelBuilder {
245 session: None,
246 options: Default::default(),
247 }
248 .allow_cidr(ALLOW_CIDR)
249 .deny_cidr(DENY_CIDR)
250 .proxy_proto(ProxyProto::V2)
251 .metadata(METADATA)
252 .remote_addr(REMOTE_ADDR)
253 .forwards_to(TEST_FORWARD)
254 .policy(POLICY_JSON)
255 .unwrap()
256 .options,
257 );
258 }
259
260 fn tunnel_test<C>(tunnel_cfg: &C)
261 where
262 C: TunnelConfig,
263 {
264 assert_eq!(TEST_FORWARD, tunnel_cfg.forwards_to());
265
266 let extra = tunnel_cfg.extra();
267 assert_eq!(String::default(), *extra.token);
268 assert_eq!(METADATA, extra.metadata);
269 assert_eq!(Vec::<String>::new(), extra.bindings);
270 assert_eq!(String::default(), extra.ip_policy_ref);
271
272 assert_eq!("tcp", tunnel_cfg.proto());
273
274 let opts = tunnel_cfg.opts().unwrap();
275 assert!(matches!(opts, BindOpts::Tcp { .. }));
276 if let BindOpts::Tcp(endpoint) = opts {
277 assert_eq!(REMOTE_ADDR, endpoint.addr);
278 assert!(matches!(endpoint.proxy_proto, ProxyProto::V2));
279
280 let ip_restriction = endpoint.ip_restriction.unwrap();
281 assert_eq!(Vec::from([ALLOW_CIDR]), ip_restriction.allow_cidrs);
282 assert_eq!(Vec::from([DENY_CIDR]), ip_restriction.deny_cidrs);
283 }
284
285 assert_eq!(HashMap::new(), tunnel_cfg.labels());
286 }
287
288 #[test]
289 fn test_binding_valid_values() {
290 let mut builder = TcpTunnelBuilder {
291 session: None,
292 options: Default::default(),
293 };
294
295 builder.binding("public");
297 assert_eq!(vec!["public"], builder.options.bindings);
298
299 let mut builder = TcpTunnelBuilder {
301 session: None,
302 options: Default::default(),
303 };
304 builder.binding("internal");
305 assert_eq!(vec!["internal"], builder.options.bindings);
306
307 let mut builder = TcpTunnelBuilder {
309 session: None,
310 options: Default::default(),
311 };
312 builder.binding("kubernetes");
313 assert_eq!(vec!["kubernetes"], builder.options.bindings);
314
315 let mut builder = TcpTunnelBuilder {
317 session: None,
318 options: Default::default(),
319 };
320 builder.binding(Binding::Public);
321 assert_eq!(vec!["public"], builder.options.bindings);
322 }
323
324 #[test]
325 #[should_panic(expected = "Invalid binding value")]
326 fn test_binding_invalid_value() {
327 let mut builder = TcpTunnelBuilder {
328 session: None,
329 options: Default::default(),
330 };
331 builder.binding("invalid");
332 }
333
334 #[test]
335 #[should_panic(expected = "binding() can only be called once")]
336 fn test_binding_called_twice() {
337 let mut builder = TcpTunnelBuilder {
338 session: None,
339 options: Default::default(),
340 };
341 builder.binding("public");
342 builder.binding("internal");
343 }
344}