wrappers.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. package main
  2. /*
  3. Wrappers.go
  4. This script provide wrapping functions
  5. for modules that do not provide
  6. handler interface within the modules
  7. --- NOTES ---
  8. If your module have more than one layer
  9. or require state keeping, please move
  10. the abstraction up one layer into
  11. your own module. Do not keep state on
  12. the global scope other than single
  13. Manager instance
  14. */
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "net/http"
  19. "strings"
  20. "time"
  21. "imuslab.com/zoraxy/mod/dynamicproxy"
  22. "imuslab.com/zoraxy/mod/ipscan"
  23. "imuslab.com/zoraxy/mod/mdns"
  24. "imuslab.com/zoraxy/mod/uptime"
  25. "imuslab.com/zoraxy/mod/utils"
  26. "imuslab.com/zoraxy/mod/wakeonlan"
  27. )
  28. /*
  29. Proxy Utils
  30. */
  31. //Check if site support TLS
  32. func HandleCheckSiteSupportTLS(w http.ResponseWriter, r *http.Request) {
  33. targetURL, err := utils.PostPara(r, "url")
  34. if err != nil {
  35. utils.SendErrorResponse(w, "invalid url given")
  36. return
  37. }
  38. httpsUrl := fmt.Sprintf("https://%s", targetURL)
  39. httpUrl := fmt.Sprintf("http://%s", targetURL)
  40. client := http.Client{Timeout: 5 * time.Second}
  41. resp, err := client.Head(httpsUrl)
  42. if err == nil && resp.StatusCode == http.StatusOK {
  43. js, _ := json.Marshal("https")
  44. utils.SendJSONResponse(w, string(js))
  45. return
  46. }
  47. resp, err = client.Head(httpUrl)
  48. if err == nil && resp.StatusCode == http.StatusOK {
  49. js, _ := json.Marshal("http")
  50. utils.SendJSONResponse(w, string(js))
  51. return
  52. }
  53. utils.SendErrorResponse(w, "invalid url given")
  54. }
  55. /*
  56. Statistic Summary
  57. */
  58. // Handle conversion of statistic daily summary to country summary
  59. func HandleCountryDistrSummary(w http.ResponseWriter, r *http.Request) {
  60. requestClientCountry := map[string]int{}
  61. statisticCollector.DailySummary.RequestClientIp.Range(func(key, value interface{}) bool {
  62. //Get this client country of original
  63. clientIp := key.(string)
  64. //requestCount := value.(int)
  65. ci, err := geodbStore.ResolveCountryCodeFromIP(clientIp)
  66. if err != nil {
  67. return true
  68. }
  69. isoCode := ci.CountryIsoCode
  70. if isoCode == "" {
  71. //local or reserved addr
  72. isoCode = "local"
  73. }
  74. uc, ok := requestClientCountry[isoCode]
  75. if !ok {
  76. //Create the counter
  77. requestClientCountry[isoCode] = 1
  78. } else {
  79. requestClientCountry[isoCode] = uc + 1
  80. }
  81. return true
  82. })
  83. js, _ := json.Marshal(requestClientCountry)
  84. utils.SendJSONResponse(w, string(js))
  85. }
  86. /*
  87. Up Time Monitor
  88. */
  89. // Update uptime monitor targets after rules updated
  90. // See https://github.com/tobychui/zoraxy/issues/77
  91. func UpdateUptimeMonitorTargets() {
  92. if uptimeMonitor != nil {
  93. uptimeMonitor.Config.Targets = GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter)
  94. go func() {
  95. uptimeMonitor.ExecuteUptimeCheck()
  96. }()
  97. SystemWideLogger.PrintAndLog("Uptime", "Uptime monitor config updated", nil)
  98. }
  99. }
  100. // Generate uptime monitor targets from reverse proxy rules
  101. func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Target {
  102. subds := dp.GetSDProxyEndpointsAsMap()
  103. vdirs := dp.GetVDProxyEndpointsAsMap()
  104. UptimeTargets := []*uptime.Target{}
  105. for subd, target := range subds {
  106. url := "http://" + target.Domain
  107. protocol := "http"
  108. if target.RequireTLS {
  109. url = "https://" + target.Domain
  110. protocol = "https"
  111. }
  112. UptimeTargets = append(UptimeTargets, &uptime.Target{
  113. ID: subd,
  114. Name: subd,
  115. URL: url,
  116. Protocol: protocol,
  117. })
  118. }
  119. for vdir, target := range vdirs {
  120. url := "http://" + target.Domain
  121. protocol := "http"
  122. if target.RequireTLS {
  123. url = "https://" + target.Domain
  124. protocol = "https"
  125. }
  126. UptimeTargets = append(UptimeTargets, &uptime.Target{
  127. ID: vdir,
  128. Name: "*" + vdir,
  129. URL: url,
  130. Protocol: protocol,
  131. })
  132. }
  133. return UptimeTargets
  134. }
  135. // Handle rendering up time monitor data
  136. func HandleUptimeMonitorListing(w http.ResponseWriter, r *http.Request) {
  137. if uptimeMonitor != nil {
  138. uptimeMonitor.HandleUptimeLogRead(w, r)
  139. } else {
  140. http.Error(w, "500 - Internal Server Error", http.StatusInternalServerError)
  141. return
  142. }
  143. }
  144. // Handle listing current registered mdns nodes
  145. func HandleMdnsListing(w http.ResponseWriter, r *http.Request) {
  146. if mdnsScanner == nil {
  147. utils.SendErrorResponse(w, "mDNS scanner is disabled on this host")
  148. return
  149. }
  150. js, _ := json.Marshal(previousmdnsScanResults)
  151. utils.SendJSONResponse(w, string(js))
  152. }
  153. func HandleMdnsScanning(w http.ResponseWriter, r *http.Request) {
  154. if mdnsScanner == nil {
  155. utils.SendErrorResponse(w, "mDNS scanner is disabled on this host")
  156. return
  157. }
  158. domain, err := utils.PostPara(r, "domain")
  159. var hosts []*mdns.NetworkHost
  160. if err != nil {
  161. //Search for arozos node
  162. hosts = mdnsScanner.Scan(30, "")
  163. previousmdnsScanResults = hosts
  164. } else {
  165. //Search for other nodes
  166. hosts = mdnsScanner.Scan(30, domain)
  167. }
  168. js, _ := json.Marshal(hosts)
  169. utils.SendJSONResponse(w, string(js))
  170. }
  171. // handle ip scanning
  172. func HandleIpScan(w http.ResponseWriter, r *http.Request) {
  173. cidr, err := utils.PostPara(r, "cidr")
  174. if err != nil {
  175. //Ip range mode
  176. start, err := utils.PostPara(r, "start")
  177. if err != nil {
  178. utils.SendErrorResponse(w, "missing start ip")
  179. return
  180. }
  181. end, err := utils.PostPara(r, "end")
  182. if err != nil {
  183. utils.SendErrorResponse(w, "missing end ip")
  184. return
  185. }
  186. discoveredHosts, err := ipscan.ScanIpRange(start, end)
  187. if err != nil {
  188. utils.SendErrorResponse(w, err.Error())
  189. return
  190. }
  191. js, _ := json.Marshal(discoveredHosts)
  192. utils.SendJSONResponse(w, string(js))
  193. } else {
  194. //CIDR mode
  195. discoveredHosts, err := ipscan.ScanCIDRRange(cidr)
  196. if err != nil {
  197. utils.SendErrorResponse(w, err.Error())
  198. return
  199. }
  200. js, _ := json.Marshal(discoveredHosts)
  201. utils.SendJSONResponse(w, string(js))
  202. }
  203. }
  204. /*
  205. WAKE ON LAN
  206. Handle wake on LAN
  207. Support following methods
  208. /?set=xxx&name=xxx Record a new MAC address into the database
  209. /?wake=xxx Wake a server given its MAC address
  210. /?del=xxx Delete a server given its MAC address
  211. / Default: list all recorded WoL MAC address
  212. */
  213. func HandleWakeOnLan(w http.ResponseWriter, r *http.Request) {
  214. set, _ := utils.PostPara(r, "set")
  215. del, _ := utils.PostPara(r, "del")
  216. wake, _ := utils.PostPara(r, "wake")
  217. if set != "" {
  218. //Get the name of the describing server
  219. servername, err := utils.PostPara(r, "name")
  220. if err != nil {
  221. utils.SendErrorResponse(w, "invalid server name given")
  222. return
  223. }
  224. //Check if the given mac address is a valid mac address
  225. set = strings.TrimSpace(set)
  226. if !wakeonlan.IsValidMacAddress(set) {
  227. utils.SendErrorResponse(w, "invalid mac address given")
  228. return
  229. }
  230. //Store this into the database
  231. sysdb.Write("wolmac", set, servername)
  232. utils.SendOK(w)
  233. } else if wake != "" {
  234. //Wake the target up by MAC address
  235. if !wakeonlan.IsValidMacAddress(wake) {
  236. utils.SendErrorResponse(w, "invalid mac address given")
  237. return
  238. }
  239. SystemWideLogger.PrintAndLog("WoL", "Sending Wake on LAN magic packet to "+wake, nil)
  240. err := wakeonlan.WakeTarget(wake)
  241. if err != nil {
  242. utils.SendErrorResponse(w, err.Error())
  243. return
  244. }
  245. utils.SendOK(w)
  246. } else if del != "" {
  247. if !wakeonlan.IsValidMacAddress(del) {
  248. utils.SendErrorResponse(w, "invalid mac address given")
  249. return
  250. }
  251. sysdb.Delete("wolmac", del)
  252. utils.SendOK(w)
  253. } else {
  254. //List all the saved WoL MAC Address
  255. entries, err := sysdb.ListTable("wolmac")
  256. if err != nil {
  257. utils.SendErrorResponse(w, "unknown error occured")
  258. return
  259. }
  260. type MacAddrRecord struct {
  261. ServerName string
  262. MacAddr string
  263. }
  264. results := []*MacAddrRecord{}
  265. for _, keypairs := range entries {
  266. macAddr := string(keypairs[0])
  267. serverName := ""
  268. json.Unmarshal(keypairs[1], &serverName)
  269. results = append(results, &MacAddrRecord{
  270. ServerName: serverName,
  271. MacAddr: macAddr,
  272. })
  273. }
  274. js, _ := json.Marshal(results)
  275. utils.SendJSONResponse(w, string(js))
  276. }
  277. }
  278. /*
  279. Zoraxy Host Info
  280. */
  281. func HandleZoraxyInfo(w http.ResponseWriter, r *http.Request) {
  282. type ZoraxyInfo struct {
  283. Version string
  284. NodeUUID string
  285. Development bool
  286. BootTime int64
  287. EnableSshLoopback bool
  288. ZerotierConnected bool
  289. }
  290. info := ZoraxyInfo{
  291. Version: version,
  292. NodeUUID: nodeUUID,
  293. Development: development,
  294. BootTime: bootTime,
  295. EnableSshLoopback: *allowSshLoopback,
  296. ZerotierConnected: ganManager.ControllerID != "",
  297. }
  298. js, _ := json.MarshalIndent(info, "", " ")
  299. utils.SendJSONResponse(w, string(js))
  300. }
  301. func HandleGeoIpLookup(w http.ResponseWriter, r *http.Request) {
  302. ip, err := utils.GetPara(r, "ip")
  303. if err != nil {
  304. utils.SendErrorResponse(w, "ip not given")
  305. return
  306. }
  307. cc, err := geodbStore.ResolveCountryCodeFromIP(ip)
  308. if err != nil {
  309. utils.SendErrorResponse(w, err.Error())
  310. return
  311. }
  312. js, _ := json.Marshal(cc)
  313. utils.SendJSONResponse(w, string(js))
  314. }