1
0

reverseproxy.go 44 KB

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