reverseproxy.go 19 KB

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