Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

meethigher/tcp-reverse-proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

100 Commits

Repository files navigation

tcp-reverse-proxy

基于Vert.x实现的网络库。支持HTTP反向代理、TCP反向代理、TCP内网穿透、TCP单端口多路复用

开发环境

  • jdk: 8
  • vertx: 4.5.10

依赖引入,可以访问mvnrepository.com查看版本

<dependency>
 <groupId>top.meethigher</groupId>
 <artifactId>tcp-reverse-proxy</artifactId>
 <version>${tcp-reverse-proxy.version}</version>
</dependency>
<dependency>
 <groupId>io.vertx</groupId>
 <artifactId>vertx-core</artifactId>
 <version>4.5.10</version>
</dependency>
<!-- 若不使用http反向代理,可不加此依赖 -->
<dependency>
 <groupId>io.vertx</groupId>
 <artifactId>vertx-web</artifactId>
 <version>4.5.10</version>
</dependency>
<!-- 若不想添加日志,可只添加slf4j-api -->
<dependency>
 <groupId>ch.qos.logback</groupId>
 <artifactId>logback-classic</artifactId>
 <version>1.2.12</version>
</dependency>
<!-- 若不使用TCP内网穿透,可不加此依赖 -->
<dependency>
 <groupId>com.google.protobuf</groupId>
 <artifactId>protobuf-javalite</artifactId>
 <version>4.30.2</version>
</dependency>

一、HTTP反向代理

