reverseproxy.go 19 KB

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