dashboard_api.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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"
  20. "github.com/fatedier/frp/pkg/consts"
  21. "github.com/fatedier/frp/pkg/metrics/mem"
  22. "github.com/fatedier/frp/pkg/util/log"
  23. "github.com/fatedier/frp/pkg/util/version"
  24. )
  25. type GeneralResponse struct {
  26. Code int
  27. Msg string
  28. }
  29. type serverInfoResp struct {
  30. Version string `json:"version"`
  31. BindPort int `json:"bind_port"`
  32. BindUDPPort int `json:"bind_udp_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, r *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. BindUDPPort: svr.cfg.BindUDPPort,
  70. VhostHTTPPort: svr.cfg.VhostHTTPPort,
  71. VhostHTTPSPort: svr.cfg.VhostHTTPSPort,
  72. TCPMuxHTTPConnectPort: svr.cfg.TCPMuxHTTPConnectPort,
  73. KCPBindPort: svr.cfg.KCPBindPort,
  74. QUICBindPort: svr.cfg.QUICBindPort,
  75. SubdomainHost: svr.cfg.SubDomainHost,
  76. MaxPoolCount: svr.cfg.MaxPoolCount,
  77. MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
  78. HeartBeatTimeout: svr.cfg.HeartbeatTimeout,
  79. AllowPortsStr: svr.cfg.AllowPortsStr,
  80. TLSOnly: svr.cfg.TLSOnly,
  81. TotalTrafficIn: serverStats.TotalTrafficIn,
  82. TotalTrafficOut: serverStats.TotalTrafficOut,
  83. CurConns: serverStats.CurConns,
  84. ClientCounts: serverStats.ClientCounts,
  85. ProxyTypeCounts: serverStats.ProxyTypeCounts,
  86. }
  87. buf, _ := json.Marshal(&svrResp)
  88. res.Msg = string(buf)
  89. }
  90. type BaseOutConf struct {
  91. config.BaseProxyConf
  92. }
  93. type TCPOutConf struct {
  94. BaseOutConf
  95. RemotePort int `json:"remote_port"`
  96. }
  97. type TCPMuxOutConf struct {
  98. BaseOutConf
  99. config.DomainConf
  100. Multiplexer string `json:"multiplexer"`
  101. }
  102. type UDPOutConf struct {
  103. BaseOutConf
  104. RemotePort int `json:"remote_port"`
  105. }
  106. type HTTPOutConf struct {
  107. BaseOutConf
  108. config.DomainConf
  109. Locations []string `json:"locations"`
  110. HostHeaderRewrite string `json:"host_header_rewrite"`
  111. }
  112. type HTTPSOutConf struct {
  113. BaseOutConf
  114. config.DomainConf
  115. }
  116. type STCPOutConf struct {
  117. BaseOutConf
  118. }
  119. type XTCPOutConf struct {
  120. BaseOutConf
  121. }
  122. func getConfByType(proxyType string) interface{} {
  123. switch proxyType {
  124. case consts.TCPProxy:
  125. return &TCPOutConf{}
  126. case consts.TCPMuxProxy:
  127. return &TCPMuxOutConf{}
  128. case consts.UDPProxy:
  129. return &UDPOutConf{}
  130. case consts.HTTPProxy:
  131. return &HTTPOutConf{}
  132. case consts.HTTPSProxy:
  133. return &HTTPSOutConf{}
  134. case consts.STCPProxy:
  135. return &STCPOutConf{}
  136. case consts.XTCPProxy:
  137. return &XTCPOutConf{}
  138. default:
  139. return nil
  140. }
  141. }
  142. // Get proxy info.
  143. type ProxyStatsInfo struct {
  144. Name string `json:"name"`
  145. Conf interface{} `json:"conf"`
  146. ClientVersion string `json:"client_version,omitempty"`
  147. TodayTrafficIn int64 `json:"today_traffic_in"`
  148. TodayTrafficOut int64 `json:"today_traffic_out"`
  149. CurConns int64 `json:"cur_conns"`
  150. LastStartTime string `json:"last_start_time"`
  151. LastCloseTime string `json:"last_close_time"`
  152. Status string `json:"status"`
  153. }
  154. type GetProxyInfoResp struct {
  155. Proxies []*ProxyStatsInfo `json:"proxies"`
  156. }
  157. // api/proxy/:type
  158. func (svr *Service) APIProxyByType(w http.ResponseWriter, r *http.Request) {
  159. res := GeneralResponse{Code: 200}
  160. params := mux.Vars(r)
  161. proxyType := params["type"]
  162. defer func() {
  163. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  164. w.WriteHeader(res.Code)
  165. if len(res.Msg) > 0 {
  166. _, _ = w.Write([]byte(res.Msg))
  167. }
  168. }()
  169. log.Info("Http request: [%s]", r.URL.Path)
  170. proxyInfoResp := GetProxyInfoResp{}
  171. proxyInfoResp.Proxies = svr.getProxyStatsByType(proxyType)
  172. buf, _ := json.Marshal(&proxyInfoResp)
  173. res.Msg = string(buf)
  174. }
  175. func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxyStatsInfo) {
  176. proxyStats := mem.StatsCollector.GetProxiesByType(proxyType)
  177. proxyInfos = make([]*ProxyStatsInfo, 0, len(proxyStats))
  178. for _, ps := range proxyStats {
  179. proxyInfo := &ProxyStatsInfo{}
  180. if pxy, ok := svr.pxyManager.GetByName(ps.Name); ok {
  181. content, err := json.Marshal(pxy.GetConf())
  182. if err != nil {
  183. log.Warn("marshal proxy [%s] conf info error: %v", ps.Name, err)
  184. continue
  185. }
  186. proxyInfo.Conf = getConfByType(ps.Type)
  187. if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil {
  188. log.Warn("unmarshal proxy [%s] conf info error: %v", ps.Name, err)
  189. continue
  190. }
  191. proxyInfo.Status = consts.Online
  192. if pxy.GetLoginMsg() != nil {
  193. proxyInfo.ClientVersion = pxy.GetLoginMsg().Version
  194. }
  195. } else {
  196. proxyInfo.Status = consts.Offline
  197. }
  198. proxyInfo.Name = ps.Name
  199. proxyInfo.TodayTrafficIn = ps.TodayTrafficIn
  200. proxyInfo.TodayTrafficOut = ps.TodayTrafficOut
  201. proxyInfo.CurConns = ps.CurConns
  202. proxyInfo.LastStartTime = ps.LastStartTime
  203. proxyInfo.LastCloseTime = ps.LastCloseTime
  204. proxyInfos = append(proxyInfos, proxyInfo)
  205. }
  206. return
  207. }
  208. // Get proxy info by name.
  209. type GetProxyStatsResp struct {
  210. Name string `json:"name"`
  211. Conf interface{} `json:"conf"`
  212. TodayTrafficIn int64 `json:"today_traffic_in"`
  213. TodayTrafficOut int64 `json:"today_traffic_out"`
  214. CurConns int64 `json:"cur_conns"`
  215. LastStartTime string `json:"last_start_time"`
  216. LastCloseTime string `json:"last_close_time"`
  217. Status string `json:"status"`
  218. }
  219. // api/proxy/:type/:name
  220. func (svr *Service) APIProxyByTypeAndName(w http.ResponseWriter, r *http.Request) {
  221. res := GeneralResponse{Code: 200}
  222. params := mux.Vars(r)
  223. proxyType := params["type"]
  224. name := params["name"]
  225. defer func() {
  226. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  227. w.WriteHeader(res.Code)
  228. if len(res.Msg) > 0 {
  229. _, _ = w.Write([]byte(res.Msg))
  230. }
  231. }()
  232. log.Info("Http request: [%s]", r.URL.Path)
  233. var proxyStatsResp GetProxyStatsResp
  234. proxyStatsResp, res.Code, res.Msg = svr.getProxyStatsByTypeAndName(proxyType, name)
  235. if res.Code != 200 {
  236. return
  237. }
  238. buf, _ := json.Marshal(&proxyStatsResp)
  239. res.Msg = string(buf)
  240. }
  241. func (svr *Service) getProxyStatsByTypeAndName(proxyType string, proxyName string) (proxyInfo GetProxyStatsResp, code int, msg string) {
  242. proxyInfo.Name = proxyName
  243. ps := mem.StatsCollector.GetProxiesByTypeAndName(proxyType, proxyName)
  244. if ps == nil {
  245. code = 404
  246. msg = "no proxy info found"
  247. } else {
  248. if pxy, ok := svr.pxyManager.GetByName(proxyName); ok {
  249. content, err := json.Marshal(pxy.GetConf())
  250. if err != nil {
  251. log.Warn("marshal proxy [%s] conf info error: %v", ps.Name, err)
  252. code = 400
  253. msg = "parse conf error"
  254. return
  255. }
  256. proxyInfo.Conf = getConfByType(ps.Type)
  257. if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil {
  258. log.Warn("unmarshal proxy [%s] conf info error: %v", ps.Name, err)
  259. code = 400
  260. msg = "parse conf error"
  261. return
  262. }
  263. proxyInfo.Status = consts.Online
  264. } else {
  265. proxyInfo.Status = consts.Offline
  266. }
  267. proxyInfo.TodayTrafficIn = ps.TodayTrafficIn
  268. proxyInfo.TodayTrafficOut = ps.TodayTrafficOut
  269. proxyInfo.CurConns = ps.CurConns
  270. proxyInfo.LastStartTime = ps.LastStartTime
  271. proxyInfo.LastCloseTime = ps.LastCloseTime
  272. code = 200
  273. }
  274. return
  275. }
  276. // api/traffic/:name
  277. type GetProxyTrafficResp struct {
  278. Name string `json:"name"`
  279. TrafficIn []int64 `json:"traffic_in"`
  280. TrafficOut []int64 `json:"traffic_out"`
  281. }
  282. func (svr *Service) APIProxyTraffic(w http.ResponseWriter, r *http.Request) {
  283. res := GeneralResponse{Code: 200}
  284. params := mux.Vars(r)
  285. name := params["name"]
  286. defer func() {
  287. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  288. w.WriteHeader(res.Code)
  289. if len(res.Msg) > 0 {
  290. _, _ = w.Write([]byte(res.Msg))
  291. }
  292. }()
  293. log.Info("Http request: [%s]", r.URL.Path)
  294. trafficResp := GetProxyTrafficResp{}
  295. trafficResp.Name = name
  296. proxyTrafficInfo := mem.StatsCollector.GetProxyTraffic(name)
  297. if proxyTrafficInfo == nil {
  298. res.Code = 404
  299. res.Msg = "no proxy info found"
  300. return
  301. }
  302. trafficResp.TrafficIn = proxyTrafficInfo.TrafficIn
  303. trafficResp.TrafficOut = proxyTrafficInfo.TrafficOut
  304. buf, _ := json.Marshal(&trafficResp)
  305. res.Msg = string(buf)
  306. }