Skip to content

Commit

Permalink
Merge pull request #16 from editso/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
editso authored Dec 13, 2021
2 parents 34930fb + 34c7742 commit 06dd56e
Show file tree
Hide file tree
Showing 15 changed files with 483 additions and 91 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
build-release.sh
build-release.sh
.vscode
77 changes: 77 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ path = "src/server.rs"
name = "fuc"
path = "src/client.rs"


[dependencies]
aes = {version = "0.7.5"}
block-modes = "0.8.1"
hex-literal = "0.3.4"
log = {version = "0.4.14"}
clap = {version = "3.0.0-beta.5", features = ["yaml"]}
smol = {version = "1.2.5"}
Expand Down
107 changes: 79 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ A fast, stable, cross-platform and efficient intranet penetration and port forwa
[![GitHub license](https://img.shields.io/github/license/editso/fuso)](https://github.com/editso/fuso)
[![Downloads](https://img.shields.io/github/downloads/editso/fuso/total?label=Release%20Download)](https://github.com/editso/fuso/releases/latest)

### Fuso make PortForward & IntranetAccess Easy 😁
### Fuso make PortForward & IntranetAccess Easy

👉 这是一款用于内网穿透 端口转发的神器,帮助运维 开发 快速部署与接入内网 同时支持CobaltStrike 一键转发等功能

👉 还在因为工具的参数过多,体积大而烦恼吗? 我们只实现Socks5与端口转发,快捷的接入与转发内网流量且体积小方便实用
👉 这是一款用于内网穿透 端口转发的工具,帮助运维,开发人员快速部署与接入内网

👉 该项目可直接当做库来使用

Expand All @@ -31,30 +29,82 @@ A fast, stable, cross-platform and efficient intranet penetration and port forwa


### 👀如何使用 (How to use) ❓

1. 你需要先[下载](https://github.com/editso/fuso/releases/latest)[构建](#Build)Fuso

2. 服务端程序为`fus`, 客户端程序为`fuc`

3. 测试
1. 运行`fus`(服务端默认监听`9003`端口) 与 `fuc`(客户端默认转发`80`端口)
2. 确保服务端端口(`9003`)未被使用
3. 确保转发的端口(`80`)有服务在运行
4. 转发成功后需要访问的端口由服务端随机分配
5. 服务端出现 **New mapping xxxx -> xxxx**日志则代表转发服务已准备就绪

4. 配置
`Fuso` 的所有配置都是通过参数传递的方式
打开终端运行 `[fus or fuc] --help` 即可获取帮助信息

5. 高级用法 `>1.0.2`
1. 支持从客户端指定服务端要监听的端口(*前提你所指定的端口没有被占用!*) 用法:
`fuc [--bind or -b] 端口`
2. 支持多连接
3. 级联代理(`桥接模式`), 支持级联代理, 用法:
开启桥模式 `fuc [--bridge ] 端口` **开启后它既支持桥接也支持穿透互不影响**
使用 `fuc 已开启桥接模式的地址 端口` 其它参数基本一致

1. 你需要先[下载](https://github.com/editso/fuso/releases/latest)[构建](#Build)`Fuso`
2. `fuso` 分为客户端(`fuc`)与服务端(`fus`)
3. 将你下载或构建好的`fus`程序[部署](#服务端部署)到服务器
4. 将你下载或构建好的`fuc`程序[部署](#客户端部署)到你需要穿透的电脑上

#### 服务端部署
1. 采用参数传递的形式来部署无需任何配置文件, 并且配置简单大多情况下可使用默认配置

2. **参数说明**
`-h`: 绑定的地址
`-p`: 监听的端口, 也就是客户端需要连接到服务端的端口
`-x`: `xor`加密的`key` (*目前暂时定义为`xor`加密的`key`, 未来可能因加密方式变化所改动*)
`-l`: 日志信息级别 (`debug`, `info`, `trace`, `error`, `warn`)
`-v`: 该参数打印的版本目前无效
`-h`: 获取帮助信息


#### 客户端部署
客户端配置相对服务端来说可能会复杂一点, 但大多数情况下也可使用默认配置

1 **参数说明**
fuc [options] <server-host> <server-port>

`<server-host>`: 服务端地址, 支持域名
`<server-port>`: 服务端监听的端口
`-h`: 需要转发的地址, 也就是穿透地址
`-p`: 转发的端口, 需要配合 `-h`参数
`-b`: 真实映射成功后访问的端口号, 不指定将自动分配
`-n`: 一个标识, 映射服务的名称
`-w`: 使用`Websocket`进程握手连接
`-x`: `xor`加密的`key` (*目前暂时定义为`xor`加密的`key`, 未来可能因加密方式 变化所改动*)
`-l`: 日志信息级别 (`debug`, `info`, `trace`, `error`, `warn`)
`--bridge-host`: 桥接服务监听的地址
`--bridge-port`: 桥接服务监听的端口

```
# 一个转发例子
# 服务端绑定在 xxx.xxx.xxx.xxx:9003
# 转发内网中 10.10.10.8:80 到 xxx.xxx.xxx.xxx:8080
# 需要注意的是:
# 10.10.10.8 必须是能 ping 通的
# 80 端口必须有服务在运行
# 服务端已经在运行,并且服务端80端口没有被占用
# 运行:
> fuc -h 10.10.10.8 -p 80 -b 8080 xxx.xxx.xxx.xxx 9003
# 该命令运行后既可以是转发模式, 也可以是Socks5模式都可以使用8080端口进行访问
# 一个桥接例子
# 什么时候能用到桥接模式呢?
# 比如:
# 你的内网中只有一台机器可以出网, 但是我想访问不能出网机器上所运行的服务
# 那么此时就可以使用桥接模式, 通过可以在出网的机器上开启桥接模式来转发不能出网的服务
# 前提是你不能出网的机器和可以出网的机器在同一个内网中, 并且可以相互 ping 通
# 在可以出网的机器上开启桥接 (0.0.0.0:9004)
# 假设可以出网的内网ip地址为 10.10.10.5
# 运行:
> fuc -h 10.10.10.8 -p 80 -b 8080 --bridge-host 0.0.0.0 --bridge-port 9004 xxx.xxx.xxx.xxx 9003
# 在不可以出网的机器上需要穿透80服务, 并且服务端监听8081端口
# 此时fuc的服务端地址就不应该是服务器地址, 因为并不能出网, 所有需要连接到开启桥接服务的地址
# 运行:
> fuc -h 127.0.0.1 -p 80 -b 8081 10.10.10.5 9004
# 另一种桥接做法
# 假设不能出网机器的ip地址为 10.10.10.6
# 在可以出网的机器上运行:
> fuc -h 10.10.10.6 -p 80 -b 8081 xxx.xxx.xxx.xxx 9003
# 此时也可以达到效果, 但是这样一来可以出网的就无法转发自己所监听的服务
```

### 🤔Features
| Name | <font color="green">✔(Achieved)</font> / <font color="red">❌(Unrealized)</font>) |
Expand All @@ -67,6 +117,7 @@ A fast, stable, cross-platform and efficient intranet penetration and port forwa
| 多映射 | <font color="green">✔</font> |
| 级联代理 | <font color="green">✔</font> |
| 数据传输压缩 ||
| Websocket | <font color="green">✔</font> |


### 😶部分功能还待完善敬请期待..
Expand Down
42 changes: 40 additions & 2 deletions fuso-api/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ pub trait FusoPacket {
async fn send(&mut self, packet: Packet) -> Result<()>;
}

#[async_trait]
pub trait FusoStreamEx {
async fn send_opt_data(&mut self, data: Option<Bytes>) -> Result<()>;
}

#[async_trait]
pub trait FusoEncoder<OUT> {
async fn encode(&self) -> Result<OUT>;
Expand Down Expand Up @@ -165,6 +170,7 @@ impl Packet {
let magic = packet.get_u32();

if Self::magic() != magic {
log::warn!("{:?}", String::from_utf8_lossy(&data));
return Err(error::ErrorKind::BadPacket.into());
}

Expand Down Expand Up @@ -204,10 +210,12 @@ impl Packet {
self.cmd
}

#[inline]
pub fn get_data(&self) -> &Bytes {
&self.data
}

#[inline]
pub fn get_mut_data(&mut self) -> &mut Bytes {
&mut self.data
}
Expand Down Expand Up @@ -301,6 +309,22 @@ where
}
}

#[async_trait]
impl<T> FusoStreamEx for T
where
T: AsyncWrite + Unpin + Send + Sync + 'static,
{
#[inline]
async fn send_opt_data(&mut self, mut data: Option<Bytes>) -> Result<()> {
if let Some(data) = data.take() {
log::debug!("[send_opt_data] len={}", data.len());
self.write_all(&data).await.map_err(|e| e.into())
} else {
Ok(())
}
}
}

impl<T, A> Spawn for T
where
A: Send + 'static,
Expand All @@ -309,8 +333,9 @@ where
#[inline]
fn detach(self) {
static GLOBAL: once_cell::sync::Lazy<Executor<'_>> = once_cell::sync::Lazy::new(|| {
for n in 1..num_cpus::get() {
log::trace!("spwan executor thread fuso-{}", n);
println!("cpu {}", num_cpus::get());
for n in 0..num_cpus::get() {
log::trace!("spawn executor thread fuso-{}", n);
std::thread::Builder::new()
.name(format!("fuso-{}", n))
.spawn(|| loop {
Expand Down Expand Up @@ -364,6 +389,19 @@ impl AsyncTcpSocketEx<TcpListener, TcpStream> for SocketAddr {
}
}

#[async_trait]
impl AsyncTcpSocketEx<TcpListener, TcpStream> for String {
#[inline]
async fn tcp_listen(self) -> Result<TcpListener> {
TcpListener::bind(self).await.map_err(|e| e.into())
}

#[inline]
async fn tcp_connect(self) -> Result<TcpStream> {
TcpStream::connect(self).await.map_err(|e| e.into())
}
}

impl<T> RollbackEx<T, Buffer<u8>> for T
where
T: AsyncRead + AsyncWrite + Send + Sync + 'static,
Expand Down
2 changes: 1 addition & 1 deletion fuso-api/src/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl UdpListener {
loop {
let mut buf = Vec::new();

buf.resize(1350, 0);
buf.resize(MTU_BUF_SIZE, 0);

let packet = udp.recv_from(&mut buf).await;

Expand Down
2 changes: 1 addition & 1 deletion fuso-core/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub struct Bridge {

impl Bridge {
#[inline]
pub async fn bind(bind_addr: SocketAddr, server_addr: SocketAddr) -> Result<Self> {
pub async fn bind(bind_addr: String, server_addr: SocketAddr) -> Result<Self> {
let listen = bind_addr.tcp_listen().await?;

let (accept_tx, accept_ax) = unbounded();
Expand Down
Loading

0 comments on commit 06dd56e

Please sign in to comment.