reverseproxy.go 49 KB

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