实现HTTP反向代理,代理路由优先级如下

  1. /local/*↔️http://127.0.0.1:888
    • http://127.0.0.1:8080/local/1↔️http://127.0.0.1:888/1
    • http://127.0.0.1:8080/local/1/2/3↔️http://127.0.0.1:888/1/2/3
  2. /*↔️https://reqres.in
    • http://127.0.0.1:8080/api/users?page=2↔️https://reqres.in/api/users?page=2

HTTP反向代理支持如下配置

  1. 请求头转发客户端IP: 默认值F
  2. 保留响应头Cookie: 默认值T
  3. 保留请求头Host: 默认值F
  4. 跟随跳转: 默认值T
  5. 长连接: 默认值T
  6. 日志及日志格式自定义
  7. 代理服务完全接管跨域控制: 默认值F
// addRoute第二个参数表示优先级,值越小、优先级越高
ReverseHttpProxy.create(vertx).port(8080)
 .addRoute(new ProxyRoute()
 .setName("proxy")
 .setSourceUrl("/local/*")
 .setTargetUrl("http://127.0.0.1:888"),-1)
 .addRoute(new ProxyRoute()
 .setName("proxy")
 .setSourceUrl("/*")
 .setTargetUrl("https://reqres.in"),1)
 .start();

二、TCP反向代理

实现TCP反向代理:0.0.0.0:22↔️10.0.0.1:8080

ReverseTcpProxy.create(Vertx.vertx(), "10.0.0.1", 8080)
 .port(22)
 .start();

三、TCP内网穿透

虚线表示控制连接通信,实线表示非控制连接通信。

一些代码上的设计思路,参考socket.io-client-java

sequenceDiagram
 autonumber
 participant u as User
 participant dps as DataProxyServer
 participant ts as TunnelServer
 participant tc as TunnelClient
 participant bs as BackendServer
 bs->bs: 监听22端口
 ts->ts: 监听44444端口
 tc-->>ts: 建立控制连接、发送鉴权密钥、申请启用2222端口数据服务
 ts->ts: 鉴权校验通过
 ts->>dps: 你要开启2222端口
 dps->dps: 监听2222端口
 dps->>ts: 已开启
 ts-->>tc: 端口已启用
 tc->tc: 开启与控制服务的周期心跳
 loop 控制连接保活
 tc-->>ts: 发送心跳
 ts-->>tc: 响应心跳
 end
 u->>dps: 建立用户连接
 dps->>ts: 
 ts-->>tc: 你需要主动与2222数据服务端口建立数据连接
 tc->>dps: 建立数据连接,并告知对方"我是数据连接"
 tc-->>ts: 连接已建立
 note left of dps: 用户连接和数据连接绑定双向生命周期、双向数据传输
 dps->>dps: 绑定用户连接与数据连接
 dps->>tc: 用户连接与数据连接已绑定
 tc->>bs: 建立后端连接
 bs->>tc: 后端连接已建立
 note right of tc: 数据连接和后端连接绑定双向生命周期、双向数据传输
 tc->>tc: 绑定数据连接和后端连接 
 u->dps: 双向传输
 dps->tc: 双向传输
 tc->bs: 双向传输 
Loading

假如我有一个内网SSH服务10.0.0.10:22,需要通过192.168.0.200:22穿透出去。并且网络条件受限如下

  1. 10.0.0.10可以主动连接192.168.0.200
  2. 192.168.0.200无法主动连接10.0.0.10
  3. 只要双方建立连接,即可实现双向数据传输

这就需要TCP内网穿透了。假设你内网穿透使用的控制端口为44444

首先,在192.168.0.200这台机器,使用如下代码启动TunnelServer

ReverseTcpProxyTunnelServer.create(Vertx.vertx())
 .port(44444)
 // 用于用户连接和数据连接的延迟判定,如果网络较差/DNS解析较慢的情况下,建议将该参数调大
 .judgeDelay(2000)
 .start();

10.0.0.10这台机器,使用如下代码启动TunnelClient

ReverseTcpProxyTunnelClient.create(Vertx.vertx())
 .backendHost("10.0.0.10")
 .backendPort(22)
 .dataProxyName("ssh-proxy")
 .dataProxyHost("192.168.0.200")
 .dataProxyPort(22)
 .connect("192.168.0.200", 44444);

四、TCPMux单端口多路复用

参考RFC 1078 - TCP port service Multiplexer (TCPMUX)

现有场景如下

flowchart LR
 subgraph Network-A
 TMC-1[<b>TCPMux Client-1</b><br>Listen :6666]
 TMC-2[<b>TCPMux Client-2</b><br>Listen :6667]
 TMC-3[<b>TCPMux Client-3</b><br>Listen :6668]
 end
 TMS[<b>TCPMux Server</b></br>Listen :44444]
 subgraph Network-B
 SSH[<b>SSH</b><br>Listen :22]
 PSQL[<b>PostgreSQL</b><br>Listen :5432]
 MYSQL[<b>MySQL</b><br>Listen :3306]
 HTTP-1[<b>HTTP-1</b><br>Listen :80]
 HTTP-2[<b>HTTP-2</b><br>Listen :80]
 end
 TMC-1 -->|service HTTP-1|TMS -->HTTP-1
 TMC-2 -->|service HTTP-2|TMS -->HTTP-2
 TMC-3 -->|service SSH|TMS -->SSH
Loading

上述场景代码实践

// TCPMux Server
ReverseTcpProxyMuxServer.create(Vertx.vertx())
 .port(44444)
 .start();
// TCPMux Client
Map<MuxNetAddress, NetAddress> map = new LinkedHashMap<>();
map.put(new MuxNetAddress(6666, "HTTP-1"), new NetAddress("HTTP-1", 80));
map.put(new MuxNetAddress(6667, "HTTP-2"), new NetAddress("HTTP-2", 80));
map.put(new MuxNetAddress(6668, "SSH"), new NetAddress("SSG", 22));
NetAddress muxServerAddress = new NetAddress("10.0.0.1", 44444);
ReverseTcpProxyMuxClient.create(Vertx.vertx(), map, muxServerAddress)
 .start();

TCPMux实现思路

sequenceDiagram
 participant u as User
 participant c as TcpMuxClient
 participant s as TcpMuxServer
 participant b1 as Backend1
 participant b2 as Backend2
 
 autonumber
 s->>s: 监听44444端口
 c->>c: 监听22222端口
 u->>c: 1. 建立用户连接 2. 发送数据
 c->>s: 1. 建立数据连接 2. 发送数据(包括加密的mux配置信息、用户连接的数据包)
 note left of c: 用户连接和数据连接绑定双向生命周期、双向数据传输
 s->>s: 对mux配置信息进行解密,获取实际的后端地址
 s->>b2: 1. 建立后端连接 2. 转发用户连接的数据包
 note left of s: 数据连接和后端连接绑定双向生命周期、双向数据传输
 b2->>s: 
 s->>c: 
 c->>u: 
Loading

About

基于Vert.x实现的网络库。支持HTTP反向代理、UDP反向代理、TCP反向代理、TCP内网穿透、TCP单端口多路复用

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /