Skip to content

Commit 43ea244

Browse files
authored
Merge pull request #20 from Sesame2/socks5
feat: 添加SOCKS5代理支持,更新配置和初始化逻辑
2 parents be68a8b + a37a19a commit 43ea244

File tree

8 files changed

+402
-46
lines changed

8 files changed

+402
-46
lines changed

README-CN.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,13 @@ gotun --listen :8888 user@example.com
135135
# 自动设置系统代理(默认开启)
136136
# 若你希望启动时不修改系统代理,请显式关闭:
137137
gotun --sys-proxy=false user@example.com
138+
139+
# 开启 SOCKS5 代理 (默认 :1080)
140+
gotun --socks5 :1080 user@example.com
138141
```
139142

143+
> **注意**: 使用 SOCKS5 代理配合自定义路由规则时,建议在客户端(如浏览器或代理插件)中开启 "Proxy DNS when using SOCKS5" (远程DNS解析) 选项。否则客户端可能会在本地解析域名为 IP,导致基于域名的路由规则失效。
144+
140145
### 在浏览器中使用
141146

142147
启动代理后,在浏览器中配置HTTP代理:
@@ -158,6 +163,7 @@ gotun --sys-proxy=false user@example.com
158163
| `--identity_file` | `-i` | 用于认证的私钥文件路径 | |
159164
| `--jump` | `-J` | 跳板机列表,用逗号分隔 (格式: user@host:port) | |
160165
| `--target` | | 可选的目标网络覆盖 | |
166+
| `--socks5` | | SOCKS5 代理监听地址 | `:1080` |
161167
| `--timeout` | | 连接超时时间 | `10s` |
162168
| `--verbose` | `-v` | 启用详细日志 | `false` |
163169
| `--log` | | 日志文件路径 | 输出到标准输出 |
@@ -350,10 +356,10 @@ sudo gotun user@example.com
350356
- [x] **跳板机 (Jump Host)**: 支持单级和多级SSH跳板机
351357
- [x] **自定义路由规则**: 支持自定义的规则文件进行流量分流
352358
- [x] **命令行自动补全**: 基于 Cobra 的智能提示
359+
- [x] **SOCKS5 代理支持**: 更广泛的协议支持
353360
- [ ] **RDP网关**:支持RDP远程桌面网关
354361
- [ ] **托盘 GUI 界面**: 图形化用户界面
355362
- [ ] **配置文件导出/导入**: 配置管理功能
356-
- [ ] **SOCKS5 代理支持**: 更广泛的协议支持
357363
- [ ] **连接池优化**: 提升性能和稳定性
358364
- [ ] **统计和监控**: 流量统计和连接监控
359365

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Your machine SSH (tcp/22) Bastion I
7373
- Rule-based traffic splitting via configuration file
7474
- Shell completion support for Bash, Zsh, Fish, PowerShell
7575
- Structured logging and verbose mode for debugging
76+
- SOCKS5 proxy support
7677

7778
---
7879

@@ -141,8 +142,13 @@ gotun --listen :8888 user@example.com
141142

142143
# Disable automatic system proxy configuration
143144
gotun --sys-proxy=false user@example.com
145+
146+
# Enable SOCKS5 proxy (default listen on :1080)
147+
gotun --socks5 :1080 user@example.com
144148
```
145149

150+
> **Note**: When using SOCKS5 with custom routing rules, it is recommended to enable "Proxy DNS when using SOCKS5" (Remote DNS) in your client. Otherwise, the client might resolve domains to IPs locally, causing domain-based routing rules to fail.
151+
146152
### Browser configuration
147153

