update
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 29s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 49s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 34s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 59s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 34s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 55s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 37s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m7s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 50s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 33s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 59s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 52s

This commit is contained in:
Flik
2025-12-29 14:24:46 +08:00
parent c728cc3bb7
commit e10736e05e
23 changed files with 591 additions and 910 deletions

View File

@@ -0,0 +1,95 @@
package builtin
import (
"io"
"log"
"net"
"sync"
"github.com/gotunnel/pkg/plugin"
)
func init() {
RegisterClientPlugin(NewEchoPlugin())
}
// EchoPlugin 回显插件 - 客户端插件示例
type EchoPlugin struct {
config map[string]string
listener net.Listener
running bool
mu sync.Mutex
}
// NewEchoPlugin 创建 Echo 插件
func NewEchoPlugin() *EchoPlugin {
return &EchoPlugin{}
}
// Metadata 返回插件信息
func (p *EchoPlugin) Metadata() plugin.PluginMetadata {
return plugin.PluginMetadata{
Name: "echo",
Version: "1.0.0",
Type: plugin.PluginTypeApp,
Source: plugin.PluginSourceBuiltin,
RunAt: plugin.SideClient,
Description: "Echo server (client plugin example)",
Author: "GoTunnel",
RuleSchema: &plugin.RuleSchema{
NeedsLocalAddr: false,
},
}
}
// Init 初始化插件
func (p *EchoPlugin) Init(config map[string]string) error {
p.config = config
return nil
}
// Start 启动服务
func (p *EchoPlugin) Start() (string, error) {
p.mu.Lock()
defer p.mu.Unlock()
if p.running {
return "", nil
}
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return "", err
}
p.listener = ln
p.running = true
log.Printf("[Echo] Started on %s", ln.Addr().String())
return ln.Addr().String(), nil
}
// HandleConn 处理连接
func (p *EchoPlugin) HandleConn(conn net.Conn) error {
defer conn.Close()
log.Printf("[Echo] New connection from tunnel")
_, err := io.Copy(conn, conn)
return err
}
// Stop 停止服务
func (p *EchoPlugin) Stop() error {
p.mu.Lock()
defer p.mu.Unlock()
if !p.running {
return nil
}
if p.listener != nil {
p.listener.Close()
}
p.running = false
log.Printf("[Echo] Stopped")
return nil
}

View File

@@ -1,116 +0,0 @@
package builtin
import (
"bufio"
"io"
"net"
"net/http"
"strings"
"github.com/gotunnel/pkg/plugin"
)
// HTTPPlugin 将现有 HTTP 代理实现封装为 plugin
type HTTPPlugin struct {
config map[string]string
}
// NewHTTPPlugin 创建 HTTP plugin
func NewHTTPPlugin() *HTTPPlugin {
return &HTTPPlugin{}
}
// Metadata 返回 plugin 信息
func (p *HTTPPlugin) Metadata() plugin.PluginMetadata {
return plugin.PluginMetadata{
Name: "http",
Version: "1.0.0",
Type: plugin.PluginTypeProxy,
Source: plugin.PluginSourceBuiltin,
Description: "HTTP/HTTPS proxy protocol handler",
Author: "GoTunnel",
Capabilities: []string{
"dial", "read", "write", "close",
},
}
}
// Init 初始化 plugin
func (p *HTTPPlugin) Init(config map[string]string) error {
p.config = config
return nil
}
// HandleConn 处理 HTTP 代理连接
func (p *HTTPPlugin) HandleConn(conn net.Conn, dialer plugin.Dialer) error {
defer conn.Close()
reader := bufio.NewReader(conn)
req, err := http.ReadRequest(reader)
if err != nil {
return err
}
if req.Method == http.MethodConnect {
return p.handleConnect(conn, req, dialer)
}
return p.handleHTTP(conn, req, dialer)
}
// Close 释放资源
func (p *HTTPPlugin) Close() error {
return nil
}
// handleConnect 处理 CONNECT 方法 (HTTPS)
func (p *HTTPPlugin) handleConnect(conn net.Conn, req *http.Request, dialer plugin.Dialer) error {
target := req.Host
if !strings.Contains(target, ":") {
target = target + ":443"
}
remote, err := dialer.Dial("tcp", target)
if err != nil {
conn.Write([]byte("HTTP/1.1 502 Bad Gateway\r\n\r\n"))
return err
}
defer remote.Close()
conn.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n"))
go io.Copy(remote, conn)
io.Copy(conn, remote)
return nil
}
// handleHTTP 处理普通 HTTP 请求
func (p *HTTPPlugin) handleHTTP(conn net.Conn, req *http.Request, dialer plugin.Dialer) error {
target := req.Host
if !strings.Contains(target, ":") {
target = target + ":80"
}
remote, err := dialer.Dial("tcp", target)
if err != nil {
conn.Write([]byte("HTTP/1.1 502 Bad Gateway\r\n\r\n"))
return err
}
defer remote.Close()
// 修改请求路径为相对路径
req.URL.Scheme = ""
req.URL.Host = ""
req.RequestURI = req.URL.Path
if req.URL.RawQuery != "" {
req.RequestURI += "?" + req.URL.RawQuery
}
// 发送请求到目标
if err := req.Write(remote); err != nil {
return err
}
// 转发响应
_, err = io.Copy(conn, remote)
return err
}

