clash/hub/route/server.go

304 lines
6.5 KiB
Go
Raw Normal View History

2018-11-21 05:47:46 +00:00
package route
2018-06-18 03:31:49 +00:00
import (
"bytes"
"crypto/tls"
2018-06-18 03:31:49 +00:00
"encoding/json"
"net/http"
"runtime/debug"
2018-10-06 05:15:02 +00:00
"strings"
2018-06-18 03:31:49 +00:00
"time"
2022-11-16 02:43:16 +00:00
"github.com/Dreamacro/clash/adapter/inbound"
CN "github.com/Dreamacro/clash/common/net"
2019-09-13 09:44:30 +00:00
C "github.com/Dreamacro/clash/constant"
2018-11-21 05:47:46 +00:00
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel/statistic"
2021-04-03 06:59:03 +00:00
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
2018-07-19 01:31:53 +00:00
"github.com/go-chi/cors"
2018-06-18 03:31:49 +00:00
"github.com/go-chi/render"
"github.com/gorilla/websocket"
2018-06-18 03:31:49 +00:00
)
2018-11-21 05:47:46 +00:00
var (
serverSecret = ""
serverAddr = ""
2018-12-19 17:29:13 +00:00
uiPath = ""
2019-09-30 06:13:29 +00:00
upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
2018-11-21 05:47:46 +00:00
)
2018-10-06 05:15:02 +00:00
2018-06-18 03:31:49 +00:00
type Traffic struct {
Up int64 `json:"up"`
Down int64 `json:"down"`
}
2018-12-19 17:29:13 +00:00
func SetUIPath(path string) {
uiPath = C.Path.Resolve(path)
2018-12-19 17:29:13 +00:00
}
2022-12-03 06:14:15 +00:00
func Start(addr string, tlsAddr string, secret string,
certificat, privateKey string, isDebug bool) {
2018-11-21 05:47:46 +00:00
if serverAddr != "" {
return
}
2018-11-21 05:47:46 +00:00
serverAddr = addr
serverSecret = secret
2018-06-18 03:31:49 +00:00
r := chi.NewRouter()
2022-04-23 18:07:57 +00:00
corsM := cors.New(cors.Options{
2018-07-19 01:31:53 +00:00
AllowedOrigins: []string{"*"},
2018-12-29 06:11:54 +00:00
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"},
2018-10-06 05:15:02 +00:00
AllowedHeaders: []string{"Content-Type", "Authorization"},
2018-07-19 01:31:53 +00:00
MaxAge: 300,
})
2022-04-23 18:07:57 +00:00
r.Use(corsM.Handler)
if isDebug {
r.Mount("/debug", func() http.Handler {
r := chi.NewRouter()
r.Put("/gc", func(w http.ResponseWriter, r *http.Request) {
debug.FreeOSMemory()
})
handler := middleware.Profiler
r.Mount("/", handler())
return r
}())
}
r.Group(func(r chi.Router) {
r.Use(authentication)
2020-02-21 10:00:19 +00:00
r.Get("/", hello)
r.Get("/logs", getLogs)
r.Get("/traffic", traffic)
2019-09-13 09:44:30 +00:00
r.Get("/version", version)
r.Mount("/configs", configRouter())
r.Mount("/proxies", proxyRouter())
2022-05-30 13:55:09 +00:00
r.Mount("/group", GroupRouter())
r.Mount("/rules", ruleRouter())
r.Mount("/connections", connectionRouter())
r.Mount("/providers/proxies", proxyProviderRouter())
2021-12-02 14:56:17 +00:00
r.Mount("/providers/rules", ruleProviderRouter())
2022-03-22 17:05:43 +00:00
r.Mount("/cache", cacheRouter())
2023-01-16 07:20:39 +00:00
r.Mount("/dns", dnsRouter())
2023-03-14 14:18:55 +00:00
r.Mount("/restart", restartRouter())
r.Mount("/upgrade", upgradeRouter())
})
2018-06-18 03:31:49 +00:00
2018-12-19 17:29:13 +00:00
if uiPath != "" {
r.Group(func(r chi.Router) {
fs := http.StripPrefix("/ui", http.FileServer(http.Dir(uiPath)))
2019-09-08 14:33:52 +00:00
r.Get("/ui", http.RedirectHandler("/ui/", http.StatusTemporaryRedirect).ServeHTTP)
r.Get("/ui/*", func(w http.ResponseWriter, r *http.Request) {
fs.ServeHTTP(w, r)
})
2018-12-19 17:29:13 +00:00
})
}
2022-12-03 06:14:15 +00:00
if len(tlsAddr) > 0 {
go func() {
2022-12-03 06:14:15 +00:00
c, err := CN.ParseCert(certificat, privateKey)
if err != nil {
log.Errorln("External controller tls listen error: %s", err)
return
}
l, err := inbound.Listen("tcp", tlsAddr)
if err != nil {
log.Errorln("External controller tls listen error: %s", err)
return
}
serverAddr = l.Addr().String()
log.Infoln("RESTful API tls listening at: %s", serverAddr)
tlsServe := &http.Server{
Handler: r,
TLSConfig: &tls.Config{
Certificates: []tls.Certificate{c},
},
}
if err = tlsServe.ServeTLS(l, "", ""); err != nil {
log.Errorln("External controller tls serve error: %s", err)
}
}()
}
2018-12-19 17:29:13 +00:00
2022-11-16 02:43:16 +00:00
l, err := inbound.Listen("tcp", addr)
2018-06-18 03:31:49 +00:00
if err != nil {
log.Errorln("External controller listen error: %s", err)
return
}
serverAddr = l.Addr().String()
log.Infoln("RESTful API listening at: %s", serverAddr)
if err = http.Serve(l, r); err != nil {
log.Errorln("External controller serve error: %s", err)
2018-06-18 03:31:49 +00:00
}
2018-06-18 03:31:49 +00:00
}
2018-10-06 05:15:02 +00:00
func authentication(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
2018-11-21 05:47:46 +00:00
if serverSecret == "" {
2018-10-06 05:15:02 +00:00
next.ServeHTTP(w, r)
return
}
2019-09-30 06:13:29 +00:00
// Browser websocket not support custom header
if websocket.IsWebSocketUpgrade(r) && r.URL.Query().Get("token") != "" {
token := r.URL.Query().Get("token")
if token != serverSecret {
render.Status(r, http.StatusUnauthorized)
render.JSON(w, r, ErrUnauthorized)
return
}
next.ServeHTTP(w, r)
return
}
header := r.Header.Get("Authorization")
2022-03-16 04:10:13 +00:00
bearer, token, found := strings.Cut(header, " ")
2019-09-30 06:13:29 +00:00
2022-03-16 04:10:13 +00:00
hasInvalidHeader := bearer != "Bearer"
hasInvalidSecret := !found || token != serverSecret
2020-04-24 15:49:35 +00:00
if hasInvalidHeader || hasInvalidSecret {
2018-12-10 03:33:37 +00:00
render.Status(r, http.StatusUnauthorized)
render.JSON(w, r, ErrUnauthorized)
2018-10-06 05:15:02 +00:00
return
}
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
2018-12-29 06:11:54 +00:00
func hello(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, render.M{"hello": "clash.meta"})
2018-12-29 06:11:54 +00:00
}
2018-06-18 03:31:49 +00:00
func traffic(w http.ResponseWriter, r *http.Request) {
var wsConn *websocket.Conn
if websocket.IsWebSocketUpgrade(r) {
var err error
wsConn, err = upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
}
if wsConn == nil {
w.Header().Set("Content-Type", "application/json")
render.Status(r, http.StatusOK)
}
2018-06-18 03:31:49 +00:00
tick := time.NewTicker(time.Second)
2020-07-12 16:25:54 +00:00
defer tick.Stop()
t := statistic.DefaultManager
buf := &bytes.Buffer{}
var err error
2018-06-18 03:31:49 +00:00
for range tick.C {
buf.Reset()
2018-06-18 03:31:49 +00:00
up, down := t.Now()
if err := json.NewEncoder(buf).Encode(Traffic{
2018-06-18 03:31:49 +00:00
Up: up,
Down: down,
}); err != nil {
break
}
if wsConn == nil {
_, err = w.Write(buf.Bytes())
w.(http.Flusher).Flush()
} else {
err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes())
}
if err != nil {
break
}
2018-06-18 03:31:49 +00:00
}
}
2018-06-22 05:15:20 +00:00
type Log struct {
Type string `json:"type"`
Payload string `json:"payload"`
}
2018-06-18 03:31:49 +00:00
func getLogs(w http.ResponseWriter, r *http.Request) {
2018-08-12 11:35:13 +00:00
levelText := r.URL.Query().Get("level")
if levelText == "" {
levelText = "info"
2018-06-22 05:15:20 +00:00
}
2018-11-21 05:47:46 +00:00
level, ok := log.LogLevelMapping[levelText]
2018-06-22 05:15:20 +00:00
if !ok {
2018-12-10 03:33:37 +00:00
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, ErrBadRequest)
2018-06-22 05:15:20 +00:00
return
}
var wsConn *websocket.Conn
if websocket.IsWebSocketUpgrade(r) {
var err error
wsConn, err = upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
}
if wsConn == nil {
w.Header().Set("Content-Type", "application/json")
render.Status(r, http.StatusOK)
}
2022-04-25 15:22:58 +00:00
ch := make(chan log.Event, 1024)
2018-11-21 05:47:46 +00:00
sub := log.Subscribe()
defer log.UnSubscribe(sub)
buf := &bytes.Buffer{}
2022-04-25 15:22:58 +00:00
go func() {
for logM := range sub {
2022-04-25 15:22:58 +00:00
select {
case ch <- logM:
2022-04-25 15:22:58 +00:00
default:
}
}
close(ch)
}()
for logM := range ch {
2022-04-23 18:07:57 +00:00
if logM.LogLevel < level {
2018-06-22 05:15:20 +00:00
continue
}
2022-04-25 15:22:58 +00:00
buf.Reset()
2018-06-22 05:15:20 +00:00
if err := json.NewEncoder(buf).Encode(Log{
2022-04-23 18:07:57 +00:00
Type: logM.Type(),
Payload: logM.Payload,
2018-06-18 03:31:49 +00:00
}); err != nil {
break
}
2022-04-25 15:22:58 +00:00
var err error
if wsConn == nil {
_, err = w.Write(buf.Bytes())
w.(http.Flusher).Flush()
} else {
err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes())
}
if err != nil {
break
}
2018-06-18 03:31:49 +00:00
}
}
2019-09-13 09:44:30 +00:00
func version(w http.ResponseWriter, r *http.Request) {
2021-12-03 13:54:45 +00:00
render.JSON(w, r, render.M{"meta": C.Meta, "version": C.Version})
2019-09-13 09:44:30 +00:00
}