-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Alexandru Eftimie - mac
committed
Oct 31, 2022
0 parents
commit b1d91d9
Showing
7 changed files
with
358 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package main | ||
|
||
import ( | ||
"crypto/tls" | ||
"errors" | ||
"log" | ||
"net" | ||
|
||
"github.com/fatih/color" | ||
"golang.org/x/net/http2" | ||
) | ||
|
||
var accTransp *http2.Transport | ||
|
||
func checkErr(err error, str string) { | ||
if err != nil { | ||
log.Fatalln("Error: ", err, "context:", str) | ||
} else { | ||
log.Println(color.WhiteString("No error:"), str) | ||
} | ||
} | ||
|
||
func setupTransport() { | ||
accTransp = &http2.Transport{ | ||
AllowHTTP: true, | ||
// Pretend we are dialing a TLS endpoint. | ||
// Note, we ignore the passed tls.Config | ||
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { | ||
return nil, errors.New("Should not be called") | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package main | ||
|
||
import ( | ||
apiconfig "github.com/Alex-Eftimie/api-config" | ||
) | ||
|
||
type ConfigType struct { | ||
apiconfig.Configuration | ||
ProxyAddr string | ||
BindPort int | ||
} | ||
|
||
var Co *ConfigType | ||
|
||
func init() { | ||
// log.Println("Reading Config") | ||
Co = &ConfigType{ | ||
Configuration: *apiconfig.NewConfig("config.jsonc"), | ||
} | ||
|
||
apiconfig.LoadConfig(Co) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
|
||
"github.com/Alex-Eftimie/netutils" | ||
"github.com/fatih/color" | ||
"golang.org/x/net/http2" | ||
) | ||
|
||
var h2cc *http2.ClientConn | ||
|
||
// HTTPServer handles http proxy | ||
type HTTPServer struct { | ||
*http.Server | ||
} | ||
|
||
func newHTTPServer(addr string) *HTTPServer { | ||
hs := &HTTPServer{} | ||
hs.Server = &http.Server{ | ||
Addr: addr, | ||
Handler: hs, | ||
} | ||
return hs | ||
} | ||
|
||
func (cs *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
log.Println("[HTTP]", r.RemoteAddr, r.Method, r.URL) | ||
|
||
// r.Write(os.Stderr) | ||
|
||
var pipW *io.PipeWriter | ||
var pipR *io.PipeReader | ||
|
||
if r.Method == "CONNECT" { | ||
pipR, pipW = io.Pipe() | ||
r.Body = pipR | ||
} | ||
|
||
resp, err := h2cc.RoundTrip(r) | ||
if err != nil { | ||
http.Error(w, err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
_, isInternal := w.(Internal) | ||
|
||
if r.Method == "CONNECT" { | ||
hijacker, ok := w.(http.Hijacker) | ||
if !ok { | ||
http.Error(w, "Tunneling not supported", http.StatusInternalServerError) | ||
return | ||
} | ||
clientConn, _, err := hijacker.Hijack() | ||
if err != nil { | ||
http.Error(w, err.Error(), http.StatusServiceUnavailable) | ||
return | ||
} | ||
defer clientConn.Close() | ||
|
||
if !isInternal { | ||
downR := http.Response{ | ||
StatusCode: http.StatusOK, | ||
Status: http.StatusText(http.StatusOK), | ||
Close: true, | ||
ProtoMajor: r.ProtoMajor, | ||
ProtoMinor: r.ProtoMinor, | ||
Body: ioutil.NopCloser(bytes.NewBufferString("")), | ||
Header: make(http.Header), | ||
} | ||
|
||
log.Println("We are connected, writing response") | ||
// if we don't close the body, write will just hang | ||
downR.Body.Close() | ||
downR.Write(clientConn) | ||
} | ||
|
||
data := netutils.HTTPReadWriteCloser{ | ||
Writer: pipW, | ||
ReadCloser: resp.Body, | ||
} | ||
|
||
netutils.RunPiper(clientConn, data) | ||
color.Yellow("Piper Finished") | ||
|
||
return | ||
} | ||
|
||
resp.ProtoMajor = r.ProtoMajor | ||
resp.ProtoMinor = r.ProtoMinor | ||
resp.Proto = r.Proto | ||
|
||
netutils.CopyHeader(w.Header(), resp.Header) | ||
w.WriteHeader(resp.StatusCode) | ||
io.Copy(w, resp.Body) | ||
resp.Body.Close() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"net" | ||
"time" | ||
|
||
"github.com/Alex-Eftimie/utils" | ||
"github.com/fatih/color" | ||
"github.com/soheilhy/cmux" | ||
) | ||
|
||
var proxyConn net.Conn | ||
var s5s *Socks5Server | ||
var h1s *HTTPServer | ||
|
||
func main() { | ||
utils.DebugLevel = 1000 | ||
var err error | ||
setupTransport() | ||
|
||
manageUpstream(Co.ProxyAddr) | ||
|
||
// if len(os.Args) > 1 { | ||
// os.Exit(0) | ||
// } | ||
addr := fmt.Sprintf("127.0.0.1:%d", Co.BindPort) | ||
cl, err := net.Listen("tcp", addr) | ||
if err != nil { | ||
log.Fatalln("Failed to start: ", err) | ||
} | ||
mux := cmux.New(cl) | ||
|
||
// run the matchers | ||
socks5Matcher := mux.Match(Socks5Matcher()) | ||
httpMatcher := mux.Match(cmux.HTTP1Fast()) | ||
|
||
// initialize the servers | ||
s5s := newSocks5Server(addr) | ||
h1s := newHTTPServer(addr) | ||
// h1s. | ||
// run the servers | ||
go h1s.Serve(httpMatcher) | ||
go s5s.Serve(socks5Matcher) | ||
|
||
mux.Serve() | ||
} | ||
|
||
func manageUpstream(host string) { | ||
var err error | ||
var ctx = context.Background() | ||
|
||
for { | ||
proxyConn, err = net.Dial("tcp", host) | ||
if err == nil { | ||
break | ||
} | ||
log.Println(color.RedString("net.Dial error:"), err) | ||
log.Println("Retrying in 5 seconds") | ||
alert("Accelerator Error", fmt.Sprintf("Retrying in 5 seconds\n\nError: %s", err.Error())) | ||
time.Sleep(5 * time.Second) | ||
} | ||
h2cc, err = accTransp.NewClientConn(proxyConn) | ||
checkErr(err, "accTransp.NewClientConn") | ||
log.Println(color.GreenString("Connected to upstream:"), host) | ||
|
||
first := true | ||
go func() { | ||
for { | ||
time.Sleep(5 * time.Second) | ||
// keep alive | ||
err = h2cc.Ping(ctx) | ||
if err != nil { | ||
log.Println(color.RedString("Keepalive error:"), err, ", reconnecting") | ||
alert("Accelerator Error", fmt.Sprintf("Failed keepalive, reconnecting\n\nError: %s", err.Error())) | ||
go manageUpstream(host) | ||
return | ||
} | ||
log.Println(color.GreenString("Alive")) | ||
if first { | ||
|
||
notify("", fmt.Sprintf("Listening on port %d, forwarding to: %s", Co.BindPort, Co.ProxyAddr)) | ||
first = false | ||
} | ||
} | ||
}() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package main | ||
|
||
import "github.com/gen2brain/beeep" | ||
|
||
func notify(title, body string) { | ||
if len(title) == 0 { | ||
title = "Accelerator" | ||
} | ||
err := beeep.Notify(title, body, "") | ||
if err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func alert(title, body string) { | ||
if len(title) == 0 { | ||
title = "Accelerator" | ||
} | ||
err := beeep.Alert(title, body, "") | ||
if err != nil { | ||
panic(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"log" | ||
"net" | ||
"net/http" | ||
|
||
"github.com/Alex-Eftimie/netutils" | ||
"github.com/Alex-Eftimie/socks5" | ||
"github.com/Alex-Eftimie/utils" | ||
"github.com/davecgh/go-spew/spew" | ||
"github.com/fatih/color" | ||
"github.com/soheilhy/cmux" | ||
) | ||
|
||
// Socks5Server handles socks5 proxy | ||
type Socks5Server struct { | ||
*socks5.Server | ||
} | ||
|
||
// InternalHTTPWriter is used by socks5 to pipe content | ||
type InternalHTTPWriter struct { | ||
net.Conn | ||
} | ||
|
||
// Hijack returns the inner net.Conn | ||
func (m InternalHTTPWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { | ||
return m.Conn, nil, nil | ||
} | ||
|
||
// Header returns a Internal http.Header | ||
func (InternalHTTPWriter) Header() http.Header { return make(http.Header) } | ||
|
||
// WriteHeader does nothing | ||
func (InternalHTTPWriter) WriteHeader(int) {} | ||
|
||
// Internal returns true if it's a Internal request | ||
func (InternalHTTPWriter) Internal() bool { return true } | ||
|
||
// Internal interface will be used to identify internal requests in http | ||
type Internal interface { | ||
Internal() bool | ||
} | ||
|
||
// Socks5Matcher helps cmux determine if a request is socks5 | ||
func Socks5Matcher() cmux.Matcher { | ||
return func(r io.Reader) bool { | ||
b := make([]byte, 1) | ||
r.Read(b) | ||
return b[0] == 0x05 | ||
} | ||
} | ||
|
||
func newSocks5Server(addr string) *Socks5Server { | ||
s5s := &Socks5Server{} | ||
s5s.Server = &socks5.Server{ | ||
Addr: addr, | ||
TunnelHandler: s5s.HandleTunnel, | ||
} | ||
return s5s | ||
} | ||
|
||
// HandleTunnel is called when a socks5 client requests to connect | ||
func (s *Socks5Server) HandleTunnel(uinfo *netutils.UserInfo, ip string, c net.Conn, upstreamHost string, upstreamPort int, sc socks5.StatusCallback) { | ||
color.Yellow(spew.Sdump("[Socks5] Connect", upstreamHost, uinfo)) | ||
|
||
w := &InternalHTTPWriter{c} | ||
|
||
r, err := http.NewRequest("CONNECT", fmt.Sprintf("http://%s:%d", upstreamHost, upstreamPort), utils.PrintReader{Reader: c, Prefix: "from HTTP"}) | ||
r.RemoteAddr = "Socks5Server" | ||
if err != nil { | ||
log.Println("Error at http.NewRequest,", err) | ||
sc("general-failure.status", socks5.StatusGeneralFailure) | ||
return | ||
} | ||
sc("succeeded.status", socks5.StatusSucceeded) | ||
|
||
h1s.ServeHTTP(w, r) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"folders": [ | ||
{ | ||
"path": ".." | ||
} | ||
], | ||
"settings": {} | ||
} |