reverseproxy.go 46 KB

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