1
0

reverseproxy.go 49 KB

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