dashboard_api.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // Copyright 2017 fatedier, fatedier@gmail.com
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package server
  15. import (
  16. "encoding/json"
  17. "net/http"
  18. "github.com/gorilla/mux"
  19. "github.com/fatedier/frp/pkg/config/types"
  20. v1 "github.com/fatedier/frp/pkg/config/v1"
  21. "github.com/fatedier/frp/pkg/consts"
  22. "github.com/fatedier/frp/pkg/metrics/mem"
  23. "github.com/fatedier/frp/pkg/util/log"
  24. "github.com/fatedier/frp/pkg/util/version"
  25. )
  26. type GeneralResponse struct {
  27. Code int
  28. Msg string
  29. }
  30. type serverInfoResp struct {
  31. Version string `json:"version"`
  32. BindPort int `json:"bind_port"`
  33. VhostHTTPPort int `json:"vhost_http_port"`
  34. VhostHTTPSPort int `json:"vhost_https_port"`
  35. TCPMuxHTTPConnectPort int `json:"tcpmux_httpconnect_port"`
  36. KCPBindPort int `json:"kcp_bind_port"`
  37. QUICBindPort int `json:"quic_bind_port"`
  38. SubdomainHost string `json:"subdomain_host"`
  39. MaxPoolCount int64 `json:"max_pool_count"`
  40. MaxPortsPerClient int64 `json:"max_ports_per_client"`
  41. HeartBeatTimeout int64 `json:"heart_beat_timeout"`
  42. AllowPortsStr string `json:"allow_ports_str,omitempty"`
  43. TLSOnly bool `json:"tls_only,omitempty"`
  44. TotalTrafficIn int64 `json:"total_traffic_in"`
  45. TotalTrafficOut int64 `json:"total_traffic_out"`
  46. CurConns int64 `json:"cur_conns"`
  47. ClientCounts int64 `json:"client_counts"`
  48. ProxyTypeCounts map[string]int64 `json:"proxy_type_count"`
  49. }
  50. // /healthz
  51. func (svr *Service) Healthz(w http.ResponseWriter, _ *http.Request) {
  52. w.WriteHeader(200)
  53. }
  54. // /api/serverinfo
  55. func (svr *Service) APIServerInfo(w http.ResponseWriter, r *http.Request) {
  56. res := GeneralResponse{Code: 200}
  57. defer func() {
  58. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  59. w.WriteHeader(res.Code)
  60. if len(res.Msg) > 0 {
  61. _, _ = w.Write([]byte(res.Msg))
  62. }
  63. }()
  64. log.Info("Http request: [%s]", r.URL.Path)
  65. serverStats := mem.StatsCollector.GetServer()
  66. svrResp := serverInfoResp{
  67. Version: version.Full(),
  68. BindPort: svr.cfg.BindPort,
  69. VhostHTTPPort: svr.cfg.VhostHTTPPort,
  70. VhostHTTPSPort: svr.cfg.VhostHTTPSPort,
  71. TCPMuxHTTPConnectPort: svr.cfg.TCPMuxHTTPConnectPort,
  72. KCPBindPort: svr.cfg.KCPBindPort,
  73. QUICBindPort: svr.cfg.QUICBindPort,
  74. SubdomainHost: svr.cfg.SubDomainHost,
  75. MaxPoolCount: svr.cfg.Transport.MaxPoolCount,
  76. MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
  77. HeartBeatTimeout: svr.cfg.Transport.HeartbeatTimeout,
  78. AllowPortsStr: types.PortsRangeSlice(svr.cfg.AllowPorts).String(),
  79. TLSOnly: svr.cfg.Transport.TLS.Force,
  80. TotalTrafficIn: serverStats.TotalTrafficIn,
  81. TotalTrafficOut: serverStats.TotalTrafficOut,
  82. CurConns: serverStats.CurConns,
  83. ClientCounts: serverStats.ClientCounts,
  84. ProxyTypeCounts: serverStats.ProxyTypeCounts,
  85. }
  86. buf, _ := json.Marshal(&svrResp)
  87. res.Msg = string(buf)
  88. }
  89. type BaseOutConf struct {
  90. v1.ProxyBaseConfig
  91. }
  92. type TCPOutConf struct {
  93. BaseOutConf
  94. RemotePort int `json:"remote_port"`
  95. }
  96. type TCPMuxOutConf struct {
  97. BaseOutConf
  98. v1.DomainConfig
  99. Multiplexer string `json:"multiplexer"`
  100. }
  101. type UDPOutConf struct {
  102. BaseOutConf
  103. RemotePort int `json:"remote_port"`
  104. }
  105. type HTTPOutConf struct {
  106. BaseOutConf
  107. v1.DomainConfig
  108. Locations []string `json:"locations"`
  109. HostHeaderRewrite string `json:"host_header_rewrite"`
  110. }
  111. type HTTPSOutConf struct {
  112. BaseOutConf
  113. v1.DomainConfig
  114. }
  115. type STCPOutConf struct {
  116. BaseOutConf
  117. }
  118. type XTCPOutConf struct {
  119. BaseOutConf
  120. }
  121. func getConfByType(proxyType string) interface{} {
  122. switch proxyType {
  123. case consts.TCPProxy:
  124. return &TCPOutConf{}
  125. case consts.TCPMuxProxy:
  126. return &TCPMuxOutConf{}
  127. case consts.UDPProxy:
  128. return &UDPOutConf{}
  129. case consts.HTTPProxy:
  130. return &HTTPOutConf{}
  131. case consts.HTTPSProxy:
  132. return &HTTPSOutConf{}
  133. case consts.STCPProxy:
  134. return &STCPOutConf{}
  135. case consts.XTCPProxy:
  136. return &XTCPOutConf{}
  137. default:
  138. return nil
  139. }
  140. }
  141. // Get proxy info.
  142. type ProxyStatsInfo struct {
  143. Name string `json:"name"`
  144. Conf interface{} `json:"conf"`
  145. ClientVersion string `json:"client_version,omitempty"`
  146. TodayTrafficIn int64 `json:"today_traffic_in"`
  147. TodayTrafficOut int64 `json:"today_traffic_out"`
  148. CurConns int64 `json:"cur_conns"`
  149. LastStartTime string `json:"last_start_time"`
  150. LastCloseTime string `json:"last_close_time"`
  151. Status string `json:"status"`
  152. }
  153. type GetProxyInfoResp struct {
  154. Proxies []*ProxyStatsInfo `json:"proxies"`
  155. }
  156. // /api/proxy/:type
  157. func (svr *Service) APIProxyByType(w http.ResponseWriter, r *http.Request) {
  158. res := GeneralResponse{Code: 200}
  159. params := mux.Vars(r)
  160. proxyType := params["type"]
  161. defer func() {
  162. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  163. w.WriteHeader(res.Code)
  164. if len(res.Msg) > 0 {
  165. _, _ = w.Write([]byte(res.Msg))
  166. }
  167. }()
  168. log.Info("Http request: [%s]", r.URL.Path)
  169. proxyInfoResp := GetProxyInfoResp{}
  170. proxyInfoResp.Proxies = svr.getProxyStatsByType(proxyType)
  171. buf, _ := json.Marshal(&proxyInfoResp)
  172. res.Msg = string(buf)
  173. }
  174. func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxyStatsInfo) {
  175. proxyStats := mem.StatsCollector.GetProxiesByType(proxyType)
  176. proxyInfos = make([]*ProxyStatsInfo, 0, len(proxyStats))
  177. for _, ps := range proxyStats {
  178. proxyInfo := &ProxyStatsInfo{}
  179. if pxy, ok := svr.pxyManager.GetByName(ps.Name); ok {
  180. content, err := json.Marshal(pxy.GetConfigurer())
  181. if err != nil {
  182. log.Warn("marshal proxy [%s] conf info error: %v", ps.Name, err)
  183. continue
  184. }
  185. proxyInfo.Conf = getConfByType(ps.Type)
  186. if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil {
  187. log.Warn("unmarshal proxy [%s] conf info error: %v", ps.Name, err)
  188. continue
  189. }
  190. proxyInfo.Status = consts.Online
  191. if pxy.GetLoginMsg() != nil {
  192. proxyInfo.ClientVersion = pxy.GetLoginMsg().Version
  193. }
  194. } else {
  195. proxyInfo.Status = consts.Offline
  196. }
  197. proxyInfo.Name = ps.Name
  198. proxyInfo.TodayTrafficIn = ps.TodayTrafficIn
  199. proxyInfo.TodayTrafficOut = ps.TodayTrafficOut
  200. proxyInfo.CurConns = ps.CurConns
  201. proxyInfo.LastStartTime = ps.LastStartTime
  202. proxyInfo.LastCloseTime = ps.LastCloseTime
  203. proxyInfos = append(proxyInfos, proxyInfo)
  204. }
  205. return
  206. }
  207. // Get proxy info by name.
  208. type GetProxyStatsResp struct {
  209. Name string `json:"name"`
  210. Conf interface{} `json:"conf"`
  211. TodayTrafficIn int64 `json:"today_traffic_in"`
  212. TodayTrafficOut int64 `json:"today_traffic_out"`
  213. CurConns int64 `json:"cur_conns"`
  214. LastStartTime string `json:"last_start_time"`
  215. LastCloseTime string `json:"last_close_time"`
  216. Status string `json:"status"`
  217. }
  218. // /api/proxy/:type/:name
  219. func (svr *Service) APIProxyByTypeAndName(w http.ResponseWriter, r *http.Request) {
  220. res := GeneralResponse{Code: 200}
  221. params := mux.Vars(r)
  222. proxyType := params["type"]
  223. name := params["name"]
  224. defer func() {
  225. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  226. w.WriteHeader(res.Code)
  227. if len(res.Msg) > 0 {
  228. _, _ = w.Write([]byte(res.Msg))
  229. }
  230. }()
  231. log.Info("Http request: [%s]", r.URL.Path)
  232. var proxyStatsResp GetProxyStatsResp
  233. proxyStatsResp, res.Code, res.Msg = svr.getProxyStatsByTypeAndName(proxyType, name)
  234. if res.Code != 200 {
  235. return
  236. }
  237. buf, _ := json.Marshal(&proxyStatsResp)
  238. res.Msg = string(buf)
  239. }
  240. func (svr *Service) getProxyStatsByTypeAndName(proxyType string, proxyName string) (proxyInfo GetProxyStatsResp, code int, msg string) {
  241. proxyInfo.Name = proxyName
  242. ps := mem.StatsCollector.GetProxiesByTypeAndName(proxyType, proxyName)
  243. if ps == nil {
  244. code = 404
  245. msg = "no proxy info found"
  246. } else {
  247. if pxy, ok := svr.pxyManager.GetByName(proxyName); ok {
  248. content, err := json.Marshal(pxy.GetConfigurer())
  249. if err != nil {
  250. log.Warn("marshal proxy [%s] conf info error: %v", ps.Name, err)
  251. code = 400
  252. msg = "parse conf error"
  253. return
  254. }
  255. proxyInfo.Conf = getConfByType(ps.Type)
  256. if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil {
  257. log.Warn("unmarshal proxy [%s] conf info error: %v", ps.Name, err)
  258. code = 400
  259. msg = "parse conf error"
  260. return
  261. }
  262. proxyInfo.Status = consts.Online
  263. } else {
  264. proxyInfo.Status = consts.Offline
  265. }
  266. proxyInfo.TodayTrafficIn = ps.TodayTrafficIn
  267. proxyInfo.TodayTrafficOut = ps.TodayTrafficOut
  268. proxyInfo.CurConns = ps.CurConns
  269. proxyInfo.LastStartTime = ps.LastStartTime
  270. proxyInfo.LastCloseTime = ps.LastCloseTime
  271. code = 200
  272. }
  273. return
  274. }
  275. // /api/traffic/:name
  276. type GetProxyTrafficResp struct {
  277. Name string `json:"name"`
  278. TrafficIn []int64 `json:"traffic_in"`
  279. TrafficOut []int64 `json:"traffic_out"`
  280. }
  281. func (svr *Service) APIProxyTraffic(w http.ResponseWriter, r *http.Request) {
  282. res := GeneralResponse{Code: 200}
  283. params := mux.Vars(r)
  284. name := params["name"]
  285. defer func() {
  286. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  287. w.WriteHeader(res.Code)
  288. if len(res.Msg) > 0 {
  289. _, _ = w.Write([]byte(res.Msg))
  290. }
  291. }()
  292. log.Info("Http request: [%s]", r.URL.Path)
  293. trafficResp := GetProxyTrafficResp{}
  294. trafficResp.Name = name
  295. proxyTrafficInfo := mem.StatsCollector.GetProxyTraffic(name)
  296. if proxyTrafficInfo == nil {
  297. res.Code = 404
  298. res.Msg = "no proxy info found"
  299. return
  300. }
  301. trafficResp.TrafficIn = proxyTrafficInfo.TrafficIn
  302. trafficResp.TrafficOut = proxyTrafficInfo.TrafficOut
  303. buf, _ := json.Marshal(&trafficResp)
  304. res.Msg = string(buf)
  305. }