reverseproxy.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. package main
  2. import (
  3. "encoding/json"
  4. "log"
  5. "net/http"
  6. "path/filepath"
  7. "sort"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "imuslab.com/zoraxy/mod/auth"
  12. "imuslab.com/zoraxy/mod/dynamicproxy"
  13. "imuslab.com/zoraxy/mod/uptime"
  14. "imuslab.com/zoraxy/mod/utils"
  15. )
  16. var (
  17. dynamicProxyRouter *dynamicproxy.Router
  18. )
  19. // Add user customizable reverse proxy
  20. func ReverseProxtInit() {
  21. inboundPort := 80
  22. if sysdb.KeyExists("settings", "inbound") {
  23. sysdb.Read("settings", "inbound", &inboundPort)
  24. log.Println("Serving inbound port ", inboundPort)
  25. } else {
  26. log.Println("Inbound port not set. Using default (80)")
  27. }
  28. useTls := false
  29. sysdb.Read("settings", "usetls", &useTls)
  30. if useTls {
  31. log.Println("TLS mode enabled. Serving proxxy request with TLS")
  32. } else {
  33. log.Println("TLS mode disabled. Serving proxy request with plain http")
  34. }
  35. forceLatestTLSVersion := false
  36. sysdb.Read("settings", "forceLatestTLS", &forceLatestTLSVersion)
  37. if forceLatestTLSVersion {
  38. log.Println("Force latest TLS mode enabled. Minimum TLS LS version is set to v1.2")
  39. } else {
  40. log.Println("Force latest TLS mode disabled. Minimum TLS version is set to v1.0")
  41. }
  42. forceHttpsRedirect := false
  43. sysdb.Read("settings", "redirect", &forceHttpsRedirect)
  44. if forceHttpsRedirect {
  45. log.Println("Force HTTPS mode enabled")
  46. } else {
  47. log.Println("Force HTTPS mode disabled")
  48. }
  49. dprouter, err := dynamicproxy.NewDynamicProxy(dynamicproxy.RouterOption{
  50. HostUUID: nodeUUID,
  51. Port: inboundPort,
  52. UseTls: useTls,
  53. ForceTLSLatest: forceLatestTLSVersion,
  54. ForceHttpsRedirect: forceHttpsRedirect,
  55. TlsManager: tlsCertManager,
  56. RedirectRuleTable: redirectTable,
  57. GeodbStore: geodbStore,
  58. StatisticCollector: statisticCollector,
  59. })
  60. if err != nil {
  61. log.Println(err.Error())
  62. return
  63. }
  64. dynamicProxyRouter = dprouter
  65. //Load all conf from files
  66. confs, _ := filepath.Glob("./conf/proxy/*.config")
  67. for _, conf := range confs {
  68. record, err := LoadReverseProxyConfig(conf)
  69. if err != nil {
  70. log.Println("Failed to load "+filepath.Base(conf), err.Error())
  71. return
  72. }
  73. if record.ProxyType == "root" {
  74. dynamicProxyRouter.SetRootProxy(&dynamicproxy.RootOptions{
  75. ProxyLocation: record.ProxyTarget,
  76. RequireTLS: record.UseTLS,
  77. })
  78. } else if record.ProxyType == "subd" {
  79. dynamicProxyRouter.AddSubdomainRoutingService(&dynamicproxy.SubdOptions{
  80. MatchingDomain: record.Rootname,
  81. Domain: record.ProxyTarget,
  82. RequireTLS: record.UseTLS,
  83. SkipCertValidations: record.SkipTlsValidation,
  84. RequireBasicAuth: record.RequireBasicAuth,
  85. BasicAuthCredentials: record.BasicAuthCredentials,
  86. })
  87. } else if record.ProxyType == "vdir" {
  88. dynamicProxyRouter.AddVirtualDirectoryProxyService(&dynamicproxy.VdirOptions{
  89. RootName: record.Rootname,
  90. Domain: record.ProxyTarget,
  91. RequireTLS: record.UseTLS,
  92. SkipCertValidations: record.SkipTlsValidation,
  93. RequireBasicAuth: record.RequireBasicAuth,
  94. BasicAuthCredentials: record.BasicAuthCredentials,
  95. })
  96. } else {
  97. log.Println("Unsupported endpoint type: " + record.ProxyType + ". Skipping " + filepath.Base(conf))
  98. }
  99. }
  100. //Start Service
  101. //Not sure why but delay must be added if you have another
  102. //reverse proxy server in front of this service
  103. time.Sleep(300 * time.Millisecond)
  104. dynamicProxyRouter.StartProxyService()
  105. log.Println("Dynamic Reverse Proxy service started")
  106. //Add all proxy services to uptime monitor
  107. //Create a uptime monitor service
  108. go func() {
  109. //This must be done in go routine to prevent blocking on system startup
  110. uptimeMonitor, _ = uptime.NewUptimeMonitor(&uptime.Config{
  111. Targets: GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter),
  112. Interval: 300, //5 minutes
  113. MaxRecordsStore: 288, //1 day
  114. })
  115. log.Println("Uptime Monitor background service started")
  116. }()
  117. }
  118. func ReverseProxyHandleOnOff(w http.ResponseWriter, r *http.Request) {
  119. enable, _ := utils.PostPara(r, "enable") //Support root, vdir and subd
  120. if enable == "true" {
  121. err := dynamicProxyRouter.StartProxyService()
  122. if err != nil {
  123. utils.SendErrorResponse(w, err.Error())
  124. return
  125. }
  126. } else {
  127. //Check if it is loopback
  128. if dynamicProxyRouter.IsProxiedSubdomain(r) {
  129. //Loopback routing. Turning it off will make the user lost control
  130. //of the whole system. Do not allow shutdown
  131. utils.SendErrorResponse(w, "Unable to shutdown in loopback rp mode. Remove proxy rules for management interface and retry.")
  132. return
  133. }
  134. err := dynamicProxyRouter.StopProxyService()
  135. if err != nil {
  136. utils.SendErrorResponse(w, err.Error())
  137. return
  138. }
  139. }
  140. utils.SendOK(w)
  141. }
  142. func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
  143. eptype, err := utils.PostPara(r, "type") //Support root, vdir and subd
  144. if err != nil {
  145. utils.SendErrorResponse(w, "type not defined")
  146. return
  147. }
  148. endpoint, err := utils.PostPara(r, "ep")
  149. if err != nil {
  150. utils.SendErrorResponse(w, "endpoint not defined")
  151. return
  152. }
  153. tls, _ := utils.PostPara(r, "tls")
  154. if tls == "" {
  155. tls = "false"
  156. }
  157. useTLS := (tls == "true")
  158. stv, _ := utils.PostPara(r, "tlsval")
  159. if stv == "" {
  160. stv = "false"
  161. }
  162. skipTlsValidation := (stv == "true")
  163. rba, _ := utils.PostPara(r, "bauth")
  164. if rba == "" {
  165. rba = "false"
  166. }
  167. requireBasicAuth := (rba == "true")
  168. //Prase the basic auth to correct structure
  169. cred, _ := utils.PostPara(r, "cred")
  170. basicAuthCredentials := []*dynamicproxy.BasicAuthCredentials{}
  171. if requireBasicAuth {
  172. preProcessCredentials := []*dynamicproxy.BasicAuthUnhashedCredentials{}
  173. err = json.Unmarshal([]byte(cred), &preProcessCredentials)
  174. if err != nil {
  175. utils.SendErrorResponse(w, "invalid user credentials")
  176. return
  177. }
  178. //Check if there are empty password credentials
  179. for _, credObj := range preProcessCredentials {
  180. if strings.TrimSpace(credObj.Password) == "" {
  181. utils.SendErrorResponse(w, credObj.Username+" has empty password")
  182. return
  183. }
  184. }
  185. //Convert and hash the passwords
  186. for _, credObj := range preProcessCredentials {
  187. basicAuthCredentials = append(basicAuthCredentials, &dynamicproxy.BasicAuthCredentials{
  188. Username: credObj.Username,
  189. PasswordHash: auth.Hash(credObj.Password),
  190. })
  191. }
  192. }
  193. rootname := ""
  194. if eptype == "vdir" {
  195. vdir, err := utils.PostPara(r, "rootname")
  196. if err != nil {
  197. utils.SendErrorResponse(w, "vdir not defined")
  198. return
  199. }
  200. //Vdir must start with /
  201. if !strings.HasPrefix(vdir, "/") {
  202. vdir = "/" + vdir
  203. }
  204. rootname = vdir
  205. thisOption := dynamicproxy.VdirOptions{
  206. RootName: vdir,
  207. Domain: endpoint,
  208. RequireTLS: useTLS,
  209. SkipCertValidations: skipTlsValidation,
  210. RequireBasicAuth: requireBasicAuth,
  211. BasicAuthCredentials: basicAuthCredentials,
  212. }
  213. dynamicProxyRouter.AddVirtualDirectoryProxyService(&thisOption)
  214. } else if eptype == "subd" {
  215. subdomain, err := utils.PostPara(r, "rootname")
  216. if err != nil {
  217. utils.SendErrorResponse(w, "subdomain not defined")
  218. return
  219. }
  220. rootname = subdomain
  221. thisOption := dynamicproxy.SubdOptions{
  222. MatchingDomain: subdomain,
  223. Domain: endpoint,
  224. RequireTLS: useTLS,
  225. SkipCertValidations: skipTlsValidation,
  226. RequireBasicAuth: requireBasicAuth,
  227. BasicAuthCredentials: basicAuthCredentials,
  228. }
  229. dynamicProxyRouter.AddSubdomainRoutingService(&thisOption)
  230. } else if eptype == "root" {
  231. rootname = "root"
  232. thisOption := dynamicproxy.RootOptions{
  233. ProxyLocation: endpoint,
  234. RequireTLS: useTLS,
  235. }
  236. dynamicProxyRouter.SetRootProxy(&thisOption)
  237. } else {
  238. //Invalid eptype
  239. utils.SendErrorResponse(w, "Invalid endpoint type")
  240. return
  241. }
  242. //Save it
  243. thisProxyConfigRecord := Record{
  244. ProxyType: eptype,
  245. Rootname: rootname,
  246. ProxyTarget: endpoint,
  247. UseTLS: useTLS,
  248. SkipTlsValidation: skipTlsValidation,
  249. RequireBasicAuth: requireBasicAuth,
  250. BasicAuthCredentials: basicAuthCredentials,
  251. }
  252. SaveReverseProxyConfig(&thisProxyConfigRecord)
  253. //Update utm if exists
  254. if uptimeMonitor != nil {
  255. uptimeMonitor.Config.Targets = GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter)
  256. uptimeMonitor.CleanRecords()
  257. }
  258. utils.SendOK(w)
  259. }
  260. /*
  261. ReverseProxyHandleEditEndpoint handles proxy endpoint edit
  262. This endpoint do not handle
  263. basic auth credential update. The credential
  264. will be loaded from old config and reused
  265. */
  266. func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
  267. eptype, err := utils.PostPara(r, "type") //Support root, vdir and subd
  268. if err != nil {
  269. utils.SendErrorResponse(w, "type not defined")
  270. return
  271. }
  272. rootNameOrMatchingDomain, err := utils.PostPara(r, "rootname")
  273. if err != nil {
  274. utils.SendErrorResponse(w, "Target proxy rule not defined")
  275. return
  276. }
  277. endpoint, err := utils.PostPara(r, "ep")
  278. if err != nil {
  279. utils.SendErrorResponse(w, "endpoint not defined")
  280. return
  281. }
  282. tls, _ := utils.PostPara(r, "tls")
  283. if tls == "" {
  284. tls = "false"
  285. }
  286. useTLS := (tls == "true")
  287. stv, _ := utils.PostPara(r, "tlsval")
  288. if stv == "" {
  289. stv = "false"
  290. }
  291. skipTlsValidation := (stv == "true")
  292. rba, _ := utils.PostPara(r, "bauth")
  293. if rba == "" {
  294. rba = "false"
  295. }
  296. requireBasicAuth := (rba == "true")
  297. //Load the previous basic auth credentials from current proxy rules
  298. targetProxyEntry, err := dynamicProxyRouter.LoadProxy(eptype, rootNameOrMatchingDomain)
  299. if err != nil {
  300. utils.SendErrorResponse(w, "Target proxy config not found or could not be loaded")
  301. return
  302. }
  303. if eptype == "vdir" {
  304. thisOption := dynamicproxy.VdirOptions{
  305. RootName: targetProxyEntry.RootOrMatchingDomain,
  306. Domain: endpoint,
  307. RequireTLS: useTLS,
  308. SkipCertValidations: skipTlsValidation,
  309. RequireBasicAuth: requireBasicAuth,
  310. BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials,
  311. }
  312. dynamicProxyRouter.RemoveProxy("vdir", thisOption.RootName)
  313. dynamicProxyRouter.AddVirtualDirectoryProxyService(&thisOption)
  314. } else if eptype == "subd" {
  315. thisOption := dynamicproxy.SubdOptions{
  316. MatchingDomain: targetProxyEntry.RootOrMatchingDomain,
  317. Domain: endpoint,
  318. RequireTLS: useTLS,
  319. SkipCertValidations: skipTlsValidation,
  320. RequireBasicAuth: requireBasicAuth,
  321. BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials,
  322. }
  323. dynamicProxyRouter.RemoveProxy("subd", thisOption.MatchingDomain)
  324. dynamicProxyRouter.AddSubdomainRoutingService(&thisOption)
  325. }
  326. //Save it to file
  327. thisProxyConfigRecord := Record{
  328. ProxyType: eptype,
  329. Rootname: targetProxyEntry.RootOrMatchingDomain,
  330. ProxyTarget: endpoint,
  331. UseTLS: useTLS,
  332. SkipTlsValidation: skipTlsValidation,
  333. RequireBasicAuth: requireBasicAuth,
  334. BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials,
  335. }
  336. SaveReverseProxyConfig(&thisProxyConfigRecord)
  337. utils.SendOK(w)
  338. }
  339. func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) {
  340. ep, err := utils.GetPara(r, "ep")
  341. if err != nil {
  342. utils.SendErrorResponse(w, "Invalid ep given")
  343. return
  344. }
  345. ptype, err := utils.PostPara(r, "ptype")
  346. if err != nil {
  347. utils.SendErrorResponse(w, "Invalid ptype given")
  348. return
  349. }
  350. err = dynamicProxyRouter.RemoveProxy(ptype, ep)
  351. if err != nil {
  352. utils.SendErrorResponse(w, err.Error())
  353. return
  354. }
  355. RemoveReverseProxyConfig(ep)
  356. //Update utm if exists
  357. if uptimeMonitor != nil {
  358. uptimeMonitor.Config.Targets = GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter)
  359. uptimeMonitor.CleanRecords()
  360. }
  361. utils.SendOK(w)
  362. }
  363. /*
  364. Handle update request for basic auth credential
  365. Require paramter: ep (Endpoint) and pytype (proxy Type)
  366. if request with GET, the handler will return current credentials
  367. on this endpoint by its username
  368. if request is POST, the handler will write the results to proxy config
  369. */
  370. func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
  371. if r.Method == http.MethodGet {
  372. ep, err := utils.GetPara(r, "ep")
  373. if err != nil {
  374. utils.SendErrorResponse(w, "Invalid ep given")
  375. return
  376. }
  377. ptype, err := utils.GetPara(r, "ptype")
  378. if err != nil {
  379. utils.SendErrorResponse(w, "Invalid ptype given")
  380. return
  381. }
  382. //Load the target proxy object from router
  383. targetProxy, err := dynamicProxyRouter.LoadProxy(ptype, ep)
  384. if err != nil {
  385. utils.SendErrorResponse(w, err.Error())
  386. return
  387. }
  388. usernames := []string{}
  389. for _, cred := range targetProxy.BasicAuthCredentials {
  390. usernames = append(usernames, cred.Username)
  391. }
  392. js, _ := json.Marshal(usernames)
  393. utils.SendJSONResponse(w, string(js))
  394. } else if r.Method == http.MethodPost {
  395. //Write to target
  396. ep, err := utils.PostPara(r, "ep")
  397. if err != nil {
  398. utils.SendErrorResponse(w, "Invalid ep given")
  399. return
  400. }
  401. ptype, err := utils.PostPara(r, "ptype")
  402. if err != nil {
  403. utils.SendErrorResponse(w, "Invalid ptype given")
  404. return
  405. }
  406. if ptype != "vdir" && ptype != "subd" {
  407. utils.SendErrorResponse(w, "Invalid ptype given")
  408. return
  409. }
  410. creds, err := utils.PostPara(r, "creds")
  411. if err != nil {
  412. utils.SendErrorResponse(w, "Invalid ptype given")
  413. return
  414. }
  415. //Load the target proxy object from router
  416. targetProxy, err := dynamicProxyRouter.LoadProxy(ptype, ep)
  417. if err != nil {
  418. utils.SendErrorResponse(w, err.Error())
  419. return
  420. }
  421. //Try to marshal the content of creds into the suitable structure
  422. newCredentials := []*dynamicproxy.BasicAuthUnhashedCredentials{}
  423. err = json.Unmarshal([]byte(creds), &newCredentials)
  424. if err != nil {
  425. utils.SendErrorResponse(w, "Malformed credential data")
  426. return
  427. }
  428. //Merge the credentials into the original config
  429. //If a new username exists in old config with no pw given, keep the old pw hash
  430. //If a new username is found with new password, hash it and push to credential slice
  431. mergedCredentials := []*dynamicproxy.BasicAuthCredentials{}
  432. for _, credential := range newCredentials {
  433. if credential.Password == "" {
  434. //Check if exists in the old credential files
  435. keepUnchange := false
  436. for _, oldCredEntry := range targetProxy.BasicAuthCredentials {
  437. if oldCredEntry.Username == credential.Username {
  438. //Exists! Reuse the old hash
  439. mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
  440. Username: oldCredEntry.Username,
  441. PasswordHash: oldCredEntry.PasswordHash,
  442. })
  443. keepUnchange = true
  444. }
  445. }
  446. if !keepUnchange {
  447. //This is a new username with no pw given
  448. utils.SendErrorResponse(w, "Access password for "+credential.Username+" is empty!")
  449. return
  450. }
  451. } else {
  452. //This username have given password
  453. mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
  454. Username: credential.Username,
  455. PasswordHash: auth.Hash(credential.Password),
  456. })
  457. }
  458. }
  459. targetProxy.BasicAuthCredentials = mergedCredentials
  460. //Save it to file
  461. thisProxyConfigRecord := Record{
  462. ProxyType: ptype,
  463. Rootname: targetProxy.RootOrMatchingDomain,
  464. ProxyTarget: targetProxy.Domain,
  465. UseTLS: targetProxy.RequireTLS,
  466. SkipTlsValidation: targetProxy.SkipCertValidations,
  467. RequireBasicAuth: targetProxy.RequireBasicAuth,
  468. BasicAuthCredentials: targetProxy.BasicAuthCredentials,
  469. }
  470. SaveReverseProxyConfig(&thisProxyConfigRecord)
  471. //Replace runtime configuration
  472. dynamicProxyRouter.SaveProxy(ptype, ep, targetProxy)
  473. utils.SendOK(w)
  474. } else {
  475. http.Error(w, "invalid usage", http.StatusMethodNotAllowed)
  476. }
  477. }
  478. func ReverseProxyStatus(w http.ResponseWriter, r *http.Request) {
  479. js, _ := json.Marshal(dynamicProxyRouter)
  480. utils.SendJSONResponse(w, string(js))
  481. }
  482. func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
  483. eptype, err := utils.PostPara(r, "type") //Support root, vdir and subd
  484. if err != nil {
  485. utils.SendErrorResponse(w, "type not defined")
  486. return
  487. }
  488. if eptype == "vdir" {
  489. results := []*dynamicproxy.ProxyEndpoint{}
  490. dynamicProxyRouter.ProxyEndpoints.Range(func(key, value interface{}) bool {
  491. results = append(results, value.(*dynamicproxy.ProxyEndpoint))
  492. return true
  493. })
  494. sort.Slice(results, func(i, j int) bool {
  495. return results[i].Domain < results[j].Domain
  496. })
  497. js, _ := json.Marshal(results)
  498. utils.SendJSONResponse(w, string(js))
  499. } else if eptype == "subd" {
  500. results := []*dynamicproxy.ProxyEndpoint{}
  501. dynamicProxyRouter.SubdomainEndpoint.Range(func(key, value interface{}) bool {
  502. results = append(results, value.(*dynamicproxy.ProxyEndpoint))
  503. return true
  504. })
  505. sort.Slice(results, func(i, j int) bool {
  506. return results[i].RootOrMatchingDomain < results[j].RootOrMatchingDomain
  507. })
  508. js, _ := json.Marshal(results)
  509. utils.SendJSONResponse(w, string(js))
  510. } else if eptype == "root" {
  511. js, _ := json.Marshal(dynamicProxyRouter.Root)
  512. utils.SendJSONResponse(w, string(js))
  513. } else {
  514. utils.SendErrorResponse(w, "Invalid type given")
  515. }
  516. }
  517. // Handle https redirect
  518. func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) {
  519. useRedirect, err := utils.GetPara(r, "set")
  520. if err != nil {
  521. currentRedirectToHttps := false
  522. //Load the current status
  523. err = sysdb.Read("settings", "redirect", &currentRedirectToHttps)
  524. if err != nil {
  525. utils.SendErrorResponse(w, err.Error())
  526. return
  527. }
  528. js, _ := json.Marshal(currentRedirectToHttps)
  529. utils.SendJSONResponse(w, string(js))
  530. } else {
  531. if dynamicProxyRouter.Option.Port == 80 {
  532. utils.SendErrorResponse(w, "This option is not available when listening on port 80")
  533. return
  534. }
  535. if useRedirect == "true" {
  536. sysdb.Write("settings", "redirect", true)
  537. log.Println("Updating force HTTPS redirection to true")
  538. dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
  539. } else if useRedirect == "false" {
  540. sysdb.Write("settings", "redirect", false)
  541. log.Println("Updating force HTTPS redirection to false")
  542. dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false)
  543. }
  544. utils.SendOK(w)
  545. }
  546. }
  547. // Handle checking if the current user is accessing via the reverse proxied interface
  548. // Of the management interface.
  549. func HandleManagementProxyCheck(w http.ResponseWriter, r *http.Request) {
  550. isProxied := dynamicProxyRouter.IsProxiedSubdomain(r)
  551. js, _ := json.Marshal(isProxied)
  552. utils.SendJSONResponse(w, string(js))
  553. }
  554. // Handle incoming port set. Change the current proxy incoming port
  555. func HandleIncomingPortSet(w http.ResponseWriter, r *http.Request) {
  556. newIncomingPort, err := utils.PostPara(r, "incoming")
  557. if err != nil {
  558. utils.SendErrorResponse(w, "invalid incoming port given")
  559. return
  560. }
  561. newIncomingPortInt, err := strconv.Atoi(newIncomingPort)
  562. if err != nil {
  563. utils.SendErrorResponse(w, "invalid incoming port given")
  564. return
  565. }
  566. //Check if it is identical as proxy root (recursion!)
  567. if dynamicProxyRouter.Root == nil || dynamicProxyRouter.Root.Domain == "" {
  568. //Check if proxy root is set before checking recursive listen
  569. //Fixing issue #43
  570. utils.SendErrorResponse(w, "Proxy root not set")
  571. return
  572. }
  573. proxyRoot := strings.TrimSuffix(dynamicProxyRouter.Root.Domain, "/")
  574. if strings.HasPrefix(proxyRoot, "localhost:"+strconv.Itoa(newIncomingPortInt)) || strings.HasPrefix(proxyRoot, "127.0.0.1:"+strconv.Itoa(newIncomingPortInt)) {
  575. //Listening port is same as proxy root
  576. //Not allow recursive settings
  577. utils.SendErrorResponse(w, "Recursive listening port! Check your proxy root settings.")
  578. return
  579. }
  580. //Stop and change the setting of the reverse proxy service
  581. if dynamicProxyRouter.Running {
  582. dynamicProxyRouter.StopProxyService()
  583. dynamicProxyRouter.Option.Port = newIncomingPortInt
  584. dynamicProxyRouter.StartProxyService()
  585. } else {
  586. //Only change setting but not starting the proxy service
  587. dynamicProxyRouter.Option.Port = newIncomingPortInt
  588. }
  589. sysdb.Write("settings", "inbound", newIncomingPortInt)
  590. utils.SendOK(w)
  591. }