From 5622a2be538997de6b3c20bf6125f6f57676dd99 Mon Sep 17 00:00:00 2001 From: Alexandr Kolesov Date: Sun, 27 Oct 2024 14:19:08 +0400 Subject: [PATCH] Add initial structure --- .github/workflows/lint.yaml | 23 +++++++++++ .github/workflows/test.yaml | 29 ++++++++++++++ .gitignore | 1 + Makefile | 20 ++++++++++ cmd/obfsproxy/main.go | 33 ++++++++++++++++ go.mod | 13 +++++++ go.sum | 17 +++++++++ pkg/proxy.go | 76 +++++++++++++++++++++++++++++++++++++ pkg/proxy_test.go | 47 +++++++++++++++++++++++ 9 files changed, 259 insertions(+) create mode 100644 .github/workflows/lint.yaml create mode 100644 .github/workflows/test.yaml create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 cmd/obfsproxy/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 pkg/proxy.go create mode 100644 pkg/proxy_test.go diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..01dde70 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,23 @@ +name: Lint + +on: + push: + workflow_call: + +jobs: + lint: + name: Run golanci-lint + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + + - name: golangci-lint + uses: golangci/golangci-lint-action@v5 + with: + version: v1.61.0 + args: --timeout=5m diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..6b584a7 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,29 @@ +name: Test + +on: + workflow_dispatch: + push: + branches: + - '*' + +jobs: + + build: + name: Build and test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version-file: "go.mod" + + - name: Install exiftool + run: sudo apt-get update && sudo apt-get install -y exiftool + + - name: Build + run: go build -v ./... + + - name: Test + run: go test -v ./... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..68f810f --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +BUILD_DIR := build/ + +.PHONY: all +all: build + +.PHONY: build +build: + go build -o $(BUILD_DIR) ./... + +.PHONY: test +test: + go test ./... + +.PHONY: lint +lint: + golangci-lint run + +.PHONY: clean +clean: + rm -rf $(BUILD_DIR) diff --git a/cmd/obfsproxy/main.go b/cmd/obfsproxy/main.go new file mode 100644 index 0000000..52b71be --- /dev/null +++ b/cmd/obfsproxy/main.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "os" + + "github.com/askolesov/obfsproxy/pkg" + "github.com/spf13/cobra" +) + +func main() { + var listenAddr, targetAddr string + + rootCmd := &cobra.Command{ + Use: "obfsproxy", + Short: "A simple obfuscating proxy", + Run: func(cmd *cobra.Command, args []string) { + proxy := pkg.NewProxy(listenAddr, targetAddr) + if err := proxy.Start(); err != nil { + fmt.Println("Error:", err) + os.Exit(1) + } + }, + } + + rootCmd.Flags().StringVarP(&listenAddr, "listen", "l", "localhost:8080", "Address to listen on") + rootCmd.Flags().StringVarP(&targetAddr, "target", "t", "localhost:80", "Address to forward to") + + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..029c1ba --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module github.com/askolesov/obfsproxy + +go 1.23.2 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.9.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c7da2f0 --- /dev/null +++ b/go.sum @@ -0,0 +1,17 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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/pkg/proxy.go b/pkg/proxy.go new file mode 100644 index 0000000..d3d9e8b --- /dev/null +++ b/pkg/proxy.go @@ -0,0 +1,76 @@ +package pkg + +import ( + "io" + "log" + "net" +) + +type Proxy struct { + ListenAddr string + TargetAddr string +} + +func NewProxy(listenAddr, targetAddr string) *Proxy { + return &Proxy{ + ListenAddr: listenAddr, + TargetAddr: targetAddr, + } +} + +func (p *Proxy) Start() error { + listener, err := net.Listen("tcp", p.ListenAddr) + if err != nil { + return err + } + defer listener.Close() + + log.Printf("Proxy listening on %s, forwarding to %s", p.ListenAddr, p.TargetAddr) + + for { + clientConn, err := listener.Accept() + if err != nil { + log.Printf("Error accepting connection: %v", err) + continue + } + go p.handleConnection(clientConn) + } +} + +func (p *Proxy) handleConnection(clientConn net.Conn) { + defer clientConn.Close() + + targetConn, err := net.Dial("tcp", p.TargetAddr) + if err != nil { + log.Printf("Error connecting to target: %v", err) + return + } + defer targetConn.Close() + + go p.proxy(clientConn, targetConn) + p.proxy(targetConn, clientConn) +} + +func (p *Proxy) proxy(dst, src net.Conn) { + buf := make([]byte, 1024) + for { + n, err := src.Read(buf) + if err != nil { + if err != io.EOF { + log.Printf("Error reading from connection: %v", err) + } + return + } + + // Invert bytes + for i := 0; i < n; i++ { + buf[i] = ^buf[i] + } + + _, err = dst.Write(buf[:n]) + if err != nil { + log.Printf("Error writing to connection: %v", err) + return + } + } +} diff --git a/pkg/proxy_test.go b/pkg/proxy_test.go new file mode 100644 index 0000000..e90c2a3 --- /dev/null +++ b/pkg/proxy_test.go @@ -0,0 +1,47 @@ +package pkg + +import ( + "io" + "net" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestProxy(t *testing.T) { + // Create a proxy instance + p := &Proxy{} + + // Create pipe connections + in1, out1 := net.Pipe() + defer in1.Close() + defer out1.Close() + in2, out2 := net.Pipe() + defer in2.Close() + defer out2.Close() + + // Test data + testData := []byte("Hello, World!") + expectedData := make([]byte, len(testData)) + for i, b := range testData { + expectedData[i] = ^b // Invert bytes + } + + // Run proxy in a goroutine + go p.proxy(in2, out1) + + go func() { + // Write test data to server + _, err := in1.Write(testData) + require.NoError(t, err, "Failed to write to server") + in1.Close() + }() + + // Read from client + result := make([]byte, len(testData)) + _, err := io.ReadFull(out2, result) + require.NoError(t, err, "Failed to read from client") + + // Compare result with expected data + require.Equal(t, expectedData, result, "Proxy data mismatch") +}