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 {
162 if !self.options.bindings.is_empty() {
163 panic!("binding() can only be called once");
164 }
165 let binding_str = binding.into();
166 if let Err(e) = Binding::validate(&binding_str) {
167 panic!("{}", e);
168 }
169 self.options.bindings.push(binding_str);
170 self
171 }
172 pub fn forwards_to(&mut self, forwards_to: impl Into<String>) -> &mut Self {
181 self.options.common_opts.forwards_to = Some(forwards_to.into());
182 self
183 }
184
185 pub fn verify_upstream_tls(&mut self, verify_upstream_tls: bool) -> &mut Self {
187 self.options
188 .common_opts
189 .set_verify_upstream_tls(verify_upstream_tls);
190 self
191 }
192
193 pub fn remote_addr(&mut self, remote_addr: impl Into<String>) -> &mut Self {
197 self.options.remote_addr = Some(remote_addr.into());
198 self
199 }
200
201 pub fn policy<S>(&mut self, s: S) -> Result<&mut Self, S::Error>
203 where
204 S: TryInto<Policy>,
205 {
206 self.options.common_opts.policy = Some(s.try_into()?);
207 Ok(self)
208 }
209
210 pub fn traffic_policy(&mut self, policy_str: impl Into<String>) -> &mut Self {
212 self.options.common_opts.traffic_policy = Some(policy_str.into());
213 self
214 }
215
216 pub(crate) async fn for_forwarding_to(&mut self, to_url: &Url) -> &mut Self {
217 self.options.common_opts.for_forwarding_to(to_url);
218 self
219 }
220
221 pub fn pooling_enabled(&mut self, pooling_enabled: impl Into<bool>) -> &mut Self {
223 self.options.common_opts.pooling_enabled = Some(pooling_enabled.into());
224 self
225 }
226}
227
228#[cfg(test)]
229mod test {
230 use super::*;
231 use crate::config::policies::test::POLICY_JSON;
232 const METADATA: &str = "testmeta";
233 const TEST_FORWARD: &str = "testforward";
234 const REMOTE_ADDR: &str = "4.tcp.ngrok.io:1337";
235 const ALLOW_CIDR: &str = "0.0.0.0/0";
236 const DENY_CIDR: &str = "10.1.1.1/32";
237
238 #[test]
239 fn test_interface_to_proto() {
240 tunnel_test(
243 &TcpTunnelBuilder {
244 session: None,
245 options: Default::default(),
246 }
247 .allow_cidr(ALLOW_CIDR)
248 .deny_cidr(DENY_CIDR)
249 .proxy_proto(ProxyProto::V2)
250 .metadata(METADATA)
251 .remote_addr(REMOTE_ADDR)
252 .forwards_to(TEST_FORWARD)
253 .policy(POLICY_JSON)
254 .unwrap()
255 .options,
256 );
257 }
258
259 fn tunnel_test<C>(tunnel_cfg: &C)
260 where
261 C: TunnelConfig,
262 {
263 assert_eq!(TEST_FORWARD, tunnel_cfg.forwards_to());
264
265 let extra = tunnel_cfg.extra();
266 assert_eq!(String::default(), *extra.token);
267 assert_eq!(METADATA, extra.metadata);
268 assert_eq!(Vec::<String>::new(), extra.bindings);
269 assert_eq!(String::default(), extra.ip_policy_ref);
270
271 assert_eq!("tcp", tunnel_cfg.proto());
272
273 let opts = tunnel_cfg.opts().unwrap();
274 assert!(matches!(opts, BindOpts::Tcp { .. }));
275 if let BindOpts::Tcp(endpoint) = opts {
276 assert_eq!(REMOTE_ADDR, endpoint.addr);
277 assert!(matches!(endpoint.proxy_proto, ProxyProto::V2));
278
279 let ip_restriction = endpoint.ip_restriction.unwrap();
280 assert_eq!(Vec::from([ALLOW_CIDR]), ip_restriction.allow_cidrs);
281 assert_eq!(Vec::from([DENY_CIDR]), ip_restriction.deny_cidrs);
282 }
283
284 assert_eq!(HashMap::new(), tunnel_cfg.labels());
285 }
286
287 #[test]
288 fn test_binding_valid_values() {
289 let mut builder = TcpTunnelBuilder {
290 session: None,
291 options: Default::default(),
292 };
293
294 builder.binding("public");
296 assert_eq!(vec!["public"], builder.options.bindings);
297
298 let mut builder = TcpTunnelBuilder {
300 session: None,
301 options: Default::default(),
302 };
303 builder.binding("internal");
304 assert_eq!(vec!["internal"], builder.options.bindings);
305
306 let mut builder = TcpTunnelBuilder {
308 session: None,
309 options: Default::default(),
310 };
311 builder.binding("kubernetes");
312 assert_eq!(vec!["kubernetes"], builder.options.bindings);
313
314 let mut builder = TcpTunnelBuilder {
316 session: None,
317 options: Default::default(),
318 };
319 builder.binding(Binding::Public);
320 assert_eq!(vec!["public"], builder.options.bindings);
321 }
322
323 #[test]
324 #[should_panic(expected = "Invalid binding value")]
325 fn test_binding_invalid_value() {
326 let mut builder = TcpTunnelBuilder {
327 session: None,
328 options: Default::default(),
329 };
330 builder.binding("invalid");
331 }
332
333 #[test]
334 #[should_panic(expected = "binding() can only be called once")]
335 fn test_binding_called_twice() {
336 let mut builder = TcpTunnelBuilder {
337 session: None,
338 options: Default::default(),
339 };
340 builder.binding("public");
341 builder.binding("internal");
342 }
343}