reverseproxy.go 44 KB

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