reverseproxy.go 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645
  1. package main
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "path/filepath"
  6. "sort"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "imuslab.com/zoraxy/mod/auth"
  11. "imuslab.com/zoraxy/mod/dynamicproxy"
  12. "imuslab.com/zoraxy/mod/dynamicproxy/loadbalance"
  13. "imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
  14. "imuslab.com/zoraxy/mod/dynamicproxy/rewrite"
  15. "imuslab.com/zoraxy/mod/netutils"
  16. "imuslab.com/zoraxy/mod/uptime"
  17. "imuslab.com/zoraxy/mod/utils"
  18. )
  19. var (
  20. dynamicProxyRouter *dynamicproxy.Router
  21. )
  22. // Add user customizable reverse proxy
  23. func ReverseProxtInit() {
  24. /*
  25. Load Reverse Proxy Global Settings
  26. */
  27. inboundPort := *defaultInboundPort
  28. autoStartReverseProxy := *defaultEnableInboundTraffic
  29. if sysdb.KeyExists("settings", "inbound") {
  30. //Read settings from database
  31. sysdb.Read("settings", "inbound", &inboundPort)
  32. if netutils.CheckIfPortOccupied(inboundPort) {
  33. autoStartReverseProxy = false
  34. SystemWideLogger.Println("Inbound port ", inboundPort, " is occupied. Change the listening port in the webmin panel and press \"Start Service\" to start reverse proxy service")
  35. } else {
  36. SystemWideLogger.Println("Serving inbound port ", inboundPort)
  37. }
  38. } else {
  39. //Default port
  40. if netutils.CheckIfPortOccupied(inboundPort) {
  41. autoStartReverseProxy = false
  42. SystemWideLogger.Println("Port 443 is occupied. Change the listening port in the webmin panel and press \"Start Service\" to start reverse proxy service")
  43. }
  44. SystemWideLogger.Println("Inbound port not set. Using default (443)")
  45. }
  46. useTls := true
  47. sysdb.Read("settings", "usetls", &useTls)
  48. if useTls {
  49. SystemWideLogger.Println("TLS mode enabled. Serving proxy request with TLS")
  50. } else {
  51. SystemWideLogger.Println("TLS mode disabled. Serving proxy request with plain http")
  52. }
  53. forceLatestTLSVersion := false
  54. sysdb.Read("settings", "forceLatestTLS", &forceLatestTLSVersion)
  55. if forceLatestTLSVersion {
  56. SystemWideLogger.Println("Force latest TLS mode enabled. Minimum TLS LS version is set to v1.2")
  57. } else {
  58. SystemWideLogger.Println("Force latest TLS mode disabled. Minimum TLS version is set to v1.0")
  59. }
  60. developmentMode := false
  61. sysdb.Read("settings", "devMode", &developmentMode)
  62. if useTls {
  63. SystemWideLogger.Println("Development mode enabled. Using no-store Cache Control policy")
  64. } else {
  65. SystemWideLogger.Println("Development mode disabled. Proxying with default Cache Control policy")
  66. }
  67. listenOnPort80 := true
  68. if netutils.CheckIfPortOccupied(80) {
  69. listenOnPort80 = false
  70. }
  71. sysdb.Read("settings", "listenP80", &listenOnPort80)
  72. if listenOnPort80 {
  73. SystemWideLogger.Println("Port 80 listener enabled")
  74. } else {
  75. SystemWideLogger.Println("Port 80 listener disabled")
  76. }
  77. forceHttpsRedirect := true
  78. sysdb.Read("settings", "redirect", &forceHttpsRedirect)
  79. if forceHttpsRedirect {
  80. SystemWideLogger.Println("Force HTTPS mode enabled")
  81. //Port 80 listener must be enabled to perform http -> https redirect
  82. listenOnPort80 = true
  83. } else {
  84. SystemWideLogger.Println("Force HTTPS mode disabled")
  85. }
  86. /*
  87. Create a new proxy object
  88. The DynamicProxy is the parent of all reverse proxy handlers,
  89. use for managemening and provide functions to access proxy handlers
  90. */
  91. dprouter, err := dynamicproxy.NewDynamicProxy(dynamicproxy.RouterOption{
  92. HostUUID: nodeUUID,
  93. HostVersion: SYSTEM_VERSION,
  94. Port: inboundPort,
  95. UseTls: useTls,
  96. ForceTLSLatest: forceLatestTLSVersion,
  97. NoCache: developmentMode,
  98. ListenOnPort80: listenOnPort80,
  99. ForceHttpsRedirect: forceHttpsRedirect,
  100. TlsManager: tlsCertManager,
  101. RedirectRuleTable: redirectTable,
  102. GeodbStore: geodbStore,
  103. StatisticCollector: statisticCollector,
  104. WebDirectory: *path_webserver,
  105. AccessController: accessController,
  106. AutheliaRouter: autheliaRouter,
  107. LoadBalancer: loadBalancer,
  108. Logger: SystemWideLogger,
  109. })
  110. if err != nil {
  111. SystemWideLogger.PrintAndLog("proxy-config", "Unable to create dynamic proxy router", err)
  112. return
  113. }
  114. dynamicProxyRouter = dprouter
  115. /*
  116. Load all conf from files
  117. */
  118. confs, _ := filepath.Glob("./conf/proxy/*.config")
  119. for _, conf := range confs {
  120. err := LoadReverseProxyConfig(conf)
  121. if err != nil {
  122. SystemWideLogger.PrintAndLog("proxy-config", "Failed to load config file: "+filepath.Base(conf), err)
  123. return
  124. }
  125. }
  126. if dynamicProxyRouter.Root == nil {
  127. //Root config not set (new deployment?), use internal static web server as root
  128. defaultRootRouter, err := GetDefaultRootConfig()
  129. if err != nil {
  130. SystemWideLogger.PrintAndLog("proxy-config", "Failed to generate default root routing", err)
  131. return
  132. }
  133. dynamicProxyRouter.SetProxyRouteAsRoot(defaultRootRouter)
  134. }
  135. //Start Service
  136. //Not sure why but delay must be added if you have another
  137. //reverse proxy server in front of this service
  138. if autoStartReverseProxy {
  139. time.Sleep(300 * time.Millisecond)
  140. dynamicProxyRouter.StartProxyService()
  141. SystemWideLogger.Println("Dynamic Reverse Proxy service started")
  142. }
  143. //Add all proxy services to uptime monitor
  144. //Create a uptime monitor service
  145. go func() {
  146. //This must be done in go routine to prevent blocking on system startup
  147. uptimeMonitor, _ = uptime.NewUptimeMonitor(&uptime.Config{
  148. Targets: GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter),
  149. Interval: 300, //5 minutes
  150. MaxRecordsStore: 288, //1 day
  151. Logger: SystemWideLogger, //Logger
  152. })
  153. SystemWideLogger.Println("Uptime Monitor background service started")
  154. }()
  155. }
  156. func ReverseProxyHandleOnOff(w http.ResponseWriter, r *http.Request) {
  157. enable, _ := utils.PostPara(r, "enable") //Support root, vdir and subd
  158. if enable == "true" {
  159. err := dynamicProxyRouter.StartProxyService()
  160. if err != nil {
  161. utils.SendErrorResponse(w, err.Error())
  162. return
  163. }
  164. } else {
  165. //Check if it is loopback
  166. if dynamicProxyRouter.IsProxiedSubdomain(r) {
  167. //Loopback routing. Turning it off will make the user lost control
  168. //of the whole system. Do not allow shutdown
  169. utils.SendErrorResponse(w, "Unable to shutdown in loopback rp mode. Remove proxy rules for management interface and retry.")
  170. return
  171. }
  172. err := dynamicProxyRouter.StopProxyService()
  173. if err != nil {
  174. utils.SendErrorResponse(w, err.Error())
  175. return
  176. }
  177. }
  178. utils.SendOK(w)
  179. }
  180. func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
  181. eptype, err := utils.PostPara(r, "type") //Support root and host
  182. if err != nil {
  183. utils.SendErrorResponse(w, "type not defined")
  184. return
  185. }
  186. endpoint, err := utils.PostPara(r, "ep")
  187. if err != nil {
  188. utils.SendErrorResponse(w, "endpoint not defined")
  189. return
  190. }
  191. tls, _ := utils.PostPara(r, "tls")
  192. if tls == "" {
  193. tls = "false"
  194. }
  195. useTLS := (tls == "true")
  196. //Bypass global TLS value / allow direct access from port 80?
  197. bypassGlobalTLS, _ := utils.PostPara(r, "bypassGlobalTLS")
  198. if bypassGlobalTLS == "" {
  199. bypassGlobalTLS = "false"
  200. }
  201. useBypassGlobalTLS := bypassGlobalTLS == "true"
  202. //Enable TLS validation?
  203. skipTlsValidation, _ := utils.PostBool(r, "tlsval")
  204. //Get access rule ID
  205. accessRuleID, _ := utils.PostPara(r, "access")
  206. if accessRuleID == "" {
  207. accessRuleID = "default"
  208. }
  209. if !accessController.AccessRuleExists(accessRuleID) {
  210. utils.SendErrorResponse(w, "invalid access rule ID selected")
  211. return
  212. }
  213. // Require basic auth?
  214. requireBasicAuth, _ := utils.PostBool(r, "bauth")
  215. //Use sticky session?
  216. useStickySession, _ := utils.PostBool(r, "stickysess")
  217. // Require Rate Limiting?
  218. requireRateLimit := false
  219. proxyRateLimit := 1000
  220. requireRateLimit, err = utils.PostBool(r, "rate")
  221. if err != nil {
  222. requireRateLimit = false
  223. }
  224. if requireRateLimit {
  225. proxyRateLimit, err = utils.PostInt(r, "ratenum")
  226. if err != nil {
  227. proxyRateLimit = 0
  228. }
  229. if err != nil {
  230. utils.SendErrorResponse(w, "invalid rate limit number")
  231. return
  232. }
  233. if proxyRateLimit <= 0 {
  234. utils.SendErrorResponse(w, "rate limit number must be greater than 0")
  235. return
  236. }
  237. }
  238. // Bypass WebSocket Origin Check
  239. strbpwsorg, _ := utils.PostPara(r, "bpwsorg")
  240. if strbpwsorg == "" {
  241. strbpwsorg = "false"
  242. }
  243. bypassWebsocketOriginCheck := (strbpwsorg == "true")
  244. //Prase the basic auth to correct structure
  245. cred, _ := utils.PostPara(r, "cred")
  246. basicAuthCredentials := []*dynamicproxy.BasicAuthCredentials{}
  247. if requireBasicAuth {
  248. preProcessCredentials := []*dynamicproxy.BasicAuthUnhashedCredentials{}
  249. err = json.Unmarshal([]byte(cred), &preProcessCredentials)
  250. if err != nil {
  251. utils.SendErrorResponse(w, "invalid user credentials")
  252. return
  253. }
  254. //Check if there are empty password credentials
  255. for _, credObj := range preProcessCredentials {
  256. if strings.TrimSpace(credObj.Password) == "" {
  257. utils.SendErrorResponse(w, credObj.Username+" has empty password")
  258. return
  259. }
  260. }
  261. //Convert and hash the passwords
  262. for _, credObj := range preProcessCredentials {
  263. basicAuthCredentials = append(basicAuthCredentials, &dynamicproxy.BasicAuthCredentials{
  264. Username: credObj.Username,
  265. PasswordHash: auth.Hash(credObj.Password),
  266. })
  267. }
  268. }
  269. tagStr, _ := utils.PostPara(r, "tags")
  270. tags := []string{}
  271. if tagStr != "" {
  272. tags = strings.Split(tagStr, ",")
  273. for i := range tags {
  274. tags[i] = strings.TrimSpace(tags[i])
  275. }
  276. }
  277. // Remove empty tags
  278. filteredTags := []string{}
  279. for _, tag := range tags {
  280. if tag != "" {
  281. filteredTags = append(filteredTags, tag)
  282. }
  283. }
  284. tags = filteredTags
  285. var proxyEndpointCreated *dynamicproxy.ProxyEndpoint
  286. if eptype == "host" {
  287. rootOrMatchingDomain, err := utils.PostPara(r, "rootname")
  288. if err != nil {
  289. utils.SendErrorResponse(w, "hostname not defined")
  290. return
  291. }
  292. rootOrMatchingDomain = strings.TrimSpace(rootOrMatchingDomain)
  293. //Check if it contains ",", if yes, split the remainings as alias
  294. aliasHostnames := []string{}
  295. if strings.Contains(rootOrMatchingDomain, ",") {
  296. matchingDomains := strings.Split(rootOrMatchingDomain, ",")
  297. if len(matchingDomains) > 1 {
  298. rootOrMatchingDomain = matchingDomains[0]
  299. for _, aliasHostname := range matchingDomains[1:] {
  300. //Filter out any space
  301. aliasHostnames = append(aliasHostnames, strings.TrimSpace(aliasHostname))
  302. }
  303. }
  304. }
  305. //Generate a default authenticaion provider
  306. authMethod := dynamicproxy.AuthMethodNone
  307. if requireBasicAuth {
  308. authMethod = dynamicproxy.AuthMethodBasic
  309. }
  310. thisAuthenticationProvider := dynamicproxy.AuthenticationProvider{
  311. AuthMethod: authMethod,
  312. BasicAuthCredentials: basicAuthCredentials,
  313. BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
  314. }
  315. //Generate a proxy endpoint object
  316. thisProxyEndpoint := dynamicproxy.ProxyEndpoint{
  317. //I/O
  318. ProxyType: dynamicproxy.ProxyTypeHost,
  319. RootOrMatchingDomain: rootOrMatchingDomain,
  320. MatchingDomainAlias: aliasHostnames,
  321. ActiveOrigins: []*loadbalance.Upstream{
  322. {
  323. OriginIpOrDomain: endpoint,
  324. RequireTLS: useTLS,
  325. SkipCertValidations: skipTlsValidation,
  326. SkipWebSocketOriginCheck: bypassWebsocketOriginCheck,
  327. Weight: 1,
  328. },
  329. },
  330. InactiveOrigins: []*loadbalance.Upstream{},
  331. UseStickySession: useStickySession,
  332. //TLS
  333. BypassGlobalTLS: useBypassGlobalTLS,
  334. AccessFilterUUID: accessRuleID,
  335. //VDir
  336. VirtualDirectories: []*dynamicproxy.VirtualDirectoryEndpoint{},
  337. //Custom headers
  338. //Auth
  339. AuthenticationProvider: &thisAuthenticationProvider,
  340. //Header Rewrite
  341. HeaderRewriteRules: dynamicproxy.GetDefaultHeaderRewriteRules(),
  342. //Default Site
  343. DefaultSiteOption: 0,
  344. DefaultSiteValue: "",
  345. // Rate Limit
  346. RequireRateLimit: requireRateLimit,
  347. RateLimit: int64(proxyRateLimit),
  348. Tags: tags,
  349. }
  350. preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisProxyEndpoint)
  351. if err != nil {
  352. utils.SendErrorResponse(w, "unable to prepare proxy route to target endpoint: "+err.Error())
  353. return
  354. }
  355. dynamicProxyRouter.AddProxyRouteToRuntime(preparedEndpoint)
  356. proxyEndpointCreated = &thisProxyEndpoint
  357. } else if eptype == "root" {
  358. //Get the default site options and target
  359. dsOptString, err := utils.PostPara(r, "defaultSiteOpt")
  360. if err != nil {
  361. utils.SendErrorResponse(w, "default site action not defined")
  362. return
  363. }
  364. var defaultSiteOption int = 1
  365. opt, err := strconv.Atoi(dsOptString)
  366. if err != nil {
  367. utils.SendErrorResponse(w, "invalid default site option")
  368. return
  369. }
  370. defaultSiteOption = opt
  371. dsVal, err := utils.PostPara(r, "defaultSiteVal")
  372. if err != nil && (defaultSiteOption == 1 || defaultSiteOption == 2) {
  373. //Reverse proxy or redirect, must require value to be set
  374. utils.SendErrorResponse(w, "target not defined")
  375. return
  376. }
  377. //Write the root options to file
  378. rootRoutingEndpoint := dynamicproxy.ProxyEndpoint{
  379. ProxyType: dynamicproxy.ProxyTypeRoot,
  380. RootOrMatchingDomain: "/",
  381. ActiveOrigins: []*loadbalance.Upstream{
  382. {
  383. OriginIpOrDomain: endpoint,
  384. RequireTLS: useTLS,
  385. SkipCertValidations: true,
  386. SkipWebSocketOriginCheck: true,
  387. Weight: 1,
  388. },
  389. },
  390. InactiveOrigins: []*loadbalance.Upstream{},
  391. BypassGlobalTLS: false,
  392. DefaultSiteOption: defaultSiteOption,
  393. DefaultSiteValue: dsVal,
  394. }
  395. preparedRootProxyRoute, err := dynamicProxyRouter.PrepareProxyRoute(&rootRoutingEndpoint)
  396. if err != nil {
  397. utils.SendErrorResponse(w, "unable to prepare root routing: "+err.Error())
  398. return
  399. }
  400. err = dynamicProxyRouter.SetProxyRouteAsRoot(preparedRootProxyRoute)
  401. if err != nil {
  402. utils.SendErrorResponse(w, "unable to update default site: "+err.Error())
  403. return
  404. }
  405. proxyEndpointCreated = &rootRoutingEndpoint
  406. } else {
  407. //Invalid eptype
  408. utils.SendErrorResponse(w, "invalid endpoint type")
  409. return
  410. }
  411. //Save the config to file
  412. err = SaveReverseProxyConfig(proxyEndpointCreated)
  413. if err != nil {
  414. SystemWideLogger.PrintAndLog("proxy-config", "Unable to save new proxy rule to file", err)
  415. return
  416. }
  417. //Update utm if exists
  418. UpdateUptimeMonitorTargets()
  419. utils.SendOK(w)
  420. }
  421. /*
  422. ReverseProxyHandleEditEndpoint handles proxy endpoint edit
  423. (host only, for root use Default Site page to edit)
  424. This endpoint do not handle basic auth credential update.
  425. The credential will be loaded from old config and reused
  426. */
  427. func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
  428. rootNameOrMatchingDomain, err := utils.PostPara(r, "rootname")
  429. if err != nil {
  430. utils.SendErrorResponse(w, "Target proxy rule not defined")
  431. return
  432. }
  433. tls, _ := utils.PostPara(r, "tls")
  434. if tls == "" {
  435. tls = "false"
  436. }
  437. useStickySession, _ := utils.PostBool(r, "ss")
  438. //Load bypass TLS option
  439. bpgtls, _ := utils.PostPara(r, "bpgtls")
  440. if bpgtls == "" {
  441. bpgtls = "false"
  442. }
  443. bypassGlobalTLS := (bpgtls == "true")
  444. //Disable uptime monitor
  445. disbleUtm, err := utils.PostBool(r, "dutm")
  446. if err != nil {
  447. disbleUtm = false
  448. }
  449. // Auth Provider
  450. authProviderTypeStr, _ := utils.PostPara(r, "authprovider")
  451. if authProviderTypeStr == "" {
  452. authProviderTypeStr = "0"
  453. }
  454. authProviderType, err := strconv.Atoi(authProviderTypeStr)
  455. if err != nil {
  456. utils.SendErrorResponse(w, "Invalid auth provider type")
  457. return
  458. }
  459. // Rate Limiting?
  460. rl, _ := utils.PostPara(r, "rate")
  461. if rl == "" {
  462. rl = "false"
  463. }
  464. requireRateLimit := (rl == "true")
  465. rlnum, _ := utils.PostPara(r, "ratenum")
  466. if rlnum == "" {
  467. rlnum = "0"
  468. }
  469. proxyRateLimit, err := strconv.ParseInt(rlnum, 10, 64)
  470. if err != nil {
  471. utils.SendErrorResponse(w, "invalid rate limit number")
  472. return
  473. }
  474. if requireRateLimit && proxyRateLimit <= 0 {
  475. utils.SendErrorResponse(w, "rate limit number must be greater than 0")
  476. return
  477. } else if proxyRateLimit < 0 {
  478. proxyRateLimit = 1000
  479. }
  480. //Load the previous basic auth credentials from current proxy rules
  481. targetProxyEntry, err := dynamicProxyRouter.LoadProxy(rootNameOrMatchingDomain)
  482. if err != nil {
  483. utils.SendErrorResponse(w, "Target proxy config not found or could not be loaded")
  484. return
  485. }
  486. tagStr, _ := utils.PostPara(r, "tags")
  487. tags := []string{}
  488. if tagStr != "" {
  489. tags = strings.Split(tagStr, ",")
  490. for i := range tags {
  491. tags[i] = strings.TrimSpace(tags[i])
  492. }
  493. }
  494. //Generate a new proxyEndpoint from the new config
  495. newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry)
  496. newProxyEndpoint.BypassGlobalTLS = bypassGlobalTLS
  497. if newProxyEndpoint.AuthenticationProvider == nil {
  498. newProxyEndpoint.AuthenticationProvider = &dynamicproxy.AuthenticationProvider{
  499. AuthMethod: dynamicproxy.AuthMethodNone,
  500. BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{},
  501. BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
  502. }
  503. }
  504. if authProviderType == 1 {
  505. newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodBasic
  506. } else if authProviderType == 2 {
  507. newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodAuthelia
  508. } else if authProviderType == 3 {
  509. newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodOauth2
  510. } else {
  511. newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodNone
  512. }
  513. newProxyEndpoint.RequireRateLimit = requireRateLimit
  514. newProxyEndpoint.RateLimit = proxyRateLimit
  515. newProxyEndpoint.UseStickySession = useStickySession
  516. newProxyEndpoint.DisableUptimeMonitor = disbleUtm
  517. newProxyEndpoint.Tags = tags
  518. //Prepare to replace the current routing rule
  519. readyRoutingRule, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
  520. if err != nil {
  521. utils.SendErrorResponse(w, err.Error())
  522. return
  523. }
  524. targetProxyEntry.Remove()
  525. dynamicProxyRouter.AddProxyRouteToRuntime(readyRoutingRule)
  526. //Save it to file
  527. SaveReverseProxyConfig(newProxyEndpoint)
  528. //Update uptime monitor targets
  529. UpdateUptimeMonitorTargets()
  530. utils.SendOK(w)
  531. }
  532. func ReverseProxyHandleAlias(w http.ResponseWriter, r *http.Request) {
  533. rootNameOrMatchingDomain, err := utils.PostPara(r, "ep")
  534. if err != nil {
  535. utils.SendErrorResponse(w, "Invalid ep given")
  536. return
  537. }
  538. //No need to check for type as root (/) can be set to default route
  539. //and hence, you will not need alias
  540. //Load the previous alias from current proxy rules
  541. targetProxyEntry, err := dynamicProxyRouter.LoadProxy(rootNameOrMatchingDomain)
  542. if err != nil {
  543. utils.SendErrorResponse(w, "Target proxy config not found or could not be loaded")
  544. return
  545. }
  546. newAliasJSON, err := utils.PostPara(r, "alias")
  547. if err != nil {
  548. //No new set of alias given
  549. utils.SendErrorResponse(w, "new alias not given")
  550. return
  551. }
  552. //Write new alias to runtime and file
  553. newAlias := []string{}
  554. err = json.Unmarshal([]byte(newAliasJSON), &newAlias)
  555. if err != nil {
  556. SystemWideLogger.PrintAndLog("proxy-config", "Unable to parse new alias list", err)
  557. utils.SendErrorResponse(w, "Invalid alias list given")
  558. return
  559. }
  560. //Set the current alias
  561. newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry)
  562. newProxyEndpoint.MatchingDomainAlias = newAlias
  563. // Prepare to replace the current routing rule
  564. readyRoutingRule, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
  565. if err != nil {
  566. utils.SendErrorResponse(w, err.Error())
  567. return
  568. }
  569. targetProxyEntry.Remove()
  570. dynamicProxyRouter.AddProxyRouteToRuntime(readyRoutingRule)
  571. // Save it to file
  572. err = SaveReverseProxyConfig(newProxyEndpoint)
  573. if err != nil {
  574. utils.SendErrorResponse(w, "Alias update failed")
  575. SystemWideLogger.PrintAndLog("proxy-config", "Unable to save alias update", err)
  576. }
  577. utils.SendOK(w)
  578. }
  579. func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) {
  580. ep, err := utils.PostPara(r, "ep")
  581. if err != nil {
  582. utils.SendErrorResponse(w, "Invalid ep given")
  583. return
  584. }
  585. //Remove the config from runtime
  586. err = dynamicProxyRouter.RemoveProxyEndpointByRootname(ep)
  587. if err != nil {
  588. utils.SendErrorResponse(w, err.Error())
  589. return
  590. }
  591. //Remove the config from file
  592. err = RemoveReverseProxyConfig(ep)
  593. if err != nil {
  594. utils.SendErrorResponse(w, err.Error())
  595. return
  596. }
  597. //Update uptime monitor
  598. UpdateUptimeMonitorTargets()
  599. utils.SendOK(w)
  600. }
  601. /*
  602. Handle update request for basic auth credential
  603. Require paramter: ep (Endpoint) and pytype (proxy Type)
  604. if request with GET, the handler will return current credentials
  605. on this endpoint by its username
  606. if request is POST, the handler will write the results to proxy config
  607. */
  608. func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
  609. if r.Method == http.MethodGet {
  610. ep, err := utils.GetPara(r, "ep")
  611. if err != nil {
  612. utils.SendErrorResponse(w, "Invalid ep given")
  613. return
  614. }
  615. //Load the target proxy object from router
  616. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  617. if err != nil {
  618. utils.SendErrorResponse(w, err.Error())
  619. return
  620. }
  621. usernames := []string{}
  622. for _, cred := range targetProxy.AuthenticationProvider.BasicAuthCredentials {
  623. usernames = append(usernames, cred.Username)
  624. }
  625. js, _ := json.Marshal(usernames)
  626. utils.SendJSONResponse(w, string(js))
  627. } else if r.Method == http.MethodPost {
  628. //Write to target
  629. ep, err := utils.PostPara(r, "ep")
  630. if err != nil {
  631. utils.SendErrorResponse(w, "Invalid ep given")
  632. return
  633. }
  634. creds, err := utils.PostPara(r, "creds")
  635. if err != nil {
  636. utils.SendErrorResponse(w, "Invalid ptype given")
  637. return
  638. }
  639. //Load the target proxy object from router
  640. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  641. if err != nil {
  642. utils.SendErrorResponse(w, err.Error())
  643. return
  644. }
  645. //Try to marshal the content of creds into the suitable structure
  646. newCredentials := []*dynamicproxy.BasicAuthUnhashedCredentials{}
  647. err = json.Unmarshal([]byte(creds), &newCredentials)
  648. if err != nil {
  649. utils.SendErrorResponse(w, "Malformed credential data")
  650. return
  651. }
  652. //Merge the credentials into the original config
  653. //If a new username exists in old config with no pw given, keep the old pw hash
  654. //If a new username is found with new password, hash it and push to credential slice
  655. mergedCredentials := []*dynamicproxy.BasicAuthCredentials{}
  656. for _, credential := range newCredentials {
  657. if credential.Password == "" {
  658. //Check if exists in the old credential files
  659. keepUnchange := false
  660. for _, oldCredEntry := range targetProxy.AuthenticationProvider.BasicAuthCredentials {
  661. if oldCredEntry.Username == credential.Username {
  662. //Exists! Reuse the old hash
  663. mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
  664. Username: oldCredEntry.Username,
  665. PasswordHash: oldCredEntry.PasswordHash,
  666. })
  667. keepUnchange = true
  668. }
  669. }
  670. if !keepUnchange {
  671. //This is a new username with no pw given
  672. utils.SendErrorResponse(w, "Access password for "+credential.Username+" is empty!")
  673. return
  674. }
  675. } else {
  676. //This username have given password
  677. mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
  678. Username: credential.Username,
  679. PasswordHash: auth.Hash(credential.Password),
  680. })
  681. }
  682. }
  683. targetProxy.AuthenticationProvider.BasicAuthCredentials = mergedCredentials
  684. //Save it to file
  685. SaveReverseProxyConfig(targetProxy)
  686. //Replace runtime configuration
  687. targetProxy.UpdateToRuntime()
  688. utils.SendOK(w)
  689. } else {
  690. http.Error(w, "invalid usage", http.StatusMethodNotAllowed)
  691. }
  692. }
  693. // List, Update or Remove the exception paths for basic auth.
  694. func ListProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
  695. if r.Method != http.MethodGet {
  696. http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
  697. }
  698. ep, err := utils.GetPara(r, "ep")
  699. if err != nil {
  700. utils.SendErrorResponse(w, "Invalid ep given")
  701. return
  702. }
  703. //Load the target proxy object from router
  704. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  705. if err != nil {
  706. utils.SendErrorResponse(w, err.Error())
  707. return
  708. }
  709. //List all the exception paths for this proxy
  710. results := targetProxy.AuthenticationProvider.BasicAuthExceptionRules
  711. if results == nil {
  712. //It is a config from a really old version of zoraxy. Overwrite it with empty array
  713. results = []*dynamicproxy.BasicAuthExceptionRule{}
  714. }
  715. js, _ := json.Marshal(results)
  716. utils.SendJSONResponse(w, string(js))
  717. return
  718. }
  719. func AddProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
  720. ep, err := utils.PostPara(r, "ep")
  721. if err != nil {
  722. utils.SendErrorResponse(w, "Invalid ep given")
  723. return
  724. }
  725. matchingPrefix, err := utils.PostPara(r, "prefix")
  726. if err != nil {
  727. utils.SendErrorResponse(w, "Invalid matching prefix given")
  728. return
  729. }
  730. //Load the target proxy object from router
  731. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  732. if err != nil {
  733. utils.SendErrorResponse(w, err.Error())
  734. return
  735. }
  736. //Check if the prefix starts with /. If not, prepend it
  737. if !strings.HasPrefix(matchingPrefix, "/") {
  738. matchingPrefix = "/" + matchingPrefix
  739. }
  740. //Add a new exception rule if it is not already exists
  741. alreadyExists := false
  742. for _, thisExceptionRule := range targetProxy.AuthenticationProvider.BasicAuthExceptionRules {
  743. if thisExceptionRule.PathPrefix == matchingPrefix {
  744. alreadyExists = true
  745. break
  746. }
  747. }
  748. if alreadyExists {
  749. utils.SendErrorResponse(w, "This matching path already exists")
  750. return
  751. }
  752. targetProxy.AuthenticationProvider.BasicAuthExceptionRules = append(targetProxy.AuthenticationProvider.BasicAuthExceptionRules, &dynamicproxy.BasicAuthExceptionRule{
  753. PathPrefix: strings.TrimSpace(matchingPrefix),
  754. })
  755. //Save configs to runtime and file
  756. targetProxy.UpdateToRuntime()
  757. SaveReverseProxyConfig(targetProxy)
  758. utils.SendOK(w)
  759. }
  760. func RemoveProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
  761. // Delete a rule
  762. ep, err := utils.PostPara(r, "ep")
  763. if err != nil {
  764. utils.SendErrorResponse(w, "Invalid ep given")
  765. return
  766. }
  767. matchingPrefix, err := utils.PostPara(r, "prefix")
  768. if err != nil {
  769. utils.SendErrorResponse(w, "Invalid matching prefix given")
  770. return
  771. }
  772. // Load the target proxy object from router
  773. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  774. if err != nil {
  775. utils.SendErrorResponse(w, err.Error())
  776. return
  777. }
  778. newExceptionRuleList := []*dynamicproxy.BasicAuthExceptionRule{}
  779. matchingExists := false
  780. for _, thisExceptionalRule := range targetProxy.AuthenticationProvider.BasicAuthExceptionRules {
  781. if thisExceptionalRule.PathPrefix != matchingPrefix {
  782. newExceptionRuleList = append(newExceptionRuleList, thisExceptionalRule)
  783. } else {
  784. matchingExists = true
  785. }
  786. }
  787. if !matchingExists {
  788. utils.SendErrorResponse(w, "target matching rule not exists")
  789. return
  790. }
  791. targetProxy.AuthenticationProvider.BasicAuthExceptionRules = newExceptionRuleList
  792. // Save configs to runtime and file
  793. targetProxy.UpdateToRuntime()
  794. SaveReverseProxyConfig(targetProxy)
  795. utils.SendOK(w)
  796. }
  797. // Report the current status of the reverse proxy server
  798. func ReverseProxyStatus(w http.ResponseWriter, r *http.Request) {
  799. js, _ := json.Marshal(dynamicProxyRouter)
  800. utils.SendJSONResponse(w, string(js))
  801. }
  802. // Toggle a certain rule on and off
  803. func ReverseProxyToggleRuleSet(w http.ResponseWriter, r *http.Request) {
  804. //No need to check for type as root cannot be turned off
  805. ep, err := utils.PostPara(r, "ep")
  806. if err != nil {
  807. utils.SendErrorResponse(w, "invalid ep given")
  808. return
  809. }
  810. targetProxyRule, err := dynamicProxyRouter.LoadProxy(ep)
  811. if err != nil {
  812. utils.SendErrorResponse(w, "invalid endpoint given")
  813. return
  814. }
  815. enableStr, err := utils.PostPara(r, "enable")
  816. if err != nil {
  817. enableStr = "true"
  818. }
  819. //Flip the enable and disabled tag state
  820. ruleDisabled := enableStr == "false"
  821. targetProxyRule.Disabled = ruleDisabled
  822. err = SaveReverseProxyConfig(targetProxyRule)
  823. if err != nil {
  824. utils.SendErrorResponse(w, "unable to save updated rule")
  825. return
  826. }
  827. //Update uptime monitor
  828. UpdateUptimeMonitorTargets()
  829. utils.SendOK(w)
  830. }
  831. func ReverseProxyListDetail(w http.ResponseWriter, r *http.Request) {
  832. eptype, err := utils.PostPara(r, "type") //Support root and host
  833. if err != nil {
  834. utils.SendErrorResponse(w, "type not defined")
  835. return
  836. }
  837. if eptype == "host" {
  838. epname, err := utils.PostPara(r, "epname")
  839. if err != nil {
  840. utils.SendErrorResponse(w, "epname not defined")
  841. return
  842. }
  843. epname = strings.ToLower(strings.TrimSpace(epname))
  844. endpointRaw, ok := dynamicProxyRouter.ProxyEndpoints.Load(epname)
  845. if !ok {
  846. utils.SendErrorResponse(w, "proxy rule not found")
  847. return
  848. }
  849. targetEndpoint := dynamicproxy.CopyEndpoint(endpointRaw.(*dynamicproxy.ProxyEndpoint))
  850. js, _ := json.Marshal(targetEndpoint)
  851. utils.SendJSONResponse(w, string(js))
  852. } else if eptype == "root" {
  853. js, _ := json.Marshal(dynamicProxyRouter.Root)
  854. utils.SendJSONResponse(w, string(js))
  855. } else {
  856. utils.SendErrorResponse(w, "Invalid type given")
  857. }
  858. }
  859. func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
  860. eptype, err := utils.PostPara(r, "type") //Support root and host
  861. if err != nil {
  862. utils.SendErrorResponse(w, "type not defined")
  863. return
  864. }
  865. if eptype == "host" {
  866. results := []*dynamicproxy.ProxyEndpoint{}
  867. dynamicProxyRouter.ProxyEndpoints.Range(func(key, value interface{}) bool {
  868. thisEndpoint := dynamicproxy.CopyEndpoint(value.(*dynamicproxy.ProxyEndpoint))
  869. //Clear the auth passwords before showing to front-end
  870. cleanedCredentials := []*dynamicproxy.BasicAuthCredentials{}
  871. for _, user := range thisEndpoint.AuthenticationProvider.BasicAuthCredentials {
  872. cleanedCredentials = append(cleanedCredentials, &dynamicproxy.BasicAuthCredentials{
  873. Username: user.Username,
  874. PasswordHash: "",
  875. })
  876. }
  877. thisEndpoint.AuthenticationProvider.BasicAuthCredentials = cleanedCredentials
  878. results = append(results, thisEndpoint)
  879. return true
  880. })
  881. sort.Slice(results, func(i, j int) bool {
  882. return results[i].RootOrMatchingDomain < results[j].RootOrMatchingDomain
  883. })
  884. js, _ := json.Marshal(results)
  885. utils.SendJSONResponse(w, string(js))
  886. } else if eptype == "root" {
  887. js, _ := json.Marshal(dynamicProxyRouter.Root)
  888. utils.SendJSONResponse(w, string(js))
  889. } else {
  890. utils.SendErrorResponse(w, "Invalid type given")
  891. }
  892. }
  893. // Handle port 80 incoming traffics
  894. func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) {
  895. if r.Method == http.MethodGet {
  896. //Load the current status
  897. currentEnabled := false
  898. err := sysdb.Read("settings", "listenP80", &currentEnabled)
  899. if err != nil {
  900. utils.SendErrorResponse(w, err.Error())
  901. return
  902. }
  903. js, _ := json.Marshal(currentEnabled)
  904. utils.SendJSONResponse(w, string(js))
  905. } else if r.Method == http.MethodPost {
  906. enabled, err := utils.PostPara(r, "enable")
  907. if err != nil {
  908. utils.SendErrorResponse(w, "enable state not set")
  909. return
  910. }
  911. if enabled == "true" {
  912. sysdb.Write("settings", "listenP80", true)
  913. SystemWideLogger.Println("Enabling port 80 listener")
  914. dynamicProxyRouter.UpdatePort80ListenerState(true)
  915. } else if enabled == "false" {
  916. sysdb.Write("settings", "listenP80", false)
  917. SystemWideLogger.Println("Disabling port 80 listener")
  918. dynamicProxyRouter.UpdatePort80ListenerState(false)
  919. } else {
  920. utils.SendErrorResponse(w, "invalid mode given: "+enabled)
  921. }
  922. utils.SendOK(w)
  923. } else {
  924. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  925. }
  926. }
  927. // Handle https redirect
  928. func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) {
  929. if r.Method == http.MethodGet {
  930. currentRedirectToHttps := false
  931. //Load the current status
  932. err := sysdb.Read("settings", "redirect", &currentRedirectToHttps)
  933. if err != nil {
  934. utils.SendErrorResponse(w, err.Error())
  935. return
  936. }
  937. js, _ := json.Marshal(currentRedirectToHttps)
  938. utils.SendJSONResponse(w, string(js))
  939. } else if r.Method == http.MethodPost {
  940. useRedirect, err := utils.PostBool(r, "set")
  941. if err != nil {
  942. utils.SendErrorResponse(w, "status not set")
  943. return
  944. }
  945. if dynamicProxyRouter.Option.Port == 80 {
  946. utils.SendErrorResponse(w, "This option is not available when listening on port 80")
  947. return
  948. }
  949. if useRedirect {
  950. sysdb.Write("settings", "redirect", true)
  951. SystemWideLogger.Println("Updating force HTTPS redirection to true")
  952. dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
  953. } else {
  954. sysdb.Write("settings", "redirect", false)
  955. SystemWideLogger.Println("Updating force HTTPS redirection to false")
  956. dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false)
  957. }
  958. utils.SendOK(w)
  959. } else {
  960. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  961. }
  962. }
  963. // Handle checking if the current user is accessing via the reverse proxied interface
  964. // Of the management interface.
  965. func HandleManagementProxyCheck(w http.ResponseWriter, r *http.Request) {
  966. isProxied := dynamicProxyRouter.IsProxiedSubdomain(r)
  967. js, _ := json.Marshal(isProxied)
  968. utils.SendJSONResponse(w, string(js))
  969. }
  970. func HandleDevelopmentModeChange(w http.ResponseWriter, r *http.Request) {
  971. enableDevelopmentModeStr, err := utils.GetPara(r, "enable")
  972. if err != nil {
  973. //Load the current development mode toggle state
  974. js, _ := json.Marshal(dynamicProxyRouter.Option.NoCache)
  975. utils.SendJSONResponse(w, string(js))
  976. } else {
  977. //Write changes to runtime
  978. enableDevelopmentMode := false
  979. if enableDevelopmentModeStr == "true" {
  980. enableDevelopmentMode = true
  981. }
  982. //Write changes to runtime
  983. dynamicProxyRouter.Option.NoCache = enableDevelopmentMode
  984. //Write changes to database
  985. sysdb.Write("settings", "devMode", enableDevelopmentMode)
  986. utils.SendOK(w)
  987. }
  988. }
  989. // Handle incoming port set. Change the current proxy incoming port
  990. func HandleIncomingPortSet(w http.ResponseWriter, r *http.Request) {
  991. newIncomingPort, err := utils.PostPara(r, "incoming")
  992. if err != nil {
  993. utils.SendErrorResponse(w, "invalid incoming port given")
  994. return
  995. }
  996. newIncomingPortInt, err := strconv.Atoi(newIncomingPort)
  997. if err != nil {
  998. utils.SendErrorResponse(w, "Invalid incoming port given")
  999. return
  1000. }
  1001. rootProxyTargetOrigin := ""
  1002. if len(dynamicProxyRouter.Root.ActiveOrigins) > 0 {
  1003. rootProxyTargetOrigin = dynamicProxyRouter.Root.ActiveOrigins[0].OriginIpOrDomain
  1004. }
  1005. //Check if it is identical as proxy root (recursion!)
  1006. if dynamicProxyRouter.Root == nil || rootProxyTargetOrigin == "" {
  1007. //Check if proxy root is set before checking recursive listen
  1008. //Fixing issue #43
  1009. utils.SendErrorResponse(w, "Set Proxy Root before changing inbound port")
  1010. return
  1011. }
  1012. proxyRoot := strings.TrimSuffix(rootProxyTargetOrigin, "/")
  1013. if strings.EqualFold(proxyRoot, "localhost:"+strconv.Itoa(newIncomingPortInt)) || strings.EqualFold(proxyRoot, "127.0.0.1:"+strconv.Itoa(newIncomingPortInt)) {
  1014. //Listening port is same as proxy root
  1015. //Not allow recursive settings
  1016. utils.SendErrorResponse(w, "Recursive listening port! Check your proxy root settings.")
  1017. return
  1018. }
  1019. //Stop and change the setting of the reverse proxy service
  1020. if dynamicProxyRouter.Running {
  1021. dynamicProxyRouter.StopProxyService()
  1022. dynamicProxyRouter.Option.Port = newIncomingPortInt
  1023. time.Sleep(1 * time.Second) //Fixed start fail issue
  1024. dynamicProxyRouter.StartProxyService()
  1025. } else {
  1026. //Only change setting but not starting the proxy service
  1027. dynamicProxyRouter.Option.Port = newIncomingPortInt
  1028. }
  1029. sysdb.Write("settings", "inbound", newIncomingPortInt)
  1030. utils.SendOK(w)
  1031. }
  1032. /* Handle Custom Header Rules */
  1033. //List all the custom header defined in this proxy rule
  1034. func HandleCustomHeaderList(w http.ResponseWriter, r *http.Request) {
  1035. epType, err := utils.GetPara(r, "type")
  1036. if err != nil {
  1037. utils.SendErrorResponse(w, "endpoint type not defined")
  1038. return
  1039. }
  1040. domain, err := utils.GetPara(r, "domain")
  1041. if err != nil {
  1042. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1043. return
  1044. }
  1045. var targetProxyEndpoint *dynamicproxy.ProxyEndpoint
  1046. if epType == "root" {
  1047. targetProxyEndpoint = dynamicProxyRouter.Root
  1048. } else {
  1049. ep, err := dynamicProxyRouter.LoadProxy(domain)
  1050. if err != nil {
  1051. utils.SendErrorResponse(w, "target endpoint not exists")
  1052. return
  1053. }
  1054. targetProxyEndpoint = ep
  1055. }
  1056. //List all custom headers
  1057. customHeaderList := targetProxyEndpoint.HeaderRewriteRules.UserDefinedHeaders
  1058. if customHeaderList == nil {
  1059. customHeaderList = []*rewrite.UserDefinedHeader{}
  1060. }
  1061. js, _ := json.Marshal(customHeaderList)
  1062. utils.SendJSONResponse(w, string(js))
  1063. }
  1064. // Add a new header to the target endpoint
  1065. func HandleCustomHeaderAdd(w http.ResponseWriter, r *http.Request) {
  1066. rewriteType, err := utils.PostPara(r, "type")
  1067. if err != nil {
  1068. utils.SendErrorResponse(w, "rewriteType not defined")
  1069. return
  1070. }
  1071. domain, err := utils.PostPara(r, "domain")
  1072. if err != nil {
  1073. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1074. return
  1075. }
  1076. direction, err := utils.PostPara(r, "direction")
  1077. if err != nil {
  1078. utils.SendErrorResponse(w, "HTTP modifiy direction not set")
  1079. return
  1080. }
  1081. name, err := utils.PostPara(r, "name")
  1082. if err != nil {
  1083. utils.SendErrorResponse(w, "HTTP header name not set")
  1084. return
  1085. }
  1086. value, err := utils.PostPara(r, "value")
  1087. if err != nil && rewriteType == "add" {
  1088. utils.SendErrorResponse(w, "HTTP header value not set")
  1089. return
  1090. }
  1091. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1092. if err != nil {
  1093. utils.SendErrorResponse(w, "target endpoint not exists")
  1094. return
  1095. }
  1096. //Create a Custom Header Definition type
  1097. var rewriteDirection rewrite.HeaderDirection
  1098. if direction == "toOrigin" {
  1099. rewriteDirection = rewrite.HeaderDirection_ZoraxyToUpstream
  1100. } else if direction == "toClient" {
  1101. rewriteDirection = rewrite.HeaderDirection_ZoraxyToDownstream
  1102. } else {
  1103. //Unknown direction
  1104. utils.SendErrorResponse(w, "header rewrite direction not supported")
  1105. return
  1106. }
  1107. isRemove := false
  1108. if rewriteType == "remove" {
  1109. isRemove = true
  1110. }
  1111. headerRewriteDefinition := rewrite.UserDefinedHeader{
  1112. Key: name,
  1113. Value: value,
  1114. Direction: rewriteDirection,
  1115. IsRemove: isRemove,
  1116. }
  1117. //Create a new custom header object
  1118. err = targetProxyEndpoint.AddUserDefinedHeader(&headerRewriteDefinition)
  1119. if err != nil {
  1120. utils.SendErrorResponse(w, "unable to add header rewrite rule: "+err.Error())
  1121. return
  1122. }
  1123. //Save it (no need reload as header are not handled by dpcore)
  1124. err = SaveReverseProxyConfig(targetProxyEndpoint)
  1125. if err != nil {
  1126. utils.SendErrorResponse(w, "unable to save update")
  1127. return
  1128. }
  1129. utils.SendOK(w)
  1130. }
  1131. // Remove a header from the target endpoint
  1132. func HandleCustomHeaderRemove(w http.ResponseWriter, r *http.Request) {
  1133. domain, err := utils.PostPara(r, "domain")
  1134. if err != nil {
  1135. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1136. return
  1137. }
  1138. name, err := utils.PostPara(r, "name")
  1139. if err != nil {
  1140. utils.SendErrorResponse(w, "HTTP header name not set")
  1141. return
  1142. }
  1143. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1144. if err != nil {
  1145. utils.SendErrorResponse(w, "target endpoint not exists")
  1146. return
  1147. }
  1148. err = targetProxyEndpoint.RemoveUserDefinedHeader(name)
  1149. if err != nil {
  1150. utils.SendErrorResponse(w, "unable to remove header rewrite rule: "+err.Error())
  1151. return
  1152. }
  1153. err = SaveReverseProxyConfig(targetProxyEndpoint)
  1154. if err != nil {
  1155. utils.SendErrorResponse(w, "unable to save update")
  1156. return
  1157. }
  1158. utils.SendOK(w)
  1159. }
  1160. func HandleHostOverwrite(w http.ResponseWriter, r *http.Request) {
  1161. domain, err := utils.PostPara(r, "domain")
  1162. if err != nil {
  1163. domain, err = utils.GetPara(r, "domain")
  1164. if err != nil {
  1165. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1166. return
  1167. }
  1168. }
  1169. //Get the proxy endpoint object dedicated to this domain
  1170. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1171. if err != nil {
  1172. utils.SendErrorResponse(w, "target endpoint not exists")
  1173. return
  1174. }
  1175. if r.Method == http.MethodGet {
  1176. //Get the current host header
  1177. js, _ := json.Marshal(targetProxyEndpoint.HeaderRewriteRules.RequestHostOverwrite)
  1178. utils.SendJSONResponse(w, string(js))
  1179. } else if r.Method == http.MethodPost {
  1180. //Set the new host header
  1181. newHostname, _ := utils.PostPara(r, "hostname")
  1182. //As this will require change in the proxy instance we are running
  1183. //we need to clone and respawn this proxy endpoint
  1184. newProxyEndpoint := targetProxyEndpoint.Clone()
  1185. newProxyEndpoint.HeaderRewriteRules.RequestHostOverwrite = newHostname
  1186. //Save proxy endpoint
  1187. err = SaveReverseProxyConfig(newProxyEndpoint)
  1188. if err != nil {
  1189. utils.SendErrorResponse(w, err.Error())
  1190. return
  1191. }
  1192. //Spawn a new endpoint with updated dpcore
  1193. preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
  1194. if err != nil {
  1195. utils.SendErrorResponse(w, err.Error())
  1196. return
  1197. }
  1198. //Remove the old endpoint
  1199. err = targetProxyEndpoint.Remove()
  1200. if err != nil {
  1201. utils.SendErrorResponse(w, err.Error())
  1202. return
  1203. }
  1204. //Add the newly prepared endpoint to runtime
  1205. err = dynamicProxyRouter.AddProxyRouteToRuntime(preparedEndpoint)
  1206. if err != nil {
  1207. utils.SendErrorResponse(w, err.Error())
  1208. return
  1209. }
  1210. //Print log message
  1211. if newHostname != "" {
  1212. SystemWideLogger.Println("Updated " + domain + " hostname overwrite to: " + newHostname)
  1213. } else {
  1214. SystemWideLogger.Println("Removed " + domain + " hostname overwrite")
  1215. }
  1216. utils.SendOK(w)
  1217. } else {
  1218. //Invalid method
  1219. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1220. }
  1221. }
  1222. // HandleHopByHop get and set the hop by hop remover state
  1223. // note that it shows the DISABLE STATE of hop-by-hop remover, not the enable state
  1224. func HandleHopByHop(w http.ResponseWriter, r *http.Request) {
  1225. domain, err := utils.PostPara(r, "domain")
  1226. if err != nil {
  1227. domain, err = utils.GetPara(r, "domain")
  1228. if err != nil {
  1229. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1230. return
  1231. }
  1232. }
  1233. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1234. if err != nil {
  1235. utils.SendErrorResponse(w, "target endpoint not exists")
  1236. return
  1237. }
  1238. if r.Method == http.MethodGet {
  1239. //Get the current hop by hop header state
  1240. js, _ := json.Marshal(!targetProxyEndpoint.HeaderRewriteRules.DisableHopByHopHeaderRemoval)
  1241. utils.SendJSONResponse(w, string(js))
  1242. } else if r.Method == http.MethodPost {
  1243. //Set the hop by hop header state
  1244. enableHopByHopRemover, _ := utils.PostBool(r, "removeHopByHop")
  1245. //As this will require change in the proxy instance we are running
  1246. //we need to clone and respawn this proxy endpoint
  1247. newProxyEndpoint := targetProxyEndpoint.Clone()
  1248. //Storage file use false as default, so disable removal = not enable remover
  1249. newProxyEndpoint.HeaderRewriteRules.DisableHopByHopHeaderRemoval = !enableHopByHopRemover
  1250. //Save proxy endpoint
  1251. err = SaveReverseProxyConfig(newProxyEndpoint)
  1252. if err != nil {
  1253. utils.SendErrorResponse(w, err.Error())
  1254. return
  1255. }
  1256. //Spawn a new endpoint with updated dpcore
  1257. preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
  1258. if err != nil {
  1259. utils.SendErrorResponse(w, err.Error())
  1260. return
  1261. }
  1262. //Remove the old endpoint
  1263. err = targetProxyEndpoint.Remove()
  1264. if err != nil {
  1265. utils.SendErrorResponse(w, err.Error())
  1266. return
  1267. }
  1268. //Add the newly prepared endpoint to runtime
  1269. err = dynamicProxyRouter.AddProxyRouteToRuntime(preparedEndpoint)
  1270. if err != nil {
  1271. utils.SendErrorResponse(w, err.Error())
  1272. return
  1273. }
  1274. //Print log message
  1275. if enableHopByHopRemover {
  1276. SystemWideLogger.Println("Enabled hop-by-hop headers removal on " + domain)
  1277. } else {
  1278. SystemWideLogger.Println("Disabled hop-by-hop headers removal on " + domain)
  1279. }
  1280. utils.SendOK(w)
  1281. } else {
  1282. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1283. }
  1284. }
  1285. // Handle view or edit HSTS states
  1286. func HandleHSTSState(w http.ResponseWriter, r *http.Request) {
  1287. domain, err := utils.PostPara(r, "domain")
  1288. if err != nil {
  1289. domain, err = utils.GetPara(r, "domain")
  1290. if err != nil {
  1291. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1292. return
  1293. }
  1294. }
  1295. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1296. if err != nil {
  1297. utils.SendErrorResponse(w, "target endpoint not exists")
  1298. return
  1299. }
  1300. if r.Method == http.MethodGet {
  1301. //Return current HSTS enable state
  1302. hstsAge := targetProxyEndpoint.HeaderRewriteRules.HSTSMaxAge
  1303. js, _ := json.Marshal(hstsAge)
  1304. utils.SendJSONResponse(w, string(js))
  1305. return
  1306. } else if r.Method == http.MethodPost {
  1307. newMaxAge, err := utils.PostInt(r, "maxage")
  1308. if err != nil {
  1309. utils.SendErrorResponse(w, "maxage not defeined")
  1310. return
  1311. }
  1312. if newMaxAge == 0 || newMaxAge >= 31536000 {
  1313. targetProxyEndpoint.HeaderRewriteRules.HSTSMaxAge = int64(newMaxAge)
  1314. err = SaveReverseProxyConfig(targetProxyEndpoint)
  1315. if err != nil {
  1316. utils.SendErrorResponse(w, "save HSTS state failed: "+err.Error())
  1317. return
  1318. }
  1319. targetProxyEndpoint.UpdateToRuntime()
  1320. } else {
  1321. utils.SendErrorResponse(w, "invalid max age given")
  1322. return
  1323. }
  1324. utils.SendOK(w)
  1325. return
  1326. }
  1327. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1328. }
  1329. // HandlePermissionPolicy handle read or write to permission policy
  1330. func HandlePermissionPolicy(w http.ResponseWriter, r *http.Request) {
  1331. domain, err := utils.PostPara(r, "domain")
  1332. if err != nil {
  1333. domain, err = utils.GetPara(r, "domain")
  1334. if err != nil {
  1335. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1336. return
  1337. }
  1338. }
  1339. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1340. if err != nil {
  1341. utils.SendErrorResponse(w, "target endpoint not exists")
  1342. return
  1343. }
  1344. if r.Method == http.MethodGet {
  1345. type CurrentPolicyState struct {
  1346. PPEnabled bool
  1347. CurrentPolicy *permissionpolicy.PermissionsPolicy
  1348. }
  1349. currentPolicy := permissionpolicy.GetDefaultPermissionPolicy()
  1350. if targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy != nil {
  1351. currentPolicy = targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy
  1352. }
  1353. result := CurrentPolicyState{
  1354. PPEnabled: targetProxyEndpoint.HeaderRewriteRules.EnablePermissionPolicyHeader,
  1355. CurrentPolicy: currentPolicy,
  1356. }
  1357. js, _ := json.Marshal(result)
  1358. utils.SendJSONResponse(w, string(js))
  1359. return
  1360. } else if r.Method == http.MethodPost {
  1361. //Update the enable state of permission policy
  1362. enableState, err := utils.PostBool(r, "enable")
  1363. if err != nil {
  1364. utils.SendErrorResponse(w, "invalid enable state given")
  1365. return
  1366. }
  1367. targetProxyEndpoint.HeaderRewriteRules.EnablePermissionPolicyHeader = enableState
  1368. SaveReverseProxyConfig(targetProxyEndpoint)
  1369. targetProxyEndpoint.UpdateToRuntime()
  1370. utils.SendOK(w)
  1371. return
  1372. } else if r.Method == http.MethodPut {
  1373. //Store the new permission policy
  1374. newPermissionPolicyJSONString, err := utils.PostPara(r, "pp")
  1375. if err != nil {
  1376. utils.SendErrorResponse(w, "missing pp (permission policy) paramter")
  1377. return
  1378. }
  1379. //Parse the permission policy from JSON string
  1380. newPermissionPolicy := permissionpolicy.GetDefaultPermissionPolicy()
  1381. err = json.Unmarshal([]byte(newPermissionPolicyJSONString), &newPermissionPolicy)
  1382. if err != nil {
  1383. utils.SendErrorResponse(w, "permission policy parse error: "+err.Error())
  1384. return
  1385. }
  1386. //Save it to file
  1387. targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy = newPermissionPolicy
  1388. SaveReverseProxyConfig(targetProxyEndpoint)
  1389. targetProxyEndpoint.UpdateToRuntime()
  1390. utils.SendOK(w)
  1391. return
  1392. }
  1393. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1394. }
  1395. func HandleWsHeaderBehavior(w http.ResponseWriter, r *http.Request) {
  1396. domain, err := utils.PostPara(r, "domain")
  1397. if err != nil {
  1398. domain, err = utils.GetPara(r, "domain")
  1399. if err != nil {
  1400. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1401. return
  1402. }
  1403. }
  1404. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1405. if err != nil {
  1406. utils.SendErrorResponse(w, "target endpoint not exists")
  1407. return
  1408. }
  1409. if r.Method == http.MethodGet {
  1410. js, _ := json.Marshal(targetProxyEndpoint.EnableWebsocketCustomHeaders)
  1411. utils.SendJSONResponse(w, string(js))
  1412. } else if r.Method == http.MethodPost {
  1413. enableWsHeader, err := utils.PostBool(r, "enable")
  1414. if err != nil {
  1415. utils.SendErrorResponse(w, "invalid enable state given")
  1416. return
  1417. }
  1418. targetProxyEndpoint.EnableWebsocketCustomHeaders = enableWsHeader
  1419. SaveReverseProxyConfig(targetProxyEndpoint)
  1420. targetProxyEndpoint.UpdateToRuntime()
  1421. utils.SendOK(w)
  1422. } else {
  1423. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1424. }
  1425. }