Compare commits
3 Commits
a866deb3e4
...
220830
| Author | SHA1 | Date | |
|---|---|---|---|
| 884018a90d | |||
| 53ad29727e | |||
| dde219a717 |
22
README.MD
Normal file
22
README.MD
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# TCP over HTTP
|
||||||
|
This project aims to provide an easy-to-setup TCP forwarding solution:
|
||||||
|
|
||||||
|
```
|
||||||
|
|--------| |--------| |--------| | -------|
|
||||||
|
| | | Client | | Server | | |
|
||||||
|
| Client | -- TCP xx -- | | -- HTTP 80 / 443 -- | | -- TCP xx -- | Server |
|
||||||
|
| | | Relay | | Relay | | |
|
||||||
|
|--------| |--------| |--------| |--------|
|
||||||
|
```
|
||||||
|
|
||||||
|
This project can be used especially to bypass firewalls that blocks traffics
|
||||||
|
from ports others than the 80 / 443 duo.
|
||||||
|
|
||||||
|
This repository contains two binaries:
|
||||||
|
|
||||||
|
* `tpc_relay_server`: The server relay
|
||||||
|
* `tcp_relay_client`: The client relay
|
||||||
|
|
||||||
|
The clients relay authenticates itself to the server using a token.
|
||||||
|
|
||||||
|
A single server - client relay pair can relay multiple ports simultaneously from the same machine.
|
||||||
@@ -8,6 +8,10 @@ pub struct Args {
|
|||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
pub tokens: Vec<String>,
|
pub tokens: Vec<String>,
|
||||||
|
|
||||||
|
/// Access tokens stored in a file, one token per line
|
||||||
|
#[clap(long)]
|
||||||
|
pub tokens_file: Option<String>,
|
||||||
|
|
||||||
/// Forwarded ports
|
/// Forwarded ports
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
pub ports: Vec<u16>,
|
pub ports: Vec<u16>,
|
||||||
|
|||||||
@@ -35,14 +35,22 @@ pub async fn config_route(req: HttpRequest, data: Data<Arc<Args>>) -> impl Respo
|
|||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||||
|
|
||||||
let args: Args = Args::parse();
|
let mut args: Args = Args::parse();
|
||||||
let args = Arc::new(args);
|
|
||||||
|
|
||||||
if args.ports.is_empty() {
|
if args.ports.is_empty() {
|
||||||
log::error!("No port to forward!");
|
log::error!("No port to forward!");
|
||||||
std::process::exit(2);
|
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() {
|
if args.tokens.is_empty() {
|
||||||
log::error!("No tokens specified!");
|
log::error!("No tokens specified!");
|
||||||
std::process::exit(3);
|
std::process::exit(3);
|
||||||
@@ -50,6 +58,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
|
|
||||||
log::info!("Starting relay on http://{}", args.listen_address);
|
log::info!("Starting relay on http://{}", args.listen_address);
|
||||||
|
|
||||||
|
let args = Arc::new(args);
|
||||||
let args_clone = args.clone();
|
let args_clone = args.clone();
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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::{Error, HttpRequest, HttpResponse, web};
|
||||||
use actix_web_actors::ws;
|
use actix_web_actors::ws;
|
||||||
|
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;
|
||||||
@@ -20,6 +21,9 @@ const CLIENT_TIMEOUT: Duration = Duration::from_secs(60);
|
|||||||
#[rtype(result = "bool")]
|
#[rtype(result = "bool")]
|
||||||
pub struct DataForWebSocket(Vec<u8>);
|
pub struct DataForWebSocket(Vec<u8>);
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct TCPReadEndClosed;
|
||||||
|
|
||||||
/// Define HTTP actor
|
/// Define HTTP actor
|
||||||
struct RelayWS {
|
struct RelayWS {
|
||||||
@@ -72,6 +76,7 @@ impl Actor for RelayWS {
|
|||||||
Ok(l) => {
|
Ok(l) => {
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
log::info!("Got empty read. Closing read end...");
|
log::info!("Got empty read. Closing read end...");
|
||||||
|
addr.do_send(TCPReadEndClosed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +134,16 @@ impl Handler<DataForWebSocket> for RelayWS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Handler<TCPReadEndClosed> for RelayWS {
|
||||||
|
type Result = ();
|
||||||
|
|
||||||
|
fn handle(&mut self, _msg: TCPReadEndClosed, ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
ctx.close(Some(CloseReason {
|
||||||
|
code: CloseCode::Away,
|
||||||
|
description: Some("TCP read end closed.".to_string()),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct WebSocketQuery {
|
pub struct WebSocketQuery {
|
||||||
|
|||||||
Reference in New Issue
Block a user