mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-11-16 11:42:43 +08:00
feat: support external-doh-server
Some checks are pending
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
Some checks are pending
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
This commit is contained in:
parent
4eb13a73bf
commit
de61e81ff7
|
@ -96,6 +96,7 @@ type Controller struct {
|
|||
ExternalControllerTLS string `json:"-"`
|
||||
ExternalControllerUnix string `json:"-"`
|
||||
ExternalUI string `json:"-"`
|
||||
ExternalDohServer string `json:"-"`
|
||||
Secret string `json:"-"`
|
||||
}
|
||||
|
||||
|
@ -322,6 +323,7 @@ type RawConfig struct {
|
|||
ExternalUI string `yaml:"external-ui"`
|
||||
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
|
||||
ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"`
|
||||
ExternalDohServer string `yaml:"external-doh-server"`
|
||||
Secret string `yaml:"secret"`
|
||||
Interface string `yaml:"interface-name"`
|
||||
RoutingMark int `yaml:"routing-mark"`
|
||||
|
@ -697,6 +699,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
|
|||
Secret: cfg.Secret,
|
||||
ExternalControllerUnix: cfg.ExternalControllerUnix,
|
||||
ExternalControllerTLS: cfg.ExternalControllerTLS,
|
||||
ExternalDohServer: cfg.ExternalDohServer,
|
||||
},
|
||||
UnifiedDelay: cfg.UnifiedDelay,
|
||||
Mode: cfg.Mode,
|
||||
|
|
|
@ -70,6 +70,10 @@ external-ui: /path/to/ui/folder/
|
|||
external-ui-name: xd
|
||||
external-ui-url: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip"
|
||||
|
||||
# 在RESTful API端口上开启DOH服务器
|
||||
# !!!该URL不会验证secret, 如果开启请自行保证安全问题 !!!
|
||||
external-doh-server: /dns-query
|
||||
|
||||
# interface-name: en0 # 设置出口网卡
|
||||
|
||||
# 全局 TLS 指纹,优先低于 proxy 内的 client-fingerprint
|
||||
|
|
|
@ -50,11 +50,12 @@ func Parse(options ...Option) error {
|
|||
|
||||
if cfg.General.ExternalController != "" {
|
||||
go route.Start(cfg.General.ExternalController, cfg.General.ExternalControllerTLS,
|
||||
cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.General.LogLevel == log.DEBUG)
|
||||
cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.General.ExternalDohServer,
|
||||
cfg.General.LogLevel == log.DEBUG)
|
||||
}
|
||||
|
||||
if cfg.General.ExternalControllerUnix != "" {
|
||||
go route.StartUnix(cfg.General.ExternalControllerUnix, cfg.General.LogLevel == log.DEBUG)
|
||||
go route.StartUnix(cfg.General.ExternalControllerUnix, cfg.General.ExternalDohServer, cfg.General.LogLevel == log.DEBUG)
|
||||
}
|
||||
|
||||
executor.ApplyConfig(cfg, true)
|
||||
|
|
67
hub/route/doh.go
Normal file
67
hub/route/doh.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package route
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
func dohRouter() http.Handler {
|
||||
return http.HandlerFunc(dohHandler)
|
||||
}
|
||||
|
||||
func dohHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if resolver.DefaultResolver == nil {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.JSON(w, r, newError("DNS section is disabled"))
|
||||
return
|
||||
}
|
||||
|
||||
if r.Header.Get("Accept") != "application/dns-message" {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.JSON(w, r, newError("invalid accept header"))
|
||||
return
|
||||
}
|
||||
|
||||
var dnsData []byte
|
||||
var err error
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
dnsData, err = base64.RawURLEncoding.DecodeString(r.URL.Query().Get("dns"))
|
||||
case "POST":
|
||||
if r.Header.Get("Content-Type") != "application/dns-message" {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.JSON(w, r, newError("invalid content-type"))
|
||||
return
|
||||
}
|
||||
dnsData, err = io.ReadAll(r.Body)
|
||||
_ = r.Body.Close()
|
||||
default:
|
||||
render.Status(r, http.StatusMethodNotAllowed)
|
||||
render.JSON(w, r, newError("method not allowed"))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.JSON(w, r, newError(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout)
|
||||
defer cancel()
|
||||
|
||||
dnsData, err = resolver.RelayDnsPacket(ctx, dnsData, dnsData)
|
||||
if err != nil {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.JSON(w, r, newError(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
render.Data(w, r, dnsData)
|
||||
}
|
|
@ -50,7 +50,7 @@ func SetUIPath(path string) {
|
|||
uiPath = C.Path.Resolve(path)
|
||||
}
|
||||
|
||||
func router(isDebug bool, withAuth bool) *chi.Mux {
|
||||
func router(isDebug bool, withAuth bool, dohServer string) *chi.Mux {
|
||||
r := chi.NewRouter()
|
||||
corsM := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"*"},
|
||||
|
@ -104,11 +104,15 @@ func router(isDebug bool, withAuth bool) *chi.Mux {
|
|||
})
|
||||
})
|
||||
}
|
||||
if len(dohServer) > 0 && dohServer[0] == '/' {
|
||||
r.Mount(dohServer, dohRouter())
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func Start(addr string, tlsAddr string, secret string,
|
||||
certificate, privateKey string, isDebug bool) {
|
||||
certificate, privateKey string, dohServer string, isDebug bool) {
|
||||
if serverAddr != "" {
|
||||
return
|
||||
}
|
||||
|
@ -133,7 +137,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: router(isDebug, true),
|
||||
Handler: router(isDebug, true, dohServer),
|
||||
TLSConfig: &tls.Config{
|
||||
Certificates: []tls.Certificate{c},
|
||||
},
|
||||
|
@ -152,13 +156,13 @@ 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, router(isDebug, true)); err != nil {
|
||||
if err = http.Serve(l, router(isDebug, true, dohServer)); err != nil {
|
||||
log.Errorln("External controller serve error: %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func StartUnix(addr string, isDebug bool) {
|
||||
func StartUnix(addr string, dohServer string, isDebug bool) {
|
||||
addr = C.Path.Resolve(addr)
|
||||
|
||||
dir := filepath.Dir(addr)
|
||||
|
@ -186,7 +190,7 @@ func StartUnix(addr string, isDebug bool) {
|
|||
serverAddr = l.Addr().String()
|
||||
log.Infoln("RESTful API unix listening at: %s", serverAddr)
|
||||
|
||||
if err = http.Serve(l, router(isDebug, false)); err != nil {
|
||||
if err = http.Serve(l, router(isDebug, false, dohServer)); err != nil {
|
||||
log.Errorln("External controller unix serve error: %s", err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user