reverseproxy.go 44 KB

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