mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-11-16 11:42:43 +08:00
feat: add external-controller-pipe
for windows
maybe useful for electron and tauri client, node.js and rust still not support AF_UNIX on windows
This commit is contained in:
parent
43cb48231a
commit
88bfe7cffe
14
adapter/inbound/listen_notwindows.go
Normal file
14
adapter/inbound/listen_notwindows.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package inbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const SupportNamedPipe = false
|
||||||
|
|
||||||
|
func ListenNamedPipe(path string) (net.Listener, error) {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
27
adapter/inbound/listen_windows.go
Normal file
27
adapter/inbound/listen_windows.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package inbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/metacubex/wireguard-go/ipc/namedpipe"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
const SupportNamedPipe = true
|
||||||
|
|
||||||
|
// windowsSDDL is the Security Descriptor set on the namedpipe.
|
||||||
|
// It provides read/write access to all users and the local system.
|
||||||
|
const windowsSDDL = "D:PAI(A;OICI;GWGR;;;BU)(A;OICI;GWGR;;;SY)"
|
||||||
|
|
||||||
|
func ListenNamedPipe(path string) (net.Listener, error) {
|
||||||
|
securityDescriptor, err := windows.SecurityDescriptorFromString(windowsSDDL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
namedpipeLC := namedpipe.ListenConfig{
|
||||||
|
SecurityDescriptor: securityDescriptor,
|
||||||
|
InputBufferSize: 256 * 1024,
|
||||||
|
OutputBufferSize: 256 * 1024,
|
||||||
|
}
|
||||||
|
return namedpipeLC.Listen(path)
|
||||||
|
}
|
|
@ -103,6 +103,7 @@ type Controller struct {
|
||||||
ExternalController string
|
ExternalController string
|
||||||
ExternalControllerTLS string
|
ExternalControllerTLS string
|
||||||
ExternalControllerUnix string
|
ExternalControllerUnix string
|
||||||
|
ExternalControllerPipe string
|
||||||
ExternalUI string
|
ExternalUI string
|
||||||
ExternalDohServer string
|
ExternalDohServer string
|
||||||
Secret string
|
Secret string
|
||||||
|
@ -364,6 +365,7 @@ type RawConfig struct {
|
||||||
LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
|
LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
|
||||||
IPv6 bool `yaml:"ipv6" json:"ipv6"`
|
IPv6 bool `yaml:"ipv6" json:"ipv6"`
|
||||||
ExternalController string `yaml:"external-controller" json:"external-controller"`
|
ExternalController string `yaml:"external-controller" json:"external-controller"`
|
||||||
|
ExternalControllerPipe string `yaml:"external-controller-pipe" json:"external-controller-pipe"`
|
||||||
ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"`
|
ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"`
|
||||||
ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"`
|
ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"`
|
||||||
ExternalUI string `yaml:"external-ui" json:"external-ui"`
|
ExternalUI string `yaml:"external-ui" json:"external-ui"`
|
||||||
|
@ -769,6 +771,7 @@ func parseController(cfg *RawConfig) (*Controller, error) {
|
||||||
ExternalController: cfg.ExternalController,
|
ExternalController: cfg.ExternalController,
|
||||||
ExternalUI: cfg.ExternalUI,
|
ExternalUI: cfg.ExternalUI,
|
||||||
Secret: cfg.Secret,
|
Secret: cfg.Secret,
|
||||||
|
ExternalControllerPipe: cfg.ExternalControllerPipe,
|
||||||
ExternalControllerUnix: cfg.ExternalControllerUnix,
|
ExternalControllerUnix: cfg.ExternalControllerUnix,
|
||||||
ExternalControllerTLS: cfg.ExternalControllerTLS,
|
ExternalControllerTLS: cfg.ExternalControllerTLS,
|
||||||
ExternalDohServer: cfg.ExternalDohServer,
|
ExternalDohServer: cfg.ExternalDohServer,
|
||||||
|
|
|
@ -63,6 +63,10 @@ external-controller-tls: 0.0.0.0:9443 # RESTful API HTTPS 监听地址,需要
|
||||||
# 测试方法: curl -v --unix-socket "mihomo.sock" http://localhost/
|
# 测试方法: curl -v --unix-socket "mihomo.sock" http://localhost/
|
||||||
external-controller-unix: mihomo.sock
|
external-controller-unix: mihomo.sock
|
||||||
|
|
||||||
|
# RESTful API Windows namedpipe 监听地址
|
||||||
|
# !!!注意: 从Windows namedpipe访问api接口不会验证secret, 如果开启请自行保证安全问题 !!!
|
||||||
|
external-controller-pipe: \\.\pipe\mihomo
|
||||||
|
|
||||||
# tcp-concurrent: true # TCP 并发连接所有 IP, 将使用最快握手的 TCP
|
# tcp-concurrent: true # TCP 并发连接所有 IP, 将使用最快握手的 TCP
|
||||||
|
|
||||||
# 配置 WEB UI 目录,使用 http://{{external-controller}}/ui 访问
|
# 配置 WEB UI 目录,使用 http://{{external-controller}}/ui 访问
|
||||||
|
|
|
@ -27,6 +27,12 @@ func WithExternalControllerUnix(externalControllerUnix string) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithExternalControllerPipe(externalControllerPipe string) Option {
|
||||||
|
return func(cfg *config.Config) {
|
||||||
|
cfg.Controller.ExternalControllerPipe = externalControllerPipe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WithSecret(secret string) Option {
|
func WithSecret(secret string) Option {
|
||||||
return func(cfg *config.Config) {
|
return func(cfg *config.Config) {
|
||||||
cfg.Controller.Secret = secret
|
cfg.Controller.Secret = secret
|
||||||
|
@ -47,6 +53,7 @@ func applyRoute(cfg *config.Config) {
|
||||||
Addr: cfg.Controller.ExternalController,
|
Addr: cfg.Controller.ExternalController,
|
||||||
TLSAddr: cfg.Controller.ExternalControllerTLS,
|
TLSAddr: cfg.Controller.ExternalControllerTLS,
|
||||||
UnixAddr: cfg.Controller.ExternalControllerUnix,
|
UnixAddr: cfg.Controller.ExternalControllerUnix,
|
||||||
|
PipeAddr: cfg.Controller.ExternalControllerPipe,
|
||||||
Secret: cfg.Controller.Secret,
|
Secret: cfg.Controller.Secret,
|
||||||
Certificate: cfg.TLS.Certificate,
|
Certificate: cfg.TLS.Certificate,
|
||||||
PrivateKey: cfg.TLS.PrivateKey,
|
PrivateKey: cfg.TLS.PrivateKey,
|
||||||
|
|
|
@ -35,6 +35,7 @@ var (
|
||||||
httpServer *http.Server
|
httpServer *http.Server
|
||||||
tlsServer *http.Server
|
tlsServer *http.Server
|
||||||
unixServer *http.Server
|
unixServer *http.Server
|
||||||
|
pipeServer *http.Server
|
||||||
)
|
)
|
||||||
|
|
||||||
type Traffic struct {
|
type Traffic struct {
|
||||||
|
@ -51,6 +52,7 @@ type Config struct {
|
||||||
Addr string
|
Addr string
|
||||||
TLSAddr string
|
TLSAddr string
|
||||||
UnixAddr string
|
UnixAddr string
|
||||||
|
PipeAddr string
|
||||||
Secret string
|
Secret string
|
||||||
Certificate string
|
Certificate string
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
|
@ -62,6 +64,9 @@ func ReCreateServer(cfg *Config) {
|
||||||
go start(cfg)
|
go start(cfg)
|
||||||
go startTLS(cfg)
|
go startTLS(cfg)
|
||||||
go startUnix(cfg)
|
go startUnix(cfg)
|
||||||
|
if inbound.SupportNamedPipe {
|
||||||
|
go startPipe(cfg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetUIPath(path string) {
|
func SetUIPath(path string) {
|
||||||
|
@ -233,7 +238,37 @@ func startUnix(cfg *Config) {
|
||||||
log.Errorln("External controller unix serve error: %s", err)
|
log.Errorln("External controller unix serve error: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func startPipe(cfg *Config) {
|
||||||
|
// first stop existing server
|
||||||
|
if pipeServer != nil {
|
||||||
|
_ = pipeServer.Close()
|
||||||
|
pipeServer = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle addr
|
||||||
|
if len(cfg.PipeAddr) > 0 {
|
||||||
|
if !strings.HasPrefix(cfg.PipeAddr, "\\\\.\\pipe\\") { // windows namedpipe must start with "\\.\pipe\"
|
||||||
|
log.Errorln("External controller pipe listen error: windows namedpipe must start with \"\\\\.\\pipe\\\"")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l, err := inbound.ListenNamedPipe(cfg.PipeAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("External controller pipe listen error: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Infoln("RESTful API pipe listening at: %s", l.Addr().String())
|
||||||
|
|
||||||
|
server := &http.Server{
|
||||||
|
Handler: router(cfg.IsDebug, "", cfg.DohServer),
|
||||||
|
}
|
||||||
|
pipeServer = server
|
||||||
|
if err = server.Serve(l); err != nil {
|
||||||
|
log.Errorln("External controller pipe serve error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPrivateNetworkAccess(next http.Handler) http.Handler {
|
func setPrivateNetworkAccess(next http.Handler) http.Handler {
|
||||||
|
|
17
main.go
17
main.go
|
@ -35,6 +35,7 @@ var (
|
||||||
externalUI string
|
externalUI string
|
||||||
externalController string
|
externalController string
|
||||||
externalControllerUnix string
|
externalControllerUnix string
|
||||||
|
externalControllerPipe string
|
||||||
secret string
|
secret string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,6 +46,7 @@ func init() {
|
||||||
flag.StringVar(&externalUI, "ext-ui", os.Getenv("CLASH_OVERRIDE_EXTERNAL_UI_DIR"), "override external ui directory")
|
flag.StringVar(&externalUI, "ext-ui", os.Getenv("CLASH_OVERRIDE_EXTERNAL_UI_DIR"), "override external ui directory")
|
||||||
flag.StringVar(&externalController, "ext-ctl", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER"), "override external controller address")
|
flag.StringVar(&externalController, "ext-ctl", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER"), "override external controller address")
|
||||||
flag.StringVar(&externalControllerUnix, "ext-ctl-unix", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER_UNIX"), "override external controller unix address")
|
flag.StringVar(&externalControllerUnix, "ext-ctl-unix", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER_UNIX"), "override external controller unix address")
|
||||||
|
flag.StringVar(&externalControllerPipe, "ext-ctl-pipe", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER_PIPE"), "override external controller pipe address")
|
||||||
flag.StringVar(&secret, "secret", os.Getenv("CLASH_OVERRIDE_SECRET"), "override secret for RESTful API")
|
flag.StringVar(&secret, "secret", os.Getenv("CLASH_OVERRIDE_SECRET"), "override secret for RESTful API")
|
||||||
flag.BoolVar(&geodataMode, "m", false, "set geodata mode")
|
flag.BoolVar(&geodataMode, "m", false, "set geodata mode")
|
||||||
flag.BoolVar(&version, "v", false, "show current version of mihomo")
|
flag.BoolVar(&version, "v", false, "show current version of mihomo")
|
||||||
|
@ -133,6 +135,9 @@ func main() {
|
||||||
if externalControllerUnix != "" {
|
if externalControllerUnix != "" {
|
||||||
options = append(options, hub.WithExternalControllerUnix(externalControllerUnix))
|
options = append(options, hub.WithExternalControllerUnix(externalControllerUnix))
|
||||||
}
|
}
|
||||||
|
if externalControllerPipe != "" {
|
||||||
|
options = append(options, hub.WithExternalControllerPipe(externalControllerPipe))
|
||||||
|
}
|
||||||
if secret != "" {
|
if secret != "" {
|
||||||
options = append(options, hub.WithSecret(secret))
|
options = append(options, hub.WithSecret(secret))
|
||||||
}
|
}
|
||||||
|
@ -156,19 +161,9 @@ func main() {
|
||||||
case <-termSign:
|
case <-termSign:
|
||||||
return
|
return
|
||||||
case <-hupSign:
|
case <-hupSign:
|
||||||
var cfg *config.Config
|
if err := hub.Parse(configBytes, options...); err != nil {
|
||||||
var err error
|
|
||||||
if configString != "" {
|
|
||||||
cfg, err = executor.ParseWithBytes(configBytes)
|
|
||||||
} else {
|
|
||||||
cfg, err = executor.ParseWithPath(C.Path.Config())
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
hub.ApplyConfig(cfg)
|
|
||||||
} else {
|
|
||||||
log.Errorln("Parse config error: %s", err.Error())
|
log.Errorln("Parse config error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user