148154
By default, gotun listens on `127.0.0.1:8080` (unless changed by `--listen`).
@@ -166,6 +172,7 @@ If system proxy support is enabled, some platforms can be configured automatical
166172
| `--identity_file` | `-i` | Private key file path | |
167173
| `--jump` | `-J` | Comma-separated jump hosts (`user@host:port`) | |
168174
| `--target` | | Optional target network scope/coverage | |
175+
| `--socks5` | | SOCKS5 proxy bind address | `:1080` |
169176
| `--timeout` | | SSH connection timeout | `10s` |
170177
| `--verbose` | `-v` | Enable verbose logging | `false` |
171178
| `--log` | | Log file path | stdout |
@@ -400,13 +407,13 @@ Implemented:
400407
- [x] Single and multi-hop jump host support
401408
- [x] Rule-based routing
402409
- [x] Shell completion for common shells
410+
- [x] SOCKS5 proxy support
403411

404412
Planned:
405413

406414
- [ ] RDP gateway support
407415
- [ ] Tray/GUI frontend
408416
- [ ] Export/import of configuration profiles
409-
- [ ] SOCKS5 proxy support
410417
- [ ] Connection pooling and performance tuning
411418
- [ ] Traffic statistics and basic monitoring
412419

cmd/gotun/cli/root.go

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/Sesame2/gotun/internal/config"
1212
"github.com/Sesame2/gotun/internal/logger"
1313
"github.com/Sesame2/gotun/internal/proxy"
14+
"github.com/Sesame2/gotun/internal/router"
1415
"github.com/Sesame2/gotun/internal/sysproxy"
1516
"github.com/spf13/cobra"
1617
)
@@ -57,14 +58,43 @@ var rootCmd = &cobra.Command{
5758
}
5859
log.Infof("GoTun %s 启动中...", Version)
5960

60-
httpProxy, err := proxy.NewHTTPOverSSH(cfg, log)
61+
// 1. 初始化 Router
62+
var r *router.Router
63+
if cfg.RuleFile != "" {
64+
var err error
65+
r, err = router.NewRouter(cfg.RuleFile)
66+
if err != nil {
67+
log.Warnf("加载规则文件失败: %v。将以全局代理模式运行。", err)
68+
} else {
69+
log.Infof("已加载规则文件: %s", cfg.RuleFile)
70+
}
71+
}
72+
73+
// 2. 初始化 SSHClient
74+
sshClient, err := proxy.NewSSHClient(cfg, log)
6175
if err != nil {
62-
return fmt.Errorf("代理初始化失败: %w", err)
76+
return fmt.Errorf("SSH连接失败: %w", err)
77+
}
78+
defer sshClient.Close()
79+
80+
// 3. 初始化 HTTP 代理
81+
httpProxy, err := proxy.NewHTTPOverSSH(cfg, log, sshClient, r)
82+
if err != nil {
83+
return fmt.Errorf("HTTP代理初始化失败: %w", err)
84+
}
85+
86+
// 4. 初始化 SOCKS5 代理
87+
var socksProxy *proxy.SOCKS5OverSSH
88+
if cfg.SocksAddr != "" {
89+
socksProxy, err = proxy.NewSOCKS5OverSSH(cfg, log, sshClient, r)
90+
if err != nil {
91+
return fmt.Errorf("SOCKS5代理初始化失败: %w", err)
92+
}
6393
}
6494

6595
var proxyMgr *sysproxy.Manager
6696
if cfg.SystemProxy {
67-
proxyMgr = sysproxy.NewManager(log, cfg.ListenAddr)
97+
proxyMgr = sysproxy.NewManager(log, cfg.ListenAddr, cfg.SocksAddr)
6898
}
6999

70100
sigChan := make(chan os.Signal, 1)
@@ -77,12 +107,26 @@ var rootCmd = &cobra.Command{
77107
}
78108
}
79109
if err := httpProxy.Start(); err != nil {
80-
log.Errorf("代理服务启动失败: %v", err)
110+
log.Errorf("HTTP代理服务启动失败: %v", err)
81111
sigChan <- syscall.SIGTERM
82112
}
83113
}()
84114

