Compare commits
	
		
			282 Commits
		
	
	
		
			220830
			...
			658d1970fd
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 658d1970fd | |||
| fc727422ab | |||
| 21de91b318 | |||
| 0da7e74c09 | |||
| 7742ea17da | |||
| 150a5cd012 | |||
| bf78fc3abf | |||
| f09cd78c57 | |||
| d73a2268a1 | |||
| b6bd55afa7 | |||
| 40039dee9f | |||
| 3422c2af89 | |||
| 285fa1b984 | |||
| 0bf05d056d | |||
| 113bf913e2 | |||
| 718acfa696 | |||
| add3dcefae | |||
| 80eb736787 | |||
| d88afaa459 | |||
| 0ea59a0fb0 | |||
| 268f8fcd64 | |||
| 3c3a84d9ea | |||
| d73f54ce0f | |||
| 023bf935eb | |||
| 6c24739c44 | |||
| 6e89eb03f5 | |||
| c4a46a0609 | |||
| 16f4e815a5 | |||
| 9d81fc4fff | |||
| e83c8389b3 | |||
| 6d96850c84 | |||
| 32322ec8c9 | |||
| 4a19b8eb6b | |||
| 70981b4f8b | |||
| 808f3b1acc | |||
| cba0bf53e0 | |||
| 61f98e2e70 | |||
| f0dd97dcac | |||
| 44851be0c0 | |||
| fdded8b5ce | |||
| df6e2fdae2 | |||
| 627fbbf399 | |||
| cb332240e0 | |||
| 3a387f7839 | |||
| 2a9c5d388f | |||
| 1e573e18f6 | |||
| 316f3223c7 | |||
| 45a860fea4 | |||
| d39f3229b5 | |||
| 1e5dc5a712 | |||
| 952c3f22c9 | |||
| 229c9bbdd9 | |||
| d613f7a1ef | |||
| 3aa7beb012 | |||
| 570e40d790 | |||
| 19a0ae0e7f | |||
| e683505314 | |||
| e0ad9ad050 | |||
| 2145b8cd2d | |||
| ab765f0da9 | |||
| dbc84463d6 | |||
| a415c328b1 | |||
| ce3bfac99b | |||
| 386c5f545b | |||
| 2334bac822 | |||
| 445dd8ede5 | |||
| 2db7e9596a | |||
| afe09b6cd0 | |||
| d0543a193f | |||
| e5f9291cd7 | |||
| 4e6f314e64 | |||
| 5d38025bb5 | |||
| 1552c5c678 | |||
| f5dd68c255 | |||
| ff5bfabe8a | |||
| 6d03789e08 | |||
| e37cb74d0f | |||
| 4ab86531fa | |||
| 1187b1d853 | |||
| 78cc13f25f | |||
| 1ebd4822c4 | |||
| 71522517fa | |||
| 54774488c6 | |||
| b0eeb004a9 | |||
| 228ff22dc1 | |||
| 2276e4eca0 | |||
| 824744aade | |||
| 23e28b0480 | |||
| b3a1be7c18 | |||
| 8bc3518a2d | |||
| e534deefae | |||
| 5609708848 | |||
| 9e396262ff | |||
| 4ee0d8c49d | |||
| ce5a4562a7 | |||
| c873c29339 | |||
| c561441a4c | |||
| a31868fb27 | |||
| 8a5cc2952f | |||
| 5d15ba4515 | |||
| 6d56f50512 | |||
| 41bef1bdcd | |||
| 88a11b143a | |||
| 8622488028 | |||
| 9500df553a | |||
| 804c3e433b | |||
| 9ba0125cfa | |||
| 8ebe46d2e4 | |||
| 27d62d6552 | |||
| 62fd095171 | |||
| 7c5e82d9de | |||
| a73a87b636 | |||
| edfce0a15e | |||
| 41e6e43da9 | |||
| 301ee29e95 | |||
| 50c88074f8 | |||
| 965c235169 | |||
| 863a835e9a | |||
| 6310d8a55f | |||
| b6b196f2fb | |||
| f1d31d0496 | |||
| db1f3fccad | |||
| 16803df507 | |||
| 781e5860af | |||
| e0c29e8aa8 | |||
| 80e5c3abc3 | |||
| 5b6b525b1e | |||
| 17282b82df | |||
| 07124b452b | |||
| fa057bd233 | |||
| 0df1567020 | |||
| 9ac7c74379 | |||
| 07622a7cec | |||
| 85a728319c | |||
| 985457da43 | |||
| 917b035b6f | |||
| ddd4fed0ca | |||
| cc99e5052b | |||
| d89fef263e | |||
| 7774c946cf | |||
| 404cd681e8 | |||
| 6db636638c | |||
| 9d8caeeac5 | |||
| 590bc33aa7 | |||
| 33aa208cdb | |||
| ed4c7b066f | |||
| 83bea2a428 | |||
| 5d1e2510f5 | |||
| 5779410575 | |||
| 7ce658ab92 | |||
| 1d0c3a719c | |||
| b3060aef43 | |||
| 6439c36b8c | |||
| 600f441c14 | |||
| 75400eec47 | |||
| b96e045ecf | |||
| 35a7aee89f | |||
| 2d368dfdd5 | |||
| 4c7ab677de | |||
| 6998400962 | |||
| ca64c20397 | |||
| a44820ba0c | |||
| 5654bc25f9 | |||
| 835164d431 | |||
| af6974d769 | |||
| 08f27b61bb | |||
| 87c5ec87b3 | |||
| 85f5828446 | |||
| ab14d9f6cf | |||
| 35b10ea4a9 | |||
| 6847e080d2 | |||
| 4fa1ea491a | |||
| f87f259af5 | |||
| 4bd92e7ee2 | |||
| b3cc6f01a2 | |||
| 830003e527 | |||
| 968a485b44 | |||
| 41d3d7f69e | |||
| e65c0d7eb9 | |||
| 5df45fd295 | |||
| c3084982b3 | |||
| 858f01e1b9 | |||
| 4766f8b796 | |||
| 9c7157d591 | |||
| e7d5bac8db | |||
| a3052e08e7 | |||
| 61774e13b2 | |||
| 9e848225e2 | |||
| 266c906abf | |||
| 40f1d720fe | |||
| ecc77ccb99 | |||
| 764f04da38 | |||
| 865b854409 | |||
| d65a7d232c | |||
| 76469dd6fc | |||
| c839a52f4c | |||
| c98bacb070 | |||
| 02fe48cb0d | |||
| a9ca0584ed | |||
| 82f2358f32 | |||
| 4e1302cf3f | |||
| ea177f6eb8 | |||
| 15d640127a | |||
| fefe684fdd | |||
| efa26e3d01 | |||
| 1ba7c9602b | |||
| 1ef7d3a52c | |||
| 0bb37ddfb2 | |||
| cdb0afc601 | |||
| 0cfe671320 | |||
| d15455e5ce | |||
| 6c75064a1c | |||
| 3e2720099e | |||
| 45bf153682 | |||
| 9920c63b8b | |||
| 369639510a | |||
| 0e1076cfb6 | |||
| 79cb4ff469 | |||
| 3c2ea933c4 | |||
| 0205a40600 | |||
| 0c7c6c4df2 | |||
| 9fa409df26 | |||
| 2f4af66a19 | |||
| 4b61f79be8 | |||
| 96bb688a32 | |||
| 6d6c8e4bfa | |||
| 27f6834ab5 | |||
| 5e3a36dbcc | |||
| 4468a75326 | |||
| 05474fd50e | |||
| 0572161b00 | |||
| 68f6d85ffe | |||
| 9ac66b702f | |||
| aa7bea05f5 | |||
| 5625a0d738 | |||
| 50c8ac03b2 | |||
| f0fec7564c | |||
| 9e383fc7cf | |||
| 8f688b54e3 | |||
| 47dde332d2 | |||
| a30122b533 | |||
| 011f70c119 | |||
| 2b1b2484af | |||
| 8efccaaa45 | |||
| 1574dd7196 | |||
| 3f5f92eaa6 | |||
| 58b21bf59d | |||
| 585735769f | |||
| d5f1f2c925 | |||
| 4ce1988e4c | |||
| edb88bb8c8 | |||
| dcb00ccc6e | |||
| eaddcc699b | |||
| 72f9e00b80 | |||
| 55da596587 | |||
| 1321cf79c6 | |||
| 391d0facd2 | |||
| 59aadeacd4 | |||
| a5e48cf9d0 | |||
| 4f89bc06a0 | |||
| 019ae92605 | |||
| 6f8055f1c7 | |||
| 54214a3308 | |||
| 40c1bfc938 | |||
| 886843d087 | |||
| 62fa71ea6e | |||
| 43a6d2c3a2 | |||
| caa62b8e49 | |||
| 7c64003b13 | |||
| b24e8ba68b | |||
| 3be4c5a68e | |||
| 27b50d2333 | |||
| ce1237a13b | |||
| c173ed3c5c | |||
| 1ce19ff56a | |||
| c063cdcef6 | |||
| 3cbbd72a14 | |||
| cd0f6fea94 | |||
| 27b52dfcb7 | |||
| 1b95b10553 | |||
| 723ed5e390 | |||
| 3b2866fa6a | 
							
								
								
									
										13
									
								
								.drone.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								.drone.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					kind: pipeline
 | 
				
			||||||
 | 
					type: docker
 | 
				
			||||||
 | 
					name: default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					steps:
 | 
				
			||||||
 | 
					- name: cargo_check
 | 
				
			||||||
 | 
					  image: rust
 | 
				
			||||||
 | 
					  commands:
 | 
				
			||||||
 | 
					  - rustup component add clippy
 | 
				
			||||||
 | 
					  - cargo clippy -- -D warnings
 | 
				
			||||||
 | 
					  - cargo test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,3 @@
 | 
				
			|||||||
target
 | 
					target
 | 
				
			||||||
.idea
 | 
					.idea
 | 
				
			||||||
 | 
					pki
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1878
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1878
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										37
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								Cargo.toml
									
									
									
									
									
								
							@@ -1,7 +1,32 @@
 | 
				
			|||||||
[workspace]
 | 
					[package]
 | 
				
			||||||
 | 
					name = "tcp_over_http"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					description = "TCP-over-HTTP solution"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
members = [
 | 
					[dependencies]
 | 
				
			||||||
	"base",
 | 
					clap = { version = "4.5.4", features = ["derive", "env"] }
 | 
				
			||||||
	"tcp_relay_server",
 | 
					log = "0.4.21"
 | 
				
			||||||
	"tcp_relay_client"
 | 
					env_logger = "0.11.3"
 | 
				
			||||||
]
 | 
					actix = "0.13.3"
 | 
				
			||||||
 | 
					actix-web = { version = "4.5.1", features = ["rustls-0_21"] }
 | 
				
			||||||
 | 
					actix-web-actors = "4.3.0"
 | 
				
			||||||
 | 
					actix-tls = "3.3.0"
 | 
				
			||||||
 | 
					serde = { version = "1.0.200", features = ["derive"] }
 | 
				
			||||||
 | 
					tokio = { version = "1.37.0", features = ["full"] }
 | 
				
			||||||
 | 
					futures = "0.3.30"
 | 
				
			||||||
 | 
					webpki = "0.22.4"
 | 
				
			||||||
 | 
					x509-parser = "0.16.0"
 | 
				
			||||||
 | 
					pem = "3.0.4"
 | 
				
			||||||
 | 
					reqwest = { version = "0.12.4", features = ["json", "rustls-tls"], default-features = false }
 | 
				
			||||||
 | 
					tokio-tungstenite = { version = "0.20.0", features = ["__rustls-tls", "rustls-tls-native-roots"] }
 | 
				
			||||||
 | 
					urlencoding = "2.1.3"
 | 
				
			||||||
 | 
					hyper-rustls = { version = "0.23.2", features = ["rustls-native-certs"] }
 | 
				
			||||||
 | 
					bytes = "1.6.0"
 | 
				
			||||||
 | 
					rustls-pemfile = "2.0.0"
 | 
				
			||||||
 | 
					rustls = { version = "0.21.0", features = ["dangerous_configuration"] }
 | 
				
			||||||
 | 
					rustls-native-certs = "0.6.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dev-dependencies]
 | 
				
			||||||
 | 
					rand = "0.8.5"
 | 
				
			||||||
 | 
					mktemp = "0.5.1"
 | 
				
			||||||
							
								
								
									
										25
									
								
								README.MD
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.MD
									
									
									
									
									
								
							@@ -1,4 +1,6 @@
 | 
				
			|||||||
