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
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:
95
pkg/plugin/builtin/echo.go
Normal file
95
pkg/plugin/builtin/echo.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user