From 68bbd67c01aaebbf8d14cb6589da4112c0305688 Mon Sep 17 00:00:00 2001 From: MrMelon54 Date: Wed, 19 Apr 2023 01:30:23 +0100 Subject: [PATCH] First commit --- .idea/.gitignore | 8 +++ .idea/discord.xml | 7 ++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 +++ .idea/violet.iml | 9 +++ cmd/violet/main.go | 5 ++ go.mod | 16 +++++ go.sum | 23 +++++++ proxy/reverse-proxy.go | 145 +++++++++++++++++++++++++++++++++++++++++ target/redirect.go | 15 +++++ target/service.go | 7 ++ 11 files changed, 249 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/discord.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/violet.iml create mode 100644 cmd/violet/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 proxy/reverse-proxy.go create mode 100644 target/redirect.go create mode 100644 target/service.go diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..d8e9561 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..3ce3588 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e95f680 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/violet.iml b/.idea/violet.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/violet.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/cmd/violet/main.go b/cmd/violet/main.go new file mode 100644 index 0000000..ace8a1e --- /dev/null +++ b/cmd/violet/main.go @@ -0,0 +1,5 @@ +package violet + +func main() { + +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..75ed3dc --- /dev/null +++ b/go.mod @@ -0,0 +1,16 @@ +module github.com/MrMelon54/violet + +go 1.20 + +require ( + github.com/julienschmidt/httprouter v1.3.0 + github.com/stretchr/testify v1.8.2 + github.com/yousuf64/shift v0.4.0 + golang.org/x/net v0.9.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..499b05b --- /dev/null +++ b/go.sum @@ -0,0 +1,23 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/yousuf64/shift v0.4.0 h1:jiuYPa9KGyTShM08GEcSRSaZeO2jPEIpdqaplsRtk8g= +github.com/yousuf64/shift v0.4.0/go.mod h1:D9b+mj37s3goL48EGX2oCrYHW4rg4c3Il2w6fukjxas= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/proxy/reverse-proxy.go b/proxy/reverse-proxy.go new file mode 100644 index 0000000..46657d1 --- /dev/null +++ b/proxy/reverse-proxy.go @@ -0,0 +1,145 @@ +package proxy + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "golang.org/x/net/proxy" + "log" + "net" + "net/http" + "net/http/httputil" + "sync" + "time" +) + +type reverseProxyHostKey int + +type ReverseProxyContext interface { + IsIgnoreCert() bool + UpdateHeaders(http.Header) +} + +func SetReverseProxyHost(req *http.Request, hf ReverseProxyContext) *http.Request { + ctx := req.Context() + ctx2 := context.WithValue(ctx, reverseProxyHostKey(0), hf) + return req.WithContext(ctx2) +} + +func CreateHybridReverseProxy() *httputil.ReverseProxy { + return &httputil.ReverseProxy{ + Director: func(req *http.Request) {}, + Transport: NewHybridTransport(), + ModifyResponse: func(rw *http.Response) error { return nil }, + ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) { + log.Printf("[ReverseProxy] Request: %#v\n -- Error: %s\n", req, err) + rw.WriteHeader(http.StatusBadGateway) + _, _ = rw.Write([]byte("502 Bad gateway\n")) + }, + } +} + +type HybridTransport struct { + baseDialer *net.Dialer + normalTransport http.RoundTripper + insecureTransport http.RoundTripper + socksSync *sync.RWMutex + socksTransport map[string]http.RoundTripper +} + +func NewHybridTransport() *HybridTransport { + h := &HybridTransport{ + baseDialer: &net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }, + socksSync: &sync.RWMutex{}, + socksTransport: make(map[string]http.RoundTripper), + } + h.normalTransport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: h.baseDialer.DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 15, + TLSHandshakeTimeout: 10 * time.Second, + IdleConnTimeout: 30 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + ResponseHeaderTimeout: 10 * time.Second, + } + h.insecureTransport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: h.baseDialer.DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 15, + TLSHandshakeTimeout: 10 * time.Second, + IdleConnTimeout: 30 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + ResponseHeaderTimeout: 10 * time.Second, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + return h +} + +func (h *HybridTransport) RoundTrip(req *http.Request) (*http.Response, error) { + newHost := req.Context().Value(reverseProxyHostKey(0)) + hf, ok := newHost.(ReverseProxyContext) + if !ok { + return nil, errors.New("failed to detect reverse proxy configuration") + } + + // Do a round trip using existing transports + var trip *http.Response + var err error + if hf.IsIgnoreCert() { + trip, err = h.insecureTransport.RoundTrip(req) + } else { + trip, err = h.normalTransport.RoundTrip(req) + } + if err != nil { + return nil, err + } + + // Override headers + hf.UpdateHeaders(trip.Header) + return trip, nil +} + +func (h *HybridTransport) getSocksProxy(addr string, insecure bool) (http.RoundTripper, error) { + if insecure { + addr = "%i-" + addr + } + h.socksSync.RLock() + s, ok := h.socksTransport[addr] + h.socksSync.RUnlock() + if ok { + return s, nil + } + + dialer, err := proxy.SOCKS5("tcp", addr, nil, proxy.Direct) + if err != nil { + return nil, fmt.Errorf("cannot connect to the proxy: %s", err) + } + + if f, ok := dialer.(proxy.ContextDialer); ok { + t := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: f.DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 15, + TLSHandshakeTimeout: 10 * time.Second, + IdleConnTimeout: 30 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + ResponseHeaderTimeout: 10 * time.Second, + DisableKeepAlives: true, + } + if insecure { + t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + } + h.socksSync.Lock() + h.socksTransport[addr] = t + h.socksSync.Unlock() + return t, nil + } + return nil, errors.New("cannot create socks5 dialer") +} diff --git a/target/redirect.go b/target/redirect.go new file mode 100644 index 0000000..10c4c88 --- /dev/null +++ b/target/redirect.go @@ -0,0 +1,15 @@ +package target + +import ( + "net/http" + "net/url" +) + +type Redirect struct { + url.URL + Code int +} + +func (r Redirect) Handler() http.Handler { + return http.RedirectHandler(r.URL.String(), r.Code) +} diff --git a/target/service.go b/target/service.go new file mode 100644 index 0000000..c9dea4d --- /dev/null +++ b/target/service.go @@ -0,0 +1,7 @@ +package target + +type Service struct { + Host string + Port int + Absolute bool +}