From 823f2eaa1aef99fcb23e1b6a6f0e613dbd60b33e Mon Sep 17 00:00:00 2001 From: eleksir Date: Thu, 3 Oct 2024 19:17:23 +0300 Subject: [PATCH] SpoofDPI: fix https-proxy premature connection close --- ...0430c7d855a63d15337e9781933f6e55707f.patch | 31 +++++ SpoofDPI/SpoofDPI.SlackBuild | 5 +- ...13eb4b347899b18cf8df57cc423e55313e2a.patch | 125 ++++++++++++++++++ SpoofDPI/spoofdpi.sysconfig | 2 +- 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 SpoofDPI/8a370430c7d855a63d15337e9781933f6e55707f.patch create mode 100644 SpoofDPI/a12a13eb4b347899b18cf8df57cc423e55313e2a.patch diff --git a/SpoofDPI/8a370430c7d855a63d15337e9781933f6e55707f.patch b/SpoofDPI/8a370430c7d855a63d15337e9781933f6e55707f.patch new file mode 100644 index 0000000..57c89f5 --- /dev/null +++ b/SpoofDPI/8a370430c7d855a63d15337e9781933f6e55707f.patch @@ -0,0 +1,31 @@ +From 8a370430c7d855a63d15337e9781933f6e55707f Mon Sep 17 00:00:00 2001 +From: Andrey Semenov +Date: Thu, 19 Sep 2024 17:32:37 +0500 +Subject: [PATCH] fix: write to lConn even if any error met and some bytes was + read + +--- + proxy/handler/https.go | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/proxy/handler/https.go b/proxy/handler/https.go +index f709925..bc320fd 100644 +--- a/proxy/handler/https.go ++++ b/proxy/handler/https.go +@@ -2,7 +2,6 @@ package handler + + import ( + "context" +- "errors" + "io" + "net" + "regexp" +@@ -134,7 +133,7 @@ func (h *HttpsHandler) communicate(ctx context.Context, from *net.TCPConn, to *n + + bytesRead, err := ReadBytes(ctx, from, buf) + if err != nil { +- if errors.Is(err, io.EOF) && len(bytesRead) > 0 { ++ if len(bytesRead) > 0 { + h.write(logger, td, to, bytesRead) + } + logger.Debug().Msgf("error reading from %s: %s", fd, err) diff --git a/SpoofDPI/SpoofDPI.SlackBuild b/SpoofDPI/SpoofDPI.SlackBuild index 618d824..a48ea7f 100644 --- a/SpoofDPI/SpoofDPI.SlackBuild +++ b/SpoofDPI/SpoofDPI.SlackBuild @@ -27,7 +27,7 @@ cd $(dirname $0) ; CWD=$(pwd) PRGNAM=SpoofDPI VERSION=${VERSION:-0.12.0} -BUILD=${BUILD:-1} +BUILD=${BUILD:-2} TAG=${TAG:-_EXs} PKGTYPE=${PKGTYPE:-tgz} @@ -77,6 +77,9 @@ find -L . \ \( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \ -exec chmod 644 {} \+ +patch -p1 -i $CWD/a12a13eb4b347899b18cf8df57cc423e55313e2a.patch +patch -p1 -i $CWD/8a370430c7d855a63d15337e9781933f6e55707f.patch + CGO_ENABLED=0 go build -ldflags '-w -s -extldflags "-static"' -trimpath -tags timetzdata -o spoofdpi ./cmd/spoofdpi install -Dpm 0755 spoofdpi $PKG/usr/sbin/spoofdpi diff --git a/SpoofDPI/a12a13eb4b347899b18cf8df57cc423e55313e2a.patch b/SpoofDPI/a12a13eb4b347899b18cf8df57cc423e55313e2a.patch new file mode 100644 index 0000000..b438cb3 --- /dev/null +++ b/SpoofDPI/a12a13eb4b347899b18cf8df57cc423e55313e2a.patch @@ -0,0 +1,125 @@ +From a12a13eb4b347899b18cf8df57cc423e55313e2a Mon Sep 17 00:00:00 2001 +From: Andrey Semenov +Date: Thu, 19 Sep 2024 17:21:03 +0500 +Subject: [PATCH] fix: write to lConn even if io.EOF met and some bytes was + read + +--- + proxy/handler/https.go | 58 ++++++++++++++++++++++++++++++++---------- + 1 file changed, 45 insertions(+), 13 deletions(-) + +diff --git a/proxy/handler/https.go b/proxy/handler/https.go +index 857fead..f709925 100644 +--- a/proxy/handler/https.go ++++ b/proxy/handler/https.go +@@ -2,10 +2,14 @@ package handler + + import ( + "context" ++ "errors" ++ "io" + "net" + "regexp" + "strconv" ++ "sync" + ++ "github.com/rs/zerolog" + "github.com/xvzc/SpoofDPI/packet" + "github.com/xvzc/SpoofDPI/util" + "github.com/xvzc/SpoofDPI/util/log" +@@ -74,36 +78,53 @@ func (h *HttpsHandler) Serve(ctx context.Context, lConn *net.TCPConn, initPkt *p + logger.Debug().Msgf("client sent hello %d bytes", len(clientHello)) + + // Generate a go routine that reads from the server +- go h.communicate(ctx, rConn, lConn, initPkt.Domain(), lConn.RemoteAddr().String()) +- go h.communicate(ctx, lConn, rConn, lConn.RemoteAddr().String(), initPkt.Domain()) ++ closeWg := sync.WaitGroup{} ++ closeWg.Add(2) ++ done := make(chan struct{}) ++ doneOnce := sync.Once{} ++ closeDoneFunc := func() { ++ close(done) ++ } ++ go func() { ++ defer closeWg.Done() ++ h.communicate(ctx, rConn, lConn, initPkt.Domain(), lConn.RemoteAddr().String()) ++ }() ++ go func() { ++ defer closeWg.Done() ++ h.communicate(ctx, lConn, rConn, lConn.RemoteAddr().String(), initPkt.Domain()) ++ }() ++ go func(wg *sync.WaitGroup) { ++ wg.Wait() ++ doneOnce.Do(closeDoneFunc) ++ }(&closeWg) + + if h.exploit { + logger.Debug().Msgf("writing chunked client hello to %s", initPkt.Domain()) + chunks := splitInChunks(ctx, clientHello, h.windowsize) + if _, err := writeChunks(rConn, chunks); err != nil { + logger.Debug().Msgf("error writing chunked client hello to %s: %s", initPkt.Domain(), err) +- return ++ doneOnce.Do(closeDoneFunc) + } + } else { + logger.Debug().Msgf("writing plain client hello to %s", initPkt.Domain()) + if _, err := rConn.Write(clientHello); err != nil { + logger.Debug().Msgf("error writing plain client hello to %s: %s", initPkt.Domain(), err) +- return ++ doneOnce.Do(closeDoneFunc) + } + } ++ // wait while conn handling routines stop, then close both connections ++ // current routine will sleep until conn handling routines works ++ <-done ++ _ = lConn.Close() ++ _ = rConn.Close() ++ ++ logger.Debug().Msgf("closing proxy connection: %s -> %s", lConn.RemoteAddr(), initPkt.Domain()) + } + + func (h *HttpsHandler) communicate(ctx context.Context, from *net.TCPConn, to *net.TCPConn, fd string, td string) { + ctx = util.GetCtxWithScope(ctx, h.protocol) + logger := log.GetCtxLogger(ctx) + +- defer func() { +- from.Close() +- to.Close() +- +- logger.Debug().Msgf("closing proxy connection: %s -> %s", fd, td) +- }() +- + buf := make([]byte, h.bufferSize) + for { + err := setConnectionTimeout(from, h.timeout) +@@ -113,17 +134,28 @@ func (h *HttpsHandler) communicate(ctx context.Context, from *net.TCPConn, to *n + + bytesRead, err := ReadBytes(ctx, from, buf) + if err != nil { ++ if errors.Is(err, io.EOF) && len(bytesRead) > 0 { ++ h.write(logger, td, to, bytesRead) ++ } + logger.Debug().Msgf("error reading from %s: %s", fd, err) + return + } + +- if _, err := to.Write(bytesRead); err != nil { +- logger.Debug().Msgf("error writing to %s", td) ++ if !h.write(logger, td, to, bytesRead) { + return + } + } + } + ++func (h *HttpsHandler) write(logger zerolog.Logger, connName string, to io.Writer, bytes []byte) (ok bool) { ++ ok = true ++ if _, err := to.Write(bytes); err != nil { ++ logger.Debug().Msgf("error writing to %s", connName) ++ ok = false ++ } ++ return ++} ++ + func splitInChunks(ctx context.Context, bytes []byte, size int) [][]byte { + logger := log.GetCtxLogger(ctx) + diff --git a/SpoofDPI/spoofdpi.sysconfig b/SpoofDPI/spoofdpi.sysconfig index 52d6622..ca704bc 100644 --- a/SpoofDPI/spoofdpi.sysconfig +++ b/SpoofDPI/spoofdpi.sysconfig @@ -1,2 +1,2 @@ # Options for running SpoofDPI daemon -OPTIONS="-addr 127.0.0.1 -port 8080 -no-banner -system-proxy false" \ No newline at end of file +OPTIONS="-addr 127.0.0.1 -port 8080 -no-banner -system-proxy false"