reverseproxy.go 49 KB

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