reverseproxy.go 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616
  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 := 443
  28. autoStartReverseProxy := true
  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. inboundPort = 8743
  42. SystemWideLogger.Println("Port 443 is occupied. Switching to backup port 8743 instead")
  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. var proxyEndpointCreated *dynamicproxy.ProxyEndpoint
  270. if eptype == "host" {
  271. rootOrMatchingDomain, err := utils.PostPara(r, "rootname")
  272. if err != nil {
  273. utils.SendErrorResponse(w, "hostname not defined")
  274. return
  275. }
  276. rootOrMatchingDomain = strings.TrimSpace(rootOrMatchingDomain)
  277. //Check if it contains ",", if yes, split the remainings as alias
  278. aliasHostnames := []string{}
  279. if strings.Contains(rootOrMatchingDomain, ",") {
  280. matchingDomains := strings.Split(rootOrMatchingDomain, ",")
  281. if len(matchingDomains) > 1 {
  282. rootOrMatchingDomain = matchingDomains[0]
  283. for _, aliasHostname := range matchingDomains[1:] {
  284. //Filter out any space
  285. aliasHostnames = append(aliasHostnames, strings.TrimSpace(aliasHostname))
  286. }
  287. }
  288. }
  289. //Generate a default authenticaion provider
  290. authMethod := dynamicproxy.AuthMethodNone
  291. if requireBasicAuth {
  292. authMethod = dynamicproxy.AuthMethodBasic
  293. }
  294. thisAuthenticationProvider := dynamicproxy.AuthenticationProvider{
  295. AuthMethod: authMethod,
  296. BasicAuthCredentials: basicAuthCredentials,
  297. BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
  298. }
  299. //Generate a proxy endpoint object
  300. thisProxyEndpoint := dynamicproxy.ProxyEndpoint{
  301. //I/O
  302. ProxyType: dynamicproxy.ProxyTypeHost,
  303. RootOrMatchingDomain: rootOrMatchingDomain,
  304. MatchingDomainAlias: aliasHostnames,
  305. ActiveOrigins: []*loadbalance.Upstream{
  306. {
  307. OriginIpOrDomain: endpoint,
  308. RequireTLS: useTLS,
  309. SkipCertValidations: skipTlsValidation,
  310. SkipWebSocketOriginCheck: bypassWebsocketOriginCheck,
  311. Weight: 1,
  312. },
  313. },
  314. InactiveOrigins: []*loadbalance.Upstream{},
  315. UseStickySession: useStickySession,
  316. //TLS
  317. BypassGlobalTLS: useBypassGlobalTLS,
  318. AccessFilterUUID: accessRuleID,
  319. //VDir
  320. VirtualDirectories: []*dynamicproxy.VirtualDirectoryEndpoint{},
  321. //Custom headers
  322. //Auth
  323. AuthenticationProvider: &thisAuthenticationProvider,
  324. //Header Rewrite
  325. HeaderRewriteRules: dynamicproxy.GetDefaultHeaderRewriteRules(),
  326. //Default Site
  327. DefaultSiteOption: 0,
  328. DefaultSiteValue: "",
  329. // Rate Limit
  330. RequireRateLimit: requireRateLimit,
  331. RateLimit: int64(proxyRateLimit),
  332. }
  333. preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisProxyEndpoint)
  334. if err != nil {
  335. utils.SendErrorResponse(w, "unable to prepare proxy route to target endpoint: "+err.Error())
  336. return
  337. }
  338. dynamicProxyRouter.AddProxyRouteToRuntime(preparedEndpoint)
  339. proxyEndpointCreated = &thisProxyEndpoint
  340. } else if eptype == "root" {
  341. //Get the default site options and target
  342. dsOptString, err := utils.PostPara(r, "defaultSiteOpt")
  343. if err != nil {
  344. utils.SendErrorResponse(w, "default site action not defined")
  345. return
  346. }
  347. var defaultSiteOption int = 1
  348. opt, err := strconv.Atoi(dsOptString)
  349. if err != nil {
  350. utils.SendErrorResponse(w, "invalid default site option")
  351. return
  352. }
  353. defaultSiteOption = opt
  354. dsVal, err := utils.PostPara(r, "defaultSiteVal")
  355. if err != nil && (defaultSiteOption == 1 || defaultSiteOption == 2) {
  356. //Reverse proxy or redirect, must require value to be set
  357. utils.SendErrorResponse(w, "target not defined")
  358. return
  359. }
  360. //Write the root options to file
  361. rootRoutingEndpoint := dynamicproxy.ProxyEndpoint{
  362. ProxyType: dynamicproxy.ProxyTypeRoot,
  363. RootOrMatchingDomain: "/",
  364. ActiveOrigins: []*loadbalance.Upstream{
  365. {
  366. OriginIpOrDomain: endpoint,
  367. RequireTLS: useTLS,
  368. SkipCertValidations: true,
  369. SkipWebSocketOriginCheck: true,
  370. Weight: 1,
  371. },
  372. },
  373. InactiveOrigins: []*loadbalance.Upstream{},
  374. BypassGlobalTLS: false,
  375. DefaultSiteOption: defaultSiteOption,
  376. DefaultSiteValue: dsVal,
  377. }
  378. preparedRootProxyRoute, err := dynamicProxyRouter.PrepareProxyRoute(&rootRoutingEndpoint)
  379. if err != nil {
  380. utils.SendErrorResponse(w, "unable to prepare root routing: "+err.Error())
  381. return
  382. }
  383. err = dynamicProxyRouter.SetProxyRouteAsRoot(preparedRootProxyRoute)
  384. if err != nil {
  385. utils.SendErrorResponse(w, "unable to update default site: "+err.Error())
  386. return
  387. }
  388. proxyEndpointCreated = &rootRoutingEndpoint
  389. } else {
  390. //Invalid eptype
  391. utils.SendErrorResponse(w, "invalid endpoint type")
  392. return
  393. }
  394. //Save the config to file
  395. err = SaveReverseProxyConfig(proxyEndpointCreated)
  396. if err != nil {
  397. SystemWideLogger.PrintAndLog("proxy-config", "Unable to save new proxy rule to file", err)
  398. return
  399. }
  400. //Update utm if exists
  401. UpdateUptimeMonitorTargets()
  402. utils.SendOK(w)
  403. }
  404. /*
  405. ReverseProxyHandleEditEndpoint handles proxy endpoint edit
  406. (host only, for root use Default Site page to edit)
  407. This endpoint do not handle basic auth credential update.
  408. The credential will be loaded from old config and reused
  409. */
  410. func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
  411. rootNameOrMatchingDomain, err := utils.PostPara(r, "rootname")
  412. if err != nil {
  413. utils.SendErrorResponse(w, "Target proxy rule not defined")
  414. return
  415. }
  416. tls, _ := utils.PostPara(r, "tls")
  417. if tls == "" {
  418. tls = "false"
  419. }
  420. useStickySession, _ := utils.PostBool(r, "ss")
  421. //Load bypass TLS option
  422. bpgtls, _ := utils.PostPara(r, "bpgtls")
  423. if bpgtls == "" {
  424. bpgtls = "false"
  425. }
  426. bypassGlobalTLS := (bpgtls == "true")
  427. //Disable uptime monitor
  428. disbleUtm, err := utils.PostBool(r, "dutm")
  429. if err != nil {
  430. disbleUtm = false
  431. }
  432. // Auth Provider
  433. authProviderTypeStr, _ := utils.PostPara(r, "authprovider")
  434. if authProviderTypeStr == "" {
  435. authProviderTypeStr = "0"
  436. }
  437. authProviderType, err := strconv.Atoi(authProviderTypeStr)
  438. if err != nil {
  439. utils.SendErrorResponse(w, "Invalid auth provider type")
  440. return
  441. }
  442. // Rate Limiting?
  443. rl, _ := utils.PostPara(r, "rate")
  444. if rl == "" {
  445. rl = "false"
  446. }
  447. requireRateLimit := (rl == "true")
  448. rlnum, _ := utils.PostPara(r, "ratenum")
  449. if rlnum == "" {
  450. rlnum = "0"
  451. }
  452. proxyRateLimit, err := strconv.ParseInt(rlnum, 10, 64)
  453. if err != nil {
  454. utils.SendErrorResponse(w, "invalid rate limit number")
  455. return
  456. }
  457. if requireRateLimit && proxyRateLimit <= 0 {
  458. utils.SendErrorResponse(w, "rate limit number must be greater than 0")
  459. return
  460. } else if proxyRateLimit < 0 {
  461. proxyRateLimit = 1000
  462. }
  463. //Load the previous basic auth credentials from current proxy rules
  464. targetProxyEntry, err := dynamicProxyRouter.LoadProxy(rootNameOrMatchingDomain)
  465. if err != nil {
  466. utils.SendErrorResponse(w, "Target proxy config not found or could not be loaded")
  467. return
  468. }
  469. //Generate a new proxyEndpoint from the new config
  470. newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry)
  471. newProxyEndpoint.BypassGlobalTLS = bypassGlobalTLS
  472. if newProxyEndpoint.AuthenticationProvider == nil {
  473. newProxyEndpoint.AuthenticationProvider = &dynamicproxy.AuthenticationProvider{
  474. AuthMethod: dynamicproxy.AuthMethodNone,
  475. BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{},
  476. BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
  477. }
  478. }
  479. if authProviderType == 1 {
  480. newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodBasic
  481. } else if authProviderType == 2 {
  482. newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodAuthelia
  483. } else if authProviderType == 3 {
  484. newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodOauth2
  485. } else {
  486. newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodNone
  487. }
  488. newProxyEndpoint.RequireRateLimit = requireRateLimit
  489. newProxyEndpoint.RateLimit = proxyRateLimit
  490. newProxyEndpoint.UseStickySession = useStickySession
  491. newProxyEndpoint.DisableUptimeMonitor = disbleUtm
  492. //Prepare to replace the current routing rule
  493. readyRoutingRule, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
  494. if err != nil {
  495. utils.SendErrorResponse(w, err.Error())
  496. return
  497. }
  498. targetProxyEntry.Remove()
  499. dynamicProxyRouter.AddProxyRouteToRuntime(readyRoutingRule)
  500. //Save it to file
  501. SaveReverseProxyConfig(newProxyEndpoint)
  502. //Update uptime monitor targets
  503. UpdateUptimeMonitorTargets()
  504. utils.SendOK(w)
  505. }
  506. func ReverseProxyHandleAlias(w http.ResponseWriter, r *http.Request) {
  507. rootNameOrMatchingDomain, err := utils.PostPara(r, "ep")
  508. if err != nil {
  509. utils.SendErrorResponse(w, "Invalid ep given")
  510. return
  511. }
  512. //No need to check for type as root (/) can be set to default route
  513. //and hence, you will not need alias
  514. //Load the previous alias from current proxy rules
  515. targetProxyEntry, err := dynamicProxyRouter.LoadProxy(rootNameOrMatchingDomain)
  516. if err != nil {
  517. utils.SendErrorResponse(w, "Target proxy config not found or could not be loaded")
  518. return
  519. }
  520. newAliasJSON, err := utils.PostPara(r, "alias")
  521. if err != nil {
  522. //No new set of alias given
  523. utils.SendErrorResponse(w, "new alias not given")
  524. return
  525. }
  526. //Write new alias to runtime and file
  527. newAlias := []string{}
  528. err = json.Unmarshal([]byte(newAliasJSON), &newAlias)
  529. if err != nil {
  530. SystemWideLogger.PrintAndLog("proxy-config", "Unable to parse new alias list", err)
  531. utils.SendErrorResponse(w, "Invalid alias list given")
  532. return
  533. }
  534. //Set the current alias
  535. newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry)
  536. newProxyEndpoint.MatchingDomainAlias = newAlias
  537. // Prepare to replace the current routing rule
  538. readyRoutingRule, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
  539. if err != nil {
  540. utils.SendErrorResponse(w, err.Error())
  541. return
  542. }
  543. targetProxyEntry.Remove()
  544. dynamicProxyRouter.AddProxyRouteToRuntime(readyRoutingRule)
  545. // Save it to file
  546. err = SaveReverseProxyConfig(newProxyEndpoint)
  547. if err != nil {
  548. utils.SendErrorResponse(w, "Alias update failed")
  549. SystemWideLogger.PrintAndLog("proxy-config", "Unable to save alias update", err)
  550. }
  551. utils.SendOK(w)
  552. }
  553. func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) {
  554. ep, err := utils.PostPara(r, "ep")
  555. if err != nil {
  556. utils.SendErrorResponse(w, "Invalid ep given")
  557. return
  558. }
  559. //Remove the config from runtime
  560. err = dynamicProxyRouter.RemoveProxyEndpointByRootname(ep)
  561. if err != nil {
  562. utils.SendErrorResponse(w, err.Error())
  563. return
  564. }
  565. //Remove the config from file
  566. err = RemoveReverseProxyConfig(ep)
  567. if err != nil {
  568. utils.SendErrorResponse(w, err.Error())
  569. return
  570. }
  571. //Update uptime monitor
  572. UpdateUptimeMonitorTargets()
  573. utils.SendOK(w)
  574. }
  575. /*
  576. Handle update request for basic auth credential
  577. Require paramter: ep (Endpoint) and pytype (proxy Type)
  578. if request with GET, the handler will return current credentials
  579. on this endpoint by its username
  580. if request is POST, the handler will write the results to proxy config
  581. */
  582. func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
  583. if r.Method == http.MethodGet {
  584. ep, err := utils.GetPara(r, "ep")
  585. if err != nil {
  586. utils.SendErrorResponse(w, "Invalid ep given")
  587. return
  588. }
  589. //Load the target proxy object from router
  590. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  591. if err != nil {
  592. utils.SendErrorResponse(w, err.Error())
  593. return
  594. }
  595. usernames := []string{}
  596. for _, cred := range targetProxy.AuthenticationProvider.BasicAuthCredentials {
  597. usernames = append(usernames, cred.Username)
  598. }
  599. js, _ := json.Marshal(usernames)
  600. utils.SendJSONResponse(w, string(js))
  601. } else if r.Method == http.MethodPost {
  602. //Write to target
  603. ep, err := utils.PostPara(r, "ep")
  604. if err != nil {
  605. utils.SendErrorResponse(w, "Invalid ep given")
  606. return
  607. }
  608. creds, err := utils.PostPara(r, "creds")
  609. if err != nil {
  610. utils.SendErrorResponse(w, "Invalid ptype given")
  611. return
  612. }
  613. //Load the target proxy object from router
  614. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  615. if err != nil {
  616. utils.SendErrorResponse(w, err.Error())
  617. return
  618. }
  619. //Try to marshal the content of creds into the suitable structure
  620. newCredentials := []*dynamicproxy.BasicAuthUnhashedCredentials{}
  621. err = json.Unmarshal([]byte(creds), &newCredentials)
  622. if err != nil {
  623. utils.SendErrorResponse(w, "Malformed credential data")
  624. return
  625. }
  626. //Merge the credentials into the original config
  627. //If a new username exists in old config with no pw given, keep the old pw hash
  628. //If a new username is found with new password, hash it and push to credential slice
  629. mergedCredentials := []*dynamicproxy.BasicAuthCredentials{}
  630. for _, credential := range newCredentials {
  631. if credential.Password == "" {
  632. //Check if exists in the old credential files
  633. keepUnchange := false
  634. for _, oldCredEntry := range targetProxy.AuthenticationProvider.BasicAuthCredentials {
  635. if oldCredEntry.Username == credential.Username {
  636. //Exists! Reuse the old hash
  637. mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
  638. Username: oldCredEntry.Username,
  639. PasswordHash: oldCredEntry.PasswordHash,
  640. })
  641. keepUnchange = true
  642. }
  643. }
  644. if !keepUnchange {
  645. //This is a new username with no pw given
  646. utils.SendErrorResponse(w, "Access password for "+credential.Username+" is empty!")
  647. return
  648. }
  649. } else {
  650. //This username have given password
  651. mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
  652. Username: credential.Username,
  653. PasswordHash: auth.Hash(credential.Password),
  654. })
  655. }
  656. }
  657. targetProxy.AuthenticationProvider.BasicAuthCredentials = mergedCredentials
  658. //Save it to file
  659. SaveReverseProxyConfig(targetProxy)
  660. //Replace runtime configuration
  661. targetProxy.UpdateToRuntime()
  662. utils.SendOK(w)
  663. } else {
  664. http.Error(w, "invalid usage", http.StatusMethodNotAllowed)
  665. }
  666. }
  667. // List, Update or Remove the exception paths for basic auth.
  668. func ListProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
  669. if r.Method != http.MethodGet {
  670. http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
  671. }
  672. ep, err := utils.GetPara(r, "ep")
  673. if err != nil {
  674. utils.SendErrorResponse(w, "Invalid ep given")
  675. return
  676. }
  677. //Load the target proxy object from router
  678. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  679. if err != nil {
  680. utils.SendErrorResponse(w, err.Error())
  681. return
  682. }
  683. //List all the exception paths for this proxy
  684. results := targetProxy.AuthenticationProvider.BasicAuthExceptionRules
  685. if results == nil {
  686. //It is a config from a really old version of zoraxy. Overwrite it with empty array
  687. results = []*dynamicproxy.BasicAuthExceptionRule{}
  688. }
  689. js, _ := json.Marshal(results)
  690. utils.SendJSONResponse(w, string(js))
  691. return
  692. }
  693. func AddProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
  694. ep, err := utils.PostPara(r, "ep")
  695. if err != nil {
  696. utils.SendErrorResponse(w, "Invalid ep given")
  697. return
  698. }
  699. matchingPrefix, err := utils.PostPara(r, "prefix")
  700. if err != nil {
  701. utils.SendErrorResponse(w, "Invalid matching prefix given")
  702. return
  703. }
  704. //Load the target proxy object from router
  705. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  706. if err != nil {
  707. utils.SendErrorResponse(w, err.Error())
  708. return
  709. }
  710. //Check if the prefix starts with /. If not, prepend it
  711. if !strings.HasPrefix(matchingPrefix, "/") {
  712. matchingPrefix = "/" + matchingPrefix
  713. }
  714. //Add a new exception rule if it is not already exists
  715. alreadyExists := false
  716. for _, thisExceptionRule := range targetProxy.AuthenticationProvider.BasicAuthExceptionRules {
  717. if thisExceptionRule.PathPrefix == matchingPrefix {
  718. alreadyExists = true
  719. break
  720. }
  721. }
  722. if alreadyExists {
  723. utils.SendErrorResponse(w, "This matching path already exists")
  724. return
  725. }
  726. targetProxy.AuthenticationProvider.BasicAuthExceptionRules = append(targetProxy.AuthenticationProvider.BasicAuthExceptionRules, &dynamicproxy.BasicAuthExceptionRule{
  727. PathPrefix: strings.TrimSpace(matchingPrefix),
  728. })
  729. //Save configs to runtime and file
  730. targetProxy.UpdateToRuntime()
  731. SaveReverseProxyConfig(targetProxy)
  732. utils.SendOK(w)
  733. }
  734. func RemoveProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
  735. // Delete a rule
  736. ep, err := utils.PostPara(r, "ep")
  737. if err != nil {
  738. utils.SendErrorResponse(w, "Invalid ep given")
  739. return
  740. }
  741. matchingPrefix, err := utils.PostPara(r, "prefix")
  742. if err != nil {
  743. utils.SendErrorResponse(w, "Invalid matching prefix given")
  744. return
  745. }
  746. // Load the target proxy object from router
  747. targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
  748. if err != nil {
  749. utils.SendErrorResponse(w, err.Error())
  750. return
  751. }
  752. newExceptionRuleList := []*dynamicproxy.BasicAuthExceptionRule{}
  753. matchingExists := false
  754. for _, thisExceptionalRule := range targetProxy.AuthenticationProvider.BasicAuthExceptionRules {
  755. if thisExceptionalRule.PathPrefix != matchingPrefix {
  756. newExceptionRuleList = append(newExceptionRuleList, thisExceptionalRule)
  757. } else {
  758. matchingExists = true
  759. }
  760. }
  761. if !matchingExists {
  762. utils.SendErrorResponse(w, "target matching rule not exists")
  763. return
  764. }
  765. targetProxy.AuthenticationProvider.BasicAuthExceptionRules = newExceptionRuleList
  766. // Save configs to runtime and file
  767. targetProxy.UpdateToRuntime()
  768. SaveReverseProxyConfig(targetProxy)
  769. utils.SendOK(w)
  770. }
  771. // Report the current status of the reverse proxy server
  772. func ReverseProxyStatus(w http.ResponseWriter, r *http.Request) {
  773. js, _ := json.Marshal(dynamicProxyRouter)
  774. utils.SendJSONResponse(w, string(js))
  775. }
  776. // Toggle a certain rule on and off
  777. func ReverseProxyToggleRuleSet(w http.ResponseWriter, r *http.Request) {
  778. //No need to check for type as root cannot be turned off
  779. ep, err := utils.PostPara(r, "ep")
  780. if err != nil {
  781. utils.SendErrorResponse(w, "invalid ep given")
  782. return
  783. }
  784. targetProxyRule, err := dynamicProxyRouter.LoadProxy(ep)
  785. if err != nil {
  786. utils.SendErrorResponse(w, "invalid endpoint given")
  787. return
  788. }
  789. enableStr, err := utils.PostPara(r, "enable")
  790. if err != nil {
  791. enableStr = "true"
  792. }
  793. //Flip the enable and disabled tag state
  794. ruleDisabled := enableStr == "false"
  795. targetProxyRule.Disabled = ruleDisabled
  796. err = SaveReverseProxyConfig(targetProxyRule)
  797. if err != nil {
  798. utils.SendErrorResponse(w, "unable to save updated rule")
  799. return
  800. }
  801. //Update uptime monitor
  802. UpdateUptimeMonitorTargets()
  803. utils.SendOK(w)
  804. }
  805. func ReverseProxyListDetail(w http.ResponseWriter, r *http.Request) {
  806. eptype, err := utils.PostPara(r, "type") //Support root and host
  807. if err != nil {
  808. utils.SendErrorResponse(w, "type not defined")
  809. return
  810. }
  811. if eptype == "host" {
  812. epname, err := utils.PostPara(r, "epname")
  813. if err != nil {
  814. utils.SendErrorResponse(w, "epname not defined")
  815. return
  816. }
  817. epname = strings.ToLower(strings.TrimSpace(epname))
  818. endpointRaw, ok := dynamicProxyRouter.ProxyEndpoints.Load(epname)
  819. if !ok {
  820. utils.SendErrorResponse(w, "proxy rule not found")
  821. return
  822. }
  823. targetEndpoint := dynamicproxy.CopyEndpoint(endpointRaw.(*dynamicproxy.ProxyEndpoint))
  824. js, _ := json.Marshal(targetEndpoint)
  825. utils.SendJSONResponse(w, string(js))
  826. } else if eptype == "root" {
  827. js, _ := json.Marshal(dynamicProxyRouter.Root)
  828. utils.SendJSONResponse(w, string(js))
  829. } else {
  830. utils.SendErrorResponse(w, "Invalid type given")
  831. }
  832. }
  833. func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
  834. eptype, err := utils.PostPara(r, "type") //Support root and host
  835. if err != nil {
  836. utils.SendErrorResponse(w, "type not defined")
  837. return
  838. }
  839. if eptype == "host" {
  840. results := []*dynamicproxy.ProxyEndpoint{}
  841. dynamicProxyRouter.ProxyEndpoints.Range(func(key, value interface{}) bool {
  842. thisEndpoint := dynamicproxy.CopyEndpoint(value.(*dynamicproxy.ProxyEndpoint))
  843. //Clear the auth passwords before showing to front-end
  844. cleanedCredentials := []*dynamicproxy.BasicAuthCredentials{}
  845. for _, user := range thisEndpoint.AuthenticationProvider.BasicAuthCredentials {
  846. cleanedCredentials = append(cleanedCredentials, &dynamicproxy.BasicAuthCredentials{
  847. Username: user.Username,
  848. PasswordHash: "",
  849. })
  850. }
  851. thisEndpoint.AuthenticationProvider.BasicAuthCredentials = cleanedCredentials
  852. results = append(results, thisEndpoint)
  853. return true
  854. })
  855. sort.Slice(results, func(i, j int) bool {
  856. return results[i].RootOrMatchingDomain < results[j].RootOrMatchingDomain
  857. })
  858. js, _ := json.Marshal(results)
  859. utils.SendJSONResponse(w, string(js))
  860. } else if eptype == "root" {
  861. js, _ := json.Marshal(dynamicProxyRouter.Root)
  862. utils.SendJSONResponse(w, string(js))
  863. } else {
  864. utils.SendErrorResponse(w, "Invalid type given")
  865. }
  866. }
  867. // Handle port 80 incoming traffics
  868. func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) {
  869. if r.Method == http.MethodGet {
  870. //Load the current status
  871. currentEnabled := false
  872. err := sysdb.Read("settings", "listenP80", &currentEnabled)
  873. if err != nil {
  874. utils.SendErrorResponse(w, err.Error())
  875. return
  876. }
  877. js, _ := json.Marshal(currentEnabled)
  878. utils.SendJSONResponse(w, string(js))
  879. } else if r.Method == http.MethodPost {
  880. enabled, err := utils.PostPara(r, "enable")
  881. if err != nil {
  882. utils.SendErrorResponse(w, "enable state not set")
  883. return
  884. }
  885. if enabled == "true" {
  886. sysdb.Write("settings", "listenP80", true)
  887. SystemWideLogger.Println("Enabling port 80 listener")
  888. dynamicProxyRouter.UpdatePort80ListenerState(true)
  889. } else if enabled == "false" {
  890. sysdb.Write("settings", "listenP80", false)
  891. SystemWideLogger.Println("Disabling port 80 listener")
  892. dynamicProxyRouter.UpdatePort80ListenerState(false)
  893. } else {
  894. utils.SendErrorResponse(w, "invalid mode given: "+enabled)
  895. }
  896. utils.SendOK(w)
  897. } else {
  898. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  899. }
  900. }
  901. // Handle https redirect
  902. func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) {
  903. if r.Method == http.MethodGet {
  904. currentRedirectToHttps := false
  905. //Load the current status
  906. err := sysdb.Read("settings", "redirect", &currentRedirectToHttps)
  907. if err != nil {
  908. utils.SendErrorResponse(w, err.Error())
  909. return
  910. }
  911. js, _ := json.Marshal(currentRedirectToHttps)
  912. utils.SendJSONResponse(w, string(js))
  913. } else if r.Method == http.MethodPost {
  914. useRedirect, err := utils.PostBool(r, "set")
  915. if err != nil {
  916. utils.SendErrorResponse(w, "status not set")
  917. return
  918. }
  919. if dynamicProxyRouter.Option.Port == 80 {
  920. utils.SendErrorResponse(w, "This option is not available when listening on port 80")
  921. return
  922. }
  923. if useRedirect {
  924. sysdb.Write("settings", "redirect", true)
  925. SystemWideLogger.Println("Updating force HTTPS redirection to true")
  926. dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
  927. } else {
  928. sysdb.Write("settings", "redirect", false)
  929. SystemWideLogger.Println("Updating force HTTPS redirection to false")
  930. dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false)
  931. }
  932. utils.SendOK(w)
  933. } else {
  934. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  935. }
  936. }
  937. // Handle checking if the current user is accessing via the reverse proxied interface
  938. // Of the management interface.
  939. func HandleManagementProxyCheck(w http.ResponseWriter, r *http.Request) {
  940. isProxied := dynamicProxyRouter.IsProxiedSubdomain(r)
  941. js, _ := json.Marshal(isProxied)
  942. utils.SendJSONResponse(w, string(js))
  943. }
  944. func HandleDevelopmentModeChange(w http.ResponseWriter, r *http.Request) {
  945. enableDevelopmentModeStr, err := utils.GetPara(r, "enable")
  946. if err != nil {
  947. //Load the current development mode toggle state
  948. js, _ := json.Marshal(dynamicProxyRouter.Option.NoCache)
  949. utils.SendJSONResponse(w, string(js))
  950. } else {
  951. //Write changes to runtime
  952. enableDevelopmentMode := false
  953. if enableDevelopmentModeStr == "true" {
  954. enableDevelopmentMode = true
  955. }
  956. //Write changes to runtime
  957. dynamicProxyRouter.Option.NoCache = enableDevelopmentMode
  958. //Write changes to database
  959. sysdb.Write("settings", "devMode", enableDevelopmentMode)
  960. utils.SendOK(w)
  961. }
  962. }
  963. // Handle incoming port set. Change the current proxy incoming port
  964. func HandleIncomingPortSet(w http.ResponseWriter, r *http.Request) {
  965. newIncomingPort, err := utils.PostPara(r, "incoming")
  966. if err != nil {
  967. utils.SendErrorResponse(w, "invalid incoming port given")
  968. return
  969. }
  970. newIncomingPortInt, err := strconv.Atoi(newIncomingPort)
  971. if err != nil {
  972. utils.SendErrorResponse(w, "Invalid incoming port given")
  973. return
  974. }
  975. rootProxyTargetOrigin := ""
  976. if len(dynamicProxyRouter.Root.ActiveOrigins) > 0 {
  977. rootProxyTargetOrigin = dynamicProxyRouter.Root.ActiveOrigins[0].OriginIpOrDomain
  978. }
  979. //Check if it is identical as proxy root (recursion!)
  980. if dynamicProxyRouter.Root == nil || rootProxyTargetOrigin == "" {
  981. //Check if proxy root is set before checking recursive listen
  982. //Fixing issue #43
  983. utils.SendErrorResponse(w, "Set Proxy Root before changing inbound port")
  984. return
  985. }
  986. proxyRoot := strings.TrimSuffix(rootProxyTargetOrigin, "/")
  987. if strings.EqualFold(proxyRoot, "localhost:"+strconv.Itoa(newIncomingPortInt)) || strings.EqualFold(proxyRoot, "127.0.0.1:"+strconv.Itoa(newIncomingPortInt)) {
  988. //Listening port is same as proxy root
  989. //Not allow recursive settings
  990. utils.SendErrorResponse(w, "Recursive listening port! Check your proxy root settings.")
  991. return
  992. }
  993. //Stop and change the setting of the reverse proxy service
  994. if dynamicProxyRouter.Running {
  995. dynamicProxyRouter.StopProxyService()
  996. dynamicProxyRouter.Option.Port = newIncomingPortInt
  997. time.Sleep(1 * time.Second) //Fixed start fail issue
  998. dynamicProxyRouter.StartProxyService()
  999. } else {
  1000. //Only change setting but not starting the proxy service
  1001. dynamicProxyRouter.Option.Port = newIncomingPortInt
  1002. }
  1003. sysdb.Write("settings", "inbound", newIncomingPortInt)
  1004. utils.SendOK(w)
  1005. }
  1006. /* Handle Custom Header Rules */
  1007. //List all the custom header defined in this proxy rule
  1008. func HandleCustomHeaderList(w http.ResponseWriter, r *http.Request) {
  1009. epType, err := utils.GetPara(r, "type")
  1010. if err != nil {
  1011. utils.SendErrorResponse(w, "endpoint type not defined")
  1012. return
  1013. }
  1014. domain, err := utils.GetPara(r, "domain")
  1015. if err != nil {
  1016. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1017. return
  1018. }
  1019. var targetProxyEndpoint *dynamicproxy.ProxyEndpoint
  1020. if epType == "root" {
  1021. targetProxyEndpoint = dynamicProxyRouter.Root
  1022. } else {
  1023. ep, err := dynamicProxyRouter.LoadProxy(domain)
  1024. if err != nil {
  1025. utils.SendErrorResponse(w, "target endpoint not exists")
  1026. return
  1027. }
  1028. targetProxyEndpoint = ep
  1029. }
  1030. //List all custom headers
  1031. customHeaderList := targetProxyEndpoint.HeaderRewriteRules.UserDefinedHeaders
  1032. if customHeaderList == nil {
  1033. customHeaderList = []*rewrite.UserDefinedHeader{}
  1034. }
  1035. js, _ := json.Marshal(customHeaderList)
  1036. utils.SendJSONResponse(w, string(js))
  1037. }
  1038. // Add a new header to the target endpoint
  1039. func HandleCustomHeaderAdd(w http.ResponseWriter, r *http.Request) {
  1040. rewriteType, err := utils.PostPara(r, "type")
  1041. if err != nil {
  1042. utils.SendErrorResponse(w, "rewriteType not defined")
  1043. return
  1044. }
  1045. domain, err := utils.PostPara(r, "domain")
  1046. if err != nil {
  1047. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1048. return
  1049. }
  1050. direction, err := utils.PostPara(r, "direction")
  1051. if err != nil {
  1052. utils.SendErrorResponse(w, "HTTP modifiy direction not set")
  1053. return
  1054. }
  1055. name, err := utils.PostPara(r, "name")
  1056. if err != nil {
  1057. utils.SendErrorResponse(w, "HTTP header name not set")
  1058. return
  1059. }
  1060. value, err := utils.PostPara(r, "value")
  1061. if err != nil && rewriteType == "add" {
  1062. utils.SendErrorResponse(w, "HTTP header value not set")
  1063. return
  1064. }
  1065. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1066. if err != nil {
  1067. utils.SendErrorResponse(w, "target endpoint not exists")
  1068. return
  1069. }
  1070. //Create a Custom Header Definition type
  1071. var rewriteDirection rewrite.HeaderDirection
  1072. if direction == "toOrigin" {
  1073. rewriteDirection = rewrite.HeaderDirection_ZoraxyToUpstream
  1074. } else if direction == "toClient" {
  1075. rewriteDirection = rewrite.HeaderDirection_ZoraxyToDownstream
  1076. } else {
  1077. //Unknown direction
  1078. utils.SendErrorResponse(w, "header rewrite direction not supported")
  1079. return
  1080. }
  1081. isRemove := false
  1082. if rewriteType == "remove" {
  1083. isRemove = true
  1084. }
  1085. headerRewriteDefinition := rewrite.UserDefinedHeader{
  1086. Key: name,
  1087. Value: value,
  1088. Direction: rewriteDirection,
  1089. IsRemove: isRemove,
  1090. }
  1091. //Create a new custom header object
  1092. err = targetProxyEndpoint.AddUserDefinedHeader(&headerRewriteDefinition)
  1093. if err != nil {
  1094. utils.SendErrorResponse(w, "unable to add header rewrite rule: "+err.Error())
  1095. return
  1096. }
  1097. //Save it (no need reload as header are not handled by dpcore)
  1098. err = SaveReverseProxyConfig(targetProxyEndpoint)
  1099. if err != nil {
  1100. utils.SendErrorResponse(w, "unable to save update")
  1101. return
  1102. }
  1103. utils.SendOK(w)
  1104. }
  1105. // Remove a header from the target endpoint
  1106. func HandleCustomHeaderRemove(w http.ResponseWriter, r *http.Request) {
  1107. domain, err := utils.PostPara(r, "domain")
  1108. if err != nil {
  1109. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1110. return
  1111. }
  1112. name, err := utils.PostPara(r, "name")
  1113. if err != nil {
  1114. utils.SendErrorResponse(w, "HTTP header name not set")
  1115. return
  1116. }
  1117. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1118. if err != nil {
  1119. utils.SendErrorResponse(w, "target endpoint not exists")
  1120. return
  1121. }
  1122. err = targetProxyEndpoint.RemoveUserDefinedHeader(name)
  1123. if err != nil {
  1124. utils.SendErrorResponse(w, "unable to remove header rewrite rule: "+err.Error())
  1125. return
  1126. }
  1127. err = SaveReverseProxyConfig(targetProxyEndpoint)
  1128. if err != nil {
  1129. utils.SendErrorResponse(w, "unable to save update")
  1130. return
  1131. }
  1132. utils.SendOK(w)
  1133. }
  1134. func HandleHostOverwrite(w http.ResponseWriter, r *http.Request) {
  1135. domain, err := utils.PostPara(r, "domain")
  1136. if err != nil {
  1137. domain, err = utils.GetPara(r, "domain")
  1138. if err != nil {
  1139. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1140. return
  1141. }
  1142. }
  1143. //Get the proxy endpoint object dedicated to this domain
  1144. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1145. if err != nil {
  1146. utils.SendErrorResponse(w, "target endpoint not exists")
  1147. return
  1148. }
  1149. if r.Method == http.MethodGet {
  1150. //Get the current host header
  1151. js, _ := json.Marshal(targetProxyEndpoint.HeaderRewriteRules.RequestHostOverwrite)
  1152. utils.SendJSONResponse(w, string(js))
  1153. } else if r.Method == http.MethodPost {
  1154. //Set the new host header
  1155. newHostname, _ := utils.PostPara(r, "hostname")
  1156. //As this will require change in the proxy instance we are running
  1157. //we need to clone and respawn this proxy endpoint
  1158. newProxyEndpoint := targetProxyEndpoint.Clone()
  1159. newProxyEndpoint.HeaderRewriteRules.RequestHostOverwrite = newHostname
  1160. //Save proxy endpoint
  1161. err = SaveReverseProxyConfig(newProxyEndpoint)
  1162. if err != nil {
  1163. utils.SendErrorResponse(w, err.Error())
  1164. return
  1165. }
  1166. //Spawn a new endpoint with updated dpcore
  1167. preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
  1168. if err != nil {
  1169. utils.SendErrorResponse(w, err.Error())
  1170. return
  1171. }
  1172. //Remove the old endpoint
  1173. err = targetProxyEndpoint.Remove()
  1174. if err != nil {
  1175. utils.SendErrorResponse(w, err.Error())
  1176. return
  1177. }
  1178. //Add the newly prepared endpoint to runtime
  1179. err = dynamicProxyRouter.AddProxyRouteToRuntime(preparedEndpoint)
  1180. if err != nil {
  1181. utils.SendErrorResponse(w, err.Error())
  1182. return
  1183. }
  1184. //Print log message
  1185. if newHostname != "" {
  1186. SystemWideLogger.Println("Updated " + domain + " hostname overwrite to: " + newHostname)
  1187. } else {
  1188. SystemWideLogger.Println("Removed " + domain + " hostname overwrite")
  1189. }
  1190. utils.SendOK(w)
  1191. } else {
  1192. //Invalid method
  1193. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1194. }
  1195. }
  1196. // HandleHopByHop get and set the hop by hop remover state
  1197. // note that it shows the DISABLE STATE of hop-by-hop remover, not the enable state
  1198. func HandleHopByHop(w http.ResponseWriter, r *http.Request) {
  1199. domain, err := utils.PostPara(r, "domain")
  1200. if err != nil {
  1201. domain, err = utils.GetPara(r, "domain")
  1202. if err != nil {
  1203. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1204. return
  1205. }
  1206. }
  1207. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1208. if err != nil {
  1209. utils.SendErrorResponse(w, "target endpoint not exists")
  1210. return
  1211. }
  1212. if r.Method == http.MethodGet {
  1213. //Get the current hop by hop header state
  1214. js, _ := json.Marshal(!targetProxyEndpoint.HeaderRewriteRules.DisableHopByHopHeaderRemoval)
  1215. utils.SendJSONResponse(w, string(js))
  1216. } else if r.Method == http.MethodPost {
  1217. //Set the hop by hop header state
  1218. enableHopByHopRemover, _ := utils.PostBool(r, "removeHopByHop")
  1219. //As this will require change in the proxy instance we are running
  1220. //we need to clone and respawn this proxy endpoint
  1221. newProxyEndpoint := targetProxyEndpoint.Clone()
  1222. //Storage file use false as default, so disable removal = not enable remover
  1223. newProxyEndpoint.HeaderRewriteRules.DisableHopByHopHeaderRemoval = !enableHopByHopRemover
  1224. //Save proxy endpoint
  1225. err = SaveReverseProxyConfig(newProxyEndpoint)
  1226. if err != nil {
  1227. utils.SendErrorResponse(w, err.Error())
  1228. return
  1229. }
  1230. //Spawn a new endpoint with updated dpcore
  1231. preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
  1232. if err != nil {
  1233. utils.SendErrorResponse(w, err.Error())
  1234. return
  1235. }
  1236. //Remove the old endpoint
  1237. err = targetProxyEndpoint.Remove()
  1238. if err != nil {
  1239. utils.SendErrorResponse(w, err.Error())
  1240. return
  1241. }
  1242. //Add the newly prepared endpoint to runtime
  1243. err = dynamicProxyRouter.AddProxyRouteToRuntime(preparedEndpoint)
  1244. if err != nil {
  1245. utils.SendErrorResponse(w, err.Error())
  1246. return
  1247. }
  1248. //Print log message
  1249. if enableHopByHopRemover {
  1250. SystemWideLogger.Println("Enabled hop-by-hop headers removal on " + domain)
  1251. } else {
  1252. SystemWideLogger.Println("Disabled hop-by-hop headers removal on " + domain)
  1253. }
  1254. utils.SendOK(w)
  1255. } else {
  1256. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1257. }
  1258. }
  1259. // Handle view or edit HSTS states
  1260. func HandleHSTSState(w http.ResponseWriter, r *http.Request) {
  1261. domain, err := utils.PostPara(r, "domain")
  1262. if err != nil {
  1263. domain, err = utils.GetPara(r, "domain")
  1264. if err != nil {
  1265. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1266. return
  1267. }
  1268. }
  1269. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1270. if err != nil {
  1271. utils.SendErrorResponse(w, "target endpoint not exists")
  1272. return
  1273. }
  1274. if r.Method == http.MethodGet {
  1275. //Return current HSTS enable state
  1276. hstsAge := targetProxyEndpoint.HeaderRewriteRules.HSTSMaxAge
  1277. js, _ := json.Marshal(hstsAge)
  1278. utils.SendJSONResponse(w, string(js))
  1279. return
  1280. } else if r.Method == http.MethodPost {
  1281. newMaxAge, err := utils.PostInt(r, "maxage")
  1282. if err != nil {
  1283. utils.SendErrorResponse(w, "maxage not defeined")
  1284. return
  1285. }
  1286. if newMaxAge == 0 || newMaxAge >= 31536000 {
  1287. targetProxyEndpoint.HeaderRewriteRules.HSTSMaxAge = int64(newMaxAge)
  1288. err = SaveReverseProxyConfig(targetProxyEndpoint)
  1289. if err != nil {
  1290. utils.SendErrorResponse(w, "save HSTS state failed: "+err.Error())
  1291. return
  1292. }
  1293. targetProxyEndpoint.UpdateToRuntime()
  1294. } else {
  1295. utils.SendErrorResponse(w, "invalid max age given")
  1296. return
  1297. }
  1298. utils.SendOK(w)
  1299. return
  1300. }
  1301. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1302. }
  1303. // HandlePermissionPolicy handle read or write to permission policy
  1304. func HandlePermissionPolicy(w http.ResponseWriter, r *http.Request) {
  1305. domain, err := utils.PostPara(r, "domain")
  1306. if err != nil {
  1307. domain, err = utils.GetPara(r, "domain")
  1308. if err != nil {
  1309. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1310. return
  1311. }
  1312. }
  1313. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1314. if err != nil {
  1315. utils.SendErrorResponse(w, "target endpoint not exists")
  1316. return
  1317. }
  1318. if r.Method == http.MethodGet {
  1319. type CurrentPolicyState struct {
  1320. PPEnabled bool
  1321. CurrentPolicy *permissionpolicy.PermissionsPolicy
  1322. }
  1323. currentPolicy := permissionpolicy.GetDefaultPermissionPolicy()
  1324. if targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy != nil {
  1325. currentPolicy = targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy
  1326. }
  1327. result := CurrentPolicyState{
  1328. PPEnabled: targetProxyEndpoint.HeaderRewriteRules.EnablePermissionPolicyHeader,
  1329. CurrentPolicy: currentPolicy,
  1330. }
  1331. js, _ := json.Marshal(result)
  1332. utils.SendJSONResponse(w, string(js))
  1333. return
  1334. } else if r.Method == http.MethodPost {
  1335. //Update the enable state of permission policy
  1336. enableState, err := utils.PostBool(r, "enable")
  1337. if err != nil {
  1338. utils.SendErrorResponse(w, "invalid enable state given")
  1339. return
  1340. }
  1341. targetProxyEndpoint.HeaderRewriteRules.EnablePermissionPolicyHeader = enableState
  1342. SaveReverseProxyConfig(targetProxyEndpoint)
  1343. targetProxyEndpoint.UpdateToRuntime()
  1344. utils.SendOK(w)
  1345. return
  1346. } else if r.Method == http.MethodPut {
  1347. //Store the new permission policy
  1348. newPermissionPolicyJSONString, err := utils.PostPara(r, "pp")
  1349. if err != nil {
  1350. utils.SendErrorResponse(w, "missing pp (permission policy) paramter")
  1351. return
  1352. }
  1353. //Parse the permission policy from JSON string
  1354. newPermissionPolicy := permissionpolicy.GetDefaultPermissionPolicy()
  1355. err = json.Unmarshal([]byte(newPermissionPolicyJSONString), &newPermissionPolicy)
  1356. if err != nil {
  1357. utils.SendErrorResponse(w, "permission policy parse error: "+err.Error())
  1358. return
  1359. }
  1360. //Save it to file
  1361. targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy = newPermissionPolicy
  1362. SaveReverseProxyConfig(targetProxyEndpoint)
  1363. targetProxyEndpoint.UpdateToRuntime()
  1364. utils.SendOK(w)
  1365. return
  1366. }
  1367. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1368. }
  1369. func HandleWsHeaderBehavior(w http.ResponseWriter, r *http.Request) {
  1370. domain, err := utils.PostPara(r, "domain")
  1371. if err != nil {
  1372. domain, err = utils.GetPara(r, "domain")
  1373. if err != nil {
  1374. utils.SendErrorResponse(w, "domain or matching rule not defined")
  1375. return
  1376. }
  1377. }
  1378. targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
  1379. if err != nil {
  1380. utils.SendErrorResponse(w, "target endpoint not exists")
  1381. return
  1382. }
  1383. if r.Method == http.MethodGet {
  1384. js, _ := json.Marshal(targetProxyEndpoint.EnableWebsocketCustomHeaders)
  1385. utils.SendJSONResponse(w, string(js))
  1386. } else if r.Method == http.MethodPost {
  1387. enableWsHeader, err := utils.PostBool(r, "enable")
  1388. if err != nil {
  1389. utils.SendErrorResponse(w, "invalid enable state given")
  1390. return
  1391. }
  1392. targetProxyEndpoint.EnableWebsocketCustomHeaders = enableWsHeader
  1393. SaveReverseProxyConfig(targetProxyEndpoint)
  1394. targetProxyEndpoint.UpdateToRuntime()
  1395. utils.SendOK(w)
  1396. } else {
  1397. http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
  1398. }
  1399. }