# TCP over HTTP
 | 
					# TCP over HTTP
 | 
				
			||||||
 | 
					[](https://drone.communiquons.org/pierre/tcp-over-http)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This project aims to provide an easy-to-setup TCP forwarding solution:
 | 
					This project aims to provide an easy-to-setup TCP forwarding solution:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
@@ -6,17 +8,28 @@ This project aims to provide an easy-to-setup TCP forwarding solution:
 | 
				
			|||||||
|        |              | Client |                     | Server |              |        |
 | 
					|        |              | Client |                     | Server |              |        |
 | 
				
			||||||
| Client | -- TCP xx -- |        | -- HTTP 80 / 443 -- |        | -- TCP xx -- | Server |
 | 
					| Client | -- TCP xx -- |        | -- HTTP 80 / 443 -- |        | -- TCP xx -- | Server |
 | 
				
			||||||
|        |              |  Relay |                     |  Relay |              |        |
 | 
					|        |              |  Relay |                     |  Relay |              |        |
 | 
				
			||||||
|--------|              |--------|                     |--------|              |--------|
 | 
					|--------|              |--------|                     |--------|              |--------|
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This project can be used especially to bypass firewalls that blocks traffics
 | 
					This project can be used especially to bypass firewalls that blocks traffics
 | 
				
			||||||
from ports others than the 80 / 443 duo.
 | 
					from ports others than the HTTP / HTTPS ports. The TCP traffic is encapsulated inside an
 | 
				
			||||||
 | 
					HTTP WebSocket between the client and the server relays.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This repository contains two binaries:
 | 
					## Authentication
 | 
				
			||||||
 | 
					The client can authenticate against the server relays through two different means:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `tpc_relay_server`: The server relay
 | 
					* Using a token (the server relay can have several tokens at the same time)
 | 
				
			||||||
* `tcp_relay_client`: The client relay
 | 
					* Using a client TLS certificate. In this case, the server relay must act as a HTTPS server, and you must provide the
 | 
				
			||||||
 | 
					  server the required certificates / key files in PEM format. It is also possible to provide the  server a CRL file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The clients relay authenticates itself to the server using a token.
 | 
					
 | 
				
			||||||
 | 
					## Binary
 | 
				
			||||||
 | 
					This repository contains a single binary which can be used as a server or a client, depending of command line arguments:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Server mode: Act as a server relay. In case of token authentication (NOT TLS authentication), it can be put behind a reverse proxy.
 | 
				
			||||||
 | 
					* Client mode: Act as a client relay. It basically does three things:
 | 
				
			||||||
 | 
					  * Fetch the list of forwared ports configuration from the server
 | 
				
			||||||
 | 
					  * Listen to these port locally
 | 
				
			||||||
 | 
					  * When a connection occurs on one of these ports, it forward the data exchanged by the socket to and from the server.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A single server - client relay pair can relay multiple ports simultaneously from the same machine.
 | 
					A single server - client relay pair can relay multiple ports simultaneously from the same machine.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +0,0 @@
 | 
				
			|||||||
[package]
 | 
					 | 
				
			||||||
name = "base"
 | 
					 | 
				
			||||||
version = "0.1.0"
 | 
					 | 
				
			||||||
edition = "2021"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
serde = { version = "1.0.144", features = ["derive"] }
 | 
					 | 
				
			||||||
							
								
								
									
										9
									
								
								renovate.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								renovate.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
 | 
				
			||||||
 | 
					  "packageRules": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "matchUpdateTypes": ["major", "minor", "patch"],
 | 
				
			||||||
 | 
					      "automerge": true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										86
									
								
								src/base/cert_utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/base/cert_utils.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					use std::error::Error;
 | 
				
			||||||
 | 
					use std::io::{Cursor, ErrorKind};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use rustls::{Certificate, PrivateKey};
 | 
				
			||||||
 | 
					use rustls_pemfile::Item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Parse PEM certificates bytes into a [`rustls::Certificate`] structure
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// An error is returned if not any certificate could be found
 | 
				
			||||||
 | 
					pub fn parse_pem_certificates(certs: &[u8]) -> Result<Vec<Certificate>, Box<dyn Error>> {
 | 
				
			||||||
 | 
					    let certs = rustls_pemfile::certs(&mut Cursor::new(certs))
 | 
				
			||||||
 | 
					        .map(|c| c.map(|c| Certificate(c.to_vec())))
 | 
				
			||||||
 | 
					        .collect::<Result<Vec<_>, _>>()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if certs.is_empty() {
 | 
				
			||||||
 | 
					        Err(std::io::Error::new(
 | 
				
			||||||
 | 
					            ErrorKind::InvalidData,
 | 
				
			||||||
 | 
					            "Could not find any certificate!",
 | 
				
			||||||
 | 
					        ))?;
 | 
				
			||||||
 | 
					        unreachable!();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(certs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Parse PEM private key bytes into a [`rustls::PrivateKey`] structure
 | 
				
			||||||
 | 
					pub fn parse_pem_private_key(privkey: &[u8]) -> Result<PrivateKey, Box<dyn Error>> {
 | 
				
			||||||
 | 
					    let key = match rustls_pemfile::read_one(&mut Cursor::new(privkey))? {
 | 
				
			||||||
 | 
					        None => {
 | 
				
			||||||
 | 
					            Err(std::io::Error::new(
 | 
				
			||||||
 | 
					                ErrorKind::Other,
 | 
				
			||||||
 | 
					                "Failed to extract private key!",
 | 
				
			||||||
 | 
					            ))?;
 | 
				
			||||||
 | 
					            unreachable!()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Some(Item::Pkcs8Key(key)) => key.secret_pkcs8_der().to_vec(),
 | 
				
			||||||
 | 
					        Some(Item::Pkcs1Key(key)) => key.secret_pkcs1_der().to_vec(),
 | 
				
			||||||
 | 
					        _ => {
 | 
				
			||||||
 | 
					            Err(std::io::Error::new(
 | 
				
			||||||
 | 
					                ErrorKind::Other,
 | 
				
			||||||
 | 
					                "Unsupported private key type!",
 | 
				
			||||||
 | 
					            ))?;
 | 
				
			||||||
 | 
					            unreachable!();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(PrivateKey(key))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod test {
 | 
				
			||||||
 | 
					    use crate::base::cert_utils::{parse_pem_certificates, parse_pem_private_key};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const SAMPLE_CERT: &[u8] = include_bytes!("samples/TCPTunnelTest.crt");
 | 
				
			||||||
 | 
					    const SAMPLE_KEY: &[u8] = include_bytes!("samples/TCPTunnelTest.key");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn parse_valid_cert() {
 | 
				
			||||||
 | 
					        parse_pem_certificates(SAMPLE_CERT).unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn parse_invalid_cert_1() {
 | 
				
			||||||
 | 
					        parse_pem_certificates("Random content".as_bytes()).unwrap_err();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn parse_invalid_cert_2() {
 | 
				
			||||||
 | 
					        parse_pem_certificates(SAMPLE_KEY).unwrap_err();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn parse_valid_key() {
 | 
				
			||||||
 | 
					        parse_pem_private_key(SAMPLE_KEY).unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn parse_invalid_key_1() {
 | 
				
			||||||
 | 
					        parse_pem_private_key("Random content".as_bytes()).unwrap_err();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn parse_invalid_key_2() {
 | 
				
			||||||
 | 
					        parse_pem_private_key(SAMPLE_CERT).unwrap_err();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/base/err_utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/base/err_utils.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					use std::fmt::Display;
 | 
				
			||||||
 | 
					use std::io::ErrorKind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Encapsulate errors in [`std::io::Error`] with a message
 | 
				
			||||||
 | 
					pub fn encpasulate_error<E: Display, F: ToString>(e: E, msg: F) -> std::io::Error {
 | 
				
			||||||
 | 
					    std::io::Error::new(ErrorKind::Other, format!("{}:\n* {}", msg.to_string(), e))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Create a new [`std::io::Error`]
 | 
				
			||||||
 | 
					pub fn new_err(msg: &str) -> std::io::Error {
 | 
				
			||||||
 | 
					    std::io::Error::new(ErrorKind::Other, msg.to_string())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/base/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/base/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					pub mod cert_utils;
 | 
				
			||||||
 | 
					pub mod err_utils;
 | 
				
			||||||
 | 
					mod structs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use structs::{RelayedPort, RemoteConfig};
 | 
				
			||||||
							
								
								
									
										29
									
								
								src/base/samples/TCPTunnelTest.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/base/samples/TCPTunnelTest.crt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIE8DCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDEw1UQ1BU
 | 
				
			||||||
 | 
					dW5uZWxUZXN0MB4XDTIyMDkwMTA2MzMyMFoXDTI0MDMwMTA2MzMxOFowGDEWMBQG
 | 
				
			||||||
 | 
					A1UEAxMNVENQVHVubmVsVGVzdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
 | 
				
			||||||
 | 
					ggIBALqh3EXg3TYq5TwZPjOX35bM7kol+fLlwjLaXCTx/lTXU0hTFsIa0kFCiPsT
 | 
				
			||||||
 | 
					Vhm5nwhDLxnAARagc74gUHfhr6meMbsje2NzylmCpW1As1s1xo2n8oNi2YsqIA9A
 | 
				
			||||||
 | 
					HWQWsihf7fPlyZOgBIwUQBsLd6ujpwbvaEhwBArS+peVYuB3zDbuNBJ2lqdvD5fa
 | 
				
			||||||
 | 
					8aCyoPyseaJcaMMJ3R2W/8OYrUsJECKgg26A8zxF55RdvjJcBONG0kRlNsrxS6uO
 | 
				
			||||||
 | 
					9dnQ8kyvUReluPgTEfZm/M54dCi9VvKVRKA/5md/+SQWwQhPyIig3+XXeYQNoUN6
 | 
				
			||||||
 | 
					YXvlWw704VBg/hDBqrY42LjpS/FyMGsp4cHVCMXBLwRNHWPfik6w3rNTpFp7h4Mm
 | 
				
			||||||
 | 
					effxX2V/xuBr3IciVcsmeD4Xmfp0o6g3o5VPK4KIR5/b+aKe7uL8/9hTTLSqWpm8
 | 
				
			||||||
 | 
					+k0boE796/gb8egyELwBrPsrdGQIiIP2Ac6m53iTtEtceIOmMB+t7mUPkQHsiLoC
 | 
				
			||||||
 | 
					LeRm2dbPWEKz2mO8fOVjVYT9nxY92l/AveuksTui5GZ2z4ZVp1m6pAxVjVf+L/Sg
 | 
				
			||||||
 | 
					MMkEfcIUW6Xb8Ba+KYRCc/5U8Xkz26F80dhjGdeledTpBhkyKqsxcKpLqFsuYj3W
 | 
				
			||||||
 | 
					b5FfLBlQe/Yargqd8HhvgMydi+lHG14FAflhp8emnOGOzaPbAgMBAAGjRTBDMA4G
 | 
				
			||||||
 | 
					A1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTQ9A38
 | 
				
			||||||
 | 
					JD46Si69hfW4me3CJZNK0DANBgkqhkiG9w0BAQsFAAOCAgEAIpNieyvlaO0E5oUz
 | 
				
			||||||
 | 
					1o7QJ+YtwwhPriOifrXAV+NaJj0n7Y1Fq4ztIhBPGtqwhPqgDUEn0G/mIr0BjA1w
 | 
				
			||||||
 | 
					/zQGJx1U8g9wNP8SERKVtD4Gx4S1ruLzTqK1V4xyV6bRhqmfi+YHNKviFNAEDDfz
 | 
				
			||||||
 | 
					rhiH1ULuoVfww8mH3FpL2oGhR+x900WkG98xtJ43ik/EIQu2kN+r5x9GPYC+NTC2
 | 
				
			||||||
 | 
					xScVG3OGbJLE7fHDJBPSa5vOCk4DkBXKyOjYwnfd8Saz2E1u6w7eH3dgzCqiw66K
 | 
				
			||||||
 | 
					lcksjKD4+F1t4Jhy1p/K3qzZsZQ/NpHH9v++LATtwvUN2bzPLiZ/LhV5QH/kg9Qf
 | 
				
			||||||
 | 
					49OBRMKjUJ6MgQ7/JOwtaHyu8jBuJWUNEE47hpHGUrIxmLUi2AWlxxQZdPic+Rxf
 | 
				
			||||||
 | 
					LKWoNlGx5OrzcIuIc3lb11zinRdaawOjVV0yCKWIlSkb77Flp8WJIlZ6ZHLtqwsU
 | 
				
			||||||
 | 
					8D9zN4EXefc9dXYMLyWvRHmHOTr8430PebYc/G5BA+XjOgpFQ3vu8trIA/3Dbuyc
 | 
				
			||||||
 | 
					ggz1abiDnBmp+I66AYV+Ker81maM6CQU+03WKHbHZyJWr74SKuILY1knys/fXJvT
 | 
				
			||||||
 | 
					UZRMhmaQqxc1QcWVOkWLv0RcAhEjwIX0+36NUC1W35JfrRpHtmqIiJH9kjcjr94w
 | 
				
			||||||
 | 
					5sjM2EUFmMC5z0zjF9cSYKSHLSI=
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/base/samples/TCPTunnelTest.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/base/samples/TCPTunnelTest.key
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					-----BEGIN RSA PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIIJKAIBAAKCAgEAuqHcReDdNirlPBk+M5fflszuSiX58uXCMtpcJPH+VNdTSFMW
 | 
				
			||||||
 | 
					whrSQUKI+xNWGbmfCEMvGcABFqBzviBQd+GvqZ4xuyN7Y3PKWYKlbUCzWzXGjafy
 | 
				
			||||||
 | 
					g2LZiyogD0AdZBayKF/t8+XJk6AEjBRAGwt3q6OnBu9oSHAECtL6l5Vi4HfMNu40
 | 
				
			||||||
 | 
					EnaWp28Pl9rxoLKg/Kx5olxowwndHZb/w5itSwkQIqCDboDzPEXnlF2+MlwE40bS
 | 
				
			||||||
 | 
					RGU2yvFLq4712dDyTK9RF6W4+BMR9mb8znh0KL1W8pVEoD/mZ3/5JBbBCE/IiKDf
 | 
				
			||||||
 | 
					5dd5hA2hQ3phe+VbDvThUGD+EMGqtjjYuOlL8XIwaynhwdUIxcEvBE0dY9+KTrDe
 | 
				
			||||||
 | 
					s1OkWnuHgyZ59/FfZX/G4GvchyJVyyZ4PheZ+nSjqDejlU8rgohHn9v5op7u4vz/
 | 
				
			||||||
 | 
					2FNMtKpambz6TRugTv3r+Bvx6DIQvAGs+yt0ZAiIg/YBzqbneJO0S1x4g6YwH63u
 | 
				
			||||||
 | 
					ZQ+RAeyIugIt5GbZ1s9YQrPaY7x85WNVhP2fFj3aX8C966SxO6LkZnbPhlWnWbqk
 | 
				
			||||||
 | 
					DFWNV/4v9KAwyQR9whRbpdvwFr4phEJz/lTxeTPboXzR2GMZ16V51OkGGTIqqzFw
 | 
				
			||||||
 | 
					qkuoWy5iPdZvkV8sGVB79hquCp3weG+AzJ2L6UcbXgUB+WGnx6ac4Y7No9sCAwEA
 | 
				
			||||||
 | 
					AQKCAgEAlgh6+N4NV3dic07jtzw3bZZvVcJzzjWwSYtLGhREXlX/yJurJv3C2t2v
 | 
				
			||||||
 | 
					GxBvXhzf4ReJbMzy0wrIISb/KXCP8+6NkiCzF79FA3JIpKynwwJXDRffmInF0t9Z
 | 
				
			||||||
 | 
					iIkFV6n7LQP5WeH3i6rPHQFGi7dLS/sy0htyHRGX3k+/Tk60fzkvPVV/HPyinhVl
 | 
				
			||||||
 | 
					VrGXH5WaX6YT3lcljO2ICTqTf91kKncttniNUC9v2ptj0N0PgpKBB2iurncjdkBG
 | 
				
			||||||
 | 
					kbNKpwEXWFhz+2upaByEiy49u4oP75ROqpMe6SiVg8zYL4/vPExPLK8Pb0kqkeMX
 | 
				
			||||||
 | 
					KhTe+2flLP/lheWDOVtHblgCuZwrBJzbfyCS4/+xkd/SSwqlSWpxTlnBlF3s5y81
 | 
				
			||||||
 | 
					C2tO1N0cciMOjQdkjw45zJ1QFOt6tM7ZydXrm6XexOMcGX7lU44VFc76HrK4NePW
 | 
				
			||||||
 | 
					wzrRQ7V4SUwzd9sfioInqIFfai/zRF+u0gz1WFwi0Bgvz24d26h7l/UzdS3XGX7q
 | 
				
			||||||
 | 
					3AcLAXycByT1AOhQeEtfVGMvgjYLnmCOB7JrD3TAlAXTJbgjUQEK/WtCM6H49gZB
 | 
				
			||||||
 | 
					1h4WK8gvNJZ3lz+dSz2ShwS0A6ay6nJnyFXBUwZ4ABqjmy8kxMzIdD9Fkn/PBH7W
 | 
				
			||||||
 | 
					OaNwVPbeLQdiQaihLGfZFciswaMqdUoT+BKQVVajMpvAjkq/Y3kCggEBAMd5ozuR
 | 
				
			||||||
 | 
					SIIzrI/M5DeDUFijbISLH6NDiOZ3XLySsrgiv3T1NXNtmmjCYcB8pn77lm1GCsC9
 | 
				
			||||||
 | 
					k9Mui+ywd/mWqvOGVUSsppV8id87c4ySJK4Yhmzm9eSB5tCUx5KGXy4mWcrVLNpt
 | 
				
			||||||
 | 
					KwNWSfmSLu/ypx/SkEf88GJZuaNdtcumfmeKjO4SmpItsfjL4m7tQ6a4xj1B3GgA
 | 
				
			||||||
 | 
					dk13GR67RLMo2xVy6UvAZMkQR4SJYPNb35TUgOe4lWrF9puFAMdoQN877qnY5E3r
 | 
				
			||||||
 | 
					EMy974MgFhd1QxGICoEavEJr1FyGeNUK5livHfdH/z5lt9F2u9CyAJucUCLYS413
 | 
				
			||||||
 | 
					3x4wKjNf1f6Wi/UCggEBAO+EkoKOAaHVTzgPEKl4rzj3+U1QpXOG2tzQ2lBpWMlV
 | 
				
			||||||
 | 
					/0WREO202+2bgLno+xZ0sFZ1bRHNqzgObFG8z4WuaXoHBxvkeibuCGuPYPTqNpLq
 | 
				
			||||||
 | 
					hVbCrp5HG8Cfups0GamiZFBViYlFrEapMIf4c4SpTffGX3qlSbxPzLIBbFBsNteH
 | 
				
			||||||
 | 
					6FvJtRvLFH3iD2Vy+O/IBh1PlQRTHQhuqZYv3mgOtKz3I8o1JD8G+XTsahdyrT2F
 | 
				
			||||||
 | 
					PsGSRwwZIRQhNYBO3csefJKUuyANx5LieJTZ3sIsJubmCZK4dBJVv6M2eLIGfhU1
 | 
				
			||||||
 | 
					46miPZqtGu3XIn3rQ8E7a/gZ/isEUr2aKC6AVBab3o8CggEASJL01KNTIivyyI7f
 | 
				
			||||||
 | 
					KWNZRCaRQNftNtVHZbJfxywIYf4ickcUn15tI1g1gHbZjLG0VSV6nA1dTyRMPF0o
 | 
				
			||||||
 | 
					CWLL57YkJ8w4/4JEFzfmHmq9danunoiZRf4NIC5BPgotbvj9ClLs8rttPtWSLH8H
 | 
				
			||||||
 | 
					HL3IGEffvpFEVEQYyls53VJCAyHhjGywWCbP7ZkgVQN17Z6kYX0o153zbNO8C/ZO
 | 
				
			||||||
 | 
					VHC05OTeBHWHNa/6lTn2UBRJEDkQfT4m/qXvxz1ovyQrFg0UFC+ZQNAZWKRyE98E
 | 
				
			||||||
 | 
					qpw7PpGkYLx9ah0ZMmCqbbh9fh6YZHOJZgZUDp2IT7GzjuocLdFMC7hlMPKNKAvi
 | 
				
			||||||
 | 
					K7JSUQKCAQB7jthFoRwWcAO914ew5SD/MmzZBZFUV2zwHI2CjdXPhx14ta0V8wbB
 | 
				
			||||||
 | 
					PEbboORmYSvWbh0l4gNBl68pO02SmLawzI9ORD7/divB0OUjcu9UOscuSp/p5qTa
 | 
				
			||||||
 | 
					aYvKJMZYS/2Ts4yP0/FbQkxW2EQ/W1dtSlhW3I19J21hJnrJwglIhkPHlfZnsAuS
 | 
				
			||||||
 | 
					JNvsabMhfv4ogLVO1dFUWEIDyA3jgDKUR6me1mssWFy3hH32OqJD6kjFcsBT7WKz
 | 
				
			||||||
 | 
					D66Z0hV4gvGgbDlb/7/Edi/eGcZgRIaM9n5Zwe2ex71kZOU+cTr5liMrjxZYhJQv
 | 
				
			||||||
 | 
					vZt9ebAqLo00H7SOXFySksPHuUunniDhAoIBAFH3wC6kW3RLX7vuKqgZMLIR93ey
 | 
				
			||||||
 | 
					bJKwFFwBk7Jc4PT47sp7B8Vi58DOl4eFzktYhn5lh/YN9K/Tj1zLSEqJqxO+SBO+
 | 
				
			||||||
 | 
					irArxdHaUzQ1lzeRpvYxP3cB5ZBBDHvZCtNkmqfnGCxQtvoxuCt9m8brpfPAmZaW
 | 
				
			||||||
 | 
					8jrLNrWqvkxJE9GFfmZ8R+pTIFCBDRC6E2RuHFrQK5NCr717zDJ/OPe5GDmWp48d
 | 
				
			||||||
 | 
					GiPu+CUqew2yt9XQw7Ol+QVY6NVyqDAZR34jIc3/TtsISfYahN0zAxUHtW3BdAOF
 | 
				
			||||||
 | 
					HOfvisKnygWsUi7efFAVfRop5UUeoxDqGh/UvFy0JsUbFfeRynTH7FIwBSA=
 | 
				
			||||||
 | 
					-----END RSA PRIVATE KEY-----
 | 
				
			||||||
							
								
								
									
										6
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					mod base;
 | 
				
			||||||
 | 
					pub mod tcp_relay_client;
 | 
				
			||||||
 | 
					pub mod tcp_relay_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod test;
 | 
				
			||||||
							
								
								
									
										49
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					use clap::{Parser, Subcommand};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use tcp_over_http::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use tcp_over_http::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
 | 
					#[clap(
 | 
				
			||||||
 | 
					    author,
 | 
				
			||||||
 | 
					    version,
 | 
				
			||||||
 | 
					    about,
 | 
				
			||||||
 | 
					    long_about = "Encapsulate TCP sockets inside HTTP WebSockets\nSource code: https://gitea.communiquons.org/pierre/tcp-over-http"
 | 
				
			||||||
 | 
					)]
 | 
				
			||||||
 | 
					struct CliArgs {
 | 
				
			||||||
 | 
					    #[clap(subcommand)]
 | 
				
			||||||
 | 
					    command: SubCommands,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Subcommand, Debug)]
 | 
				
			||||||
 | 
					enum SubCommands {
 | 
				
			||||||
 | 
					    /// Run as server
 | 
				
			||||||
 | 
					    Server(ServerConfig),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Run as client
 | 
				
			||||||
 | 
					    Client(ClientConfig),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[actix_web::main]
 | 
				
			||||||
 | 
					async fn main() -> std::io::Result<()> {
 | 
				
			||||||
 | 
					    env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let args: CliArgs = CliArgs::parse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Dispatch the request to the appropriate part of the program
 | 
				
			||||||
 | 
					    match args.command {
 | 
				
			||||||
 | 
					        SubCommands::Server(c) => tcp_over_http::tcp_relay_server::run_app(c).await,
 | 
				
			||||||
 | 
					        SubCommands::Client(c) => tcp_over_http::tcp_relay_client::run_app(c).await,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod test {
 | 
				
			||||||
 | 
					    use crate::CliArgs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn verify_cli() {
 | 
				
			||||||
 | 
					        use clap::CommandFactory;
 | 
				
			||||||
 | 
					        CliArgs::command().debug_assert()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										110
									
								
								src/tcp_relay_client/client_config.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/tcp_relay_client/client_config.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					use crate::base::err_utils::encpasulate_error;
 | 
				
			||||||
 | 
					use bytes::BufMut;
 | 
				
			||||||
 | 
					use clap::Parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// TCP relay client
 | 
				
			||||||
 | 
					#[derive(Parser, Debug, Clone, Default)]
 | 
				
			||||||
 | 
					#[clap(author, version, about, long_about = None)]
 | 
				
			||||||
 | 
					pub struct ClientConfig {
 | 
				
			||||||
 | 
					    /// Access token
 | 
				
			||||||
 | 
					    #[clap(short, long)]
 | 
				
			||||||
 | 
					    pub token: Option<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Relay server
 | 
				
			||||||
 | 
					    #[clap(short, long, default_value = "http://127.0.0.1:8000")]
 | 
				
			||||||
 | 
					    pub relay_url: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Listen address
 | 
				
			||||||
 | 
					    #[clap(short, long, default_value = "127.0.0.1")]
 | 
				
			||||||
 | 
					    pub listen_address: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Alternative root certificate to use for server authentication
 | 
				
			||||||
 | 
					    #[clap(short = 'c', long)]
 | 
				
			||||||
 | 
					    pub root_certificate: Option<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// TLS certificate for TLS authentication.
 | 
				
			||||||
 | 
					    #[clap(long)]
 | 
				
			||||||
 | 
					    pub tls_cert: Option<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// TLS key for TLS authentication.
 | 
				
			||||||
 | 
					    #[clap(long)]
 | 
				
			||||||
 | 
					    pub tls_key: Option<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[clap(skip)]
 | 
				
			||||||
 | 
					    pub _keys_cache: KeysCache,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Parser, Debug, Clone, Default)]
 | 
				
			||||||
 | 
					pub struct KeysCache {
 | 
				
			||||||
 | 
					    #[clap(skip)]
 | 
				
			||||||
 | 
					    _root_certificate_cache: Option<Vec<u8>>,
 | 
				
			||||||
 | 
					    #[clap(skip)]
 | 
				
			||||||
 | 
					    _tls_cert_cache: Option<Vec<u8>>,
 | 
				
			||||||
 | 
					    #[clap(skip)]
 | 
				
			||||||
 | 
					    _tls_key_cache: Option<Vec<u8>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ClientConfig {
 | 
				
			||||||
 | 
					    /// Load certificates and put them in cache
 | 
				
			||||||
 | 
					    pub fn load_certificates(&mut self) -> std::io::Result<()> {
 | 
				
			||||||
 | 
					        self._keys_cache = KeysCache {
 | 
				
			||||||
 | 
					            _root_certificate_cache: load_pem_file(&self.root_certificate, "root certificate")?,
 | 
				
			||||||
 | 
					            _tls_cert_cache: load_pem_file(&self.tls_cert, "client certificate")?,
 | 
				
			||||||
 | 
					            _tls_key_cache: load_pem_file(&self.tls_key, "client key")?,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Get client token, returning a dummy token if none was specified
 | 
				
			||||||
 | 
					    pub fn get_auth_token(&self) -> &str {
 | 
				
			||||||
 | 
					        self.token.as_deref().unwrap_or("none")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Get root certificate content
 | 
				
			||||||
 | 
					    pub fn get_root_certificate(&self) -> Option<Vec<u8>> {
 | 
				
			||||||
 | 
					        self._keys_cache._root_certificate_cache.clone()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Get client certificate & key pair, if available
 | 
				
			||||||
 | 
					    pub fn get_client_keypair(&self) -> Option<(&Vec<u8>, &Vec<u8>)> {
 | 
				
			||||||
 | 
					        if let (Some(cert), Some(key)) = (
 | 
				
			||||||
 | 
					            &self._keys_cache._tls_cert_cache,
 | 
				
			||||||
 | 
					            &self._keys_cache._tls_key_cache,
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            Some((cert, key))
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            None
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Get client certificate & key pair, in a single memory buffer
 | 
				
			||||||
 | 
					    pub fn get_merged_client_keypair(&self) -> Option<Vec<u8>> {
 | 
				
			||||||
 | 
					        self.get_client_keypair().map(|(c, k)| {
 | 
				
			||||||
 | 
					            let mut out = k.to_vec();
 | 
				
			||||||
 | 
					            out.put_slice("\n".as_bytes());
 | 
				
			||||||
 | 
					            out.put_slice(c);
 | 
				
			||||||
 | 
					            out
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn load_pem_file(path: &Option<String>, name: &str) -> std::io::Result<Option<Vec<u8>>> {
 | 
				
			||||||
 | 
					    Ok(match path {
 | 
				
			||||||
 | 
					        None => None,
 | 
				
			||||||
 | 
					        Some(p) => Some(
 | 
				
			||||||
 | 
					            std::fs::read(p)
 | 
				
			||||||
 | 
					                .map_err(|e| encpasulate_error(e, format!("Failed to load {name}!")))?,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod test {
 | 
				
			||||||
 | 
					    use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn verify_cli() {
 | 
				
			||||||
 | 
					        use clap::CommandFactory;
 | 
				
			||||||
 | 
					        ClientConfig::command().debug_assert()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										107
									
								
								src/tcp_relay_client/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/tcp_relay_client/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					extern crate core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::error::Error;
 | 
				
			||||||
 | 
					use std::io::ErrorKind;
 | 
				
			||||||
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use futures::future::join_all;
 | 
				
			||||||
 | 
					use reqwest::{Certificate, Identity};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::base::err_utils::{encpasulate_error, new_err};
 | 
				
			||||||
 | 
					use crate::base::RemoteConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::relay_client::relay_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod client_config;
 | 
				
			||||||
 | 
					mod relay_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Get remote server config i.e. get the list of forwarded ports
 | 
				
			||||||
 | 
					async fn get_server_config(conf: &ClientConfig) -> Result<RemoteConfig, Box<dyn Error>> {
 | 
				
			||||||
 | 
					    let url = format!("{}/config", conf.relay_url);
 | 
				
			||||||
 | 
					    log::info!("Retrieving configuration on {}", url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut client = reqwest::Client::builder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Specify root certificate, if any was specified in the command line
 | 
				
			||||||
 | 
					    if let Some(cert) = conf.get_root_certificate() {
 | 
				
			||||||
 | 
					        client = client.add_root_certificate(Certificate::from_pem(&cert)?);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Specify client certificate, if any
 | 
				
			||||||
 | 
					    if let Some(kp) = conf.get_merged_client_keypair() {
 | 
				
			||||||
 | 
					        let identity = Identity::from_pem(&kp)
 | 
				
			||||||
 | 
					            .map_err(|e| encpasulate_error(e, "Failed to load certificates for reqwest!"))?;
 | 
				
			||||||
 | 
					        client = client.identity(identity).use_rustls_tls();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let client = client.build().expect("Failed to build reqwest client");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let req = client
 | 
				
			||||||
 | 
					        .get(url)
 | 
				
			||||||
 | 
					        .header("Authorization", format!("Bearer {}", conf.get_auth_token()))
 | 
				
			||||||
 | 
					        .send()
 | 
				
			||||||
 | 
					        .await?;
 | 
				
			||||||
 | 
					    if req.status().as_u16() != 200 {
 | 
				
			||||||
 | 
					        Err(std::io::Error::new(
 | 
				
			||||||
 | 
					            ErrorKind::Other,
 | 
				
			||||||
 | 
					            format!(
 | 
				
			||||||
 | 
					                "Could not retrieve configuration! (got status {})",
 | 
				
			||||||
 | 
					                req.status()
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ))?;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(req.json::<RemoteConfig>().await?)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Core logic of the application
 | 
				
			||||||
 | 
					pub async fn run_app(mut args: ClientConfig) -> std::io::Result<()> {
 | 
				
			||||||
 | 
					    args.load_certificates()?;
 | 
				
			||||||
 | 
					    let args = Arc::new(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check arguments coherence
 | 
				
			||||||
 | 
					    if args.tls_cert.is_some() != args.tls_key.is_some() {
 | 
				
			||||||
 | 
					        return Err(new_err(
 | 
				
			||||||
 | 
					            "If you specify one of TLS certificate / key, you must then specify the other!",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if args.get_client_keypair().is_some() {
 | 
				
			||||||
 | 
					        log::info!("Using client-side authentication");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Get server relay configuration (fetch the list of port to forward)
 | 
				
			||||||
 | 
					    let remote_conf = match get_server_config(&args).await {
 | 
				
			||||||
 | 
					        Ok(c) => c,
 | 
				
			||||||
 | 
					        Err(e) => {
 | 
				
			||||||
 | 
					            Err(std::io::Error::new(
 | 
				
			||||||
 | 
					                ErrorKind::Other,
 | 
				
			||||||
 | 
					                format!("Failed to fetch relay configuration from server! {e}"),
 | 
				
			||||||
 | 
					            ))?;
 | 
				
			||||||
 | 
					            unreachable!();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start to listen port
 | 
				
			||||||
 | 
					    let mut handles = vec![];
 | 
				
			||||||
 | 
					    for port in remote_conf {
 | 
				
			||||||
 | 
					        let listen_address = format!("{}:{}", args.listen_address, port.port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let h = tokio::spawn(relay_client(
 | 
				
			||||||
 | 
					            format!(
 | 
				
			||||||
 | 
					                "{}/ws?id={}&token={}",
 | 
				
			||||||
 | 
					                args.relay_url,
 | 
				
			||||||
 | 
					                port.id,
 | 
				
			||||||
 | 
					                urlencoding::encode(args.get_auth_token())
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .replace("http", "ws"),
 | 
				
			||||||
 | 
					            listen_address,
 | 
				
			||||||
 | 
					            args.clone(),
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					        handles.push(h);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    join_all(handles).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										155
									
								
								src/tcp_relay_client/relay_client.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/tcp_relay_client/relay_client.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use futures::{SinkExt, StreamExt};
 | 
				
			||||||
 | 
					use rustls::RootCertStore;
 | 
				
			||||||
 | 
					use tokio::io::{AsyncReadExt, AsyncWriteExt};
 | 
				
			||||||
 | 
					use tokio::net::{TcpListener, TcpStream};
 | 
				
			||||||
 | 
					use tokio_tungstenite::tungstenite::Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::base::cert_utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn relay_client(ws_url: String, listen_address: String, config: Arc<ClientConfig>) {
 | 
				
			||||||
 | 
					    log::info!("Start to listen on {}", listen_address);
 | 
				
			||||||
 | 
					    let listener = match TcpListener::bind(&listen_address).await {
 | 
				
			||||||
 | 
					        Ok(l) => l,
 | 
				
			||||||
 | 
					        Err(e) => {
 | 
				
			||||||
 | 
					            log::error!("Failed to start to listen on {}! {}", listen_address, e);
 | 
				
			||||||
 | 
					            std::process::exit(3);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        let (socket, _) = listener
 | 
				
			||||||
 | 
					            .accept()
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .expect("Failed to accept new connection!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tokio::spawn(relay_connection(ws_url.clone(), socket, config.clone()));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Relay connection
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// WS read => TCP write
 | 
				
			||||||
 | 
					/// TCP read => WS write
 | 
				
			||||||
 | 
					async fn relay_connection(ws_url: String, socket: TcpStream, conf: Arc<ClientConfig>) {
 | 
				
			||||||
 | 
					    log::debug!("Connecting to {}...", ws_url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let ws_stream = if ws_url.starts_with("wss") {
 | 
				
			||||||
 | 
					        let config = rustls::ClientConfig::builder().with_safe_defaults();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let config = match conf.get_root_certificate() {
 | 
				
			||||||
 | 
					            None => {
 | 
				
			||||||
 | 
					                // Perform a connection over TLS
 | 
				
			||||||
 | 
					                let mut roots = RootCertStore::empty();
 | 
				
			||||||
 | 
					                for cert in rustls_native_certs::load_native_certs()
 | 
				
			||||||
 | 
					                    .expect("Failed to load native certificates")
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    roots.add(&rustls::Certificate(cert.0)).unwrap();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                config.with_root_certificates(roots)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Some(cert) => {
 | 
				
			||||||
 | 
					                log::debug!("Using custom root certificates");
 | 
				
			||||||
 | 
					                let mut store = RootCertStore::empty();
 | 
				
			||||||
 | 
					                cert_utils::parse_pem_certificates(&cert)
 | 
				
			||||||
 | 
					                    .unwrap()
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .for_each(|c| store.add(c).expect("Failed to add certificate to chain!"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                config.with_root_certificates(store)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let config = match conf.get_client_keypair() {
 | 
				
			||||||
 | 
					            None => config.with_no_client_auth(),
 | 
				
			||||||
 | 
					            Some((certs, key)) => {
 | 
				
			||||||
 | 
					                let certs = cert_utils::parse_pem_certificates(certs)
 | 
				
			||||||
 | 
					                    .expect("Failed to parse client certificate!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let key = cert_utils::parse_pem_private_key(key)
 | 
				
			||||||
 | 
					                    .expect("Failed to parse client auth private key!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                config
 | 
				
			||||||
 | 
					                    .with_client_auth_cert(certs, key)
 | 
				
			||||||
 | 
					                    .expect("Failed to set client certificate!")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let connector = tokio_tungstenite::Connector::Rustls(Arc::new(config));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let (ws_stream, _) =
 | 
				
			||||||
 | 
					            tokio_tungstenite::connect_async_tls_with_config(ws_url, None, false, Some(connector))
 | 
				
			||||||
 | 
					                .await
 | 
				
			||||||
 | 
					                .expect("Failed to connect to server relay!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ws_stream
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        let (ws_stream, _) = tokio_tungstenite::connect_async(ws_url)
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .expect("Failed to connect to server relay!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ws_stream
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let (mut tcp_read, mut tcp_write) = socket.into_split();
 | 
				
			||||||
 | 
					    let (mut ws_write, mut ws_read) = ws_stream.split();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TCP read -> WS write
 | 
				
			||||||
 | 
					    let future = async move {
 | 
				
			||||||
 | 
					        let mut buff: [u8; 5000] = [0; 5000];
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            match tcp_read.read(&mut buff).await {
 | 
				
			||||||
 | 
					                Ok(s) => {
 | 
				
			||||||
 | 
					                    if let Err(e) = ws_write.send(Message::Binary(Vec::from(&buff[0..s]))).await {
 | 
				
			||||||
 | 
					                        log::error!(
 | 
				
			||||||
 | 
					                            "Failed to write to WS connection! {:?} Exiting TCP read -> WS write loop...",e);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if s == 0 {
 | 
				
			||||||
 | 
					                        log::info!("Got empty read TCP buffer. Stopping...");
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Err(e) => {
 | 
				
			||||||
 | 
					                    log::error!(
 | 
				
			||||||
 | 
					                        "Failed to read from TCP connection! {:?} Exitin TCP read -> WS write loop...",
 | 
				
			||||||
 | 
					                        e
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    tokio::spawn(future);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // WS read -> TCP write
 | 
				
			||||||
 | 
					    while let Some(m) = ws_read.next().await {
 | 
				
			||||||
 | 
					        match m {
 | 
				
			||||||
 | 
					            Err(e) => {
 | 
				
			||||||
 | 
					                log::error!(
 | 
				
			||||||
 | 
					                    "Failed to read from WebSocket. Breaking read loop... {:?}",
 | 
				
			||||||
 | 
					                    e
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Ok(Message::Binary(b)) => {
 | 
				
			||||||
 | 
					                if let Err(e) = tcp_write.write_all(&b).await {
 | 
				
			||||||
 | 
					                    log::error!(
 | 
				
			||||||
 | 
					                        "Failed to forward message to websocket. Closing reading end... {:?}",
 | 
				
			||||||
 | 
					                        e
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Ok(Message::Close(_r)) => {
 | 
				
			||||||
 | 
					                log::info!("Server asked to close this WebSocket connection");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Ok(m) => log::info!("{:?}", m),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										130
									
								
								src/tcp_relay_server/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/tcp_relay_server/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use actix_web::web::Data;
 | 
				
			||||||
 | 
					use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer, Responder};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::base::err_utils::{encpasulate_error, new_err};
 | 
				
			||||||
 | 
					use crate::base::{cert_utils, RelayedPort};
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::relay_ws::relay_ws;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::tls_cert_client_verifier::CustomCertClientVerifier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod relay_ws;
 | 
				
			||||||
 | 
					pub mod server_config;
 | 
				
			||||||
 | 
					mod tls_cert_client_verifier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn hello_route() -> &'static str {
 | 
				
			||||||
 | 
					    "Hello world!"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn config_route(req: HttpRequest, data: Data<Arc<ServerConfig>>) -> impl Responder {
 | 
				
			||||||
 | 
					    if data.has_token_auth() {
 | 
				
			||||||
 | 
					        let token = req
 | 
				
			||||||
 | 
					            .headers()
 | 
				
			||||||
 | 
					            .get("Authorization")
 | 
				
			||||||
 | 
					            .map(|t| t.to_str().unwrap_or_default())
 | 
				
			||||||
 | 
					            .unwrap_or_default()
 | 
				
			||||||
 | 
					            .strip_prefix("Bearer ")
 | 
				
			||||||
 | 
					            .unwrap_or_default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if !data.tokens.iter().any(|t| t.eq(token)) {
 | 
				
			||||||
 | 
					            return HttpResponse::Unauthorized().json("Missing / invalid token");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    HttpResponse::Ok().json(
 | 
				
			||||||
 | 
					        data.ports
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .enumerate()
 | 
				
			||||||
 | 
					            .map(|(id, port)| RelayedPort {
 | 
				
			||||||
 | 
					                id,
 | 
				
			||||||
 | 
					                port: port + data.increment_ports,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .collect::<Vec<_>>(),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn run_app(mut config: ServerConfig) -> std::io::Result<()> {
 | 
				
			||||||
 | 
					    // Check if no port are to be forwarded
 | 
				
			||||||
 | 
					    if config.ports.is_empty() {
 | 
				
			||||||
 | 
					        return Err(new_err("No port to forward!"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Read tokens from file, if any
 | 
				
			||||||
 | 
					    if let Some(file) = &config.tokens_file {
 | 
				
			||||||
 | 
					        std::fs::read_to_string(file)
 | 
				
			||||||
 | 
					            .map_err(|e| encpasulate_error(e, "Failed to read tokens file!"))?
 | 
				
			||||||
 | 
					            .split('\n')
 | 
				
			||||||
 | 
					            .filter(|l| !l.is_empty())
 | 
				
			||||||
 | 
					            .for_each(|t| config.tokens.push(t.to_string()));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !config.has_auth() {
 | 
				
			||||||
 | 
					        return Err(new_err("No authentication method specified!"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if config.tls_cert.is_some() != config.tls_key.is_some() {
 | 
				
			||||||
 | 
					        return Err(new_err("Incomplete server TLS configuration!"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if config.has_tls_client_auth() && !config.has_tls_config() {
 | 
				
			||||||
 | 
					        return Err(new_err(
 | 
				
			||||||
 | 
					            "Cannot provide client auth without TLS configuration!",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let args = Arc::new(config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Load TLS configuration, if any
 | 
				
			||||||
 | 
					    let tls_config = if let (Some(cert), Some(key)) = (&args.tls_cert, &args.tls_key) {
 | 
				
			||||||
 | 
					        // Load TLS certificate & private key
 | 
				
			||||||
 | 
					        let cert_file = std::fs::read(cert)
 | 
				
			||||||
 | 
					            .map_err(|e| encpasulate_error(e, "Failed to read certificate file"))?;
 | 
				
			||||||
 | 
					        let key_file = std::fs::read(key)
 | 
				
			||||||
 | 
					            .map_err(|e| encpasulate_error(e, "Failed to read server private key"))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Get certificates chain
 | 
				
			||||||
 | 
					        let cert_chain = cert_utils::parse_pem_certificates(&cert_file)
 | 
				
			||||||
 | 
					            .map_err(|e| encpasulate_error(e, "Failed to extract certificates"))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Get private key
 | 
				
			||||||
 | 
					        let key = cert_utils::parse_pem_private_key(&key_file)
 | 
				
			||||||
 | 
					            .map_err(|e| encpasulate_error(e, "Failed to extract private key!"))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let config = rustls::ServerConfig::builder().with_safe_defaults();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let config = match args.has_tls_client_auth() {
 | 
				
			||||||
 | 
					            true => config
 | 
				
			||||||
 | 
					                .with_client_cert_verifier(Arc::new(CustomCertClientVerifier::new(args.clone())?)),
 | 
				
			||||||
 | 
					            false => config.with_no_client_auth(),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let config = config
 | 
				
			||||||
 | 
					            .with_single_cert(cert_chain, key)
 | 
				
			||||||
 | 
					            .expect("Failed to load TLS certificate!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Some(config)
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        None
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log::info!("Starting relay on http://{}", args.listen_address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let args_clone = args.clone();
 | 
				
			||||||
 | 
					    let server = HttpServer::new(move || {
 | 
				
			||||||
 | 
					        App::new()
 | 
				
			||||||
 | 
					            .wrap(middleware::Logger::default())
 | 
				
			||||||
 | 
					            .app_data(Data::new(args_clone.clone()))
 | 
				
			||||||
 | 
					            .route("/", web::get().to(hello_route))
 | 
				
			||||||
 | 
					            .route("/config", web::get().to(config_route))
 | 
				
			||||||
 | 
					            .route("/ws", web::get().to(relay_ws))
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if let Some(tls_conf) = tls_config {
 | 
				
			||||||
 | 
					        server.bind_rustls_021(&args.listen_address, tls_conf)?
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        server.bind(&args.listen_address)?
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .run()
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,14 +2,14 @@ use std::sync::Arc;
 | 
				
			|||||||
use std::time::{Duration, Instant};
 | 
					use std::time::{Duration, Instant};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use actix::{Actor, ActorContext, AsyncContext, Handler, Message, StreamHandler};
 | 
					use actix::{Actor, ActorContext, AsyncContext, Handler, Message, StreamHandler};
 | 
				
			||||||
use actix_web::{Error, HttpRequest, HttpResponse, web};
 | 
					use actix_web::{web, Error, HttpRequest, HttpResponse};
 | 
				
			||||||
use actix_web_actors::ws;
 | 
					use actix_web_actors::ws;
 | 
				
			||||||
use actix_web_actors::ws::{CloseCode, CloseReason};
 | 
					use actix_web_actors::ws::{CloseCode, CloseReason};
 | 
				
			||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
 | 
					use tokio::io::{AsyncReadExt, AsyncWriteExt};
 | 
				
			||||||
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
 | 
					use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
 | 
				
			||||||
use tokio::net::TcpStream;
 | 
					use tokio::net::TcpStream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::args::Args;
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// How often heartbeat pings are sent
 | 
					/// How often heartbeat pings are sent
 | 
				
			||||||
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
 | 
					const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
 | 
				
			||||||
@@ -32,7 +32,6 @@ struct RelayWS {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Client must respond to ping at a specific interval, otherwise we drop connection
 | 
					    // Client must respond to ping at a specific interval, otherwise we drop connection
 | 
				
			||||||
    hb: Instant,
 | 
					    hb: Instant,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // TODO : handle socket close
 | 
					    // TODO : handle socket close
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,7 +93,6 @@ impl Actor for RelayWS {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            log::info!("Exited read loop");
 | 
					            log::info!("Exited read loop");
 | 
				
			||||||
            // TODO : notify context
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        tokio::spawn(future);
 | 
					        tokio::spawn(future);
 | 
				
			||||||
@@ -110,7 +108,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for RelayWS {
 | 
				
			|||||||
            Ok(ws::Message::Text(text)) => ctx.text(text),
 | 
					            Ok(ws::Message::Text(text)) => ctx.text(text),
 | 
				
			||||||
            Ok(ws::Message::Close(_reason)) => ctx.stop(),
 | 
					            Ok(ws::Message::Close(_reason)) => ctx.stop(),
 | 
				
			||||||
            Ok(ws::Message::Binary(data)) => {
 | 
					            Ok(ws::Message::Binary(data)) => {
 | 
				
			||||||
                if let Err(e) = futures::executor::block_on(self.tcp_write.write_all(&data.to_vec())) {
 | 
					                if let Err(e) = futures::executor::block_on(self.tcp_write.write_all(&data)) {
 | 
				
			||||||
                    log::error!("Failed to forward some data, closing connection! {:?}", e);
 | 
					                    log::error!("Failed to forward some data, closing connection! {:?}", e);
 | 
				
			||||||
                    ctx.stop();
 | 
					                    ctx.stop();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -148,19 +146,33 @@ impl Handler<TCPReadEndClosed> for RelayWS {
 | 
				
			|||||||
#[derive(serde::Deserialize)]
 | 
					#[derive(serde::Deserialize)]
 | 
				
			||||||
pub struct WebSocketQuery {
 | 
					pub struct WebSocketQuery {
 | 
				
			||||||
    id: usize,
 | 
					    id: usize,
 | 
				
			||||||
    token: String,
 | 
					    token: Option<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn relay_ws(req: HttpRequest, stream: web::Payload,
 | 
					pub async fn relay_ws(
 | 
				
			||||||
 | 
					    req: HttpRequest,
 | 
				
			||||||
 | 
					    stream: web::Payload,
 | 
				
			||||||
    query: web::Query<WebSocketQuery>,
 | 
					    query: web::Query<WebSocketQuery>,
 | 
				
			||||||
                      conf: web::Data<Arc<Args>>) -> Result<HttpResponse, Error> {
 | 
					    conf: web::Data<Arc<ServerConfig>>,
 | 
				
			||||||
    if !conf.tokens.contains(&query.token) {
 | 
					) -> Result<HttpResponse, Error> {
 | 
				
			||||||
        log::error!("Rejected WS request from {:?} due to invalid token!", req.peer_addr());
 | 
					    if conf.has_token_auth()
 | 
				
			||||||
 | 
					        && !conf
 | 
				
			||||||
 | 
					            .tokens
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .any(|t| t == query.token.as_deref().unwrap_or_default())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        log::error!(
 | 
				
			||||||
 | 
					            "Rejected WS request from {:?} due to invalid token!",
 | 
				
			||||||
 | 
					            req.peer_addr()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        return Ok(HttpResponse::Unauthorized().json("Invalid / missing token!"));
 | 
					        return Ok(HttpResponse::Unauthorized().json("Invalid / missing token!"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if conf.ports.len() <= query.id {
 | 
					    if conf.ports.len() <= query.id {
 | 
				
			||||||
        log::error!("Rejected WS request from {:?} due to invalid port number!", req.peer_addr());
 | 
					        log::error!(
 | 
				
			||||||
 | 
					            "Rejected WS request from {:?} due to invalid port number!",
 | 
				
			||||||
 | 
					            req.peer_addr()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        return Ok(HttpResponse::BadRequest().json("Invalid port number!"));
 | 
					        return Ok(HttpResponse::BadRequest().json("Invalid port number!"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -169,14 +181,29 @@ pub async fn relay_ws(req: HttpRequest, stream: web::Payload,
 | 
				
			|||||||
    let (tcp_read, tcp_write) = match TcpStream::connect(&upstream_addr).await {
 | 
					    let (tcp_read, tcp_write) = match TcpStream::connect(&upstream_addr).await {
 | 
				
			||||||
        Ok(s) => s.into_split(),
 | 
					        Ok(s) => s.into_split(),
 | 
				
			||||||
        Err(e) => {
 | 
					        Err(e) => {
 | 
				
			||||||
            log::error!("Failed to establish connection with upstream server! {:?}", e);
 | 
					            log::error!(
 | 
				
			||||||
            return Ok(HttpResponse::InternalServerError()
 | 
					                "Failed to establish connection with upstream server! {:?}",
 | 
				
			||||||
                .json("Failed to establish connection!"));
 | 
					                e
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            return Ok(HttpResponse::InternalServerError().json("Failed to establish connection!"));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let relay = RelayWS { tcp_read: Some(tcp_read), tcp_write, hb: Instant::now() };
 | 
					    let relay = RelayWS {
 | 
				
			||||||
 | 
					        tcp_read: Some(tcp_read),
 | 
				
			||||||
 | 
					        tcp_write,
 | 
				
			||||||
 | 
					        hb: Instant::now(),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let resp = ws::start(relay, &req, stream);
 | 
					    let resp = ws::start(relay, &req, stream);
 | 
				
			||||||
    log::info!("Opening new WS connection for {:?} to {}", req.peer_addr(), upstream_addr);
 | 
					    log::info!(
 | 
				
			||||||
 | 
					        "Opening new WS connection:\
 | 
				
			||||||
 | 
					         * for {:?}\
 | 
				
			||||||
 | 
					         * to {}\
 | 
				
			||||||
 | 
					         * token {:?}",
 | 
				
			||||||
 | 
					        req.peer_addr(),
 | 
				
			||||||
 | 
					        upstream_addr,
 | 
				
			||||||
 | 
					        query.token
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    resp
 | 
					    resp
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										84
									
								
								src/tcp_relay_server/server_config.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/tcp_relay_server/server_config.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					use clap::Parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// TCP relay server mode
 | 
				
			||||||
 | 
					#[derive(Parser, Debug, Clone)]
 | 
				
			||||||
 | 
					#[clap(
 | 
				
			||||||
 | 
					    author,
 | 
				
			||||||
 | 
					    version,
 | 
				
			||||||
 | 
					    about,
 | 
				
			||||||
 | 
					    long_about = "TCP-over-HTTP server. This program can be configured behind a reverse-proxy (without TLS authentication)."
 | 
				
			||||||
 | 
					)]
 | 
				
			||||||
 | 
					pub struct ServerConfig {
 | 
				
			||||||
 | 
					    /// Access tokens
 | 
				
			||||||
 | 
					    #[clap(short, long)]
 | 
				
			||||||
 | 
					    pub tokens: Vec<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Access tokens stored in a file, one token per line
 | 
				
			||||||
 | 
					    #[clap(long)]
 | 
				
			||||||
 | 
					    pub tokens_file: Option<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Forwarded ports
 | 
				
			||||||
 | 
					    #[clap(short, long)]
 | 
				
			||||||
 | 
					    pub ports: Vec<u16>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Upstream server
 | 
				
			||||||
 | 
					    #[clap(short, long, default_value = "127.0.0.1")]
 | 
				
			||||||
 | 
					    pub upstream_server: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// HTTP server listen address
 | 
				
			||||||
 | 
					    #[clap(short, long, default_value = "0.0.0.0:8000")]
 | 
				
			||||||
 | 
					    pub listen_address: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Increment ports on client. Useful for debugging and running both client and server
 | 
				
			||||||
 | 
					    /// on the same machine
 | 
				
			||||||
 | 
					    #[clap(short, long, default_value_t = 0)]
 | 
				
			||||||
 | 
					    pub increment_ports: u16,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// TLS certificate. Specify also private key to use HTTPS/TLS instead of HTTP
 | 
				
			||||||
 | 
					    #[clap(long)]
 | 
				
			||||||
 | 
					    pub tls_cert: Option<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// TLS private key. Specify also certificate to use HTTPS/TLS instead of HTTP
 | 
				
			||||||
 | 
					    #[clap(long)]
 | 
				
			||||||
 | 
					    pub tls_key: Option<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Restrict TLS client authentication to certificates signed directly or indirectly by the
 | 
				
			||||||
 | 
					    /// provided root certificates
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This option automatically enable TLS client authentication
 | 
				
			||||||
 | 
					    #[clap(long)]
 | 
				
			||||||
 | 
					    pub tls_client_auth_root_cert: Option<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// TLS client authentication revocation list (CRL file)
 | 
				
			||||||
 | 
					    #[clap(long)]
 | 
				
			||||||
 | 
					    pub tls_revocation_list: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ServerConfig {
 | 
				
			||||||
 | 
					    pub fn has_token_auth(&self) -> bool {
 | 
				
			||||||
 | 
					        !self.tokens.is_empty()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn has_tls_config(&self) -> bool {
 | 
				
			||||||
 | 
					        self.tls_cert.is_some() && self.tls_key.is_some()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn has_tls_client_auth(&self) -> bool {
 | 
				
			||||||
 | 
					        self.tls_client_auth_root_cert.is_some()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn has_auth(&self) -> bool {
 | 
				
			||||||
 | 
					        self.has_token_auth() || self.has_tls_client_auth()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod test {
 | 
				
			||||||
 | 
					    use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn verify_cli() {
 | 
				
			||||||
 | 
					        use clap::CommandFactory;
 | 
				
			||||||
 | 
					        ServerConfig::command().debug_assert()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										128
									
								
								src/tcp_relay_server/tls_cert_client_verifier.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/tcp_relay_server/tls_cert_client_verifier.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
				
			|||||||
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					use std::time::SystemTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use rustls::server::{AllowAnyAuthenticatedClient, ClientCertVerified, ClientCertVerifier};
 | 
				
			||||||
 | 
					use rustls::{AlertDescription, Certificate, DistinguishedName, Error, RootCertStore};
 | 
				
			||||||
 | 
					use x509_parser::prelude::{CertificateRevocationList, FromDer, X509Certificate};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::base::cert_utils::parse_pem_certificates;
 | 
				
			||||||
 | 
					use crate::base::err_utils::{encpasulate_error, new_err};
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct CustomCertClientVerifier {
 | 
				
			||||||
 | 
					    upstream_cert_verifier: Box<Arc<dyn ClientCertVerifier>>,
 | 
				
			||||||
 | 
					    crl: Option<Vec<u8>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl CustomCertClientVerifier {
 | 
				
			||||||
 | 
					    pub fn new(conf: Arc<ServerConfig>) -> std::io::Result<Self> {
 | 
				
			||||||
 | 
					        // Build root certifications list
 | 
				
			||||||
 | 
					        let cert_path = conf
 | 
				
			||||||
 | 
					            .tls_client_auth_root_cert
 | 
				
			||||||
 | 
					            .as_deref()
 | 
				
			||||||
 | 
					            .expect("No root certificates for client authentication provided!");
 | 
				
			||||||
 | 
					        let cert_file = std::fs::read(cert_path).map_err(|e| {
 | 
				
			||||||
 | 
					            encpasulate_error(
 | 
				
			||||||
 | 
					                e,
 | 
				
			||||||
 | 
					                "Failed to read root certificates for client authentication!",
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        })?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let root_certs = parse_pem_certificates(&cert_file).map_err(|e| {
 | 
				
			||||||
 | 
					            encpasulate_error(
 | 
				
			||||||
 | 
					                e,
 | 
				
			||||||
 | 
					                "Failed to read root certificates for server authentication!",
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        })?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if root_certs.is_empty() {
 | 
				
			||||||
 | 
					            return Err(new_err("No certificates found for client authentication!"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut store = RootCertStore::empty();
 | 
				
			||||||
 | 
					        for cert in root_certs {
 | 
				
			||||||
 | 
					            store
 | 
				
			||||||
 | 
					                .add(&cert)
 | 
				
			||||||
 | 
					                .expect("Failed to add certificate to root store");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Parse CRL file (if any)
 | 
				
			||||||
 | 
					        let crl = if let Some(crl_file) = &conf.tls_revocation_list {
 | 
				
			||||||
 | 
					            let crl_file = std::fs::read(crl_file)
 | 
				
			||||||
 | 
					                .map_err(|e| encpasulate_error(e, "Failed to open / read CRL file!"))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let parsed_crl = pem::parse(crl_file)
 | 
				
			||||||
 | 
					                .map_err(|e| encpasulate_error(e, "Failed to decode CRL file!"))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Some(parsed_crl.into_contents())
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            None
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            upstream_cert_verifier: Box::new(Arc::new(AllowAnyAuthenticatedClient::new(store))),
 | 
				
			||||||
 | 
					            crl,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ClientCertVerifier for CustomCertClientVerifier {
 | 
				
			||||||
 | 
					    fn offer_client_auth(&self) -> bool {
 | 
				
			||||||
 | 
					        true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn client_auth_mandatory(&self) -> bool {
 | 
				
			||||||
 | 
					        true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn client_auth_root_subjects(&self) -> &[DistinguishedName] {
 | 
				
			||||||
 | 
					        &[]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn verify_client_cert(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        end_entity: &Certificate,
 | 
				
			||||||
 | 
					        intermediates: &[Certificate],
 | 
				
			||||||
 | 
					        now: SystemTime,
 | 
				
			||||||
 | 
					    ) -> Result<ClientCertVerified, Error> {
 | 
				
			||||||
 | 
					        let (_rem, cert) =
 | 
				
			||||||
 | 
					            X509Certificate::from_der(&end_entity.0).expect("Failed to read certificate!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check the certificates sent by the client has been revoked
 | 
				
			||||||
 | 
					        if let Some(crl) = &self.crl {
 | 
				
			||||||
 | 
					            let (_rem, crl) =
 | 
				
			||||||
 | 
					                CertificateRevocationList::from_der(crl).expect("Failed to read CRL!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for revoked in crl.iter_revoked_certificates() {
 | 
				
			||||||
 | 
					                if revoked.user_certificate == cert.serial {
 | 
				
			||||||
 | 
					                    log::error!(
 | 
				
			||||||
 | 
					                        "Client attempted to use a revoked certificate! Serial={:?} Subject={}",
 | 
				
			||||||
 | 
					                        cert.serial,
 | 
				
			||||||
 | 
					                        cert.subject
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                    return Err(Error::AlertReceived(AlertDescription::CertificateRevoked));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let result = self
 | 
				
			||||||
 | 
					            .upstream_cert_verifier
 | 
				
			||||||
 | 
					            .verify_client_cert(end_entity, intermediates, now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match result.as_ref() {
 | 
				
			||||||
 | 
					            Err(e) => log::error!(
 | 
				
			||||||
 | 
					                "FAILED authentication attempt from Serial={} / Subject={} : {}",
 | 
				
			||||||
 | 
					                cert.serial,
 | 
				
			||||||
 | 
					                cert.subject,
 | 
				
			||||||
 | 
					                e
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            Ok(_) => log::info!(
 | 
				
			||||||
 | 
					                "SUCCESSFUL authentication attempt from Serial={} / Subject={}",
 | 
				
			||||||
 | 
					                cert.serial,
 | 
				
			||||||
 | 
					                cert.subject
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										160
									
								
								src/test/client_invalid_tls_configuration.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								src/test/client_invalid_tls_configuration.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::wait_for_port;
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::test_files_utils::create_temp_file_with_random_content;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, BAD_PATH, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::ClientInvalidTlsConfiguration, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn random_file_for_cert() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					    let random_file = create_temp_file_with_random_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					        token: Some("token".to_string()),
 | 
				
			||||||
 | 
					        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					        listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					        tls_cert: Some(random_file.to_string_lossy().to_string()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.valid_client_key.file_path()),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn random_file_for_key() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					    let random_file = create_temp_file_with_random_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					        token: Some("token".to_string()),
 | 
				
			||||||
 | 
					        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					        listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.valid_client_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(random_file.to_string_lossy().to_string()),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn bad_pem_file_for_cert() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					        token: Some("token".to_string()),
 | 
				
			||||||
 | 
					        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					        listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.valid_client_key.file_path()),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn bad_pem_file_for_key() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					        token: Some("token".to_string()),
 | 
				
			||||||
 | 
					        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					        listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.valid_client_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn non_existing_cert() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					        token: Some("token".to_string()),
 | 
				
			||||||
 | 
					        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					        listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					        tls_cert: Some(BAD_PATH.to_string()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.valid_client_key.file_path()),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn non_existing_key() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					        token: Some("token".to_string()),
 | 
				
			||||||
 | 
					        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					        listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.valid_client_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(BAD_PATH.to_string()),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn unmatched_key_cert_pair() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec!["dqsd".to_string()],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some("token".to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("https://localhost:{}", port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.valid_client_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.revoked_client_key.file_path()),
 | 
				
			||||||
 | 
					                root_certificate: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap_err();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								src/test/client_invalid_tls_root_certificate_file.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/test/client_invalid_tls_root_certificate_file.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::test_files_utils::create_temp_file_with_random_content;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, BAD_PATH, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn invalid_file_type() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					        token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					        listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					        root_certificate: Some(pki.expired_client_key.file_path()),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn non_existing_file() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					        token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					        listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					        root_certificate: Some(BAD_PATH.to_string()),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn random_file() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let random_file = create_temp_file_with_random_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					        token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					        listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					        root_certificate: Some(random_file.to_string_lossy().to_string()),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										55
									
								
								src/test/client_try_tls_while_there_is_no_tls.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/test/client_try_tls_while_there_is_no_tls.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::ClientTryTLSWhileThereIsNoTLS, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![VALID_TOKEN.to_string()],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: None,
 | 
				
			||||||
 | 
					                tls_key: None,
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: None,
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap_err();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										339
									
								
								src/test/dummy_tcp_sockets.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								src/test/dummy_tcp_sockets.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,339 @@
 | 
				
			|||||||
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use rand::Rng;
 | 
				
			||||||
 | 
					use tokio::io::{AsyncReadExt, AsyncWriteExt};
 | 
				
			||||||
 | 
					use tokio::net::{TcpListener, TcpStream};
 | 
				
			||||||
 | 
					use tokio::time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::test::LOCALHOST_IP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct DummyTCPServer(TcpListener);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl DummyTCPServer {
 | 
				
			||||||
 | 
					    pub async fn start(port: u16) -> Self {
 | 
				
			||||||
 | 
					        let addr = format!("{}:{}", LOCALHOST_IP, port);
 | 
				
			||||||
 | 
					        println!("[DUMMY TCP] Listen on {}", addr);
 | 
				
			||||||
 | 
					        let listener = TcpListener::bind(addr)
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .expect("Failed to bind dummy TCP listener!");
 | 
				
			||||||
 | 
					        Self(listener)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Receive chunk of data from following connection
 | 
				
			||||||
 | 
					    pub async fn read_next_connection(&self) -> Vec<u8> {
 | 
				
			||||||
 | 
					        let (mut conn, _addr) = self
 | 
				
			||||||
 | 
					            .0
 | 
				
			||||||
 | 
					            .accept()
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .expect("Could not open next connection!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut buff = Vec::with_capacity(100);
 | 
				
			||||||
 | 
					        conn.read_to_end(&mut buff).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buff
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Receive chunk of data from following connection
 | 
				
			||||||
 | 
					    pub async fn read_then_write_next_connection(&self, to_send: &[u8]) -> Vec<u8> {
 | 
				
			||||||
 | 
					        let (mut conn, _addr) = self
 | 
				
			||||||
 | 
					            .0
 | 
				
			||||||
 | 
					            .accept()
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .expect("Could not open next connection!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut buff: [u8; 100] = [0; 100];
 | 
				
			||||||
 | 
					        let size = conn.read(&mut buff).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        conn.write_all(to_send).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buff[0..size].to_vec()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Receive chunk of data from following connection
 | 
				
			||||||
 | 
					    pub async fn write_next_connection(&self, to_send: &[u8]) {
 | 
				
			||||||
 | 
					        let (mut conn, _addr) = self
 | 
				
			||||||
 | 
					            .0
 | 
				
			||||||
 | 
					            .accept()
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .expect("Could not open next connection!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        conn.write_all(to_send).await.unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Perform complex exchange: receive numbers from client and respond with their square
 | 
				
			||||||
 | 
					    pub async fn next_conn_square_operations(&self) {
 | 
				
			||||||
 | 
					        let (mut conn, _addr) = self
 | 
				
			||||||
 | 
					            .0
 | 
				
			||||||
 | 
					            .accept()
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .expect("Could not open next connection!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut buff: [u8; 100] = [0; 100];
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            let size = conn.read(&mut buff).await.unwrap();
 | 
				
			||||||
 | 
					            if size == 0 {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let content = String::from_utf8_lossy(&buff[0..size])
 | 
				
			||||||
 | 
					                .to_string()
 | 
				
			||||||
 | 
					                .parse::<i64>()
 | 
				
			||||||
 | 
					                .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            conn.write_all((content * content).to_string().as_bytes())
 | 
				
			||||||
 | 
					                .await
 | 
				
			||||||
 | 
					                .unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn loop_conn_square_operations(&self) {
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            self.next_conn_square_operations().await
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Perform complex exchange: receive numbers from client and respond with their value + a given number
 | 
				
			||||||
 | 
					    pub async fn next_conn_add_operations(&self, inc: i32) {
 | 
				
			||||||
 | 
					        let (mut conn, _addr) = self
 | 
				
			||||||
 | 
					            .0
 | 
				
			||||||
 | 
					            .accept()
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .expect("Could not open next connection!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut buff: [u8; 100] = [0; 100];
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            let size = conn.read(&mut buff).await.unwrap();
 | 
				
			||||||
 | 
					            if size == 0 {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let content = String::from_utf8_lossy(&buff[0..size])
 | 
				
			||||||
 | 
					                .to_string()
 | 
				
			||||||
 | 
					                .parse::<i64>()
 | 
				
			||||||
 | 
					                .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            conn.write_all((content + inc as i64).to_string().as_bytes())
 | 
				
			||||||
 | 
					                .await
 | 
				
			||||||
 | 
					                .unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn loop_next_conn_add_operations(&self, inc: i32) {
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            self.next_conn_add_operations(inc).await
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn dummy_tcp_client_read_conn(port: u16) -> Vec<u8> {
 | 
				
			||||||
 | 
					    let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        .expect("Failed to connect to dummy TCP server!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut buff: [u8; 100] = [0; 100];
 | 
				
			||||||
 | 
					    let size = socket.read(&mut buff).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buff[0..size].to_vec()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn dummy_tcp_client_write_then_read_conn(port: u16, data: &[u8]) -> Vec<u8> {
 | 
				
			||||||
 | 
					    let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        .expect("Failed to connect to dummy TCP server!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.write_all(data).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut buff: [u8; 100] = [0; 100];
 | 
				
			||||||
 | 
					    let size = socket.read(&mut buff).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buff[0..size].to_vec()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn dummy_tcp_client_write_conn(port: u16, data: &[u8]) {
 | 
				
			||||||
 | 
					    let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        .expect("Failed to connect to dummy TCP server!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.write_all(data).await.unwrap()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn dummy_tcp_client_square_root_requests(port: u16, num_exchanges: usize) {
 | 
				
			||||||
 | 
					    let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        .expect("Failed to connect to dummy TCP server!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut rng = rand::thread_rng();
 | 
				
			||||||
 | 
					    let mut buff: [u8; 100] = [0; 100];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for _ in 0..num_exchanges {
 | 
				
			||||||
 | 
					        let num = rng.gen::<i32>() % 100;
 | 
				
			||||||
 | 
					        socket.write_all(num.to_string().as_bytes()).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let size = socket.read(&mut buff).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if size == 0 {
 | 
				
			||||||
 | 
					            panic!("Got empty response!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let got = String::from_utf8_lossy(&buff[0..size])
 | 
				
			||||||
 | 
					            .to_string()
 | 
				
			||||||
 | 
					            .parse::<i64>()
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        println!("{} * {} = {} (based on server response)", num, num, got);
 | 
				
			||||||
 | 
					        assert_eq!((num * num) as i64, got);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn dummy_tcp_client_additions_requests(port: u16, inc: i32, num_exchanges: usize) {
 | 
				
			||||||
 | 
					    let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        .expect("Failed to connect to dummy TCP server!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut rng = rand::thread_rng();
 | 
				
			||||||
 | 
					    let mut buff: [u8; 100] = [0; 100];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for _ in 0..num_exchanges {
 | 
				
			||||||
 | 
					        let num = rng.gen::<i32>() % 100;
 | 
				
			||||||
 | 
					        socket.write_all(num.to_string().as_bytes()).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let size = socket.read(&mut buff).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if size == 0 {
 | 
				
			||||||
 | 
					            panic!("Got empty response!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let got = String::from_utf8_lossy(&buff[0..size])
 | 
				
			||||||
 | 
					            .to_string()
 | 
				
			||||||
 | 
					            .parse::<i64>()
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        println!("{} + {} = {} (based on server response)", num, inc, got);
 | 
				
			||||||
 | 
					        assert_eq!((num + inc) as i64, got);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Check whether a given port is open or not
 | 
				
			||||||
 | 
					pub async fn is_port_open(port: u16) -> bool {
 | 
				
			||||||
 | 
					    match TcpStream::connect(("127.0.0.1", port)).await {
 | 
				
			||||||
 | 
					        Ok(_) => true,
 | 
				
			||||||
 | 
					        Err(_) => false,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Wait for a port to become available
 | 
				
			||||||
 | 
					pub async fn wait_for_port(port: u16) {
 | 
				
			||||||
 | 
					    for _ in 0..50 {
 | 
				
			||||||
 | 
					        if is_port_open(port).await {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        time::sleep(Duration::from_millis(10)).await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eprintln!("Port {} did not open in time!", port);
 | 
				
			||||||
 | 
					    std::process::exit(2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod test {
 | 
				
			||||||
 | 
					    use crate::test::dummy_tcp_sockets::{
 | 
				
			||||||
 | 
					        dummy_tcp_client_additions_requests, dummy_tcp_client_read_conn,
 | 
				
			||||||
 | 
					        dummy_tcp_client_square_root_requests, dummy_tcp_client_write_conn,
 | 
				
			||||||
 | 
					        dummy_tcp_client_write_then_read_conn, DummyTCPServer,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    use crate::test::{get_port_number, PortsAllocation};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					        get_port_number(PortsAllocation::DummyTCPServer, index)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[tokio::test]
 | 
				
			||||||
 | 
					    async fn socket_read_from_server() {
 | 
				
			||||||
 | 
					        const DATA: &[u8] = "Hello world!!!".as_bytes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let listener = DummyTCPServer::start(port(0)).await;
 | 
				
			||||||
 | 
					        let handle = tokio::spawn(async move {
 | 
				
			||||||
 | 
					            listener.write_next_connection(DATA).await;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        let data = dummy_tcp_client_read_conn(port(0)).await;
 | 
				
			||||||
 | 
					        assert_eq!(data, DATA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        handle.await.unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[tokio::test]
 | 
				
			||||||
 | 
					    async fn socket_write_to_server() {
 | 
				
			||||||
 | 
					        const DATA: &[u8] = "Hello world 2".as_bytes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let listener = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					        tokio::spawn(async move {
 | 
				
			||||||
 | 
					            dummy_tcp_client_write_conn(port(1), DATA).await;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        let data = listener.read_next_connection().await;
 | 
				
			||||||
 | 
					        assert_eq!(data, DATA);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[tokio::test]
 | 
				
			||||||
 | 
					    async fn socket_read_and_write_to_server() {
 | 
				
			||||||
 | 
					        const DATA_1: &[u8] = "Hello world 3a".as_bytes();
 | 
				
			||||||
 | 
					        const DATA_2: &[u8] = "Hello world 3b".as_bytes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let listener = DummyTCPServer::start(port(2)).await;
 | 
				
			||||||
 | 
					        let handle = tokio::spawn(async move {
 | 
				
			||||||
 | 
					            println!("client handle");
 | 
				
			||||||
 | 
					            let data = dummy_tcp_client_write_then_read_conn(port(2), DATA_1).await;
 | 
				
			||||||
 | 
					            assert_eq!(data, DATA_2);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        let h2 = tokio::spawn(async move {
 | 
				
			||||||
 | 
					            println!("server handle");
 | 
				
			||||||
 | 
					            let data = listener.read_then_write_next_connection(DATA_2).await;
 | 
				
			||||||
 | 
					            assert_eq!(data, DATA_1);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        handle.await.unwrap();
 | 
				
			||||||
 | 
					        h2.await.unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[tokio::test]
 | 
				
			||||||
 | 
					    async fn socket_dummy_root_calculator() {
 | 
				
			||||||
 | 
					        let listener = DummyTCPServer::start(port(3)).await;
 | 
				
			||||||
 | 
					        let handle = tokio::spawn(async move {
 | 
				
			||||||
 | 
					            listener.next_conn_square_operations().await;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        let data = dummy_tcp_client_write_then_read_conn(port(3), "5".as_bytes()).await;
 | 
				
			||||||
 | 
					        assert_eq!(data, "25".as_bytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        handle.await.unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[tokio::test]
 | 
				
			||||||
 | 
					    async fn socket_dummy_root_calculator_multiple() {
 | 
				
			||||||
 | 
					        let listener = DummyTCPServer::start(port(4)).await;
 | 
				
			||||||
 | 
					        let handle = tokio::spawn(async move {
 | 
				
			||||||
 | 
					            listener.next_conn_square_operations().await;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        dummy_tcp_client_square_root_requests(port(4), 10).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        handle.await.unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[tokio::test]
 | 
				
			||||||
 | 
					    async fn socket_dummy_addition_calculator() {
 | 
				
			||||||
 | 
					        let listener = DummyTCPServer::start(port(5)).await;
 | 
				
			||||||
 | 
					        let handle = tokio::spawn(async move {
 | 
				
			||||||
 | 
					            listener.next_conn_add_operations(4).await;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        let data = dummy_tcp_client_write_then_read_conn(port(5), "5".as_bytes()).await;
 | 
				
			||||||
 | 
					        assert_eq!(data, "9".as_bytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        handle.await.unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[tokio::test]
 | 
				
			||||||
 | 
					    async fn socket_dummy_addition_calculator_multiple() {
 | 
				
			||||||
 | 
					        let listener = DummyTCPServer::start(port(6)).await;
 | 
				
			||||||
 | 
					        let handle = tokio::spawn(async move {
 | 
				
			||||||
 | 
					            listener.next_conn_add_operations(7).await;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        dummy_tcp_client_additions_requests(port(6), 7, 10).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        handle.await.unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										0
									
								
								src/test/expired_certificate.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/test/expired_certificate.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										57
									
								
								src/test/invalid_with_token_auth.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/test/invalid_with_token_auth.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					const INVALID_TOKEN: &str = "AnInvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::InvalidWithTokenAuth, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn invalid_with_token_auth() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        // Start internal service
 | 
				
			||||||
 | 
					        let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![VALID_TOKEN.to_string()],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: None,
 | 
				
			||||||
 | 
					                tls_key: None,
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(INVALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: None,
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap_err();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								src/test/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/test/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					#[non_exhaustive]
 | 
				
			||||||
 | 
					enum PortsAllocation {
 | 
				
			||||||
 | 
					    TestsWithoutPortOpened,
 | 
				
			||||||
 | 
					    DummyTCPServer,
 | 
				
			||||||
 | 
					    ValidWithTokenAuth,
 | 
				
			||||||
 | 
					    ValidWithTLSAuth,
 | 
				
			||||||
 | 
					    InvalidWithTokenAuth,
 | 
				
			||||||
 | 
					    ValidWithMultipleTokenAuth,
 | 
				
			||||||
 | 
					    ValidWithTokenFile,
 | 
				
			||||||
 | 
					    ClientTryTLSWhileThereIsNoTLS,
 | 
				
			||||||
 | 
					    ValidTokenWithCustomIncrement,
 | 
				
			||||||
 | 
					    ValidWithTokenAuthMultiplePorts,
 | 
				
			||||||
 | 
					    ValidWithTokenAuthAndServerTLS,
 | 
				
			||||||
 | 
					    WithTokenAuthAndInvalidServerTLSBadCA,
 | 
				
			||||||
 | 
					    WithTokenAuthAndInvalidServerTLSExpiredAndBadCN,
 | 
				
			||||||
 | 
					    TlsAuthExpiredClientCertificate,
 | 
				
			||||||
 | 
					    TlsAuthRevokedClientCertificate,
 | 
				
			||||||
 | 
					    TlsAuthInvalidClientCertificate,
 | 
				
			||||||
 | 
					    ClientInvalidTlsConfiguration,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn get_port_number(alloc: PortsAllocation, index: u16) -> u16 {
 | 
				
			||||||
 | 
					    30000 + 20 * (alloc as u16) + index
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const LOCALHOST_IP: &str = "127.0.0.1";
 | 
				
			||||||
 | 
					const BAD_PATH: &str = "/bad/path/to/key/file";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod dummy_tcp_sockets;
 | 
				
			||||||
 | 
					mod pki;
 | 
				
			||||||
 | 
					mod test_files_utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod client_invalid_tls_configuration;
 | 
				
			||||||
 | 
					mod client_invalid_tls_root_certificate_file;
 | 
				
			||||||
 | 
					mod client_try_tls_while_there_is_no_tls;
 | 
				
			||||||
 | 
					mod invalid_with_token_auth;
 | 
				
			||||||
 | 
					mod server_invalid_tls_config_invalid_cert;
 | 
				
			||||||
 | 
					mod server_invalid_tls_config_invalid_client_crl;
 | 
				
			||||||
 | 
					mod server_invalid_tls_config_invalid_client_root_cert;
 | 
				
			||||||
 | 
					mod server_invalid_tls_config_invalid_key;
 | 
				
			||||||
 | 
					mod server_invalid_token_file;
 | 
				
			||||||
 | 
					mod server_missing_auth;
 | 
				
			||||||
 | 
					mod tls_auth_expired_certificate;
 | 
				
			||||||
 | 
					mod tls_auth_invalid_certificate;
 | 
				
			||||||
 | 
					mod tls_auth_revoked_certificate;
 | 
				
			||||||
 | 
					mod valid_token_with_custom_increment;
 | 
				
			||||||
 | 
					mod valid_with_multiple_token_auth;
 | 
				
			||||||
 | 
					mod valid_with_tls_auth;
 | 
				
			||||||
 | 
					mod valid_with_token_auth;
 | 
				
			||||||
 | 
					mod valid_with_token_auth_and_server_tls;
 | 
				
			||||||
 | 
					mod valid_with_token_auth_multiple_ports;
 | 
				
			||||||
 | 
					mod valid_with_token_file;
 | 
				
			||||||
 | 
					mod with_token_auth_and_invalid_server_tls_bad_ca;
 | 
				
			||||||
 | 
					mod with_token_auth_and_invalid_server_tls_expired_and_bad_cn;
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/test/pki.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/test/pki.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					use mktemp::Temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::test::test_files_utils::create_temp_file_with_content;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct PemHolder(Temp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl PemHolder {
 | 
				
			||||||
 | 
					    fn new(b: &[u8]) -> Self {
 | 
				
			||||||
 | 
					        Self(create_temp_file_with_content(b))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn file_path(&self) -> String {
 | 
				
			||||||
 | 
					        self.0.to_str().unwrap().to_string()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Pki {
 | 
				
			||||||
 | 
					    pub expired_client_key: PemHolder,
 | 
				
			||||||
 | 
					    pub expired_client_crt: PemHolder,
 | 
				
			||||||
 | 
					    pub localhost_crt: PemHolder,
 | 
				
			||||||
 | 
					    pub localhost_key: PemHolder,
 | 
				
			||||||
 | 
					    pub other_ca_crl: PemHolder,
 | 
				
			||||||
 | 
					    pub other_ca_crt: PemHolder,
 | 
				
			||||||
 | 
					    pub other_ca_key: PemHolder,
 | 
				
			||||||
 | 
					    pub revoked_client_crt: PemHolder,
 | 
				
			||||||
 | 
					    pub revoked_client_key: PemHolder,
 | 
				
			||||||
 | 
					    pub root_ca_crl: PemHolder,
 | 
				
			||||||
 | 
					    pub root_ca_crt: PemHolder,
 | 
				
			||||||
 | 
					    pub root_ca_key: PemHolder,
 | 
				
			||||||
 | 
					    pub valid_client_crt: PemHolder,
 | 
				
			||||||
 | 
					    pub valid_client_key: PemHolder,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Pki {
 | 
				
			||||||
 | 
					    pub fn load() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            expired_client_key: PemHolder::new(include_bytes!("test_pki/ExpiredClient.key")),
 | 
				
			||||||
 | 
					            expired_client_crt: PemHolder::new(include_bytes!("test_pki/ExpiredClient.crt")),
 | 
				
			||||||
 | 
					            localhost_crt: PemHolder::new(include_bytes!("test_pki/localhost.crt")),
 | 
				
			||||||
 | 
					            localhost_key: PemHolder::new(include_bytes!("test_pki/localhost.key")),
 | 
				
			||||||
 | 
					            other_ca_crl: PemHolder::new(include_bytes!("test_pki/OtherCA.crl")),
 | 
				
			||||||
 | 
					            other_ca_crt: PemHolder::new(include_bytes!("test_pki/OtherCA.crt")),
 | 
				
			||||||
 | 
					            other_ca_key: PemHolder::new(include_bytes!("test_pki/OtherCA.key")),
 | 
				
			||||||
 | 
					            revoked_client_crt: PemHolder::new(include_bytes!("test_pki/RevokedClient.crt")),
 | 
				
			||||||
 | 
					            revoked_client_key: PemHolder::new(include_bytes!("test_pki/RevokedClient.key")),
 | 
				
			||||||
 | 
					            root_ca_crl: PemHolder::new(include_bytes!("test_pki/TCPTunnelTestCA.crl")),
 | 
				
			||||||
 | 
					            root_ca_crt: PemHolder::new(include_bytes!("test_pki/TCPTunnelTestCA.crt")),
 | 
				
			||||||
 | 
					            root_ca_key: PemHolder::new(include_bytes!("test_pki/TCPTunnelTestCA.key")),
 | 
				
			||||||
 | 
					            valid_client_crt: PemHolder::new(include_bytes!("test_pki/ValidClient.crt")),
 | 
				
			||||||
 | 
					            valid_client_key: PemHolder::new(include_bytes!("test_pki/ValidClient.key")),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										100
									
								
								src/test/server_invalid_tls_config_invalid_cert.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/test/server_invalid_tls_config_invalid_cert.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
				
			|||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::test_files_utils::create_temp_file_with_random_content;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, BAD_PATH};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TOKEN: &str = "mytok";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn unspecified() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: None,
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn incorrect_pem_type() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn random_contents() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let random_file = create_temp_file_with_random_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(random_file.to_string_lossy().to_string()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn invalid_path() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(BAD_PATH.to_string()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										78
									
								
								src/test/server_invalid_tls_config_invalid_client_crl.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/test/server_invalid_tls_config_invalid_client_crl.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::test_files_utils::create_temp_file_with_random_content;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, BAD_PATH};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TOKEN: &str = "mytok";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn bad_path() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					        tls_revocation_list: Some(BAD_PATH.to_string()),
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn random_content() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let random_file = create_temp_file_with_random_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					        tls_revocation_list: Some(random_file.to_string_lossy().to_string()),
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn invalid_pem() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					        tls_revocation_list: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::test_files_utils::create_temp_file_with_random_content;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, BAD_PATH};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TOKEN: &str = "mytok";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn invalid_path() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: Some(BAD_PATH.to_string()),
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn other_pem_file_type() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn random_content() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let random_file = create_temp_file_with_random_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: Some(random_file.to_string_lossy().to_string()),
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										100
									
								
								src/test/server_invalid_tls_config_invalid_key.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/test/server_invalid_tls_config_invalid_key.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
				
			|||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::test_files_utils::create_temp_file_with_random_content;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, BAD_PATH};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TOKEN: &str = "mytok";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn invalid_pem_file_type() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn unspecified() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: None,
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn random_content() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let random_content = create_temp_file_with_random_content();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(random_content.to_string_lossy().to_string()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn invalid_path() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![TOKEN.to_string()],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(BAD_PATH.to_string()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/test/server_invalid_token_file.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/test/server_invalid_token_file.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const INVALID_TOKEN: &str = "/tmp/a/token/file/that/does/not/exists";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![],
 | 
				
			||||||
 | 
					        tokens_file: Some(INVALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: None,
 | 
				
			||||||
 | 
					        tls_key: None,
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										71
									
								
								src/test/server_missing_auth.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/test/server_missing_auth.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TestsWithoutPortOpened, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn with_tls_server() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					        tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn without_tls_server() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: None,
 | 
				
			||||||
 | 
					        tls_key: None,
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn tls_auth_without_tls_config() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					        tokens: vec![],
 | 
				
			||||||
 | 
					        tokens_file: None,
 | 
				
			||||||
 | 
					        ports: vec![port(1)],
 | 
				
			||||||
 | 
					        upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					        listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					        increment_ports: 1,
 | 
				
			||||||
 | 
					        tls_cert: None,
 | 
				
			||||||
 | 
					        tls_key: None,
 | 
				
			||||||
 | 
					        tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					        tls_revocation_list: None,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .await
 | 
				
			||||||
 | 
					    .unwrap_err();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/test/test_files_utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/test/test_files_utils.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					use mktemp::Temp;
 | 
				
			||||||
 | 
					use rand::Rng;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Create a temporary file and feed it with some specified content
 | 
				
			||||||
 | 
					pub fn create_temp_file_with_content(content: &[u8]) -> Temp {
 | 
				
			||||||
 | 
					    let temp = Temp::new_file().unwrap();
 | 
				
			||||||
 | 
					    std::fs::write(&temp, content).unwrap();
 | 
				
			||||||
 | 
					    temp
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Generate a temporary file with some random content
 | 
				
			||||||
 | 
					pub fn create_temp_file_with_random_content() -> Temp {
 | 
				
			||||||
 | 
					    let random_bytes = rand::thread_rng().gen::<[u8; 10]>();
 | 
				
			||||||
 | 
					    let temp = Temp::new_file().unwrap();
 | 
				
			||||||
 | 
					    std::fs::write(&temp, random_bytes).unwrap();
 | 
				
			||||||
 | 
					    temp
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/test/test_pki/ExpiredClient.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/test/test_pki/ExpiredClient.crt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIELjCCAhagAwIBAgIRAOFWCcZCmPv3QHk6MwXfRogwDQYJKoZIhvcNAQELBQAw
 | 
				
			||||||
 | 
					GjEYMBYGA1UEAxMPVENQVHVubmVsVGVzdENBMB4XDTIyMDkwMjA3MDkxM1oXDTIy
 | 
				
			||||||
 | 
					MDkwMjA4MDkxM1owGDEWMBQGA1UEAxMNRXhwaXJlZENsaWVudDCCASIwDQYJKoZI
 | 
				
			||||||
 | 
					hvcNAQEBBQADggEPADCCAQoCggEBANDTInGsDJ4xq/pSnpeTDSE6B2Z//Had0WQk
 | 
				
			||||||
 | 
					Wl6z4k6W5t79xFwjmMa4cfJJijfgC1usbV2+BP0nh+dPxedTlItUhIW8Hjx2BM/r
 | 
				
			||||||
 | 
					q1OPvYNu0bB7zcmT+WHddDLdfsxjSMt53b4UMbcWscflLry7V6ahoXccnPKUyt4U
 | 
				
			||||||
 | 
					+ZcYaoyPAej32y5Ym8EB2Hv9lMoRVbF02mEoTcdanJdhP/y28NNm9ezMsiv1jtCq
 | 
				
			||||||
 | 
					aR1ipVj7XdCW3K+vVLWzdfw75+P9bS5uXcAZHVQsJk37nrtezH/6Zgum9OQYUmIx
 | 
				
			||||||
 | 
					TNzhEzZiKfUWa07l0l3SC81KVf1YVKfwO8pQKATLLaauqXIQWZ8CAwEAAaNxMG8w
 | 
				
			||||||
 | 
					DgYDVR0PAQH/BAQDAgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAd
 | 
				
			||||||
 | 
					BgNVHQ4EFgQUa/z5ULTQT52kxALqprqNhjhIcLswHwYDVR0jBBgwFoAU+53PiQbh
 | 
				
			||||||
 | 
					7KSQGc797M71fZg+JDUwDQYJKoZIhvcNAQELBQADggIBAF77OAeuaaW00zZfOuRb
 | 
				
			||||||
 | 
					9Eq6/MzS2kEUczFxkg6TZ3/cvx2tj9EQc7O5lRshbPmzjhGkRRLFBvnbL+wJrt93
 | 
				
			||||||
 | 
					YS0enQNSGkdivS/q66Vqf0ujL/FhAxZYW5Gc+f7lLt0VYHzp/ChU2ryYx9dH2AJD
 | 
				
			||||||
 | 
					AKl9vSqz/e5rUyQm/8lU1gNWbf7zb8rHA5WcHGWzTJGdz/pnUx1Mf29dtcAygzwz
 | 
				
			||||||
 | 
					8yWJI1Rb755tGzocSPULvVuQw4Pvnum0fLJusLLBU9BTZzCW2psXUOaTzjwzza5C
 | 
				
			||||||
 | 
					WedEPB+/Rtw4cwydEwoI0OvoDXezKcjo8bj8Dna4+UqBz85PFQFZKT23gYBuz4/A
 | 
				
			||||||
 | 
					8/G/3pvXKf8DTnIo9370qU9Ce0UlohCu0U3rRQDEiMiTxQgkhHn7CXe0quOem9yt
 | 
				
			||||||
 | 
					RUOXymAUz/IdB/Xu0jfuZUF4e6ObF9yULb1SzmHmsxUD7i2h+453KmsYpSDWp2CP
 | 
				
			||||||
 | 
					R9UOrhINirSOr1qRm5PCnMO8b+Th7TlhfQBY3u8VTn1l5F4fdzGiIGV5IZmGb1fV
 | 
				
			||||||
 | 
					b47WC7y3TdJ6i5fWVt2XtKQBQOjOLgPfZs5qW8GFHWrW1Z2otn6vrNMgquhV/9kd
 | 
				
			||||||
 | 
					9TzSFgbymCFKvGkHXZQ70Rqkb8Q5v3dz3VSFfqdE728hvp3GRHqZDSJhcR/FVahm
 | 
				
			||||||
 | 
					AKio0jBH1mENEttHndQhXQkE
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/test/test_pki/ExpiredClient.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/test/test_pki/ExpiredClient.key
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					-----BEGIN RSA PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIIEpAIBAAKCAQEA0NMicawMnjGr+lKel5MNIToHZn/8dp3RZCRaXrPiTpbm3v3E
 | 
				
			||||||
 | 
					XCOYxrhx8kmKN+ALW6xtXb4E/SeH50/F51OUi1SEhbwePHYEz+urU4+9g27RsHvN
 | 
				
			||||||
 | 
					yZP5Yd10Mt1+zGNIy3ndvhQxtxaxx+UuvLtXpqGhdxyc8pTK3hT5lxhqjI8B6Pfb
 | 
				
			||||||
 | 
					LlibwQHYe/2UyhFVsXTaYShNx1qcl2E//Lbw02b17MyyK/WO0KppHWKlWPtd0Jbc
 | 
				
			||||||
 | 
					r69UtbN1/Dvn4/1tLm5dwBkdVCwmTfueu17Mf/pmC6b05BhSYjFM3OETNmIp9RZr
 | 
				
			||||||
 | 
					TuXSXdILzUpV/VhUp/A7ylAoBMstpq6pchBZnwIDAQABAoIBACq3Zc5W4WXix0k3
 | 
				
			||||||
 | 
					aVWcMQ1g726aM6yX7+NKRGom5d4ppCRtSKOIbJIJ3NUxEeMII4qnJOAOJLscQQKi
 | 
				
			||||||
 | 
					INuHD1XI/irVJmI7yhQ2Ix++wYeHPcGaMahQaq0IPeLByFRK4vMshJ2DSAAp1kgL
 | 
				
			||||||
 | 
					q5nTwMRHP947ric5JJ51L/Emf3Us1SBXBPppOJjy0yMTYpxGImKv/kelfFg5nHBT
 | 
				
			||||||
 | 
					rnhJ2CuyX0H9R/7Quigwif0Ul7Vth6lUlBm5Y5Ouf9SFN6HvBwqp5J0dSRGejFbn
 | 
				
			||||||
 | 
					5P7UrKpAL4GR+zocYXi4iv+5ffOj7LKPm47pym5WUJgo04HH+CbajO4R3XFpOyP/
 | 
				
			||||||
 | 
					I7cj2uECgYEA5SYMAJDGLepkkSbyWd8pvxrHBYlbEFNXmjPaYdCQUTfLqffFl2wb
 | 
				
			||||||
 | 
					saa/WxW9vQwMKLl0oLRtrEoey2ma3Wx65RLBRke4+WDo/6KRe7jA/C6MjbBTutAn
 | 
				
			||||||
 | 
					hducVPkw4hKV/ERPb07cGGBA+N3VkS/BaxMu4Ki8oGfOyo53FJ6gvzcCgYEA6Utq
 | 
				
			||||||
 | 
					jKN86GSL3Iy3tebhWbHw1vNN6JitQYVmlJ2THiVuQBKT9NK0OfPTQgQoWUWKK0v8
 | 
				
			||||||
 | 
					lodQ1VoC0iiDGHYVjTtRwCT3ajS6/3T8mrpTWWi/gQRB6SXIoQrXC6rs/+OPrRbb
 | 
				
			||||||
 | 
					uGP/nkLBj1EzPOeldv1jN5nTxxoW634RxuPd3NkCgYEA5Lm9cTMRHfPAvkIp1hsz
 | 
				
			||||||
 | 
					CFYqIhSgmQMXhgwMB2avJuKSn+15hVObsQ/IIZrp8TF9UYkMKPzwG/FAG7oloq8N
 | 
				
			||||||
 | 
					XGoEEaq1r/ZTnBchMGWR/CZalXNToDz1tl8nBIpXiNEUdOGaiHgmqQ4qzD5hVrJc
 | 
				
			||||||
 | 
					Vgyn1geXgGUdvIHHywUrXrECgYEAzrI77+k11Oyoojqm1ep+hKrMOJYO0+LZtnCM
 | 
				
			||||||
 | 
					B2ZpH0+IlAohvsskVSg7Z4UpfpbHKT9ExtWS/8SlNTAhnn2Y8K2666OU9itL9uPe
 | 
				
			||||||
 | 
					nvQwvsm4yoVMJFaOoGhrSXIiU0F6XaAgAgnPQ5ffyKvn2rFef8NWsb9/zCrIXdMv
 | 
				
			||||||
 | 
					yui+/FkCgYB9y+OJQ/CrkHC5zQqsG6PnKw7GZOII0fOrWdCUAJwCG0dv7cZJ03LQ
 | 
				
			||||||
 | 
					yONxAVdrzTGGOZTOD2vG0oG3XDie2O75qU8d/OUcdl7OqnIqupGUZMARnW0Xny6U
 | 
				
			||||||
 | 
					fpFdGYs8KeohUfw8LSf95VwJwSBb3zjaPPTR/ZZ+LI3k8wStXlOMiQ==
 | 
				
			||||||
 | 
					-----END RSA PRIVATE KEY-----
 | 
				
			||||||
							
								
								
									
										16
									
								
								src/test/test_pki/OtherCA.crl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/test/test_pki/OtherCA.crl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					-----BEGIN X509 CRL-----
 | 
				
			||||||
 | 
					MIICgTBrAgEBMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMTB090aGVyQ0EXDTIy
 | 
				
			||||||
 | 
					MDkwMjA3MTI0MloXDTQyMDkwMjA3MTI0MFowAKAjMCEwHwYDVR0jBBgwFoAUIdv7
 | 
				
			||||||
 | 
					GAAmusKCN710x76ODIzpFDswDQYJKoZIhvcNAQELBQADggIBAJ6PEWN9ZdK6V1Z+
 | 
				
			||||||
 | 
					qb1lE6UpDwee7Gvu+WmYLc/ySDy8zpt3er5bfJFEI5zLYRvR7C8I77QuHfm6ytny
 | 
				
			||||||
 | 
					AcjdZoqLoYn6JkEnbZFj9yddcYfwmo1bxc7YsGKqitQPwUA+Ou2mq9q8pSyAIAY3
 | 
				
			||||||
 | 
					d1cAKEqHZgnWm/7D4NZZ8lWGjjFz9hlwhP8jWKqRcGsL/RGylNW9wyroECGRg18R
 | 
				
			||||||
 | 
					YiFIqgXiWAG1CAZcbcv2yKlijSm2q8OgBG5mFMClm5yHEmyju4ZyRowySraSkMkc
 | 
				
			||||||
 | 
					1lZqOpxRFn59FNE278bm4RJfWFtprvO/1UONq46VIi49q3iykjowGS9enFhd2pDX
 | 
				
			||||||
 | 
					JGRiMze5+Y9+MRqB7CkpgWr85a6VB/eZHt1klZDXHVviTPBwf7Sps0u2j63ZgMKl
 | 
				
			||||||
 | 
					NZCG4oTyPguyNF+PF76xqwhGqJJB1zK63wizC+1go4It9vn22tg3/C2X1riWiKjN
 | 
				
			||||||
 | 
					XimlHyumq1DkRoulwo716m3/DgVbAQD+dfTmGA80QnCMAEpRG0rjBwwrsbuz7TSX
 | 
				
			||||||
 | 
					38YiBCBAbgM/L/XhVXzuki0Q5xrrcvH8bhxG6/j+gpAFdI3on2R3rHgWMXS8c9tw
 | 
				
			||||||
 | 
					4gqXuPr4Th3Rb3pwZEsWvUXG3vY/5d2Pq9gCGcEUo36CCaZzMCDh7yrJHd1zY5gT
 | 
				
			||||||
 | 
					e5zdMjCWD7b5jfM0GpSthrfh7cya
 | 
				
			||||||
 | 
					-----END X509 CRL-----
 | 
				
			||||||
							
								
								
									
										29
									
								
								src/test/test_pki/OtherCA.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/test/test_pki/OtherCA.crt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIE5DCCAsygAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwdPdGhl
 | 
				
			||||||
 | 
					ckNBMB4XDTIyMDkwMjA3MTI0MloXDTQyMDkwMjA3MTI0MFowEjEQMA4GA1UEAxMH
 | 
				
			||||||
 | 
					T3RoZXJDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM802FZEmSvZ
 | 
				
			||||||
 | 
					A+SfJNWBJsAt7SvWQBxxpzmP8joriDkULG4XCiJGAHY7MsNm6uAk/A2f3TNEghiL
 | 
				
			||||||
 | 
					tbfQtJKfOEC2NDe8Y9H7bKo9cVep2YORGuXuDH4dkX4oAYYgKbdYSeMHyOsOkpEG
 | 
				
			||||||
 | 
					1FBlA4rw73RuO/aMqF25e1idLWXgi5fk8SUiWgH9Twse8KcYg8v3pA/SZcoZtc2S
 | 
				
			||||||
 | 
					rSsJFZJCrEOPZMJpTilW3Sd6KlZ+1niOAyEksYEy+ACQs9PU1H6edn6S+oNxpF24
 | 
				
			||||||
 | 
					iy3Orr4u3miU40SDOtO2qtrv/6vlbXZaIju5KyEZSMyve0Vvc4v02xUfdGxNPR2y
 | 
				
			||||||
 | 
					r7IDd0lIfewLMohpE2m2g2VPkWvC+EMkW3lA/a5xyDotF6aFGKblABRjHIRwNORT
 | 
				
			||||||
 | 
					tx7/jXoX5Cg9zGmLrs3/MhNJvGsErfnNCmDvlP7J7+JbpFgDMJo1uOv1ozLu344Y
 | 
				
			||||||
 | 
					R75trQBaOglTNNNs0D2sIgfEJTdwOt4PvGMgClcYGerjRZEKFmiX6//S6JBnlfGp
 | 
				
			||||||
 | 
					d5cWDgLv67sHKk9FXbbsZpomoGOqWKF5DuPoUH+0yOEq4LSoqMmaxFIVf3LgIvD5
 | 
				
			||||||
 | 
					G+1xV5jxkJsWv9JSY6QpYS9JDSpaOe2FqsQGF8VCd2SOnlzGxnMAISpT9xHrtYu+
 | 
				
			||||||
 | 
					fCXnf+gXWUsy5Y01It7CMHnW6cFhP+ATAgMBAAGjRTBDMA4GA1UdDwEB/wQEAwIB
 | 
				
			||||||
 | 
					BjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQh2/sYACa6woI3vXTHvo4M
 | 
				
			||||||
 | 
					jOkUOzANBgkqhkiG9w0BAQsFAAOCAgEAHLGe4p4gBwn2vCotnFxNRc/4NKkRkvO7
 | 
				
			||||||
 | 
					dlr2jKGCIFfGgU9JsgaYYUckxDzkQadOujpuqeuB4J9OfH+GmbUNG8MOuSJdhtKi
 | 
				
			||||||
 | 
					sASnYoaF17Go7cOg/6k0GfN5FuIQPjEOM8yFGhAhP4MfsWlNWxUQPh/3QewjfEUt
 | 
				
			||||||
 | 
					TNJXZ/1zyY2Bjt5hygdSJ8eDe7V8fVV+HcLj17bfgfP+ILbgxPhsc0Sqh719j0va
 | 
				
			||||||
 | 
					gptqzrLz1eSKjthwVrYh3RuJCBPJJKa51y54TKIqnDkrWEQc0YQf7K3wkJJQ7H6M
 | 
				
			||||||
 | 
					UELhZLVF2zjEltxcfDGUCHtxcWYApA6chwsDTNYoeb7KdTAmXgQS7JNTqLuvF773
 | 
				
			||||||
 | 
					nGCKQr6JYPwnQ7QOE7oWVEeINGZtSyKBb/+DpTacK0qaw7MymkJBlaRNHAGsTzfI
 | 
				
			||||||
 | 
					U0/tKLsi6ItXi8vY/wTxRt4qvlu4mFeGFoTNdTDib6rJKS4D6HoGeRglhefOpv4r
 | 
				
			||||||
 | 
					luaJ3MwANCTa0T5H/+vDN1NQTMJa6Iul6gKzDkX1vB1duenPpExAgnjm3QeNCvQ/
 | 
				
			||||||
 | 
					yqNCPEAyZBg83L6ZKCEHQWo3SM2nMwV6X+pS0FKCY/z+7EGH6A4FHriaksOnSNeD
 | 
				
			||||||
 | 
					HczdA3Kp8jCR9llFknwxvwvIzFbh73E0/KVifIfzmbKakIseohKRNF1kxhFaB+wR
 | 
				
			||||||
 | 
					DE1o4VTfHl8=
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/test/test_pki/OtherCA.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/test/test_pki/OtherCA.key
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					-----BEGIN RSA PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIIJKgIBAAKCAgEAzzTYVkSZK9kD5J8k1YEmwC3tK9ZAHHGnOY/yOiuIORQsbhcK
 | 
				
			||||||
 | 
					IkYAdjsyw2bq4CT8DZ/dM0SCGIu1t9C0kp84QLY0N7xj0ftsqj1xV6nZg5Ea5e4M
 | 
				
			||||||
 | 
					fh2RfigBhiApt1hJ4wfI6w6SkQbUUGUDivDvdG479oyoXbl7WJ0tZeCLl+TxJSJa
 | 
				
			||||||
 | 
					Af1PCx7wpxiDy/ekD9Jlyhm1zZKtKwkVkkKsQ49kwmlOKVbdJ3oqVn7WeI4DISSx
 | 
				
			||||||
 | 
					gTL4AJCz09TUfp52fpL6g3GkXbiLLc6uvi7eaJTjRIM607aq2u//q+VtdloiO7kr
 | 
				
			||||||
 | 
					IRlIzK97RW9zi/TbFR90bE09HbKvsgN3SUh97AsyiGkTabaDZU+Ra8L4QyRbeUD9
 | 
				
			||||||
 | 
					rnHIOi0XpoUYpuUAFGMchHA05FO3Hv+NehfkKD3MaYuuzf8yE0m8awSt+c0KYO+U
 | 
				
			||||||
 | 
					/snv4lukWAMwmjW46/WjMu7fjhhHvm2tAFo6CVM002zQPawiB8QlN3A63g+8YyAK
 | 
				
			||||||
 | 
					VxgZ6uNFkQoWaJfr/9LokGeV8al3lxYOAu/ruwcqT0VdtuxmmiagY6pYoXkO4+hQ
 | 
				
			||||||
 | 
					f7TI4SrgtKioyZrEUhV/cuAi8Pkb7XFXmPGQmxa/0lJjpClhL0kNKlo57YWqxAYX
 | 
				
			||||||
 | 
					xUJ3ZI6eXMbGcwAhKlP3Eeu1i758Jed/6BdZSzLljTUi3sIwedbpwWE/4BMCAwEA
 | 
				
			||||||
 | 
					AQKCAgBpNGCfNIc8vxv96VuvV7rQGsFv34F/r6kDTfXj2RR6PqbsYqBPlJFJdnco
 | 
				
			||||||
 | 
					xUl98ulTFZcfH6qaQd1K7hmw1EygdqJ+phVcmTasHTQ+GUwKRBOPKNWI9wRXNILJ
 | 
				
			||||||
 | 
					kez8XURulBZMWoLKRdho1VD+K6S4zft+DB60L6fT70IMlvzpa2GQxCdFGVMXx2bS
 | 
				
			||||||
 | 
					wFyypBLVwbLS8UjgjpeD4UHlmBqU1uqG1ybLUIJLN/jlH9NPNHOcUWAaxEEtMEtN
 | 
				
			||||||
 | 
					w6L8gwKQ85lkQb/9oeRwpp8Miwl7uhTGRYcJ1ZZcQTzkD0ILtGnrPvIKBSd0XajO
 | 
				
			||||||
 | 
					MW9OYU0XJXhcQL9GI+KXFLFtMPRViMY8CrVY88tG4MhvI8q/Yfg4An7ly1fd/PPy
 | 
				
			||||||
 | 
					5eZHRGwCOPN8psqmkCZaGPwnADy+vfoUJUa0CUffZ/KlS7PWykcVsJclwkcBWYUo
 | 
				
			||||||
 | 
					rZtbxtoAJtKIMYCCL/PndyQLRZPaOL7DuSFYq3kcj7F019N7d8jLBBtGAdXgVs1U
 | 
				
			||||||
 | 
					GcRH2JVjMfdWmbpria2Y9PjFNL3KXUQOIgQE/Y9tIlGnfEtefYTI32t4/QIdAVCA
 | 
				
			||||||
 | 
					c+olxlZz9+elrj3Z58Z4QAgfUdaljIMwiZD5EQMGC/jiOZyv/5mxHmIlrFvUdVDd
 | 
				
			||||||
 | 
					6K/1YmMBJjNnBbca92pkXSGWyKe7sJoehx2kaGGiX71+KPSjmQKCAQEA0SICiNHL
 | 
				
			||||||
 | 
					MJoMHQZhfY64wz6HF9s9vUChH8bD0rkLmWFA467e0gfhr7U62Gwsg9A8sJOq88vA
 | 
				
			||||||
 | 
					8LokprRvE89Q8hWgzGiN6Xh2myIErs+VipWS5kQW7f7qsp2ysScKnxQTZf/Gj5Mf
 | 
				
			||||||
 | 
					6qTXuAOGAjrGd7Fk+m1uQ7R/ZBVJSfPQaLdM0o+o+Vy2ddgxqz5Ytrhq8x86Fi4N
 | 
				
			||||||
 | 
					Zs3sU23PSMP/C5ZDaXraMEnn3X6rxbJYzJYWvK20nPCYfV6n6Gcavf1ca1iMYY2y
 | 
				
			||||||
 | 
					19iKKZwTVDesZCJ3zpHonm+Lbjjx4/OLUx4RVRR37FfpK7AoKSdMQ4k92jsscAD+
 | 
				
			||||||
 | 
					SBqh1Ohgb34hjwKCAQEA/aRQ2Gvf1PHYM18iVaV2rbZWn8axh0l6cOx4umlqHQbU
 | 
				
			||||||
 | 
					Qn2ZOrB3Povw2ieySGogI3vsQkxdSrGQ+l3y88bgE/0ZI0xGFxeGViiOgHhNq5Ac
 | 
				
			||||||
 | 
					QJTTNSYwh7j10zkHnwsI+ow8lmt8fKBikG2jinLCz1V3julAOAj9QnluM6RRIuT/
 | 
				
			||||||
 | 
					JA5law+3HKA25+a8e9lUSUNxJsSzLi4YmsKMhNNSjhD4SquTV4bj6znQqNd0Kehz
 | 
				
			||||||
 | 
					Ix80Rfw8g0arQwDDDuqEN5xxPdAFgZoR/ECcpb29SygMBaTlmYhsN31L2qGevzBS
 | 
				
			||||||
 | 
					yZCx+iYLZoqRUr7m0kcZH1nHwMDhn3+RuaRF7d2PPQKCAQEAjh01abJfCIT2TFcE
 | 
				
			||||||
 | 
					suTkq1D3Tn/ewZeEpmpUsgKrXixXgyFXK5TNibB275D64wwD4d5HImrIjw1/UIV2
 | 
				
			||||||
 | 
					ohiUoh2Oarl2DjydJKiGVCCeN1GTRMTqbAp5hK1jO70TG6zxzbN1RCWvX61rJhHG
 | 
				
			||||||
 | 
					5Ab6zWWQABmS/5FNrD5G0mlLq408OC4FnoahOw2SGxNAB9LkYphKyb27v6uZt8v8
 | 
				
			||||||
 | 
					Oy9tRntzDd+9G2ltlfe5VJvwef5YLxk/jhJ1HWTQZz6BTrA4OH4wzy4SZVkx8jqs
 | 
				
			||||||
 | 
					a+N1U4qUrZw7XkbgkiNCRSw/9liNYKqLH+FRgy2u7OBWk+JUVNM3TFlwcqEebecH
 | 
				
			||||||
 | 
					eVxWAwKCAQEAuD3EcACj/XWTO3WuZhIkC/j4IWVeDUyFgUN0SsxJxT3xrz62sFgA
 | 
				
			||||||
 | 
					tlFGqeDN8yYLpFre+iWoWppzGjpmQUfD+yENQoOkIh/3d9xL7uv0V1v9+bdhWCke
 | 
				
			||||||
 | 
					dWgYQM8bRx7n7b8yP31iVtDV592MPwQvmBWYHBo4iLuW49N7Bk4klblLz/AZIVSw
 | 
				
			||||||
 | 
					CT4jw/3qCfiK7hDsP2IAWdooCzqogc9TF1kiUnMhOyIDqxk7BXpDqjFseSWwfenE
 | 
				
			||||||
 | 
					NwN9YdVK2ynk0tRzuZfCeCrnR5nTb91MhCxZ1zu5f/YFzaTZFb3ypyQ97qaJcZBz
 | 
				
			||||||
 | 
					FZAwEbAT0MjOaeR4Yf55pbcvrm6yUR9wbQKCAQEAlwyZt/V8JM5g7vlxpvugKzpy
 | 
				
			||||||
 | 
					J7fdMY72fAWwWukSfJRkssx1LYGryzeFppEhJvoLQtAzDNHJNM4tQ0pIfb1xf0Oq
 | 
				
			||||||
 | 
					qk8hzN5d0R2ck/KqAYj4yli+Ik6upUCuiyR76CsnDd24ninZBWsro+iXAz+taF0g
 | 
				
			||||||
 | 
					0c+Rk/kxqL+k9InAAhU5Z8mxk/uKH1SnuSYnJzKtPbcex7l8I/7oBohXHsq7CcPJ
 | 
				
			||||||
 | 
					I76Hc7eiaF06MBfaxr/lJVJydo0wj0d19dKchfu6p6RgddMpPKTSVzd1T9bKY+i6
 | 
				
			||||||
 | 
					nHaV5mRmrjqtGN7Z/MntpjjQdDPdKv0uMtG0yfNguVbDgu1q2+7lJoIWJX8/bw==
 | 
				
			||||||
 | 
					-----END RSA PRIVATE KEY-----
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/test/test_pki/RevokedClient.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/test/test_pki/RevokedClient.crt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIELjCCAhagAwIBAgIRAMvrVtV8eUCAihX59TzwyVwwDQYJKoZIhvcNAQELBQAw
 | 
				
			||||||
 | 
					GjEYMBYGA1UEAxMPVENQVHVubmVsVGVzdENBMB4XDTIyMDkwMjA3MDcwN1oXDTQy
 | 
				
			||||||
 | 
					MDkwMjA3MDYxMlowGDEWMBQGA1UEAxMNUmV2b2tlZENsaWVudDCCASIwDQYJKoZI
 | 
				
			||||||
 | 
					hvcNAQEBBQADggEPADCCAQoCggEBAOJ0s0ukj6FaKVQW1rZ7fdT7CqFyBcbQ0yr9
 | 
				
			||||||
 | 
					nioaFIICJIiN/RsTROlwEtFBYoy68SP/9w+p4c0T+1QXr2T7JBljZ8I0RotPmUL9
 | 
				
			||||||
 | 
					Jy6fM5dD8m4GM44K4oz+Mk6JaVNOcY1+j670KLRJKLhX/gNTiiqFdmMXrLUdl2KF
 | 
				
			||||||
 | 
					3qrY2Jh4riygkO0xClKiL57m/8+tCDXI+cycftdfLMDOLkBPA7HCeVdahx2r6mHi
 | 
				
			||||||
 | 
					5tSlk+sMeXEJy7kR4w4zDUb/MwP1cQgnSMwtdGE4Xz2zSLwEk0P8xNUe7Qwwx605
 | 
				
			||||||
 | 
					syd/Y/lFDasoPeGgCqFvw/zgZE2D+6U8NbywZBAqa/Nd+UA0v+cCAwEAAaNxMG8w
 | 
				
			||||||
 | 
					DgYDVR0PAQH/BAQDAgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAd
 | 
				
			||||||
 | 
					BgNVHQ4EFgQUOJMPHK9liHjNrIt26DT1pWmat4EwHwYDVR0jBBgwFoAU+53PiQbh
 | 
				
			||||||
 | 
					7KSQGc797M71fZg+JDUwDQYJKoZIhvcNAQELBQADggIBAI7d1CIJGwwTATNv1ATl
 | 
				
			||||||
 | 
					UawbtuuV2dbasRA3C9kkG34UOmE8m9z01/rJiwXvF+57rbPMTZUvVhqOGajJNN7K
 | 
				
			||||||
 | 
					7+S1DDUNjea7snbJO4zsHT6OGV1vw/b0EI4OJKxuYRE5kkUEGPcWSoFbsUEyEXtt
 | 
				
			||||||
 | 
					Kl22TDOXCEYkvYW5vN2aJokyPl+rmCrzC6E207lkaKyDDBSBPYXxNApBkMMryxUO
 | 
				
			||||||
 | 
					1yqRxYrfayb0CW0JRHzI9dQNOPtpj3Pd8XKxC0liguTnPReoHC1scTp6GR9uP5TT
 | 
				
			||||||
 | 
					MlBPuAudcRNd4Kcz4vqBNc3M+ioWt5DBQ4n31beq772AbESpDaM5VBRdDlre6/Q3
 | 
				
			||||||
 | 
					WEasplODNer44md+V09LbhT3sDYpHuTIYwvHcf7jOO6wUKl7JulOwEkBD2IiTs+6
 | 
				
			||||||
 | 
					RMT2eIavlQjIObqNvLTWoVfm4b32vvBzyXdrZyr1FIlJ+VlhIpvEC1ZPq3ZLC831
 | 
				
			||||||
 | 
					sDPtyVI+dA4KV/+ZN3NvP0BfL9+7KE20Ma1V2u8reV51nddjRzNkYt3AdAuO3B9i
 | 
				
			||||||
 | 
					CUqauhe5o7Ey7QFRAxYvT4xmg9mRjSJSlX+jwXroKymtxgG3f/14Do+5yyN0bS3O
 | 
				
			||||||
 | 
					FC1H3uV1vwQztxkpJdh8PoWoh+1OsqwrRIYSEAx9M1xSBHz5TzgHQJmot5fwLQTn
 | 
				
			||||||
 | 
					QgvMyCyS46ciaMjRILqagt6P
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/test/test_pki/RevokedClient.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/test/test_pki/RevokedClient.key
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					-----BEGIN RSA PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIIEowIBAAKCAQEA4nSzS6SPoVopVBbWtnt91PsKoXIFxtDTKv2eKhoUggIkiI39
 | 
				
			||||||
 | 
					GxNE6XAS0UFijLrxI//3D6nhzRP7VBevZPskGWNnwjRGi0+ZQv0nLp8zl0PybgYz
 | 
				
			||||||
 | 
					jgrijP4yTolpU05xjX6PrvQotEkouFf+A1OKKoV2YxestR2XYoXeqtjYmHiuLKCQ
 | 
				
			||||||
 | 
					7TEKUqIvnub/z60INcj5zJx+118swM4uQE8DscJ5V1qHHavqYeLm1KWT6wx5cQnL
 | 
				
			||||||
 | 
					uRHjDjMNRv8zA/VxCCdIzC10YThfPbNIvASTQ/zE1R7tDDDHrTmzJ39j+UUNqyg9
 | 
				
			||||||
 | 
					4aAKoW/D/OBkTYP7pTw1vLBkECpr8135QDS/5wIDAQABAoIBAEtCJWP6KJGi+SEt
 | 
				
			||||||
 | 
					BeZXXBYv5/SHhEvyknszFiE/0ZjzRVjsdzVMThaWXGqWpD3I0uL36g+Wkagp/9iO
 | 
				
			||||||
 | 
					loekvvaBBraP0PHzXifZIfBokCixOBxAi1mlXG0m/WkEWbCJ3Ur8yJuIIQ7pUVMS
 | 
				
			||||||
 | 
					SySn2r8O461C7O60Ct9/ReTZdAIXWRj8uKiJF731RMZ/NFaOZfom5ijFyKcspyQ0
 | 
				
			||||||
 | 
					ap6CCpx8cZ3M8IUwHZJFgoET8tJX+6LftYKTKhE2LjBBzmGw1xFDuOEXmkrb62Fd
 | 
				
			||||||
 | 
					1HHUOdkgT3+2SLR3Mz8piWdhhvlg57+WTIKsA5Kx9GTDjIUUTXK5s3PsgxObEpc2
 | 
				
			||||||
 | 
					JWLhuaECgYEA695jleVohwX1z/I3idmZpSJK1MJOi09Pj4IvR+RXtKN5DpGhQGRO
 | 
				
			||||||
 | 
					x5TLGxJ9F2nQMErW8+oVBotl39iaFAlT77+CShBtBS7JfDX76whAvLwnouy8Winz
 | 
				
			||||||
 | 
					YV9IBOFl9XT4hVhvkR7BAzm5CsKAiT9OJRPxX0uHdmsWbnTjMwcG0csCgYEA9cil
 | 
				
			||||||
 | 
					Pes5ZOQ9Yn+M9wufrOJZ5FnC9NYvgre89OZTQhjISZmX0iW6McVkqEc7Av1S4IGC
 | 
				
			||||||
 | 
					t8+jVgq4f2XWle83GYrnWxwItGADJdL/X2YWWqzzEvTeyLs3zuLtZUt4wG5MDJJ/
 | 
				
			||||||
 | 
					XJaTiuA+a9r6/fsQto+0LI43R6Ge5UERi91qVtUCgYABvQLY4PbzP8z++lcEchEa
 | 
				
			||||||
 | 
					0XThuojfp/b7JMd6bSlkUGwc+l/I3LRj7inNCkbXvFTndjW9WHVNNgvLKYqBKUxw
 | 
				
			||||||
 | 
					EOZB63sSNbUQcElqAwaPHYfhQINm2rZLemtKderNc049lVhFJoffoTZG6QYPfOLz
 | 
				
			||||||
 | 
					jQETZbga3FEvATeHcb7QHwKBgH0DPzkNSbYNeUN+SP7nBKJ0xvAkz8qknqnINu4B
 | 
				
			||||||
 | 
					sNtvq3/0BYq38cqa8iW9hUByBRN4DDrd++Apt8nkzI6ai9YMFrz6t1q3cyJr/cRS
 | 
				
			||||||
 | 
					MpCQY1qC/kXvI+Ww+rqI9rQ55aiHYwx+8jCy+kz1prBEYS3aTfRTqb5fcGh+/iO7
 | 
				
			||||||
 | 
					zPi5AoGBANvsVAjy0HJxJom8yfCPw2tzMPh7o9v1jMblKN1xX8B249i27S5UOifO
 | 
				
			||||||
 | 
					Viy0OR6uiNGT6YLA7Q7esGavkiuK0bWa0M9ezWbGoNh4DmOzn9Q8yEbDz9VF23Pw
 | 
				
			||||||
 | 
					fc52Ehiq9zS9cqIXc+cQJe/o2J6YziUnBcJc2Ld7d75TISkkdYrN
 | 
				
			||||||
 | 
					-----END RSA PRIVATE KEY-----
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/test/test_pki/TCPTunnelTestCA.crl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/test/test_pki/TCPTunnelTestCA.crl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					-----BEGIN X509 CRL-----
 | 
				
			||||||
 | 
					MIICrjCBlwIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9UQ1BUdW5uZWxU
 | 
				
			||||||
 | 
					ZXN0Q0EXDTIyMDkwMjA3MDgwNFoXDTIyMDkwMjA3MDgwNFowJDAiAhEAy+tW1Xx5
 | 
				
			||||||
 | 
					QICKFfn1PPDJXBcNMjIwOTAyMDcwODA0WqAjMCEwHwYDVR0jBBgwFoAU+53PiQbh
 | 
				
			||||||
 | 
					7KSQGc797M71fZg+JDUwDQYJKoZIhvcNAQELBQADggIBAAT08Q5BJIU+yvPSsNdE
 | 
				
			||||||
 | 
					yMBQZSUfTyFOxWYeUiqohpRkCBdhWYAnrZiZN83GArW7rFi1D9p0Cdg5ayDgY1A3
 | 
				
			||||||
 | 
					4SsnXklwcEdYxIzaLskN1bRY7Idmu9TXdDssPWCyawTfWfV5AfqnqnuKx71gradf
 | 
				
			||||||
 | 
					jMixrOoOWiBqMp3kHO6F2Q5gKGTQcvjYAe9yVeOF/tchMiHEHBw59HigiHmkX4od
 | 
				
			||||||
 | 
					7GNbyWyqJlMaVoK13hOt/qnjOFKITsUSzIZ1pI8NY44sBFSIM1SzklfZZ3vBNaeC
 | 
				
			||||||
 | 
					gA6JBrBm/vEvbZ/WsfCI0uVJwLgCoY4tupocKCLwyN2tyGFhvPwlv4UFEEkabYuo
 | 
				
			||||||
 | 
					9F7/5CG3JO2yJPHMuflebLawyyfXlbjH9fqvjNRnyry3MXsdphU5OV/xavrSNgLW
 | 
				
			||||||
 | 
					i8HItaFThCvnMdlMn38UYeGUqp/lgrpQiXEA8K+BX55lJzzNK+UPLNEkf3bROWvR
 | 
				
			||||||
 | 
					01tstOAhn0rfPKW01HjqXKU8Si2ExBR+kzdamhiZoaKcxuemK/TPd+vmNXuvwede
 | 
				
			||||||
 | 
					3o2qdXycgFddbKmKejV3gy+zptnFyEGlC3E3BgfSdQ2Tdn0BBltzhRdENB6o5SYh
 | 
				
			||||||
 | 
					ZUP4Mo3Gr0Hy7eeLGQM7wzmxUxOGmVdqDoWnbOwC2ySEzR6Tsf9id7Sl50DDUcS5
 | 
				
			||||||
 | 
					G20W0UM0cWIOyaaHAxKl9frl
 | 
				
			||||||
 | 
					-----END X509 CRL-----
 | 
				
			||||||
							
								
								
									
										29
									
								
								src/test/test_pki/TCPTunnelTestCA.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/test/test_pki/TCPTunnelTestCA.crt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIE9DCCAtygAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9UQ1BU
 | 
				
			||||||
 | 
					dW5uZWxUZXN0Q0EwHhcNMjIwOTAyMDcwNjE0WhcNNDIwOTAyMDcwNjEzWjAaMRgw
 | 
				
			||||||
 | 
					FgYDVQQDEw9UQ1BUdW5uZWxUZXN0Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
 | 
				
			||||||
 | 
					ggIKAoICAQC5agi1SIe/1SqoBb+p3IstdnZa12IrKtTiSSANV/RtjLgFymqqlvNd
 | 
				
			||||||
 | 
					I3OJOglJr/ISSWrldh+ZRb661Ds7USLPYC+ZGUXK4jRoe+CvW+WjqUMKbZu2CrAO
 | 
				
			||||||
 | 
					YmlSy09QCARJX1kv1dLDgukfOmXCTz65uMpf6hZzTr/KNCWJImXSfsJLsuUqhRLn
 | 
				
			||||||
 | 
					M4mEV3P2TX6hrtAYa8vCVqRO4vlFOvmYdYIOT/TfLTMhmqqodVFQMoUFvl4/ZZEc
 | 
				
			||||||
 | 
					dEmJOInd+yktSCO9Ziv+A/24Zb9mY46X80NVSoUmvTYB2FEo3AMqmxq1QHo3I7/k
 | 
				
			||||||
 | 
					3NxK2uLE3xFkpXckHI+FfTjuNvYBn+EqR0FNuCiM+YsCapYBZOW2olMHZs3BI+A3
 | 
				
			||||||
 | 
					nFS4JGWN53qno5GqKl0mm16b5jt+O7qy6997VvvKlkOgXOFGfa3L3x9lR/i4WUIS
 | 
				
			||||||
 | 
					+oK1M94xJtbhUgVSH1N8K6J52jyl1EEGCR/LbW2762Db0jIQXT2/T6k0HsF+CVVR
 | 
				
			||||||
 | 
					BLOMdV8V2JrcXCcnW6L0jGl1pXO9idgnlNlGCndjM6E2wvr6livg7Fjpxw+xJLA1
 | 
				
			||||||
 | 
					BMhc8gaKxcVZBcHkdmK2G6q49GAO5s6DCiGuNpGgZ1YCAV6OflbKiIJWPV/sGOp9
 | 
				
			||||||
 | 
					iLEnxYXTAaYMwM86yfBqkIpQk7dqWa5Qfwfb+o2vDhWY5e6/bHdhGwIDAQABo0Uw
 | 
				
			||||||
 | 
					QzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU
 | 
				
			||||||
 | 
					+53PiQbh7KSQGc797M71fZg+JDUwDQYJKoZIhvcNAQELBQADggIBAFIqak9dGO/i
 | 
				
			||||||
 | 
					mMRZGu9E7fItltodw9Qphixn5SKc1Rgf6RRj/XGj10JrYiG0ULnEsMLMCu9G4GAp
 | 
				
			||||||
 | 
					IM2LKYLcirOvP+bM1sWS4ieMrldCVlbJdnhz8TnWInHb1+CNTvXKt41rc/NGsDCp
 | 
				
			||||||
 | 
					QODmj2Iwd2/QI13ABKGSxjXUvTWl4Cq9kSUvkDZjV/WFjb8nUs6Y6vNQZTc3rne2
 | 
				
			||||||
 | 
					CUb5+xDRmgz6q/SsAtgH8Rrzt8KYhrT5r4kMkpIFssLBWUQgHGdZEaEnt89qnIVb
 | 
				
			||||||
 | 
					/mULw7l0716yTkqUBydibyDUsvhgOh1c5Xg/8ICwVptvFzzcbvWFtMjOQCuqB/ud
 | 
				
			||||||
 | 
					lBcMPIlM2CyytQ6uJjcjEfoy2O1rAlgEb2QKR7abPinlLFo2d1kx3GwPgSzdpROB
 | 
				
			||||||
 | 
					fJalW0QDLkdeSPSX2a/99KTI8GKQKriG5D2kcHVFAY57P7yjbyrLtD2dKdCTp0M5
 | 
				
			||||||
 | 
					jPMGjWvFOJ86k8XiNB8yMtABp0K5WZLqqvPFm16sBPaJnpKGo/KUipnLOTnEOpHJ
 | 
				
			||||||
 | 
					LWDDH8P+HKjhV99s7IwBu+67sDsKO/AsZGRuLJSGh1j8nl/iKhHGgXPfGPY7oDIZ
 | 
				
			||||||
 | 
					6JyqnW0906KrIoUFZ0b8iKMwIu35aVR++rfWIdFcYqW4flNkAZI0XY5IlJ/i9d7N
 | 
				
			||||||
 | 
					0ezY2xRAYlJSvefisMIylm0OgUDg0Nv7
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/test/test_pki/TCPTunnelTestCA.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/test/test_pki/TCPTunnelTestCA.key
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					-----BEGIN RSA PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIIJKAIBAAKCAgEAuWoItUiHv9UqqAW/qdyLLXZ2WtdiKyrU4kkgDVf0bYy4Bcpq
 | 
				
			||||||
 | 
					qpbzXSNziToJSa/yEklq5XYfmUW+utQ7O1Eiz2AvmRlFyuI0aHvgr1vlo6lDCm2b
 | 
				
			||||||
 | 
					tgqwDmJpUstPUAgESV9ZL9XSw4LpHzplwk8+ubjKX+oWc06/yjQliSJl0n7CS7Ll
 | 
				
			||||||
 | 
					KoUS5zOJhFdz9k1+oa7QGGvLwlakTuL5RTr5mHWCDk/03y0zIZqqqHVRUDKFBb5e
 | 
				
			||||||
 | 
					P2WRHHRJiTiJ3fspLUgjvWYr/gP9uGW/ZmOOl/NDVUqFJr02AdhRKNwDKpsatUB6
 | 
				
			||||||
 | 
					NyO/5NzcStrixN8RZKV3JByPhX047jb2AZ/hKkdBTbgojPmLAmqWAWTltqJTB2bN
 | 
				
			||||||
 | 
					wSPgN5xUuCRljed6p6ORqipdJptem+Y7fju6suvfe1b7ypZDoFzhRn2ty98fZUf4
 | 
				
			||||||
 | 
					uFlCEvqCtTPeMSbW4VIFUh9TfCuiedo8pdRBBgkfy21tu+tg29IyEF09v0+pNB7B
 | 
				
			||||||
 | 
					fglVUQSzjHVfFdia3FwnJ1ui9IxpdaVzvYnYJ5TZRgp3YzOhNsL6+pYr4OxY6ccP
 | 
				
			||||||
 | 
					sSSwNQTIXPIGisXFWQXB5HZithuquPRgDubOgwohrjaRoGdWAgFejn5WyoiCVj1f
 | 
				
			||||||
 | 
					7BjqfYixJ8WF0wGmDMDPOsnwapCKUJO3almuUH8H2/qNrw4VmOXuv2x3YRsCAwEA
 | 
				
			||||||
 | 
					AQKCAgBB6eICoDAyEBPD+5cxSYfot45HqP3rHqTjdN+CHtxz/WyGEnls/5CwcaPn
 | 
				
			||||||
 | 
					Csy2d2f0/EiWHjIJiPPO8xfDdIqNckI5iPR4tYWwBynO7TprvgZpNKIASzhfRLjw
 | 
				
			||||||
 | 
					h/pAFzl+4/iOutLcUjORuG7obsd7uqenBU7J2xrvRS5629GazRlBU+2H+hrIOlgO
 | 
				
			||||||
 | 
					xhAhZVc5Hy43IEslYSu0J5g59kc43b1IXUBN/oGI1rUIgfxQKEWFzzEuFGtL1EM4
 | 
				
			||||||
 | 
					FvNcCKeQw26BLEtDWCPgY7txKL9OYVp0fbNsHCOQ8FeZ0O0HPnB2Mt+/rmPPdnyR
 | 
				
			||||||
 | 
					19J57lr+jpwWKFkVOXj9pmg6F54xj5zRTvEZ45oy11gfil3MBZNTVrk4QX8J58P7
 | 
				
			||||||
 | 
					U94Io7qhuAUYbZDqhu9r+vuroE00sPYDzVS3FGIDxmwF3i7jdMH0TXVY3Ugym2Js
 | 
				
			||||||
 | 
					xs+rDoSF5fJ3zZdIbk2TKcuCpbb+CtdP5Q+UYElBJK5Vs8f/aDsDvaLkMALqaR87
 | 
				
			||||||
 | 
					q9kW5vPVpfI+b+7MhY0P6xV3ea/UGU7vPdnLhuuDn3eoJFwA58P2v4avhDHrOGdC
 | 
				
			||||||
 | 
					nnFci3+hu8+oN831srIP0TNVfE5sNIXdshhVh4MqJv4vqH9rmwqTRyg709cEdE3C
 | 
				
			||||||
 | 
					e5gVyaOK5bdxauJEfeq6rhP31e7Qn2W49XxN40hT18rva9b14QKCAQEAwwmiUgr2
 | 
				
			||||||
 | 
					+q5Vg9X6TVxDKHkxBin55NcoRQtjQIScTxz6i9R01xQrQfiJaerVjxN1HrQWEFPO
 | 
				
			||||||
 | 
					v2/zfFbU4RXzW2k2Iv8MFU41ztRhLDS0/yhmAq3PDuNodZeDgY3MeTwBXfrJdGYg
 | 
				
			||||||
 | 
					GyQwQMgrIMnEvBleDI3l7hJ5pi9hBAp/hTDWTgTMzQkpLg4XmiavDXTFtGjSI2Ne
 | 
				
			||||||
 | 
					DfnigG72ENYkL28NiqfZFqFdHGh4ISYgEerHq6Iuwx4xgKDLBYOGsOsc2uVIOAxZ
 | 
				
			||||||
 | 
					3+AjdTMg2BCxWb3tbxT6bMNZfQgfg6XgDxu5hLwHwzTC9vq895sDNrY+hyJjj/48
 | 
				
			||||||
 | 
					CfQTregrhawO8wKCAQEA815cAHMQX3fYEUkKCAdvnXWdvpTjw21o10bWFuoO6fio
 | 
				
			||||||
 | 
					bTeh5vMvnC9MMMPUQN+IilqzrAxjYO9RzZ8ewmfgNcTPAVsW7kGHYWEaMnd3/92M
 | 
				
			||||||
 | 
					zDprFmzj5UT8MvFMzgCxDRlrDv1aGzOfTlklOrhgoY5Xl162mXU6WWv3GwszXekg
 | 
				
			||||||
 | 
					hFKycApURqvT7CrmR2OxPfVWHcmSYT3Q1PW6J0aEEGQsf5fI0NazZt0rJI/dCPGE
 | 
				
			||||||
 | 
					8RAKW7Z4P3HklE6f55w8HJ8RoNYFG52r+o1TKSbegFc023CZreE1okhI38+gpls/
 | 
				
			||||||
 | 
					EZdlMbjIXT6ypzlHzLo+xn1/U1FUYs1AY2Xlmaz/OQKCAQEArrq90hSCqZhvgjm8
 | 
				
			||||||
 | 
					EXxbqjHQyr3mY66iJCEMnStwwaurhoQi3ODz1BluOhaplpGO9p/NuHjsmzMXhshf
 | 
				
			||||||
 | 
					1PsOV1GNr5Kg56F2sUIxgCIEGSe/JB1EiAkRd2/y36kCi4ZHj0NzIbWwg8BK/m6V
 | 
				
			||||||
 | 
					vL0mZIGxcTvaxwuEMm710mH5VoCnLaQ9Ol8/pkP3vyFy6HI6AON7hzqpc4nv8rH1
 | 
				
			||||||
 | 
					/qVqK5ipIBQ5d32+5gltvfzi9EpK8afNjv5IyPzEhb8Mdwlbg3uv1I60Ic4y1fel
 | 
				
			||||||
 | 
					MAzcZhKyWTcJF1F3pX0WhqGfdsmWzaSKq8Zj+FIv4v/bxDNHF1emrMTOUvh4fO+n
 | 
				
			||||||
 | 
					tgysIwKCAQAbVL2AT2vHTO43Arzdqfge9taAULhDekYL5yij6iVCoWpI2baU+Tqf
 | 
				
			||||||
 | 
					j7A+yb9Mic4Lu6Px7nI6sKW/Md+Cdaf4YeHdhR1OJI3PodgPUttnILpvNSBRpGjz
 | 
				
			||||||
 | 
					lou8LN0zRWCc1/3t8QXtiB6b7ecAcTRo8FNl7H0VPtUOtdFKeDeMlGHSencPnhlY
 | 
				
			||||||
 | 
					1nM2UpsJ6Wg+TQ8eyURnJ0oMoIwHXSP3s0hMC//BdFsxciUmNgHcv0Luz55aLmPS
 | 
				
			||||||
 | 
					vDevcCUFHcaicDrKlT59m3d06+oq9PKH90M4Yazgmiorz3JfsDGafSTYFOiIbPgT
 | 
				
			||||||
 | 
					gLcPkJ8/nqruH6ns8XVIo0RX5VmjqIoBAoIBAExWSqMKxLkiVzuZVwovmeTeS1CL
 | 
				
			||||||
 | 
					+toFkgNC8eKqfgm8lAZjtN2AFS5HWQqjoEn+sHVufun8OkpoS/5Tn2WNAoicGvLa
 | 
				
			||||||
 | 
					9wsc+p4kwXQuMrS1c9xo65CAMrHh/JL6pHjgtXFr2BH1VBL5rBaPa9NB+Mb5SKCW
 | 
				
			||||||
 | 
					ObXXmMkDEmM2sZGmXE2j1YzzxzvfPDFEP0qBOVmYDk/gaNP4SyTegC3goufsxWEt
 | 
				
			||||||
 | 
					S6xGEB9ToN24/OwY/o7jWGX3sNf4GPXGUK4dPQL1fTMqxfxSK2n+m/nlnY7wVGmB
 | 
				
			||||||
 | 
					sJQl4XWOafuKq041YU+yT/KI41m0a70rqwuc7KsAdJlYnCL7dbkXTk6o6tg=
 | 
				
			||||||
 | 
					-----END RSA PRIVATE KEY-----
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/test/test_pki/ValidClient.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/test/test_pki/ValidClient.crt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIELDCCAhSgAwIBAgIRAMBV0/1Yv1gtGnyi/NMvFl0wDQYJKoZIhvcNAQELBQAw
 | 
				
			||||||
 | 
					GjEYMBYGA1UEAxMPVENQVHVubmVsVGVzdENBMB4XDTIyMDkwMjA3MDczN1oXDTQy
 | 
				
			||||||
 | 
					MDkwMjA3MDYxMlowFjEUMBIGA1UEAxMLVmFsaWRDbGllbnQwggEiMA0GCSqGSIb3
 | 
				
			||||||
 | 
					DQEBAQUAA4IBDwAwggEKAoIBAQCd5PIwp/QUA3UVHDHLBQankyDTOyQxSzKR6CbO
 | 
				
			||||||
 | 
					yh2hkTs/l78eI2KewovYgP4oowRsHYUTNcZHBBKm3fE6BoZOVuQg0Tw126opJ5WE
 | 
				
			||||||
 | 
					O57nPoeqn/Rlic+lm8r/IM6rUCU0cuPrP3OgzGKgceldlnWmBZ6z6CPtClgv0H0E
 | 
				
			||||||
 | 
					gpvW57/gfveW4JfON4w+CjWKFFwAdk7NwgwAVupDeTDvzdK4ExWY/cGDs3NynAS/
 | 
				
			||||||
 | 
					xS8C2KBVmK40l9eE0HMY6cFQ54hM9wYVeZFZsCQ+9P/3ywEtdb1xsVjcDzmk5Uhx
 | 
				
			||||||
 | 
					wVGrzu9FIowx1K3b/zINQVhefsDPCa/IfMy4NaNxwg65zqjZAgMBAAGjcTBvMA4G
 | 
				
			||||||
 | 
					A1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYD
 | 
				
			||||||
 | 
					VR0OBBYEFPw35WYKl2KasK9cNi2tROUQFX+RMB8GA1UdIwQYMBaAFPudz4kG4eyk
 | 
				
			||||||
 | 
					kBnO/ezO9X2YPiQ1MA0GCSqGSIb3DQEBCwUAA4ICAQAe33X1mHnOIWeCA7XZGBVu
 | 
				
			||||||
 | 
					+zbXTheHOSZICrM/pOzNbspTTFkQ68sBOwd2HcFhhm1WX09b05ipYiEbXNZCIELq
 | 
				
			||||||
 | 
					RWPN6yr7x7zFNjZyXxZAtL01pOVih8yfyg1WgW2hVB3VH9/9txMRIySfRoD8OMD9
 | 
				
			||||||
 | 
					rJfE8mhJcCELY1Fp2G4U6pghoGqRTyalHO5pxVFQuumudYnNlJhdSflcL6Y17Y5F
 | 
				
			||||||
 | 
					pclI8vJ3j940x/w1XfAd68xiw/Rc6SZQzIzvl6mjSGyFX5Un814wWXQZ7kAtH9fV
 | 
				
			||||||
 | 
					d8l75O02GLoocmkePwPFmhqc09WYAZTZgxJqEPyI6S1VHOUBsGru5rkY44zeRs2p
 | 
				
			||||||
 | 
					V2jHSIpcsbP04iwMDNFJV24Fio8A9hV4LFm5Nyv3O6gBgyyiRnYGvfS9R6wazGNW
 | 
				
			||||||
 | 
					LXAXQw69Wios4PxdlIX85jIJgyJ5GrjpjTTYmzkhe7fs8s3jdm4a2mFMWQcjbSia
 | 
				
			||||||
 | 
					15mF/1TdVNcKqt/M55aYY6HL3AnIc90TDIXr7UWZVJSeYicVZdI8N0Ih/1myOYw7
 | 
				
			||||||
 | 
					3NvqUetYLw/FQ7C+763N9QLgSdPlBTMkMSyB2pkXAAzWwJ/UPJ6z5REZmTVHu8Kf
 | 
				
			||||||
 | 
					I5UD0GwVnfUpBTLEpUG4oTH39PhKlncCKtmMnaZiu0DzxMy0xeskFT7YZFj0BKQc
 | 
				
			||||||
 | 
					JXXeqkcOvTFHibpLR5lQ1Q==
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/test/test_pki/ValidClient.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/test/test_pki/ValidClient.key
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					-----BEGIN RSA PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIIEpgIBAAKCAQEAneTyMKf0FAN1FRwxywUGp5Mg0zskMUsykegmzsodoZE7P5e/
 | 
				
			||||||
 | 
					HiNinsKL2ID+KKMEbB2FEzXGRwQSpt3xOgaGTlbkINE8NduqKSeVhDue5z6Hqp/0
 | 
				
			||||||
 | 
					ZYnPpZvK/yDOq1AlNHLj6z9zoMxioHHpXZZ1pgWes+gj7QpYL9B9BIKb1ue/4H73
 | 
				
			||||||
 | 
					luCXzjeMPgo1ihRcAHZOzcIMAFbqQ3kw783SuBMVmP3Bg7NzcpwEv8UvAtigVZiu
 | 
				
			||||||
 | 
					NJfXhNBzGOnBUOeITPcGFXmRWbAkPvT/98sBLXW9cbFY3A85pOVIccFRq87vRSKM
 | 
				
			||||||
 | 
					MdSt2/8yDUFYXn7AzwmvyHzMuDWjccIOuc6o2QIDAQABAoIBAQCdaZfOzFK49S1v
 | 
				
			||||||
 | 
					61j090DIJhVOoaKWhkqXTiQKe1QJNJol7yo5aLu0XW5AXXGFn+gTxWZbXXwcZsIV
 | 
				
			||||||
 | 
					nCUXXVPenB/5W8A0TZgaSX11hF8KWbu1bpyf8kGS8Hvz2IhSIKfG31e8u9iSEdGt
 | 
				
			||||||
 | 
					9YLbq9oEt4ud/qx6cJq0qJ1Kts+Y8ofAXjTqxa0+LVmCPRJFp1CjCAanq/VBx+cR
 | 
				
			||||||
 | 
					TjDMcBAnKB8u1wrMc4Hw8ew693wHaxYQEm1bZkjplQbUCA/IKTr1otIyCHRpNKUJ
 | 
				
			||||||
 | 
					XmNTr+zU0zqjGudeeNrEu8vjXMFzlWXoKlbVoYgfJ7lIp/9s2KDa/AjEpsrbmDo6
 | 
				
			||||||
 | 
					vAsH9gnFAoGBAMOcEd7LQFoIxdNl2BFV4jDoSLrTeNjTwXFfe4/UQSvb8lAwzYl5
 | 
				
			||||||
 | 
					aD7uT6XpkK5PV0vX9w6Wi0JVidbZVRmF0Ml+sXn/SpV9juQxMR5GpCWsCz1H+3Vj
 | 
				
			||||||
 | 
					a11GyAy836tX5harxLWhQq/q7HEit7SnNTe5i5Hvin8v1S7jfo6hdQ3TAoGBAM6k
 | 
				
			||||||
 | 
					D3q8yBu/JDrruL1SfyKiQT+U+9ccR6OJ713qsM9gZ1HocbFMDwVXLG3U+NRRmhxF
 | 
				
			||||||
 | 
					xbY9zyEaLERcNAPbbm/aB+hXCsBAIe5XO5EIYGi5cP2+/2UjDxx/YIZkx71fe/5+
 | 
				
			||||||
 | 
					QoVUc+TK1i9lCZUXEvDxnVZdMYsu6dOEHldxvwcjAoGBAMJ/1DERLrqXkIUj9lU+
 | 
				
			||||||
 | 
					bXut7GuATOBkpitiAs3AAtFmkSl1bVot0x8H/UB+3rLEB4xNgMYLoQrjXPy5+2k2
 | 
				
			||||||
 | 
					aqWACV7CHtpID6YM18c//IXM7RwREBLoOWB1OgOYZlrMOuf+AcmMQHAFivbvy3Sg
 | 
				
			||||||
 | 
					8kSnhQUmBzNyT2qhID0Yg/irAoGBAIDfAGhjY8kqI8Y7TDOGR5Op7Vdh6s307Rio
 | 
				
			||||||
 | 
					5YeE3k/2p3kFpiIUdSm3fBXjRGvlmF8ZhHxrf8n9MK5Rcn8VUoKfT18vKZ1MYdzq
 | 
				
			||||||
 | 
					ulNxDe9B953IiC7i9oGnTuOB5q/L5OCKjaHpUX3Wok1cjeVVRpLNnHpIFKXg1CL9
 | 
				
			||||||
 | 
					uo5+ecxRAoGBAKUr4pYT8wmu8BoNNoVkn6/c7m7ssBJxRUsj7cjxNpCIXzUKMzDj
 | 
				
			||||||
 | 
					Vqup7ex/tVOXZ10JEE96IMvm+b+Dje32x5oP2qaMYAlAhxJd6P0+5C7eRhZnwqYa
 | 
				
			||||||
 | 
					n82eXRq0ij6ggvXHvfhxgpa51hCRtEv6MGNu5qJ9QGKxb8VAFbQT3vPI
 | 
				
			||||||
 | 
					-----END RSA PRIVATE KEY-----
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/test/test_pki/localhost.crt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/test/test_pki/localhost.crt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIERzCCAi+gAwIBAgIQAtk0UZ5qjqGgxYWL7X9GhDANBgkqhkiG9w0BAQsFADAa
 | 
				
			||||||
 | 
					MRgwFgYDVQQDEw9UQ1BUdW5uZWxUZXN0Q0EwHhcNMjIwOTAyMDcwNzUxWhcNNDIw
 | 
				
			||||||
 | 
					OTAyMDcwNjEyWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB
 | 
				
			||||||
 | 
					AQUAA4IBDwAwggEKAoIBAQDLuZElNqvAPIiTBjWJIjD1Ie+Amw1MvsWMY7UP56qC
 | 
				
			||||||
 | 
					czkvHI4wfHRJ+mCsUsbKnKR8nYDCa2CiiZpI/oWDZcQZBWmOjaoeBJajw6g+sjFl
 | 
				
			||||||
 | 
					+lft4xY6aMSXnpcU71KNelOLZsZmPYs24ZUgmjnQB1s6HZlF1niGabCaNnLtd5z2
 | 
				
			||||||
 | 
					HBPqHno2YvvD4r41n/+kDjhKoZ0t0coZnZaBlEPMvnBOlC1Z/Cn41tORTGkgm3rT
 | 
				
			||||||
 | 
					+PY3aS8n2q7prLvMc7QD/4kaN5Ep6IydXYIB+gjwIscgSHEdLZq0rAU1Xk/PQrCc
 | 
				
			||||||
 | 
					P3ysdeXFnSq4VuvgVSgXPa4pACvY+cNjaSTzk1WRaLW1AgMBAAGjgY4wgYswDgYD
 | 
				
			||||||
 | 
					VR0PAQH/BAQDAgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNV
 | 
				
			||||||
 | 
					HQ4EFgQU2uwKZmO17EkQ8bLDVMdiTqLlyYEwHwYDVR0jBBgwFoAU+53PiQbh7KSQ
 | 
				
			||||||
 | 
					Gc797M71fZg+JDUwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3
 | 
				
			||||||
 | 
					DQEBCwUAA4ICAQAHf8955HzEOTpmdN34O2jVKC1Riu8Zrpv19Gi1AJpi4WJN3xNv
 | 
				
			||||||
 | 
					BR6EeaelYEazf17ia5pj3mlT+95aE9wDYVWyqzrJuni5sT94Vw2wIL87qHxFnnBc
 | 
				
			||||||
 | 
					Wd2HhTbVSduYlIBOOFpaY28d1td6S2XsiTVfare7z8HESkcP/JeERtAtCnT8NCaC
 | 
				
			||||||
 | 
					vxSPdW+fEQxIXssS+PrlOH3rOcZHj8xUD8SDxgiizf0BZw15aLG4YsEhVU8w292K
 | 
				
			||||||
 | 
					mBmV0eYcsVpWTplE71zHDc1oJqmCZtLfYjPDy6gzyikkspPDCDU+MLT6y//WJC4d
 | 
				
			||||||
 | 
					onY0JZ9CA6i9DKlSsOvQN0LypcYOFdKjWPMwXD0PXy1Mrte4KqexhxlTJfc8WHNt
 | 
				
			||||||
 | 
					GhYOCMtYvScHE0T6XD9ybrFb2u+u8TFqrHCfTabJEaCGBsMMK2XwYQvtbRiTjvtB
 | 
				
			||||||
 | 
					sTSJrB4fvKfWahYUXZtM4unll752xRjQawW+/Nt7Bi4CeKlQX/6nlpAJTmKDxLCK
 | 
				
			||||||
 | 
					OWyS4oNWrcLmVUIKnPiaXA0AsnlOmwuR1Fsrgo+SYJqCeoe90+oo+GdqOmRuSZU9
 | 
				
			||||||
 | 
					N+ry011LZMsNzaHifWqsh1jp3kUQ5XnBA4KWv1Asgg0oCpRnYmUS7GSSdBZkp9a2
 | 
				
			||||||
 | 
					0TEp4yh/gUZ+YO3/XQmpDa1/3kojfhD+WcRQoZ5lwMrlwxtvmiOit4JJQA==
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/test/test_pki/localhost.key
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/test/test_pki/localhost.key
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					-----BEGIN RSA PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIIEpAIBAAKCAQEAy7mRJTarwDyIkwY1iSIw9SHvgJsNTL7FjGO1D+eqgnM5LxyO
 | 
				
			||||||
 | 
					MHx0SfpgrFLGypykfJ2AwmtgoomaSP6Fg2XEGQVpjo2qHgSWo8OoPrIxZfpX7eMW
 | 
				
			||||||
 | 
					OmjEl56XFO9SjXpTi2bGZj2LNuGVIJo50AdbOh2ZRdZ4hmmwmjZy7Xec9hwT6h56
 | 
				
			||||||
 | 
					NmL7w+K+NZ//pA44SqGdLdHKGZ2WgZRDzL5wTpQtWfwp+NbTkUxpIJt60/j2N2kv
 | 
				
			||||||
 | 
					J9qu6ay7zHO0A/+JGjeRKeiMnV2CAfoI8CLHIEhxHS2atKwFNV5Pz0KwnD98rHXl
 | 
				
			||||||
 | 
					xZ0quFbr4FUoFz2uKQAr2PnDY2kk85NVkWi1tQIDAQABAoIBAGipZAUPSjtPngaS
 | 
				
			||||||
 | 
					iQxzsV0uWwHiJnoIBCt0yf9q0DGGiplGfVIxjfi3ldTSDejngqW2sQCw84ttUAMy
 | 
				
			||||||
 | 
					J1ty+8SzACDJbN1RFCb8DMJw/2nZrDS9lpzZWC5gvlN2BB5E+wjB+ylpcsz2JYwD
 | 
				
			||||||
 | 
					T7ItJVP9AtJbNb4wLBd945tV+SCCL4wrfaudjDAAXw5YZSIjTucxU4WRm2y8wZ86
 | 
				
			||||||
 | 
					do4J+NscjLpUvuIthfGiui75WGHEdtNu5iveM1dUsQWrIsMxk53D425ovd5Szx6x
 | 
				
			||||||
 | 
					6UJBjSwhmIAXxtAwzzrlO/U/4JAyMOHJs+hmCu78bLwjSJBzP/fZzG/KhFm0eyMD
 | 
				
			||||||
 | 
					RNMDy4ECgYEA6g42ffOGfP/58IxPk8C+xoRjc2a1TAI/z3ymAxbC+iFYPCiuabXf
 | 
				
			||||||
 | 
					twJkTl0yioupq3H0yW6dh2/nTtIpA99L2tEYr44R48LcSD2R5UyE8nYohz+LlOJf
 | 
				
			||||||
 | 
					U/vx/p7ao6I8mv7xFI5E52ChvEfkvNwmVcUJlmZ1JswGdwNf4WZzb+ECgYEA3tNc
 | 
				
			||||||
 | 
					EXdiWPbkzbOZISJwMyA6S5NqIZm5zoBLtU5ChDoqHQMYE6YmI0stgpNEwEvcmO2C
 | 
				
			||||||
 | 
					+9cGvB5mhklrYxxIRL9TzqqUi628/DqSTubBm/Xm+WblRKoDCN0dKK6SS/pkrxWw
 | 
				
			||||||
 | 
					YyIGbrCHQXWR1KOlvTvq7uHNXixOvpQVElrmkFUCgYEA6EUUhKeAJlosoi/L5NfZ
 | 
				
			||||||
 | 
					Os40l1gswHJW+sQ7R0N2WJ1wn7rLYvJvQYFpI29Pcbgpt48OGjvgroA5rrnWpBYb
 | 
				
			||||||
 | 
					g9oPQmCdlkZRLouTVlc6dBcYHyfLkAOaEJEtVL42QT8GH9ayTfDlpiv6NQuvjlB2
 | 
				
			||||||
 | 
					5pTz78JbrhW4sLCznM577mECgYAcThMC8PxgOrSj4K2SBPLlu7FMCmTP8dwlfCyh
 | 
				
			||||||
 | 
					0lgmvdC9sLftPwzXLOSSEq0IFFroXjtmTFFBskbpxgfLJjuT6A34Ubje6Wn5TGNr
 | 
				
			||||||
 | 
					fGqZqin2AnkbONF73cKneU2CM0N47jNi1F6mzuvPh+THcyZJnIPiZnKVBOHX2a23
 | 
				
			||||||
 | 
					kC57pQKBgQCchLrp2oX0q0jKVb5BqbsJiRMuBhRC96M0IABH6YRaCW372XCvgCWC
 | 
				
			||||||
 | 
					jtvXuT0XmqTYbmtpPEw1Pp9eJ3qminK4Z55N2fG+c9wtzJ+Mli8UoS3yFRSzbneD
 | 
				
			||||||
 | 
					LtbdqXEoZPYd6dLbTPTe43Pnl45o4epC+46c678nP/TrtfnKAiL1SA==
 | 
				
			||||||
 | 
					-----END RSA PRIVATE KEY-----
 | 
				
			||||||
							
								
								
									
										58
									
								
								src/test/tls_auth_expired_certificate.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/test/tls_auth_expired_certificate.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TlsAuthExpiredClientCertificate, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_revocation_list: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                relay_url: format!("https://localhost:{}", port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.expired_client_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.valid_client_key.file_path()),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap_err();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										58
									
								
								src/test/tls_auth_invalid_certificate.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/test/tls_auth_invalid_certificate.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TlsAuthInvalidClientCertificate, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: Some(pki.other_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_revocation_list: Some(pki.other_ca_crl.file_path()),
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                relay_url: format!("https://localhost:{}", port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.revoked_client_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.revoked_client_key.file_path()),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap_err();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										58
									
								
								src/test/tls_auth_revoked_certificate.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/test/tls_auth_revoked_certificate.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{wait_for_port, DummyTCPServer};
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::TlsAuthRevokedClientCertificate, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_revocation_list: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                relay_url: format!("https://localhost:{}", port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.revoked_client_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.revoked_client_key.file_path()),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap_err();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								src/test/valid_token_with_custom_increment.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/test/valid_token_with_custom_increment.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{
 | 
				
			||||||
 | 
					    dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::ValidTokenWithCustomIncrement, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![VALID_TOKEN.to_string()],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 3,
 | 
				
			||||||
 | 
					                tls_cert: None,
 | 
				
			||||||
 | 
					                tls_key: None,
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: None,
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(4)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dummy_tcp_client_square_root_requests(port(4), 10).await;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										63
									
								
								src/test/valid_with_multiple_token_auth.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/test/valid_with_multiple_token_auth.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{
 | 
				
			||||||
 | 
					    dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::ValidWithTokenFile, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn valid_with_multiple_token_auth() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![
 | 
				
			||||||
 | 
					                    "tok0".to_string(),
 | 
				
			||||||
 | 
					                    VALID_TOKEN.to_string(),
 | 
				
			||||||
 | 
					                    "tok2".to_string(),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: None,
 | 
				
			||||||
 | 
					                tls_key: None,
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: None,
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(2)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dummy_tcp_client_square_root_requests(port(2), 10).await;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										61
									
								
								src/test/valid_with_tls_auth.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/test/valid_with_tls_auth.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{
 | 
				
			||||||
 | 
					    dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::ValidWithTLSAuth, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_revocation_list: Some(pki.root_ca_crl.file_path()),
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                relay_url: format!("https://localhost:{}", port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.valid_client_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.valid_client_key.file_path()),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(2)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dummy_tcp_client_square_root_requests(port(2), 10).await;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								src/test/valid_with_token_auth.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/test/valid_with_token_auth.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{
 | 
				
			||||||
 | 
					    dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::ValidWithTokenAuth, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn valid_with_token_auth() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![VALID_TOKEN.to_string()],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: None,
 | 
				
			||||||
 | 
					                tls_key: None,
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: None,
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(2)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dummy_tcp_client_square_root_requests(port(2), 10).await;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										62
									
								
								src/test/valid_with_token_auth_and_server_tls.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/test/valid_with_token_auth_and_server_tls.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{
 | 
				
			||||||
 | 
					    dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::ValidWithTokenAuthAndServerTLS, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![VALID_TOKEN.to_string()],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("https://localhost:{}", port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(2)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dummy_tcp_client_square_root_requests(port(2), 10).await;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										67
									
								
								src/test/valid_with_token_auth_multiple_ports.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/test/valid_with_token_auth_multiple_ports.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{
 | 
				
			||||||
 | 
					    dummy_tcp_client_additions_requests, dummy_tcp_client_square_root_requests, wait_for_port,
 | 
				
			||||||
 | 
					    DummyTCPServer,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					const NUM_INC: i32 = 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::ValidWithTokenAuthMultiplePorts, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal services
 | 
				
			||||||
 | 
					    let local_server_1 = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server_1.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_server_2 = DummyTCPServer::start(port(3)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server_2.loop_next_conn_add_operations(NUM_INC).await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![VALID_TOKEN.to_string()],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1), port(3)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: None,
 | 
				
			||||||
 | 
					                tls_key: None,
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: None,
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(2)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dummy_tcp_client_square_root_requests(port(2), 10).await;
 | 
				
			||||||
 | 
					            dummy_tcp_client_additions_requests(port(4), NUM_INC, 10).await;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										62
									
								
								src/test/valid_with_token_file.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/test/valid_with_token_file.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::{
 | 
				
			||||||
 | 
					    dummy_tcp_client_square_root_requests, wait_for_port, DummyTCPServer,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(PortsAllocation::ValidWithMultipleTokenAuth, index)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn valid_with_token_file() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start internal service
 | 
				
			||||||
 | 
					    let local_server = DummyTCPServer::start(port(1)).await;
 | 
				
			||||||
 | 
					    tokio::spawn(async move {
 | 
				
			||||||
 | 
					        local_server.loop_conn_square_operations().await;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            wait_for_port(port(1)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let token_file = mktemp::Temp::new_file().unwrap();
 | 
				
			||||||
 | 
					            std::fs::write(&token_file, format!("tok1\ntok2\n{}\ntok4", VALID_TOKEN)).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![],
 | 
				
			||||||
 | 
					                tokens_file: Some(token_file.to_str().unwrap().to_string()),
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: None,
 | 
				
			||||||
 | 
					                tls_key: None,
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: None,
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(2)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dummy_tcp_client_square_root_requests(port(2), 10).await;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								src/test/with_token_auth_and_invalid_server_tls_bad_ca.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/test/with_token_auth_and_invalid_server_tls_bad_ca.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::wait_for_port;
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(
 | 
				
			||||||
 | 
					        PortsAllocation::WithTokenAuthAndInvalidServerTLSBadCA,
 | 
				
			||||||
 | 
					        index,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![VALID_TOKEN.to_string()],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.localhost_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.localhost_key.file_path()),
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("https://localhost:{}", port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: Some(pki.other_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap_err();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					use tokio::task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::tcp_relay_client::client_config::ClientConfig;
 | 
				
			||||||
 | 
					use crate::tcp_relay_server::server_config::ServerConfig;
 | 
				
			||||||
 | 
					use crate::test::dummy_tcp_sockets::wait_for_port;
 | 
				
			||||||
 | 
					use crate::test::pki::Pki;
 | 
				
			||||||
 | 
					use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const VALID_TOKEN: &str = "AvalidTOKEN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn port(index: u16) -> u16 {
 | 
				
			||||||
 | 
					    get_port_number(
 | 
				
			||||||
 | 
					        PortsAllocation::WithTokenAuthAndInvalidServerTLSExpiredAndBadCN,
 | 
				
			||||||
 | 
					        index,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::test()]
 | 
				
			||||||
 | 
					async fn test() {
 | 
				
			||||||
 | 
					    let _ = env_logger::builder().is_test(true).try_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pki = Pki::load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let local_set = task::LocalSet::new();
 | 
				
			||||||
 | 
					    local_set
 | 
				
			||||||
 | 
					        .run_until(async move {
 | 
				
			||||||
 | 
					            // Start server relay
 | 
				
			||||||
 | 
					            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
 | 
				
			||||||
 | 
					                tokens: vec![VALID_TOKEN.to_string()],
 | 
				
			||||||
 | 
					                tokens_file: None,
 | 
				
			||||||
 | 
					                ports: vec![port(1)],
 | 
				
			||||||
 | 
					                upstream_server: "127.0.0.1".to_string(),
 | 
				
			||||||
 | 
					                listen_address: format!("127.0.0.1:{}", port(0)),
 | 
				
			||||||
 | 
					                increment_ports: 1,
 | 
				
			||||||
 | 
					                tls_cert: Some(pki.expired_client_crt.file_path()),
 | 
				
			||||||
 | 
					                tls_key: Some(pki.expired_client_key.file_path()),
 | 
				
			||||||
 | 
					                tls_client_auth_root_cert: None,
 | 
				
			||||||
 | 
					                tls_revocation_list: None,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            wait_for_port(port(0)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start client relay
 | 
				
			||||||
 | 
					            crate::tcp_relay_client::run_app(ClientConfig {
 | 
				
			||||||
 | 
					                token: Some(VALID_TOKEN.to_string()),
 | 
				
			||||||
 | 
					                relay_url: format!("https://localhost:{}", port(0)),
 | 
				
			||||||
 | 
					                listen_address: LOCALHOST_IP.to_string(),
 | 
				
			||||||
 | 
					                root_certificate: Some(pki.root_ca_crt.file_path()),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap_err();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
[package]
 | 
					 | 
				
			||||||
name = "tcp_relay_client"
 | 
					 | 
				
			||||||
version = "0.1.0"
 | 
					 | 
				
			||||||
edition = "2021"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
base = { path = "../base" }
 | 
					 | 
				
			||||||
clap = { version = "3.2.18", features = ["derive", "env"] }
 | 
					 | 
				
			||||||
log = "0.4.17"
 | 
					 | 
				
			||||||
env_logger = "0.9.0"
 | 
					 | 
				
			||||||
reqwest = { version = "0.11", features = ["json"] }
 | 
					 | 
				
			||||||
tokio = { version = "1", features = ["full"] }
 | 
					 | 
				
			||||||
futures = "0.3.24"
 | 
					 | 
				
			||||||
tokio-tungstenite = "0.17.2"
 | 
					 | 
				
			||||||
urlencoding = "2.1.0"
 | 
					 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
pub mod relay_client;
 | 
					 | 
				
			||||||
@@ -1,64 +0,0 @@
 | 
				
			|||||||
use std::sync::Arc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use clap::Parser;
 | 
					 | 
				
			||||||
use futures::future::join_all;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use base::RemoteConfig;
 | 
					 | 
				
			||||||
use tcp_relay_client::relay_client::relay_client;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// TCP relay client
 | 
					 | 
				
			||||||
#[derive(Parser, Debug, Clone)]
 | 
					 | 
				
			||||||
#[clap(author, version, about, long_about = None)]
 | 
					 | 
				
			||||||
pub struct Args {
 | 
					 | 
				
			||||||
    /// Access token
 | 
					 | 
				
			||||||
    #[clap(short, long)]
 | 
					 | 
				
			||||||
    pub token: String,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Relay server
 | 
					 | 
				
			||||||
    #[clap(short, long, default_value = "http://127.0.0.1:8000")]
 | 
					 | 
				
			||||||
    pub relay_url: String,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Listen address
 | 
					 | 
				
			||||||
    #[clap(short, long, default_value = "127.0.0.1")]
 | 
					 | 
				
			||||||
    pub listen_address: String,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[tokio::main]
 | 
					 | 
				
			||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
					 | 
				
			||||||
    env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let args: Args = Args::parse();
 | 
					 | 
				
			||||||
    let args = Arc::new(args);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Get server relay configuration (fetch the list of port to forward)
 | 
					 | 
				
			||||||
    let url = format!("{}/config", args.relay_url);
 | 
					 | 
				
			||||||
    log::info!("Retrieving configuration on {}", url);
 | 
					 | 
				
			||||||
    let req = reqwest::Client::new().get(url)
 | 
					 | 
				
			||||||
        .header("Authorization", format!("Bearer {}", args.token))
 | 
					 | 
				
			||||||
        .send()
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    if req.status().as_u16() != 200 {
 | 
					 | 
				
			||||||
        log::error!("Could not retrieve configuration! (got status {})", req.status());
 | 
					 | 
				
			||||||
        std::process::exit(2);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    let conf = req.json::<RemoteConfig>()
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Start to listen port
 | 
					 | 
				
			||||||
    let mut handles = vec![];
 | 
					 | 
				
			||||||
    for port in conf {
 | 
					 | 
				
			||||||
        let listen_address = format!("{}:{}", args.listen_address, port.port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let h = tokio::spawn(relay_client(
 | 
					 | 
				
			||||||
            format!("{}/ws?id={}&token={}",
 | 
					 | 
				
			||||||
                    args.relay_url, port.id, urlencoding::encode(&args.token))
 | 
					 | 
				
			||||||
                .replace("http", "ws"),
 | 
					 | 
				
			||||||
            listen_address,
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
        handles.push(h);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    join_all(handles).await;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,87 +0,0 @@
 | 
				
			|||||||
use futures::{SinkExt, StreamExt};
 | 
					 | 
				
			||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
 | 
					 | 
				
			||||||
use tokio::net::{TcpListener, TcpStream};
 | 
					 | 
				
			||||||
use tokio_tungstenite::tungstenite::Message;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn relay_client(ws_url: String, listen_address: String) {
 | 
					 | 
				
			||||||
    log::info!("Start to listen on {}", listen_address);
 | 
					 | 
				
			||||||
    let listener = match TcpListener::bind(&listen_address).await {
 | 
					 | 
				
			||||||
        Ok(l) => l,
 | 
					 | 
				
			||||||
        Err(e) => {
 | 
					 | 
				
			||||||
            log::error!("Failed to start to listen on {}! {}", listen_address, e);
 | 
					 | 
				
			||||||
            std::process::exit(3);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    loop {
 | 
					 | 
				
			||||||
        let (socket, _) = listener.accept().await
 | 
					 | 
				
			||||||
            .expect("Failed to accept new connection!");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        tokio::spawn(relay_connection(ws_url.clone(), socket));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Relay connection
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// WS read => TCP write
 | 
					 | 
				
			||||||
/// TCP read => WS write
 | 
					 | 
				
			||||||
async fn relay_connection(ws_url: String, socket: TcpStream) {
 | 
					 | 
				
			||||||
    log::debug!("Connecting to {}...", ws_url);
 | 
					 | 
				
			||||||
    let (ws_stream, _) = tokio_tungstenite::connect_async(ws_url)
 | 
					 | 
				
			||||||
        .await.expect("Failed to connect to server relay!");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let (mut tcp_read, mut tcp_write) = socket.into_split();
 | 
					 | 
				
			||||||
    let (mut ws_write, mut ws_read) =
 | 
					 | 
				
			||||||
        ws_stream.split();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // TCP read -> WS write
 | 
					 | 
				
			||||||
    let future = async move {
 | 
					 | 
				
			||||||
        let mut buff: [u8; 5000] = [0; 5000];
 | 
					 | 
				
			||||||
        loop {
 | 
					 | 
				
			||||||
            match tcp_read.read(&mut buff).await {
 | 
					 | 
				
			||||||
                Ok(s) => {
 | 
					 | 
				
			||||||
                    if let Err(e) = ws_write.send(Message::Binary(Vec::from(&buff[0..s]))).await {
 | 
					 | 
				
			||||||
                        log::error!(
 | 
					 | 
				
			||||||
                            "Failed to write to WS connection! {:?} Exiting TCP read -> WS write loop...",e);
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if s == 0 {
 | 
					 | 
				
			||||||
                        log::info!("Got empty read TCP buffer. Stopping...");
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                Err(e) => {
 | 
					 | 
				
			||||||
                    log::error!(
 | 
					 | 
				
			||||||
                        "Failed to read from TCP connection! {:?} Exitin TCP read -> WS write loop...",
 | 
					 | 
				
			||||||
                        e
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    tokio::spawn(future);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // WS read -> TCP write
 | 
					 | 
				
			||||||
    while let Some(m) = ws_read.next().await {
 | 
					 | 
				
			||||||
        match m {
 | 
					 | 
				
			||||||
            Err(e) => {
 | 
					 | 
				
			||||||
                log::error!("Failed to read from WebSocket. Breaking read loop... {:?}", e);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Ok(Message::Binary(b)) => {
 | 
					 | 
				
			||||||
                if let Err(e) = tcp_write.write_all(&b).await {
 | 
					 | 
				
			||||||
                    log::error!("Failed to forward message to websocket. Closing reading end... {:?}", e);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Ok(Message::Close(_r)) => {
 | 
					 | 
				
			||||||
                log::info!("Server asked to close this WebSocket connection");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Ok(m) => log::info!("{:?}", m)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
[package]
 | 
					 | 
				
			||||||
name = "tcp_relay_server"
 | 
					 | 
				
			||||||
version = "0.1.0"
 | 
					 | 
				
			||||||
edition = "2021"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
base = { path = "../base" }
 | 
					 | 
				
			||||||
clap = { version = "3.2.18", features = ["derive", "env"] }
 | 
					 | 
				
			||||||
log = "0.4.17"
 | 
					 | 
				
			||||||
env_logger = "0.9.0"
 | 
					 | 
				
			||||||
actix = "0.13.0"
 | 
					 | 
				
			||||||
actix-web = "4"
 | 
					 | 
				
			||||||
actix-web-actors = "4.1.0"
 | 
					 | 
				
			||||||
serde = { version = "1.0.144", features = ["derive"] }
 | 
					 | 
				
			||||||
tokio = { version = "1", features = ["full"] }
 | 
					 | 
				
			||||||
futures = "0.3.24"
 | 
					 | 
				
			||||||
@@ -1,31 +0,0 @@
 | 
				
			|||||||
use clap::Parser;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// TCP relay server
 | 
					 | 
				
			||||||
#[derive(Parser, Debug, Clone)]
 | 
					 | 
				
			||||||
#[clap(author, version, about, long_about = None)]
 | 
					 | 
				
			||||||
pub struct Args {
 | 
					 | 
				
			||||||
    /// Access tokens
 | 
					 | 
				
			||||||
    #[clap(short, long)]
 | 
					 | 
				
			||||||
    pub tokens: Vec<String>,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Access tokens stored in a file, one token per line
 | 
					 | 
				
			||||||
    #[clap(long)]
 | 
					 | 
				
			||||||
    pub tokens_file: Option<String>,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Forwarded ports
 | 
					 | 
				
			||||||
    #[clap(short, long)]
 | 
					 | 
				
			||||||
    pub ports: Vec<u16>,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Upstream server
 | 
					 | 
				
			||||||
    #[clap(short, long, default_value = "127.0.0.1")]
 | 
					 | 
				
			||||||
    pub upstream_server: String,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// HTTP server listen address
 | 
					 | 
				
			||||||
    #[clap(short, long, default_value = "0.0.0.0:8000")]
 | 
					 | 
				
			||||||
    pub listen_address: String,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Increment ports on client. Useful for debugging and running both client and server
 | 
					 | 
				
			||||||
    /// on the same machine
 | 
					 | 
				
			||||||
    #[clap(short, long, default_value_t = 0)]
 | 
					 | 
				
			||||||
    pub increment_ports: u16,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,2 +0,0 @@
 | 
				
			|||||||
pub mod args;
 | 
					 | 
				
			||||||
pub mod relay_ws;
 | 
					 | 
				
			||||||
@@ -1,74 +0,0 @@
 | 
				
			|||||||
use std::sync::Arc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use actix_web::{App, HttpRequest, HttpResponse, HttpServer, middleware, Responder, web};
 | 
					 | 
				
			||||||
use actix_web::web::Data;
 | 
					 | 
				
			||||||
use clap::Parser;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use base::RelayedPort;
 | 
					 | 
				
			||||||
use tcp_relay_server::args::Args;
 | 
					 | 
				
			||||||
use tcp_relay_server::relay_ws::relay_ws;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn hello_route() -> &'static str {
 | 
					 | 
				
			||||||
    "Hello world!"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn config_route(req: HttpRequest, data: Data<Arc<Args>>) -> impl Responder {
 | 
					 | 
				
			||||||
    let token = req.headers().get("Authorization")
 | 
					 | 
				
			||||||
        .map(|t| t.to_str().unwrap_or_default())
 | 
					 | 
				
			||||||
        .unwrap_or_default()
 | 
					 | 
				
			||||||
        .strip_prefix("Bearer ")
 | 
					 | 
				
			||||||
        .unwrap_or_default();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if !data.tokens.iter().any(|t| t.eq(token)) {
 | 
					 | 
				
			||||||
        return HttpResponse::Unauthorized().json("Missing / invalid token");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    HttpResponse::Ok().json(
 | 
					 | 
				
			||||||
        data.ports.iter()
 | 
					 | 
				
			||||||
            .enumerate()
 | 
					 | 
				
			||||||
            .map(|(id, port)| RelayedPort { id, port: port + data.increment_ports })
 | 
					 | 
				
			||||||
            .collect::<Vec<_>>()
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[actix_web::main]
 | 
					 | 
				
			||||||
async fn main() -> std::io::Result<()> {
 | 
					 | 
				
			||||||
    env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut args: Args = Args::parse();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if args.ports.is_empty() {
 | 
					 | 
				
			||||||
        log::error!("No port to forward!");
 | 
					 | 
				
			||||||
        std::process::exit(2);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Read tokens from file, if any
 | 
					 | 
				
			||||||
    if let Some(file) = &args.tokens_file {
 | 
					 | 
				
			||||||
        std::fs::read_to_string(file)
 | 
					 | 
				
			||||||
            .expect("Failed to read tokens file!")
 | 
					 | 
				
			||||||
            .split('\n')
 | 
					 | 
				
			||||||
            .filter(|l| !l.is_empty())
 | 
					 | 
				
			||||||
            .for_each(|t| args.tokens.push(t.to_string()));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if args.tokens.is_empty() {
 | 
					 | 
				
			||||||
        log::error!("No tokens specified!");
 | 
					 | 
				
			||||||
        std::process::exit(3);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    log::info!("Starting relay on http://{}", args.listen_address);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let args = Arc::new(args);
 | 
					 | 
				
			||||||
    let args_clone = args.clone();
 | 
					 | 
				
			||||||
    HttpServer::new(move || {
 | 
					 | 
				
			||||||
        App::new()
 | 
					 | 
				
			||||||
            .wrap(middleware::Logger::default())
 | 
					 | 
				
			||||||
            .app_data(Data::new(args_clone.clone()))
 | 
					 | 
				
			||||||
            .route("/", web::get().to(hello_route))
 | 
					 | 
				
			||||||
            .route("/config", web::get().to(config_route))
 | 
					 | 
				
			||||||
            .route("/ws", web::get().to(relay_ws))
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
        .bind(&args.listen_address)?
 | 
					 | 
				
			||||||
        .run()
 | 
					 | 
				
			||||||
        .await
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user