reverseproxy.go 47 KB

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