mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-06 15:47:19 +02:00
Optimized memory usage and root routing
+ Added unset subdomain custom redirection feature #46 + Optimized memory usage by space time tradeoff in geoip lookup to fix #52 + Replaced all stori/go.uuid to google/uuid for security reasons #55
This commit is contained in:
parent
4f7f60188f
commit
73ab9ca778
@ -55,6 +55,9 @@ func initAPIs() {
|
|||||||
authRouter.HandleFunc("/api/proxy/setIncoming", HandleIncomingPortSet)
|
authRouter.HandleFunc("/api/proxy/setIncoming", HandleIncomingPortSet)
|
||||||
authRouter.HandleFunc("/api/proxy/useHttpsRedirect", HandleUpdateHttpsRedirect)
|
authRouter.HandleFunc("/api/proxy/useHttpsRedirect", HandleUpdateHttpsRedirect)
|
||||||
authRouter.HandleFunc("/api/proxy/requestIsProxied", HandleManagementProxyCheck)
|
authRouter.HandleFunc("/api/proxy/requestIsProxied", HandleManagementProxyCheck)
|
||||||
|
//Reverse proxy root related APIs
|
||||||
|
authRouter.HandleFunc("/api/proxy/root/listOptions", HandleRootRouteOptionList)
|
||||||
|
authRouter.HandleFunc("/api/proxy/root/updateOptions", HandleRootRouteOptionsUpdate)
|
||||||
//Reverse proxy auth related APIs
|
//Reverse proxy auth related APIs
|
||||||
authRouter.HandleFunc("/api/proxy/auth/exceptions/list", ListProxyBasicAuthExceptionPaths)
|
authRouter.HandleFunc("/api/proxy/auth/exceptions/list", ListProxyBasicAuthExceptionPaths)
|
||||||
authRouter.HandleFunc("/api/proxy/auth/exceptions/add", AddProxyBasicAuthExceptionPaths)
|
authRouter.HandleFunc("/api/proxy/auth/exceptions/add", AddProxyBasicAuthExceptionPaths)
|
||||||
@ -168,6 +171,7 @@ func initAPIs() {
|
|||||||
|
|
||||||
//Others
|
//Others
|
||||||
http.HandleFunc("/api/info/x", HandleZoraxyInfo)
|
http.HandleFunc("/api/info/x", HandleZoraxyInfo)
|
||||||
|
http.HandleFunc("/api/info/geoip", HandleGeoIpLookup)
|
||||||
http.HandleFunc("/api/conf/export", ExportConfigAsZip)
|
http.HandleFunc("/api/conf/export", ExportConfigAsZip)
|
||||||
http.HandleFunc("/api/conf/import", ImportConfigFromZip)
|
http.HandleFunc("/api/conf/import", ImportConfigFromZip)
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
uuid "github.com/satori/go.uuid"
|
"github.com/google/uuid"
|
||||||
"imuslab.com/zoraxy/mod/email"
|
"imuslab.com/zoraxy/mod/email"
|
||||||
"imuslab.com/zoraxy/mod/utils"
|
"imuslab.com/zoraxy/mod/utils"
|
||||||
)
|
)
|
||||||
@ -223,7 +223,7 @@ func HandleAdminAccountResetEmail(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordResetAccessToken = uuid.NewV4().String()
|
passwordResetAccessToken = uuid.New().String()
|
||||||
|
|
||||||
//SMTP info exists. Send reset account email
|
//SMTP info exists. Send reset account email
|
||||||
lastAccountResetEmail = time.Now().Unix()
|
lastAccountResetEmail = time.Now().Unix()
|
||||||
|
@ -4,16 +4,14 @@ go 1.16
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/boltdb/bolt v1.3.1
|
github.com/boltdb/bolt v1.3.1
|
||||||
github.com/go-acme/lego/v4 v4.12.1 // indirect
|
github.com/go-acme/lego/v4 v4.12.1
|
||||||
github.com/go-ping/ping v1.1.0
|
github.com/go-ping/ping v1.1.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/sessions v1.2.1
|
github.com/gorilla/sessions v1.2.1
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/grandcat/zeroconf v1.0.0
|
github.com/grandcat/zeroconf v1.0.0
|
||||||
github.com/likexian/whois v1.15.0 // indirect
|
github.com/likexian/whois v1.15.0
|
||||||
github.com/microcosm-cc/bluemonday v1.0.24
|
github.com/microcosm-cc/bluemonday v1.0.24
|
||||||
github.com/oschwald/geoip2-golang v1.8.0
|
|
||||||
github.com/satori/go.uuid v1.2.0
|
|
||||||
golang.org/x/net v0.11.0
|
golang.org/x/net v0.11.0
|
||||||
golang.org/x/sys v0.9.0
|
golang.org/x/sys v0.9.0
|
||||||
)
|
)
|
||||||
|
20
src/go.sum
20
src/go.sum
@ -123,7 +123,6 @@ cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOV
|
|||||||
cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
|
cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
|
||||||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||||
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
|
||||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||||
cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=
|
cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=
|
||||||
cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
|
cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
|
||||||
@ -611,6 +610,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
@ -770,6 +770,7 @@ github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++
|
|||||||
github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
|
github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
|
||||||
github.com/lestrrat-go/jwx v1.2.7/go.mod h1:bw24IXWbavc0R2RsOtpXL7RtMyP589yZ1+L7kd09ZGA=
|
github.com/lestrrat-go/jwx v1.2.7/go.mod h1:bw24IXWbavc0R2RsOtpXL7RtMyP589yZ1+L7kd09ZGA=
|
||||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||||
|
github.com/likexian/gokit v0.25.13 h1:p2Uw3+6fGG53CwdU2Dz0T6bOycdb2+bAFAa3ymwWVkM=
|
||||||
github.com/likexian/gokit v0.25.13/go.mod h1:qQhEWFBEfqLCO3/vOEo2EDKd+EycekVtUK4tex+l2H4=
|
github.com/likexian/gokit v0.25.13/go.mod h1:qQhEWFBEfqLCO3/vOEo2EDKd+EycekVtUK4tex+l2H4=
|
||||||
github.com/likexian/whois v1.15.0 h1:AYYJ5bNUo8Qy2T1Z5GgMp1oIcIlCcTDfg1buYz6TdAE=
|
github.com/likexian/whois v1.15.0 h1:AYYJ5bNUo8Qy2T1Z5GgMp1oIcIlCcTDfg1buYz6TdAE=
|
||||||
github.com/likexian/whois v1.15.0/go.mod h1:456fUTkh+O8F8v09bGdVl7XxBjRaQ4LvYHyVWX5Bxyg=
|
github.com/likexian/whois v1.15.0/go.mod h1:456fUTkh+O8F8v09bGdVl7XxBjRaQ4LvYHyVWX5Bxyg=
|
||||||
@ -808,7 +809,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
|||||||
github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw=
|
github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.24/go.mod h1:ArQySAMps0790cHSkdPEJ7bGkF2VePWH773hsJNSHf8=
|
github.com/microcosm-cc/bluemonday v1.0.24/go.mod h1:ArQySAMps0790cHSkdPEJ7bGkF2VePWH773hsJNSHf8=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
|
|
||||||
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||||
@ -859,10 +859,6 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl
|
|||||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||||
github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||||
github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs=
|
|
||||||
github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
|
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
|
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
|
|
||||||
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
@ -912,8 +908,6 @@ github.com/sacloud/api-client-go v0.2.1/go.mod h1:8fmYy5OpT3W8ltV5ZxF8evultNwKpd
|
|||||||
github.com/sacloud/go-http v0.1.2/go.mod h1:gvWaT8LFBFnSBFVrznOQXC62uad46bHZQM8w+xoH3eE=
|
github.com/sacloud/go-http v0.1.2/go.mod h1:gvWaT8LFBFnSBFVrznOQXC62uad46bHZQM8w+xoH3eE=
|
||||||
github.com/sacloud/iaas-api-go v1.3.2/go.mod h1:CoqpRYBG2NRB5xfqTfZNyh2lVLKyLkE/HV9ISqmbhGc=
|
github.com/sacloud/iaas-api-go v1.3.2/go.mod h1:CoqpRYBG2NRB5xfqTfZNyh2lVLKyLkE/HV9ISqmbhGc=
|
||||||
github.com/sacloud/packages-go v0.0.5/go.mod h1:XWMBSNHT9YKY3lCh6yJsx1o1RRQQGpuhNqJA6bSHdD4=
|
github.com/sacloud/packages-go v0.0.5/go.mod h1:XWMBSNHT9YKY3lCh6yJsx1o1RRQQGpuhNqJA6bSHdD4=
|
||||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
|
||||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
|
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
|
||||||
@ -960,10 +954,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
|||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.3/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
|
||||||
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||||
@ -1035,14 +1028,12 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
|
|||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||||
@ -1156,7 +1147,6 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||||
@ -1295,7 +1285,6 @@ golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -1303,7 +1292,6 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -1333,7 +1321,6 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
@ -1653,7 +1640,6 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
|||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
@ -40,6 +40,7 @@ var allowMdnsScanning = flag.Bool("mdns", true, "Enable mDNS scanner and transpo
|
|||||||
var ztAuthToken = flag.String("ztauth", "", "ZeroTier authtoken for the local node")
|
var ztAuthToken = flag.String("ztauth", "", "ZeroTier authtoken for the local node")
|
||||||
var ztAPIPort = flag.Int("ztport", 9993, "ZeroTier controller API port")
|
var ztAPIPort = flag.Int("ztport", 9993, "ZeroTier controller API port")
|
||||||
var acmeAutoRenewInterval = flag.Int("autorenew", 86400, "ACME auto TLS/SSL certificate renew check interval (seconds)")
|
var acmeAutoRenewInterval = flag.Int("autorenew", 86400, "ACME auto TLS/SSL certificate renew check interval (seconds)")
|
||||||
|
var enableHighSpeedGeoIPLookup = flag.Bool("fastgeoip", false, "Enable high speed geoip lookup, require 1GB extra memory (Not recommend for low end devices)")
|
||||||
var (
|
var (
|
||||||
name = "Zoraxy"
|
name = "Zoraxy"
|
||||||
version = "2.6.6"
|
version = "2.6.6"
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package dynamicproxy
|
package dynamicproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -21,6 +25,11 @@ import (
|
|||||||
- Vitrual Directory Routing
|
- Vitrual Directory Routing
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed tld.json
|
||||||
|
rawTldMap []byte
|
||||||
|
)
|
||||||
|
|
||||||
func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
/*
|
/*
|
||||||
Special Routing Rules, bypass most of the limitations
|
Special Routing Rules, bypass most of the limitations
|
||||||
@ -108,10 +117,69 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Redirect(w, r, r.RequestURI+"/", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, r.RequestURI+"/", http.StatusTemporaryRedirect)
|
||||||
} else {
|
} else {
|
||||||
//Passthrough the request to root
|
//Passthrough the request to root
|
||||||
h.proxyRequest(w, r, h.Parent.Root)
|
h.handleRootRouting(w, r)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//No routing rules found. Route to root.
|
//No routing rules found.
|
||||||
|
h.handleRootRouting(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
handleRootRouting
|
||||||
|
|
||||||
|
This function handle root routing situations where there are no subdomain
|
||||||
|
, vdir or special routing rule matches the requested URI.
|
||||||
|
|
||||||
|
Once entered this routing segment, the root routing options will take over
|
||||||
|
for the routing logic.
|
||||||
|
*/
|
||||||
|
func (h *ProxyHandler) handleRootRouting(w http.ResponseWriter, r *http.Request) {
|
||||||
|
domainOnly := r.Host
|
||||||
|
if strings.Contains(r.Host, ":") {
|
||||||
|
hostPath := strings.Split(r.Host, ":")
|
||||||
|
domainOnly = hostPath[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Parent.RootRoutingOptions.EnableRedirectForUnsetRules {
|
||||||
|
//Route to custom domain
|
||||||
|
if h.Parent.RootRoutingOptions.UnsetRuleRedirectTarget == "" {
|
||||||
|
//Not set. Redirect to first level of domain redirectable
|
||||||
|
fld, err := h.getTopLevelRedirectableDomain(domainOnly)
|
||||||
|
if err != nil {
|
||||||
|
//Redirect to proxy root
|
||||||
|
h.proxyRequest(w, r, h.Parent.Root)
|
||||||
|
} else {
|
||||||
|
log.Println("[Router] Redirecting request from " + domainOnly + " to " + fld)
|
||||||
|
h.logRequest(r, false, 307, "root-redirect", domainOnly)
|
||||||
|
http.Redirect(w, r, fld, http.StatusTemporaryRedirect)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if h.isTopLevelRedirectableDomain(domainOnly) {
|
||||||
|
//This is requesting a top level private domain that should be serving root
|
||||||
|
h.proxyRequest(w, r, h.Parent.Root)
|
||||||
|
} else {
|
||||||
|
//Validate the redirection target URL
|
||||||
|
parsedURL, err := url.Parse(h.Parent.RootRoutingOptions.UnsetRuleRedirectTarget)
|
||||||
|
if err != nil {
|
||||||
|
//Error when parsing target. Send to root
|
||||||
|
h.proxyRequest(w, r, h.Parent.Root)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hostname := parsedURL.Hostname()
|
||||||
|
if domainOnly != hostname {
|
||||||
|
//Redirect to target
|
||||||
|
h.logRequest(r, false, 307, "root-redirect", domainOnly)
|
||||||
|
http.Redirect(w, r, h.Parent.RootRoutingOptions.UnsetRuleRedirectTarget, http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
//Loopback request due to bad settings (Shd leave it empty)
|
||||||
|
//Forward it to root proxy
|
||||||
|
h.proxyRequest(w, r, h.Parent.Root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Route to root
|
||||||
h.proxyRequest(w, r, h.Parent.Root)
|
h.proxyRequest(w, r, h.Parent.Root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,3 +218,44 @@ func (h *ProxyHandler) handleAccessRouting(w http.ResponseWriter, r *http.Reques
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return if the given host is already topped (e.g. example.com or example.co.uk) instead of
|
||||||
|
// a host with subdomain (e.g. test.example.com)
|
||||||
|
func (h *ProxyHandler) isTopLevelRedirectableDomain(requestHost string) bool {
|
||||||
|
parts := strings.Split(requestHost, ".")
|
||||||
|
if len(parts) > 2 {
|
||||||
|
//Cases where strange tld is used like .co.uk or .com.hk
|
||||||
|
_, ok := h.Parent.tldMap[strings.Join(parts[1:], ".")]
|
||||||
|
if ok {
|
||||||
|
//Already topped
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Already topped
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTopLevelRedirectableDomain returns the toppest level of domain
|
||||||
|
// that is redirectable. E.g. a.b.c.example.co.uk will return example.co.uk
|
||||||
|
func (h *ProxyHandler) getTopLevelRedirectableDomain(unsetSubdomainHost string) (string, error) {
|
||||||
|
parts := strings.Split(unsetSubdomainHost, ".")
|
||||||
|
if h.isTopLevelRedirectableDomain(unsetSubdomainHost) {
|
||||||
|
//Already topped
|
||||||
|
return "", errors.New("already at top level domain")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(parts); i++ {
|
||||||
|
possibleTld := parts[i:]
|
||||||
|
_, ok := h.Parent.tldMap[strings.Join(possibleTld, ".")]
|
||||||
|
if ok {
|
||||||
|
//This is tld length
|
||||||
|
tld := strings.Join(parts[i-1:], ".")
|
||||||
|
return "//" + tld, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("unsupported top level domain given")
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package dynamicproxy
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -29,12 +30,19 @@ func NewDynamicProxy(option RouterOption) (*Router, error) {
|
|||||||
Running: false,
|
Running: false,
|
||||||
server: nil,
|
server: nil,
|
||||||
routingRules: []*RoutingRule{},
|
routingRules: []*RoutingRule{},
|
||||||
|
tldMap: map[string]int{},
|
||||||
}
|
}
|
||||||
|
|
||||||
thisRouter.mux = &ProxyHandler{
|
thisRouter.mux = &ProxyHandler{
|
||||||
Parent: &thisRouter,
|
Parent: &thisRouter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Prase the tld map for tld redirection in main router
|
||||||
|
//See Server.go declarations
|
||||||
|
if len(rawTldMap) > 0 {
|
||||||
|
json.Unmarshal(rawTldMap, &thisRouter.tldMap)
|
||||||
|
}
|
||||||
|
|
||||||
return &thisRouter, nil
|
return &thisRouter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,10 +73,18 @@ func (router *Router) StartProxyService() error {
|
|||||||
return errors.New("Reverse proxy server already running")
|
return errors.New("Reverse proxy server already running")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Check if root route is set
|
||||||
if router.Root == nil {
|
if router.Root == nil {
|
||||||
return errors.New("Reverse proxy router root not set")
|
return errors.New("Reverse proxy router root not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Load root options from file
|
||||||
|
loadedRootOption, err := loadRootRoutingOptionsFromFile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
router.RootRoutingOptions = loadedRootOption
|
||||||
|
|
||||||
minVersion := tls.VersionTLS10
|
minVersion := tls.VersionTLS10
|
||||||
if router.Option.ForceTLSLatest {
|
if router.Option.ForceTLSLatest {
|
||||||
minVersion = tls.VersionTLS12
|
minVersion = tls.VersionTLS12
|
||||||
@ -321,6 +337,7 @@ func (router *Router) SetRootProxy(options *RootOptions) error {
|
|||||||
SkipCertValidations: options.SkipCertValidations,
|
SkipCertValidations: options.SkipCertValidations,
|
||||||
RequireBasicAuth: options.RequireBasicAuth,
|
RequireBasicAuth: options.RequireBasicAuth,
|
||||||
BasicAuthCredentials: options.BasicAuthCredentials,
|
BasicAuthCredentials: options.BasicAuthCredentials,
|
||||||
|
BasicAuthExceptionRules: options.BasicAuthExceptionRules,
|
||||||
Proxy: proxy,
|
Proxy: proxy,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
src/mod/dynamicproxy/rootRoute.go
Normal file
51
src/mod/dynamicproxy/rootRoute.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package dynamicproxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"imuslab.com/zoraxy/mod/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
rootRoute.go
|
||||||
|
|
||||||
|
This script handle special case in routing where the root proxy
|
||||||
|
entity is involved. This also include its setting object
|
||||||
|
RootRoutingOptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
var rootConfigFilepath string = "conf/root_config.json"
|
||||||
|
|
||||||
|
func loadRootRoutingOptionsFromFile() (*RootRoutingOptions, error) {
|
||||||
|
if !utils.FileExists(rootConfigFilepath) {
|
||||||
|
//Not found. Create a root option
|
||||||
|
js, _ := json.MarshalIndent(RootRoutingOptions{}, "", " ")
|
||||||
|
err := os.WriteFile(rootConfigFilepath, js, 0775)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Unable to write root config to file: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newRootOption := RootRoutingOptions{}
|
||||||
|
rootOptionsBytes, err := os.ReadFile(rootConfigFilepath)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[Error] Unable to read root config file at " + rootConfigFilepath + ": " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(rootOptionsBytes, &newRootOption)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[Error] Unable to parse root config file: " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &newRootOption, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the new config to file. Note that this will not overwrite the runtime one
|
||||||
|
func (opt *RootRoutingOptions) SaveToFile() error {
|
||||||
|
js, _ := json.MarshalIndent(opt, "", " ")
|
||||||
|
err := os.WriteFile(rootConfigFilepath, js, 0775)
|
||||||
|
return err
|
||||||
|
}
|
9106
src/mod/dynamicproxy/tld.json
Normal file
9106
src/mod/dynamicproxy/tld.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -39,12 +39,14 @@ type Router struct {
|
|||||||
SubdomainEndpoint *sync.Map
|
SubdomainEndpoint *sync.Map
|
||||||
Running bool
|
Running bool
|
||||||
Root *ProxyEndpoint
|
Root *ProxyEndpoint
|
||||||
|
RootRoutingOptions *RootRoutingOptions
|
||||||
mux http.Handler
|
mux http.Handler
|
||||||
server *http.Server
|
server *http.Server
|
||||||
tlsListener net.Listener
|
tlsListener net.Listener
|
||||||
routingRules []*RoutingRule
|
routingRules []*RoutingRule
|
||||||
|
|
||||||
tlsRedirectStop chan bool
|
tlsRedirectStop chan bool //Stop channel for tls redirection server
|
||||||
|
tldMap map[string]int //Top level domain map, see tld.json
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auth credential for basic auth on certain endpoints
|
// Auth credential for basic auth on certain endpoints
|
||||||
@ -70,6 +72,7 @@ type ProxyEndpoint struct {
|
|||||||
RootOrMatchingDomain string //Root for vdir or Matching domain for subd, also act as key
|
RootOrMatchingDomain string //Root for vdir or Matching domain for subd, also act as key
|
||||||
Domain string //Domain or IP to proxy to
|
Domain string //Domain or IP to proxy to
|
||||||
RequireTLS bool //Target domain require TLS
|
RequireTLS bool //Target domain require TLS
|
||||||
|
BypassGlobalTLS bool //Bypass global TLS setting options if TLS Listener enabled (parent.tlsListener != nil)
|
||||||
SkipCertValidations bool //Set to true to accept self signed certs
|
SkipCertValidations bool //Set to true to accept self signed certs
|
||||||
RequireBasicAuth bool //Set to true to request basic auth before proxy
|
RequireBasicAuth bool //Set to true to request basic auth before proxy
|
||||||
BasicAuthCredentials []*BasicAuthCredentials `json:"-"` //Basic auth credentials
|
BasicAuthCredentials []*BasicAuthCredentials `json:"-"` //Basic auth credentials
|
||||||
@ -79,19 +82,31 @@ type ProxyEndpoint struct {
|
|||||||
parent *Router
|
parent *Router
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Root options are those that are required for reverse proxy handler to work
|
||||||
type RootOptions struct {
|
type RootOptions struct {
|
||||||
ProxyLocation string
|
ProxyLocation string //Proxy Root target, all unset traffic will be forward to here
|
||||||
RequireTLS bool
|
RequireTLS bool //Proxy root target require TLS connection (not recommended)
|
||||||
SkipCertValidations bool
|
BypassGlobalTLS bool //Bypass global TLS setting and make root http only (not recommended)
|
||||||
RequireBasicAuth bool
|
SkipCertValidations bool //Skip cert validation, suitable for self-signed certs, CURRENTLY NOT USED
|
||||||
|
|
||||||
|
//Basic Auth Related
|
||||||
|
RequireBasicAuth bool //Require basic auth, CURRENTLY NOT USED
|
||||||
BasicAuthCredentials []*BasicAuthCredentials
|
BasicAuthCredentials []*BasicAuthCredentials
|
||||||
BasicAuthExceptionRules []*BasicAuthExceptionRule
|
BasicAuthExceptionRules []*BasicAuthExceptionRule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Additional options are here for letting router knows how to route exception cases for root
|
||||||
|
type RootRoutingOptions struct {
|
||||||
|
//Root only configs
|
||||||
|
EnableRedirectForUnsetRules bool //Force unset rules to redirect to custom domain
|
||||||
|
UnsetRuleRedirectTarget string //Custom domain to redirect to for unset rules
|
||||||
|
}
|
||||||
|
|
||||||
type VdirOptions struct {
|
type VdirOptions struct {
|
||||||
RootName string
|
RootName string
|
||||||
Domain string
|
Domain string
|
||||||
RequireTLS bool
|
RequireTLS bool
|
||||||
|
BypassGlobalTLS bool
|
||||||
SkipCertValidations bool
|
SkipCertValidations bool
|
||||||
RequireBasicAuth bool
|
RequireBasicAuth bool
|
||||||
BasicAuthCredentials []*BasicAuthCredentials
|
BasicAuthCredentials []*BasicAuthCredentials
|
||||||
@ -102,6 +117,7 @@ type SubdOptions struct {
|
|||||||
MatchingDomain string
|
MatchingDomain string
|
||||||
Domain string
|
Domain string
|
||||||
RequireTLS bool
|
RequireTLS bool
|
||||||
|
BypassGlobalTLS bool
|
||||||
SkipCertValidations bool
|
SkipCertValidations bool
|
||||||
RequireBasicAuth bool
|
RequireBasicAuth bool
|
||||||
BasicAuthCredentials []*BasicAuthCredentials
|
BasicAuthCredentials []*BasicAuthCredentials
|
||||||
|
@ -20,13 +20,16 @@ type Store struct {
|
|||||||
WhitelistEnabled bool
|
WhitelistEnabled bool
|
||||||
geodb [][]string //Parsed geodb list
|
geodb [][]string //Parsed geodb list
|
||||||
geodbIpv6 [][]string //Parsed geodb list for ipv6
|
geodbIpv6 [][]string //Parsed geodb list for ipv6
|
||||||
|
|
||||||
geotrie *trie
|
geotrie *trie
|
||||||
geotrieIpv6 *trie
|
geotrieIpv6 *trie
|
||||||
|
|
||||||
//geoipCache sync.Map
|
//geoipCache sync.Map
|
||||||
|
|
||||||
sysdb *database.Database
|
sysdb *database.Database
|
||||||
|
option *StoreOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type StoreOptions struct {
|
||||||
|
AllowSlowIpv4LookUp bool
|
||||||
|
AllowSloeIpv6Lookup bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type CountryInfo struct {
|
type CountryInfo struct {
|
||||||
@ -34,7 +37,7 @@ type CountryInfo struct {
|
|||||||
ContinetCode string
|
ContinetCode string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGeoDb(sysdb *database.Database) (*Store, error) {
|
func NewGeoDb(sysdb *database.Database, option *StoreOptions) (*Store, error) {
|
||||||
parsedGeoData, err := parseCSV(geoipv4)
|
parsedGeoData, err := parseCSV(geoipv4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -79,14 +82,25 @@ func NewGeoDb(sysdb *database.Database) (*Store, error) {
|
|||||||
log.Println("Database pointer set to nil: Entering debug mode")
|
log.Println("Database pointer set to nil: Entering debug mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ipv4Trie *trie
|
||||||
|
if !option.AllowSlowIpv4LookUp {
|
||||||
|
ipv4Trie = constrctTrieTree(parsedGeoData)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ipv6Trie *trie
|
||||||
|
if !option.AllowSloeIpv6Lookup {
|
||||||
|
ipv6Trie = constrctTrieTree(parsedGeoDataIpv6)
|
||||||
|
}
|
||||||
|
|
||||||
return &Store{
|
return &Store{
|
||||||
BlacklistEnabled: blacklistEnabled,
|
BlacklistEnabled: blacklistEnabled,
|
||||||
WhitelistEnabled: whitelistEnabled,
|
WhitelistEnabled: whitelistEnabled,
|
||||||
geodb: parsedGeoData,
|
geodb: parsedGeoData,
|
||||||
geotrie: constrctTrieTree(parsedGeoData),
|
geotrie: ipv4Trie,
|
||||||
geodbIpv6: parsedGeoDataIpv6,
|
geodbIpv6: parsedGeoDataIpv6,
|
||||||
geotrieIpv6: constrctTrieTree(parsedGeoDataIpv6),
|
geotrieIpv6: ipv6Trie,
|
||||||
sysdb: sysdb,
|
sysdb: sysdb,
|
||||||
|
option: option,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +120,7 @@ func (s *Store) ResolveCountryCodeFromIP(ipstring string) (*CountryInfo, error)
|
|||||||
CountryIsoCode: cc,
|
CountryIsoCode: cc,
|
||||||
ContinetCode: "",
|
ContinetCode: "",
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) Close() {
|
func (s *Store) Close() {
|
||||||
|
@ -41,7 +41,10 @@ func TestTrieConstruct(t *testing.T) {
|
|||||||
|
|
||||||
func TestResolveCountryCodeFromIP(t *testing.T) {
|
func TestResolveCountryCodeFromIP(t *testing.T) {
|
||||||
// Create a new store
|
// Create a new store
|
||||||
store, err := geodb.NewGeoDb(nil)
|
store, err := geodb.NewGeoDb(nil, &geodb.StoreOptions{
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error creating store: %v", err)
|
t.Errorf("error creating store: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,10 +25,18 @@ func (s *Store) search(ip string) string {
|
|||||||
//Search in geotrie tree
|
//Search in geotrie tree
|
||||||
cc := ""
|
cc := ""
|
||||||
if IsIPv6(ip) {
|
if IsIPv6(ip) {
|
||||||
|
if s.geotrieIpv6 == nil {
|
||||||
|
cc = s.slowSearchIpv6(ip)
|
||||||
|
} else {
|
||||||
cc = s.geotrieIpv6.search(ip)
|
cc = s.geotrieIpv6.search(ip)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if s.geotrie == nil {
|
||||||
|
cc = s.slowSearchIpv4(ip)
|
||||||
} else {
|
} else {
|
||||||
cc = s.geotrie.search(ip)
|
cc = s.geotrie.search(ip)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if cc != "" {
|
if cc != "" {
|
||||||
@ -69,27 +76,3 @@ func parseCSV(content []byte) ([][]string, error) {
|
|||||||
}
|
}
|
||||||
return records, nil
|
return records, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a ip string is within the range of two others
|
|
||||||
func isIPInRange(ip, start, end string) bool {
|
|
||||||
ipAddr := net.ParseIP(ip)
|
|
||||||
if ipAddr == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
startAddr := net.ParseIP(start)
|
|
||||||
if startAddr == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
endAddr := net.ParseIP(end)
|
|
||||||
if endAddr == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ipAddr.To4() == nil || startAddr.To4() == nil || endAddr.To4() == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes.Compare(ipAddr.To4(), startAddr.To4()) >= 0 && bytes.Compare(ipAddr.To4(), endAddr.To4()) <= 0
|
|
||||||
}
|
|
||||||
|
81
src/mod/geodb/slowSearch.go
Normal file
81
src/mod/geodb/slowSearch.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package geodb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
slowSearch.go
|
||||||
|
|
||||||
|
This script implement the slow search method for ip to country code
|
||||||
|
lookup. If you have the memory allocation for near O(1) lookup,
|
||||||
|
you should not be using slow search mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
func ipv4ToUInt32(ip net.IP) uint32 {
|
||||||
|
ip = ip.To4()
|
||||||
|
return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIPv4InRange(startIP, endIP, testIP string) (bool, error) {
|
||||||
|
start := net.ParseIP(startIP)
|
||||||
|
end := net.ParseIP(endIP)
|
||||||
|
test := net.ParseIP(testIP)
|
||||||
|
|
||||||
|
if start == nil || end == nil || test == nil {
|
||||||
|
return false, errors.New("invalid IP address format")
|
||||||
|
}
|
||||||
|
|
||||||
|
startUint := ipv4ToUInt32(start)
|
||||||
|
endUint := ipv4ToUInt32(end)
|
||||||
|
testUint := ipv4ToUInt32(test)
|
||||||
|
|
||||||
|
return testUint >= startUint && testUint <= endUint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIPv6InRange(startIP, endIP, testIP string) (bool, error) {
|
||||||
|
start := net.ParseIP(startIP)
|
||||||
|
end := net.ParseIP(endIP)
|
||||||
|
test := net.ParseIP(testIP)
|
||||||
|
|
||||||
|
if start == nil || end == nil || test == nil {
|
||||||
|
return false, errors.New("invalid IP address format")
|
||||||
|
}
|
||||||
|
|
||||||
|
startInt := new(big.Int).SetBytes(start.To16())
|
||||||
|
endInt := new(big.Int).SetBytes(end.To16())
|
||||||
|
testInt := new(big.Int).SetBytes(test.To16())
|
||||||
|
|
||||||
|
return testInt.Cmp(startInt) >= 0 && testInt.Cmp(endInt) <= 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slow country code lookup for
|
||||||
|
func (s *Store) slowSearchIpv4(ipAddr string) string {
|
||||||
|
for _, ipRange := range s.geodb {
|
||||||
|
startIp := ipRange[0]
|
||||||
|
endIp := ipRange[1]
|
||||||
|
cc := ipRange[2]
|
||||||
|
|
||||||
|
inRange, _ := isIPv4InRange(startIp, endIp, ipAddr)
|
||||||
|
if inRange {
|
||||||
|
return cc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) slowSearchIpv6(ipAddr string) string {
|
||||||
|
for _, ipRange := range s.geodbIpv6 {
|
||||||
|
startIp := ipRange[0]
|
||||||
|
endIp := ipRange[1]
|
||||||
|
cc := ipRange[2]
|
||||||
|
|
||||||
|
inRange, _ := isIPv6InRange(startIp, endIp, ipAddr)
|
||||||
|
if inRange {
|
||||||
|
return cc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
@ -1,15 +1,12 @@
|
|||||||
package geodb
|
package geodb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type trie_Node struct {
|
type trie_Node struct {
|
||||||
childrens [2]*trie_Node
|
childrens [2]*trie_Node
|
||||||
ends bool
|
|
||||||
cc string
|
cc string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,7 +15,7 @@ type trie struct {
|
|||||||
root *trie_Node
|
root *trie_Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipToBitString(ip string) string {
|
func ipToBytes(ip string) []byte {
|
||||||
// Parse the IP address string into a net.IP object
|
// Parse the IP address string into a net.IP object
|
||||||
parsedIP := net.ParseIP(ip)
|
parsedIP := net.ParseIP(ip)
|
||||||
|
|
||||||
@ -29,49 +26,7 @@ func ipToBitString(ip string) string {
|
|||||||
ipBytes = parsedIP.To16()
|
ipBytes = parsedIP.To16()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert each byte in the IP address to its 8-bit binary representation
|
return ipBytes
|
||||||
var result []string
|
|
||||||
for _, b := range ipBytes {
|
|
||||||
result = append(result, fmt.Sprintf("%08b", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join the binary representation of each byte with dots to form the final bit string
|
|
||||||
return strings.Join(result, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func bitStringToIp(bitString string) string {
|
|
||||||
// Check if the bit string represents an IPv4 or IPv6 address
|
|
||||||
isIPv4 := len(bitString) == 32
|
|
||||||
|
|
||||||
// Split the bit string into 8-bit segments
|
|
||||||
segments := make([]string, 0)
|
|
||||||
if isIPv4 {
|
|
||||||
for i := 0; i < 4; i++ {
|
|
||||||
segments = append(segments, bitString[i*8:(i+1)*8])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i := 0; i < 16; i++ {
|
|
||||||
segments = append(segments, bitString[i*8:(i+1)*8])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert each segment to its decimal equivalent
|
|
||||||
decimalSegments := make([]int, len(segments))
|
|
||||||
for i, s := range segments {
|
|
||||||
val, _ := strconv.ParseInt(s, 2, 64)
|
|
||||||
decimalSegments[i] = int(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the IP address string based on the type (IPv4 or IPv6)
|
|
||||||
if isIPv4 {
|
|
||||||
return fmt.Sprintf("%d.%d.%d.%d", decimalSegments[0], decimalSegments[1], decimalSegments[2], decimalSegments[3])
|
|
||||||
} else {
|
|
||||||
ip := make(net.IP, net.IPv6len)
|
|
||||||
for i := 0; i < net.IPv6len; i++ {
|
|
||||||
ip[i] = byte(decimalSegments[i])
|
|
||||||
}
|
|
||||||
return ip.String()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// inititlaizing a new trie
|
// inititlaizing a new trie
|
||||||
@ -83,20 +38,39 @@ func newTrie() *trie {
|
|||||||
|
|
||||||
// Passing words to trie
|
// Passing words to trie
|
||||||
func (t *trie) insert(ipAddr string, cc string) {
|
func (t *trie) insert(ipAddr string, cc string) {
|
||||||
word := ipToBitString(ipAddr)
|
ipBytes := ipToBytes(ipAddr)
|
||||||
current := t.root
|
current := t.root
|
||||||
for _, wr := range word {
|
for _, b := range ipBytes {
|
||||||
index := wr - '0'
|
//For each byte in the ip address
|
||||||
if current.childrens[index] == nil {
|
//each byte is 8 bit
|
||||||
current.childrens[index] = &trie_Node{
|
for j := 0; j < 8; j++ {
|
||||||
|
bitwise := (b&uint8(math.Pow(float64(2), float64(j))) > 0)
|
||||||
|
bit := 0b0000
|
||||||
|
if bitwise {
|
||||||
|
bit = 0b0001
|
||||||
|
}
|
||||||
|
if current.childrens[bit] == nil {
|
||||||
|
current.childrens[bit] = &trie_Node{
|
||||||
childrens: [2]*trie_Node{},
|
childrens: [2]*trie_Node{},
|
||||||
ends: false,
|
|
||||||
cc: cc,
|
cc: cc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current = current.childrens[index]
|
current = current.childrens[bit]
|
||||||
}
|
}
|
||||||
current.ends = true
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
for i := 63; i >= 0; i-- {
|
||||||
|
bit := (ipInt64 >> uint(i)) & 1
|
||||||
|
if current.childrens[bit] == nil {
|
||||||
|
current.childrens[bit] = &trie_Node{
|
||||||
|
childrens: [2]*trie_Node{},
|
||||||
|
cc: cc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current = current.childrens[bit]
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func isReservedIP(ip string) bool {
|
func isReservedIP(ip string) bool {
|
||||||
@ -126,16 +100,34 @@ func (t *trie) search(ipAddr string) string {
|
|||||||
if isReservedIP(ipAddr) {
|
if isReservedIP(ipAddr) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
word := ipToBitString(ipAddr)
|
|
||||||
|
ipBytes := ipToBytes(ipAddr)
|
||||||
current := t.root
|
current := t.root
|
||||||
for _, wr := range word {
|
for _, b := range ipBytes {
|
||||||
index := wr - '0'
|
//For each byte in the ip address
|
||||||
if current.childrens[index] == nil {
|
//each byte is 8 bit
|
||||||
|
for j := 0; j < 8; j++ {
|
||||||
|
bitwise := (b&uint8(math.Pow(float64(2), float64(j))) > 0)
|
||||||
|
bit := 0b0000
|
||||||
|
if bitwise {
|
||||||
|
bit = 0b0001
|
||||||
|
}
|
||||||
|
if current.childrens[bit] == nil {
|
||||||
return current.cc
|
return current.cc
|
||||||
}
|
}
|
||||||
current = current.childrens[index]
|
current = current.childrens[bit]
|
||||||
}
|
}
|
||||||
if current.ends {
|
}
|
||||||
|
/*
|
||||||
|
for i := 63; i >= 0; i-- {
|
||||||
|
bit := (ipInt64 >> uint(i)) & 1
|
||||||
|
if current.childrens[bit] == nil {
|
||||||
|
return current.cc
|
||||||
|
}
|
||||||
|
current = current.childrens[bit]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if len(current.childrens) == 0 {
|
||||||
return current.cc
|
return current.cc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
uuid "github.com/satori/go.uuid"
|
"github.com/google/uuid"
|
||||||
"imuslab.com/zoraxy/mod/utils"
|
"imuslab.com/zoraxy/mod/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ func (h *Handler) HandleAddBlockingPath(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
targetBlockingPath := BlockingPath{
|
targetBlockingPath := BlockingPath{
|
||||||
UUID: uuid.NewV4().String(),
|
UUID: uuid.New().String(),
|
||||||
MatchingPath: matchingPath,
|
MatchingPath: matchingPath,
|
||||||
ExactMatch: exactMatch == "true",
|
ExactMatch: exactMatch == "true",
|
||||||
StatusCode: statusCode,
|
StatusCode: statusCode,
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
uuid "github.com/satori/go.uuid"
|
"github.com/google/uuid"
|
||||||
"imuslab.com/zoraxy/mod/database"
|
"imuslab.com/zoraxy/mod/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ func NewTCProxy(options *Options) *Manager {
|
|||||||
|
|
||||||
func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
|
func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
|
||||||
//Generate a new config from options
|
//Generate a new config from options
|
||||||
configUUID := uuid.NewV4().String()
|
configUUID := uuid.New().String()
|
||||||
thisConfig := ProxyRelayConfig{
|
thisConfig := ProxyRelayConfig{
|
||||||
UUID: configUUID,
|
UUID: configUUID,
|
||||||
Name: config.Name,
|
Name: config.Name,
|
||||||
|
@ -37,46 +37,6 @@ func SendOK(w http.ResponseWriter) {
|
|||||||
w.Write([]byte("\"OK\""))
|
w.Write([]byte("\"OK\""))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
The paramter move function (mv)
|
|
||||||
|
|
||||||
You can find similar things in the PHP version of ArOZ Online Beta. You need to pass in
|
|
||||||
r (HTTP Request Object)
|
|
||||||
getParamter (string, aka $_GET['This string])
|
|
||||||
|
|
||||||
Will return
|
|
||||||
Paramter string (if any)
|
|
||||||
Error (if error)
|
|
||||||
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
func Mv(r *http.Request, getParamter string, postMode bool) (string, error) {
|
|
||||||
if postMode == false {
|
|
||||||
//Access the paramter via GET
|
|
||||||
keys, ok := r.URL.Query()[getParamter]
|
|
||||||
|
|
||||||
if !ok || len(keys[0]) < 1 {
|
|
||||||
//log.Println("Url Param " + getParamter +" is missing")
|
|
||||||
return "", errors.New("GET paramter " + getParamter + " not found or it is empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query()["key"] will return an array of items,
|
|
||||||
// we only want the single item.
|
|
||||||
key := keys[0]
|
|
||||||
return string(key), nil
|
|
||||||
} else {
|
|
||||||
//Access the parameter via POST
|
|
||||||
r.ParseForm()
|
|
||||||
x := r.Form.Get(getParamter)
|
|
||||||
if len(x) == 0 || x == "" {
|
|
||||||
return "", errors.New("POST paramter " + getParamter + " not found or it is empty")
|
|
||||||
}
|
|
||||||
return string(x), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Get GET parameter
|
// Get GET parameter
|
||||||
func GetPara(r *http.Request, key string) (string, error) {
|
func GetPara(r *http.Request, key string) (string, error) {
|
||||||
keys, ok := r.URL.Query()[key]
|
keys, ok := r.URL.Query()[key]
|
||||||
@ -98,6 +58,24 @@ func PostPara(r *http.Request, key string) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get POST paramter as boolean, accept 1 or true
|
||||||
|
func PostBool(r *http.Request, key string) (bool, error) {
|
||||||
|
x, err := PostPara(r, key)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
x = strings.TrimSpace(x)
|
||||||
|
|
||||||
|
if x == "1" || strings.ToLower(x) == "true" {
|
||||||
|
return true, nil
|
||||||
|
} else if x == "0" || strings.ToLower(x) == "false" {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, errors.New("invalid boolean given")
|
||||||
|
}
|
||||||
|
|
||||||
func FileExists(filename string) bool {
|
func FileExists(filename string) bool {
|
||||||
_, err := os.Stat(filename)
|
_, err := os.Stat(filename)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
@ -128,19 +106,6 @@ func TimeToString(targetTime time.Time) string {
|
|||||||
return targetTime.Format("2006-01-02 15:04:05")
|
return targetTime.Format("2006-01-02 15:04:05")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use for redirections
|
|
||||||
func ConstructRelativePathFromRequestURL(requestURI string, redirectionLocation string) string {
|
|
||||||
if strings.Count(requestURI, "/") == 1 {
|
|
||||||
//Already root level
|
|
||||||
return redirectionLocation
|
|
||||||
}
|
|
||||||
for i := 0; i < strings.Count(requestURI, "/")-1; i++ {
|
|
||||||
redirectionLocation = "../" + redirectionLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirectionLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if given string in a given slice
|
// Check if given string in a given slice
|
||||||
func StringInArray(arr []string, str string) bool {
|
func StringInArray(arr []string, str string) bool {
|
||||||
for _, a := range arr {
|
for _, a := range arr {
|
||||||
|
@ -814,3 +814,34 @@ func HandleIncomingPortSet(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
utils.SendOK(w)
|
utils.SendOK(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle list of root route options
|
||||||
|
func HandleRootRouteOptionList(w http.ResponseWriter, r *http.Request) {
|
||||||
|
js, _ := json.Marshal(dynamicProxyRouter.RootRoutingOptions)
|
||||||
|
utils.SendJSONResponse(w, string(js))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle update of the root route edge case options. See dynamicproxy/rootRoute.go
|
||||||
|
func HandleRootRouteOptionsUpdate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
enableUnsetSubdomainRedirect, err := utils.PostBool(r, "unsetRedirect")
|
||||||
|
if err != nil {
|
||||||
|
utils.SendErrorResponse(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
unsetRedirectTarget, _ := utils.PostPara(r, "unsetRedirectTarget")
|
||||||
|
|
||||||
|
newRootOption := dynamicproxy.RootRoutingOptions{
|
||||||
|
EnableRedirectForUnsetRules: enableUnsetSubdomainRedirect,
|
||||||
|
UnsetRuleRedirectTarget: unsetRedirectTarget,
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicProxyRouter.RootRoutingOptions = &newRootOption
|
||||||
|
err = newRootOption.SaveToFile()
|
||||||
|
if err != nil {
|
||||||
|
utils.SendErrorResponse(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.SendOK(w)
|
||||||
|
}
|
||||||
|
@ -76,7 +76,10 @@ func startupSequence() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Create a geodb store
|
//Create a geodb store
|
||||||
geodbStore, err = geodb.NewGeoDb(sysdb)
|
geodbStore, err = geodb.NewGeoDb(sysdb, &geodb.StoreOptions{
|
||||||
|
AllowSlowIpv4LookUp: !*enableHighSpeedGeoIPLookup,
|
||||||
|
AllowSloeIpv6Lookup: !*enableHighSpeedGeoIPLookup,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<div class="standardContainer">
|
<div class="standardContainer">
|
||||||
<div class="ui basic segment">
|
<div class="ui basic segment">
|
||||||
<h2>Set Proxy Root</h2>
|
<h2>Set Proxy Root</h2>
|
||||||
<p>For all routing not found in the proxy rules, request will be redirected to the proxy root server.</p>
|
<p>The default routing point for all incoming traffics. For all routing not found in the proxy rules, request will be redirected to the proxy root server.</p>
|
||||||
<div class="ui form">
|
<div class="ui form">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>Proxy Root</label>
|
<label>Proxy Root</label>
|
||||||
@ -11,15 +11,53 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" id="rootReqTLS">
|
<input type="checkbox" id="rootReqTLS">
|
||||||
<label>Root require TLS Connection <br><small>(i.e. Your proxy target starts with https://)</small></label>
|
<label>Root require TLS connection <br><small>Check this if your proxy root URL starts with https://</small></label>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<button class="ui basic button" onclick="setProxyRoot()"><i class="teal home icon" ></i> Update Proxy Root</button>
|
<button class="ui basic button" onclick="setProxyRoot()"><i class="teal home icon" ></i> Update Proxy Root</button>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<div class="field">
|
||||||
|
<h4>Root Routing Options</h4>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input type="checkbox" id="unsetRedirect">
|
||||||
|
<label>Enable redirect for unset subdomains <br><small>Redirect subdomain that is not found to custom domain</small></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui basic segment" id="unsetRedirectDomainWrapper" style="background-color: #f7f7f7; border-radius: 1em; margin-left: 2em; padding-left: 2em; display:none;">
|
||||||
|
<div style="
|
||||||
|
position: absolute;
|
||||||
|
top:0;
|
||||||
|
left: 1em;
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
margin-top: -10px;
|
||||||
|
border-left: 10px solid transparent;
|
||||||
|
border-right: 10px solid transparent;
|
||||||
|
border-bottom: 10px solid #f7f7f7;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Redirect target domain</label>
|
||||||
|
<div class="ui input">
|
||||||
|
<input id="unsetRedirectDomain" type="text" placeholder="http://example.com">
|
||||||
|
</div>
|
||||||
|
<small>Unset subdomain will be redirected to the link above. Remember to include the protocol (e.g. http:// or https://)<br>
|
||||||
|
Leave empty for redirecting to upper level domain (e.g. notfound.example.com <i class="right arrow icon"></i> example.com)</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<button class="ui basic button" onclick="updateRootOptions()"><i class="blue save icon" ></i> Save Root Options</button>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
$("#advanceRootSettings").accordion();
|
||||||
|
|
||||||
function initRootInfo(){
|
function initRootInfo(){
|
||||||
$.get("/api/proxy/list?type=root", function(data){
|
$.get("/api/proxy/list?type=root", function(data){
|
||||||
if (data == null){
|
if (data == null){
|
||||||
@ -29,10 +67,60 @@
|
|||||||
checkRootRequireTLS(data.Domain);
|
checkRootRequireTLS(data.Domain);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
initRootInfo();
|
initRootInfo();
|
||||||
|
|
||||||
|
function updateRootSettingStates(){
|
||||||
|
$.get("/api/cert/tls", function(data){
|
||||||
|
if (data == true){
|
||||||
|
$("#disableRootTLS").parent().removeClass('disabled').attr("title", "");
|
||||||
|
}else{
|
||||||
|
$("#disableRootTLS").parent().addClass('disabled').attr("title", "TLS listener is not enabled");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//Bind event to tab switch
|
||||||
|
tabSwitchEventBind["setroot"] = function(){
|
||||||
|
//On switch over to this page, update root info
|
||||||
|
updateRootSettingStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Toggle the display status of the input box for domain setting
|
||||||
|
function updateRedirectionDomainSettingInputBox(useRedirect){
|
||||||
|
if(useRedirect){
|
||||||
|
$("#unsetRedirectDomainWrapper").stop().finish().slideDown("fast");
|
||||||
|
}else{
|
||||||
|
$("#unsetRedirectDomainWrapper").stop().finish().slideUp("fast");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkCustomRedirectForUnsetSubd(){
|
||||||
|
$.get("/api/proxy/root/listOptions", function(data){
|
||||||
|
$("#unsetRedirect")[0].checked = data.EnableRedirectForUnsetRules || false;
|
||||||
|
$("#unsetRedirectDomain").val(data.UnsetRuleRedirectTarget);
|
||||||
|
updateRedirectionDomainSettingInputBox(data.EnableRedirectForUnsetRules);
|
||||||
|
|
||||||
|
//Bind event to the checkbox
|
||||||
|
$("#unsetRedirect").off("change").on("change", function(){
|
||||||
|
let useRedirect = $("#unsetRedirect")[0].checked;
|
||||||
|
updateRedirectionDomainSettingInputBox(useRedirect);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
checkCustomRedirectForUnsetSubd();
|
||||||
|
|
||||||
function checkRootRequireTLS(targetDomain){
|
function checkRootRequireTLS(targetDomain){
|
||||||
|
//Trim off the http or https from the origin
|
||||||
|
if (targetDomain.startsWith("http://")){
|
||||||
|
targetDomain = targetDomain.substring(7);
|
||||||
|
$("#proxyRoot").val(targetDomain);
|
||||||
|
}else if (targetDomain.startsWith("https://")){
|
||||||
|
targetDomain = targetDomain.substring(8);
|
||||||
|
$("#proxyRoot").val(targetDomain);
|
||||||
|
}
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/api/proxy/tlscheck",
|
url: "/api/proxy/tlscheck",
|
||||||
data: {url: targetDomain},
|
data: {url: targetDomain},
|
||||||
@ -44,6 +132,8 @@
|
|||||||
}else if (data == "http"){
|
}else if (data == "http"){
|
||||||
$("#rootReqTLS").parent().checkbox("set unchecked");
|
$("#rootReqTLS").parent().checkbox("set unchecked");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -66,7 +156,7 @@
|
|||||||
data: {"type": "root", tls: rootReqTls, ep: newpr},
|
data: {"type": "root", tls: rootReqTls, ep: newpr},
|
||||||
success: function(data){
|
success: function(data){
|
||||||
if (data.error != undefined){
|
if (data.error != undefined){
|
||||||
alert(data.error);
|
msgbox(data.error, false, 5000);
|
||||||
}else{
|
}else{
|
||||||
//OK
|
//OK
|
||||||
initRootInfo();
|
initRootInfo();
|
||||||
@ -76,4 +166,25 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateRootOptions(){
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: "/api/proxy/root/updateOptions",
|
||||||
|
data: {
|
||||||
|
unsetRedirect: $("#unsetRedirect")[0].checked,
|
||||||
|
unsetRedirectTarget: $("#unsetRedirectDomain").val().trim(),
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
if (data.error != undefined){
|
||||||
|
msgbox(data.error, false);
|
||||||
|
}else{
|
||||||
|
msgbox("Root Routing Options updated");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(error) {
|
||||||
|
console.log("Error:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
@ -335,3 +335,20 @@ func HandleZoraxyInfo(w http.ResponseWriter, r *http.Request) {
|
|||||||
js, _ := json.MarshalIndent(info, "", " ")
|
js, _ := json.MarshalIndent(info, "", " ")
|
||||||
utils.SendJSONResponse(w, string(js))
|
utils.SendJSONResponse(w, string(js))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleGeoIpLookup(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ip, err := utils.GetPara(r, "ip")
|
||||||
|
if err != nil {
|
||||||
|
utils.SendErrorResponse(w, "ip not given")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cc, err := geodbStore.ResolveCountryCodeFromIP(ip)
|
||||||
|
if err != nil {
|
||||||
|
utils.SendErrorResponse(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
js, _ := json.Marshal(cc)
|
||||||
|
utils.SendJSONResponse(w, string(js))
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user