1
0

wrappers.go 9.7 KB

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