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
|
||||
ExternalControllerTLS string
|
||||
ExternalControllerUnix string
|
||||
ExternalControllerPipe string
|
||||
ExternalUI string
|
||||
ExternalDohServer string
|
||||
Secret string
|
||||
|
@ -364,6 +365,7 @@ type RawConfig struct {
|
|||
LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
|
||||
IPv6 bool `yaml:"ipv6" json:"ipv6"`
|
||||
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"`
|
||||
ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"`
|
||||
ExternalUI string `yaml:"external-ui" json:"external-ui"`
|
||||
|
@ -769,6 +771,7 @@ func parseController(cfg *RawConfig) (*Controller, error) {
|
|||
ExternalController: cfg.ExternalController,
|
||||
ExternalUI: cfg.ExternalUI,
|
||||
Secret: cfg.Secret,
|
||||
ExternalControllerPipe: cfg.ExternalControllerPipe,
|
||||
ExternalControllerUnix: cfg.ExternalControllerUnix,
|
||||
ExternalControllerTLS: cfg.ExternalControllerTLS,
|
||||
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/
|
||||
external-controller-unix: mihomo.sock
|
||||
|
||||
# RESTful API Windows namedpipe 监听地址
|
||||
# !!!注意: 从Windows namedpipe访问api接口不会验证secret, 如果开启请自行保证安全问题 !!!
|
||||
external-controller-pipe: \\.\pipe\mihomo
|
||||
|
||||
# tcp-concurrent: true # TCP 并发连接所有 IP, 将使用最快握手的 TCP
|
||||
|
||||
# 配置 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 {
|
||||
return func(cfg *config.Config) {
|
||||
cfg.Controller.Secret = secret
|
||||
|
@ -47,6 +53,7 @@ func applyRoute(cfg *config.Config) {
|
|||
Addr: cfg.Controller.ExternalController,
|
||||
TLSAddr: cfg.Controller.ExternalControllerTLS,
|
||||
UnixAddr: cfg.Controller.ExternalControllerUnix,
|
||||
PipeAddr: cfg.Controller.ExternalControllerPipe,
|
||||
Secret: cfg.Controller.Secret,
|
||||
Certificate: cfg.TLS.Certificate,
|
||||
PrivateKey: cfg.TLS.PrivateKey,
|
||||
|
|
|
@ -35,6 +35,7 @@ var (
|
|||
httpServer *http.Server
|
||||
tlsServer *http.Server
|
||||
unixServer *http.Server
|
||||
pipeServer *http.Server
|
||||
)
|
||||
|
||||
type Traffic struct {
|
||||
|
@ -51,6 +52,7 @@ type Config struct {
|
|||
Addr string
|
||||
TLSAddr string
|
||||
UnixAddr string
|
||||
PipeAddr string
|
||||
Secret string
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
|
@ -62,6 +64,9 @@ func ReCreateServer(cfg *Config) {
|
|||
go start(cfg)
|
||||
go startTLS(cfg)
|
||||
go startUnix(cfg)
|
||||
if inbound.SupportNamedPipe {
|
||||
go startPipe(cfg)
|
||||
}
|
||||
}
|
||||
|
||||
func SetUIPath(path string) {
|
||||
|
@ -233,7 +238,37 @@ func startUnix(cfg *Config) {
|
|||
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 {
|
||||
|
|
17
main.go
17
main.go
|
@ -35,6 +35,7 @@ var (
|
|||
externalUI string
|
||||
externalController string
|
||||
externalControllerUnix string
|
||||
externalControllerPipe 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(&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(&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.BoolVar(&geodataMode, "m", false, "set geodata mode")
|
||||
flag.BoolVar(&version, "v", false, "show current version of mihomo")
|
||||
|
@ -133,6 +135,9 @@ func main() {
|
|||
if externalControllerUnix != "" {
|
||||
options = append(options, hub.WithExternalControllerUnix(externalControllerUnix))
|
||||
}
|
||||
if externalControllerPipe != "" {
|
||||
options = append(options, hub.WithExternalControllerPipe(externalControllerPipe))
|
||||
}
|
||||
if secret != "" {
|
||||
options = append(options, hub.WithSecret(secret))
|
||||
}
|
||||
|
@ -156,19 +161,9 @@ func main() {
|
|||
case <-termSign:
|
||||
return
|
||||
case <-hupSign:
|
||||
var cfg *config.Config
|
||||
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 {
|
||||
if err := hub.Parse(configBytes, options...); err != nil {
|
||||
log.Errorln("Parse config error: %s", err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user