85-
fmt.Println("\n代理服务已启动:", "http://"+cfg.ListenAddr)
115+
if socksProxy != nil {
116+
go func() {
117+
if err := socksProxy.Start(); err != nil {
118+
log.Errorf("SOCKS5代理服务启动失败: %v", err)
119+
sigChan <- syscall.SIGTERM
120+
}
121+
}()
122+
}
123+
124+
fmt.Println("\n代理服务已启动:")
125+
fmt.Println("HTTP Proxy:", "http://"+cfg.ListenAddr)
126+
if cfg.SocksAddr != "" {
127+
fmt.Println("SOCKS5 Proxy:", "socks5://"+cfg.SocksAddr)
128+
}
129+
86130
if len(cfg.JumpHosts) > 0 {
87131
fmt.Printf("跳板机链: %s -> %s\n", fmt.Sprintf("%v", cfg.JumpHosts), cfg.SSHServer)
88132
} else {
@@ -106,7 +150,14 @@ var rootCmd = &cobra.Command{
106150
}
107151

108152
if err := httpProxy.Close(); err != nil {
109-
log.Errorf("关闭代理服务失败: %v", err)
153+
log.Errorf("关闭HTTP代理服务失败: %v", err)
154+
}
155+
156+
// 新增关闭逻辑
157+
if socksProxy != nil {
158+
if err := socksProxy.Close(); err != nil {
159+
log.Errorf("关闭SOCKS5代理服务失败: %v", err)
160+
}
110161
}
111162

112163
return nil
@@ -127,6 +178,7 @@ func init() {
127178
rootCmd.PersistentFlags().StringVar(&cfg.LogFile, "log", "", "日志文件路径")
128179
rootCmd.PersistentFlags().BoolVar(&cfg.SystemProxy, "sys-proxy", true, "自动设置/恢复系统代理")
129180
rootCmd.PersistentFlags().StringVar(&cfg.RuleFile, "rules", "", "代理规则配置文件路径")
181+
rootCmd.PersistentFlags().StringVar(&cfg.SocksAddr, "socks5", ":1080", "SOCKS5 代理监听地址")
130182
}
131183

132184
func Execute(version string) {

internal/config/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type Config struct {
1616
SSHKeyFile string
1717
SSHTargetDial string
1818
SSHPort string // 添加SSH端口配置
19+
SocksAddr string // SOCKS5 监听地址
1920
JumpHosts []string // 跳板机列表
2021
Timeout time.Duration
2122
Verbose bool
@@ -37,6 +38,7 @@ func NewConfig() *Config {
3738
InteractiveAuth: true,
3839
SystemProxy: true,
3940
RuleFile: "",
41+
SocksAddr: "",
4042
}
4143
}
4244

internal/proxy/http.go

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,9 @@ type HTTPOverSSH struct {
2525
}
2626

2727
// NewHTTPOverSSH 创建HTTP代理
28-
func NewHTTPOverSSH(cfg *config.Config, log *logger.Logger) (*HTTPOverSSH, error) {
28+
func NewHTTPOverSSH(cfg *config.Config, log *logger.Logger, sshClient *SSHClient, r *router.Router) (*HTTPOverSSH, error) {
2929
log.Info("初始化HTTP-over-SSH代理")
3030

31-
sshClient, err := NewSSHClient(cfg, log)
32-
if err != nil {
33-
return nil, err
34-
}
35-
36-
var r *router.Router
37-
if cfg.RuleFile != "" {
38-
r, err = router.NewRouter(cfg.RuleFile)
39-
if err != nil {
40-
log.Warnf("加载规则文件失败: %v。将以全局代理模式运行。", err)
41-
} else {
42-
log.Infof("已加载规则文件: %s", cfg.RuleFile)
43-
}
44-
}
45-
4631
proxy := &HTTPOverSSH{
4732
cfg: cfg,
4833
ssh: sshClient,
@@ -220,12 +205,6 @@ func (p *HTTPOverSSH) Close() error {
220205
defer cancel()
221206
err = p.server.Shutdown(ctx)
222207
}
223-
if p.ssh != nil {
224-
sshErr := p.ssh.Close()
225-
if sshErr != nil && err == nil {
226-
err = sshErr
227-
}
228-
}
229208
return err
230209
}
231210

0 commit comments

Comments
 (0)