Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexandru Eftimie - mac committed Oct 31, 2022
0 parents commit b1d91d9
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 0 deletions.
32 changes: 32 additions & 0 deletions accelerate.go
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")
},
}
}
23 changes: 23 additions & 0 deletions config.go
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)

}
101 changes: 101 additions & 0 deletions http.go
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()
}
89 changes: 89 additions & 0 deletions main.go
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
}
}
}()
}
23 changes: 23 additions & 0 deletions notify.go
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)
}
}
82 changes: 82 additions & 0 deletions socks5.go
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)
}
8 changes: 8 additions & 0 deletions workspace.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"folders": [
{
"path": ".."
}
],
"settings": {}
}

0 comments on commit b1d91d9

Please sign in to comment.