View File

@@ -3,14 +3,27 @@ package builtin
import "github.com/gotunnel/pkg/plugin"
// 全局插件注册表
var registry []plugin.ProxyHandler
var (
serverPlugins []plugin.ProxyHandler
clientPlugins []plugin.ClientHandler
)
// Register 插件自注册函数,由各插件的 init() 调用
// Register 注册服务端插件
func Register(handler plugin.ProxyHandler) {
registry = append(registry, handler)
serverPlugins = append(serverPlugins, handler)
}
// GetAll 返回所有已注册的内置插件
func GetAll() []plugin.ProxyHandler {
return registry
// RegisterClientPlugin 注册客户端插件
func RegisterClientPlugin(handler plugin.ClientHandler) {
clientPlugins = append(clientPlugins, handler)
}
// GetAll 返回所有服务端插件
func GetAll() []plugin.ProxyHandler {
return serverPlugins
}
// GetAllClientPlugins 返回所有客户端插件
func GetAllClientPlugins() []plugin.ClientHandler {
return clientPlugins
}

View File

@@ -45,34 +45,29 @@ func (p *SOCKS5Plugin) Metadata() plugin.PluginMetadata {
Version: "1.0.0",
Type: plugin.PluginTypeProxy,
Source: plugin.PluginSourceBuiltin,
Description: "SOCKS5 proxy protocol handler (official plugin)",
RunAt: plugin.SideServer,
Description: "SOCKS5 proxy protocol handler",
Author: "GoTunnel",
Capabilities: []string{
"dial", "read", "write", "close",
},
RuleSchema: &plugin.RuleSchema{
NeedsLocalAddr: false, // SOCKS5 不需要本地地址
NeedsLocalAddr: false,
},
ConfigSchema: []plugin.ConfigField{
{
Key: "auth",
Label: "认证方式",
Type: plugin.ConfigFieldSelect,
Default: "none",
Options: []string{"none", "password"},
Description: "SOCKS5 认证方式",
Key: "auth",
Label: "认证方式",
Type: plugin.ConfigFieldSelect,
Default: "none",
Options: []string{"none", "password"},
},
{
Key: "username",
Label: "用户名",
Type: plugin.ConfigFieldString,
Description: "认证用户名(仅 password 认证时需要)",
Key: "username",
Label: "用户名",
Type: plugin.ConfigFieldString,
},
{
Key: "password",
Label: "密码",
Type: plugin.ConfigFieldPassword,
Description: "认证密码(仅 password 认证时需要)",
Key: "password",
Label: "密码",
Type: plugin.ConfigFieldPassword,
},
},
}

View File

@@ -29,20 +29,17 @@ func (p *VNCPlugin) Metadata() plugin.PluginMetadata {
Version: "1.0.0",
Type: plugin.PluginTypeApp,
Source: plugin.PluginSourceBuiltin,
Description: "VNC remote desktop relay (connects to client's local VNC server)",
RunAt: plugin.SideServer, // 当前为服务端中继模式
Description: "VNC remote desktop relay",
Author: "GoTunnel",
Capabilities: []string{
"dial", "read", "write", "close",
},
RuleSchema: &plugin.RuleSchema{
NeedsLocalAddr: false,
ExtraFields: []plugin.ConfigField{
{
Key: "vnc_addr",
Label: "VNC 地址",
Type: plugin.ConfigFieldString,
Default: "127.0.0.1:5900",
Description: "客户端本地 VNC 服务地址",
Key: "vnc_addr",
Label: "VNC 地址",
Type: plugin.ConfigFieldString,
Default: "127.0.0.1:5900",
},
},
},