Skip to content

Commit

Permalink
feat: support external-controller-unix
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed Apr 17, 2024
1 parent d84f88b commit ca84ab1
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 21 deletions.
19 changes: 11 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,11 @@ type Inbound struct {

// Controller config
type Controller struct {
ExternalController string `json:"-"`
ExternalControllerTLS string `json:"-"`
ExternalUI string `json:"-"`
Secret string `json:"-"`
ExternalController string `json:"-"`
ExternalControllerTLS string `json:"-"`
ExternalControllerUnix string `json:"-"`
ExternalUI string `json:"-"`
Secret string `json:"-"`
}

// NTP config
Expand Down Expand Up @@ -304,6 +305,7 @@ type RawConfig struct {
LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
IPv6 bool `yaml:"ipv6" json:"ipv6"`
ExternalController string `yaml:"external-controller"`
ExternalControllerUnix string `yaml:"external-controller-unix"`
ExternalControllerTLS string `yaml:"external-controller-tls"`
ExternalUI string `yaml:"external-ui"`
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
Expand Down Expand Up @@ -678,10 +680,11 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
InboundMPTCP: cfg.InboundMPTCP,
},
Controller: Controller{
ExternalController: cfg.ExternalController,
ExternalUI: cfg.ExternalUI,
Secret: cfg.Secret,
ExternalControllerTLS: cfg.ExternalControllerTLS,
ExternalController: cfg.ExternalController,
ExternalUI: cfg.ExternalUI,
Secret: cfg.Secret,
ExternalControllerUnix: cfg.ExternalControllerUnix,
ExternalControllerTLS: cfg.ExternalControllerTLS,
},
UnifiedDelay: cfg.UnifiedDelay,
Mode: cfg.Mode,
Expand Down
5 changes: 5 additions & 0 deletions docs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ external-controller: 0.0.0.0:9093 # RESTful API 监听地址
external-controller-tls: 0.0.0.0:9443 # RESTful API HTTPS 监听地址,需要配置 tls 部分配置文件
# secret: "123456" # `Authorization:Bearer ${secret}`

# RESTful API Unix socket 监听地址( windows版本大于17063也可以使用,即大于等于1803/RS4版本即可使用 )
# !!!注意: 从Unix socket访问api接口不会验证secret, 如果开启请自行保证安全问题 !!!
# 测试方法: curl -v --unix-socket "mihomo.sock" http://localhost/
external-controller-unix: mihomo.sock

# tcp-concurrent: true # TCP 并发连接所有 IP, 将使用最快握手的 TCP

# 配置 WEB UI 目录,使用 http://{{external-controller}}/ui 访问
Expand Down
4 changes: 4 additions & 0 deletions hub/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func Parse(options ...Option) error {
cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.General.LogLevel == log.DEBUG)
}

if cfg.General.ExternalControllerUnix != "" {
go route.StartUnix(cfg.General.ExternalControllerUnix, cfg.General.LogLevel == log.DEBUG)
}

executor.ApplyConfig(cfg, true)
return nil
}
55 changes: 42 additions & 13 deletions hub/route/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"runtime/debug"
"strings"
"syscall"
"time"

"github.com/metacubex/mihomo/adapter/inbound"
Expand Down Expand Up @@ -47,15 +48,7 @@ func SetUIPath(path string) {
uiPath = C.Path.Resolve(path)
}

func Start(addr string, tlsAddr string, secret string,
certificat, privateKey string, isDebug bool) {
if serverAddr != "" {
return
}

serverAddr = addr
serverSecret = secret

func router(isDebug bool, withAuth bool) *chi.Mux {
r := chi.NewRouter()
corsM := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
Expand All @@ -77,7 +70,9 @@ func Start(addr string, tlsAddr string, secret string,
}())
}
r.Group(func(r chi.Router) {
r.Use(authentication)
if withAuth {
r.Use(authentication)
}
r.Get("/", hello)
r.Get("/logs", getLogs)
r.Get("/traffic", traffic)
Expand Down Expand Up @@ -107,10 +102,21 @@ func Start(addr string, tlsAddr string, secret string,
})
})
}
return r
}

func Start(addr string, tlsAddr string, secret string,
certificate, privateKey string, isDebug bool) {
if serverAddr != "" {
return
}

serverAddr = addr
serverSecret = secret

if len(tlsAddr) > 0 {
go func() {
c, err := CN.ParseCert(certificat, privateKey, C.Path)
c, err := CN.ParseCert(certificate, privateKey, C.Path)
if err != nil {
log.Errorln("External controller tls listen error: %s", err)
return
Expand All @@ -125,7 +131,7 @@ func Start(addr string, tlsAddr string, secret string,
serverAddr = l.Addr().String()
log.Infoln("RESTful API tls listening at: %s", serverAddr)
tlsServe := &http.Server{
Handler: r,
Handler: router(isDebug, true),
TLSConfig: &tls.Config{
Certificates: []tls.Certificate{c},
},
Expand All @@ -144,12 +150,35 @@ func Start(addr string, tlsAddr string, secret string,
serverAddr = l.Addr().String()
log.Infoln("RESTful API listening at: %s", serverAddr)

if err = http.Serve(l, r); err != nil {
if err = http.Serve(l, router(isDebug, true)); err != nil {
log.Errorln("External controller serve error: %s", err)
}

}

func StartUnix(addr string, isDebug bool) {
// https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
//
// Note: As mentioned above in the ‘security’ section, when a socket binds a socket to a valid pathname address,
// a socket file is created within the filesystem. On Linux, the application is expected to unlink
// (see the notes section in the man page for AF_UNIX) before any other socket can be bound to the same address.
// The same applies to Windows unix sockets, except that, DeleteFile (or any other file delete API)
// should be used to delete the socket file prior to calling bind with the same path.
_ = syscall.Unlink(addr)

l, err := inbound.Listen("unix", addr)
if err != nil {
log.Errorln("External controller unix listen error: %s", err)
return
}
serverAddr = l.Addr().String()
log.Infoln("RESTful API unix listening at: %s", serverAddr)

if err = http.Serve(l, router(isDebug, false)); err != nil {
log.Errorln("External controller unix serve error: %s", err)
}
}

func setPrivateNetworkAccess(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
Expand Down

0 comments on commit ca84ab1

Please sign in to comment.