From 28be4b31a9fe08df88caab94ff701a2857562cfb Mon Sep 17 00:00:00 2001 From: Weii Wang Date: Wed, 15 Oct 2025 15:27:35 +0800 Subject: [PATCH 1/7] Add X-Forwarded-For header --- .github/workflows/integration-tests.yaml | 4 ++++ aproxy.go | 18 ++++++++++++------ snap/snapcraft.yaml | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index 4dd0054..889a0d4 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -75,6 +75,10 @@ jobs: sudo apt install -y socat timeout 60 socat /dev/null TCP4:tcpbin.com:4242 + - name: Test Header + run: | + timeout 60 curl --noproxy "*" http://httpbin.org/anything -svS + - name: Test Access Logs run: | sudo snap logs aproxy.aproxy | grep -Fq "example.com:80" diff --git a/aproxy.go b/aproxy.go index 2ca9b14..511ff1e 100644 --- a/aproxy.go +++ b/aproxy.go @@ -222,7 +222,7 @@ func DialProxy(proxy string) (net.Conn, error) { // DialProxyConnect dials the TCP connection and finishes the HTTP CONNECT handshake with the proxy. // dst: HOST:PORT or IP:PORT -func DialProxyConnect(proxy string, dst string) (net.Conn, error) { +func DialProxyConnect(proxy string, src, dst string) (net.Conn, error) { conn, err := DialProxy(proxy) if err != nil { return nil, err @@ -236,7 +236,8 @@ func DialProxyConnect(proxy string, dst string) (net.Conn, error) { ProtoMajor: 1, ProtoMinor: 1, Header: map[string][]string{ - "User-Agent": {fmt.Sprintf("aproxy/%s", version)}, + "User-Agent": {fmt.Sprintf("aproxy/%s", version)}, + "X-Forwarded-For": {src}, }, Host: dst, } @@ -289,7 +290,7 @@ func RelayTCP(conn io.ReadWriter, proxyConn io.ReadWriteCloser, logger *slog.Log // RelayHTTP relays a single HTTP request and response between a local connection and a proxy. // It modifies the Connection header to "close" in both the request and response. -func RelayHTTP(conn io.ReadWriter, proxyConn io.ReadWriteCloser, logger *slog.Logger) { +func RelayHTTP(conn io.ReadWriter, src string, proxyConn io.ReadWriteCloser, logger *slog.Logger) { defer proxyConn.Close() req, err := http.ReadRequest(bufio.NewReader(conn)) if err != nil { @@ -302,6 +303,10 @@ func RelayHTTP(conn io.ReadWriter, proxyConn io.ReadWriteCloser, logger *slog.Lo req.Header.Set("User-Agent", "") } req.Header.Set("Connection", "close") + // For now strip and replace the X-Forwarded-For header from incoming requests. + // We cannot trust X-Forwarded-For on arbitrary requests for security reasons. + // In the future, consider conditionally trusting X-Forwarded-For from known clients. + req.Header.Set("X-Forwarded-For", src) if req.Proto == "HTTP/1.0" { // no matter what the request protocol is, Go enforces a minimum version of HTTP/1.1 // this causes problems for HTTP/1.0 only clients like GPG (HKP) @@ -349,6 +354,7 @@ func HandleConn(conn net.Conn, proxy string) { return } logger = logger.With("original_dst", dst) + src, _, _ := net.SplitHostPort(conn.RemoteAddr().String()) consigned := NewPrereadConn(conn) switch dst.Port { case 443: @@ -359,7 +365,7 @@ func HandleConn(conn net.Conn, proxy string) { } else { host := fmt.Sprintf("%s:%d", sni, dst.Port) logger = logger.With("host", host) - proxyConn, err := DialProxyConnect(proxy, host) + proxyConn, err := DialProxyConnect(proxy, src, host) if err != nil { logger.Error("failed to connect to http proxy", "error", err) return @@ -383,11 +389,11 @@ func HandleConn(conn net.Conn, proxy string) { return } logger.Info("relay HTTP connection to proxy") - RelayHTTP(consigned, proxyConn, logger) + RelayHTTP(consigned, src, proxyConn, logger) default: consigned.EndPreread() logger = logger.With("host", fmt.Sprintf("%s:%d", dst.IP.String(), dst.Port)) - proxyConn, err := DialProxyConnect(proxy, fmt.Sprintf("%s:%d", dst.IP.String(), dst.Port)) + proxyConn, err := DialProxyConnect(proxy, src, fmt.Sprintf("%s:%d", dst.IP.String(), dst.Port)) if err != nil { logger.Error("failed to connect to tcp proxy", "error", err) return diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index dbcc873..d4984c9 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: aproxy -version: 0.2.5 +version: 0.3.0 summary: Transparent proxy for HTTP and HTTPS/TLS connections. description: | Aproxy is a transparent proxy for HTTP and HTTPS/TLS connections. By From 85a749793db421cea27db328f35119e0cf7086f2 Mon Sep 17 00:00:00 2001 From: Weii Wang Date: Wed, 15 Oct 2025 15:32:35 +0800 Subject: [PATCH 2/7] Update integration-tests.yaml --- .github/workflows/integration-tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index 889a0d4..f95eaa1 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -92,7 +92,7 @@ jobs: sudo snap logs aproxy.aproxy -n=all - name: Stop tcpdump - if: failure() + if: always() run: | PID=$(cat tcpdump.pid) if [ -n "$PID" ]; then @@ -101,7 +101,7 @@ jobs: sleep 1 - name: Upload tcpdump capture - if: failure() + if: always() uses: actions/upload-artifact@v4 with: name: tcpdump From b6d9c0666fb4f51ed7bbfe49d799870607ebfdaa Mon Sep 17 00:00:00 2001 From: Weii Wang Date: Wed, 22 Oct 2025 14:45:55 +0800 Subject: [PATCH 3/7] Update integration-tests.yaml --- .github/workflows/integration-tests.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index f95eaa1..bb5b65a 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -10,6 +10,8 @@ jobs: runs-on: [ self-hosted, linux, x64, jammy, large ] steps: + - run: sudo nft add element ip aproxy exclude { 1.1.199.1 } + - run: sudo nft list ruleset - uses: actions/checkout@v2 - name: Build aproxy Snap From 04035b288f34ffdf2fed9fd06bac98afc8929ce8 Mon Sep 17 00:00:00 2001 From: Weii Wang Date: Wed, 22 Oct 2025 15:30:03 +0800 Subject: [PATCH 4/7] Revert "Update integration-tests.yaml" This reverts commit b6d9c0666fb4f51ed7bbfe49d799870607ebfdaa. --- .github/workflows/integration-tests.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index bb5b65a..f95eaa1 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -10,8 +10,6 @@ jobs: runs-on: [ self-hosted, linux, x64, jammy, large ] steps: - - run: sudo nft add element ip aproxy exclude { 1.1.199.1 } - - run: sudo nft list ruleset - uses: actions/checkout@v2 - name: Build aproxy Snap From 6bfba4b476d625c70e449f60f2136150d14169ba Mon Sep 17 00:00:00 2001 From: Weii Wang Date: Fri, 21 Nov 2025 10:35:15 +0800 Subject: [PATCH 5/7] test --- .github/workflows/integration-tests.yaml | 97 ++---------------------- 1 file changed, 6 insertions(+), 91 deletions(-) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index f95eaa1..414632e 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -7,102 +7,17 @@ on: jobs: integration-test: name: Run Integration Tests - runs-on: [ self-hosted, linux, x64, jammy, large ] + runs-on: [ self-hosted, linux, x64, noble, large ] steps: - uses: actions/checkout@v2 - - name: Build aproxy Snap - id: snapcraft-build - uses: snapcore/action-build@v1 - with: - snapcraft-args: --build-for amd64 + - run: cat /etc/docker/daemon.json - - name: Upload aproxy Snap - uses: actions/upload-artifact@v4 - with: - name: snap - path: aproxy*.snap + - run: which docker - - name: Install aproxy Snap - run: | - sudo snap install --dangerous aproxy_*_amd64.snap + - run: docker version - - name: Show aproxy Configuration - run: | - sudo snap get aproxy + - run: echo "FROM ubuntu:jammy" > Dockerfile - - name: Configure aproxy - run: | - sudo nft -f - << EOF - define default-ip = $(ip route get $(ip route show 0.0.0.0/0 | grep -oP 'via \K\S+') | grep -oP 'src \K\S+') - define private-ips = { 10.0.0.0/8, 127.0.0.1/8, 172.16.0.0/12, 192.168.0.0/16 } - define aproxy-port = $(sudo snap get aproxy listen | cut -d ":" -f 2) - table ip aproxy - flush table ip aproxy - table ip aproxy { - chain prerouting { - type nat hook prerouting priority dstnat; policy accept; - ip daddr != \$private-ips tcp dport { 80, 443, 11371, 4242 } counter dnat to \$default-ip:\$aproxy-port - } - - chain output { - type nat hook output priority -100; policy accept; - ip daddr != \$private-ips tcp dport { 80, 443, 11371, 4242 } counter dnat to \$default-ip:\$aproxy-port - } - } - EOF - - - name: Start tcpdump - run: | - sudo tcpdump -i any -s 65535 -w capture.pcap & - echo $! > tcpdump.pid - - - name: Test HTTP - run: | - timeout 60 curl --noproxy "*" http://example.com -svS -o /dev/null - - - name: Test HTTPS - run: | - timeout 60 curl --noproxy "*" https://example.com -svS -o /dev/null - - - name: Test HKP - run: | - timeout 60 gpg -vvv --keyserver hkp://keyserver.ubuntu.com --recv-keys E1DE584A8CCA52DC29550F18ABAC58F075A17EFA - - - name: Test TCP4 - run: | - sudo apt install -y socat - timeout 60 socat /dev/null TCP4:tcpbin.com:4242 - - - name: Test Header - run: | - timeout 60 curl --noproxy "*" http://httpbin.org/anything -svS - - - name: Test Access Logs - run: | - sudo snap logs aproxy.aproxy | grep -Fq "example.com:80" - sudo snap logs aproxy.aproxy | grep -Fq "example.com:443" - sudo snap logs aproxy.aproxy | grep -Fq "keyserver.ubuntu.com:11371" - sudo snap logs aproxy.aproxy | grep -Eq "[0-9.]+:4242" - - - name: Show Access Logs - if: failure() - run: | - sudo snap logs aproxy.aproxy -n=all - - - name: Stop tcpdump - if: always() - run: | - PID=$(cat tcpdump.pid) - if [ -n "$PID" ]; then - sudo kill -2 "$PID" || true - fi - sleep 1 - - - name: Upload tcpdump capture - if: always() - uses: actions/upload-artifact@v4 - with: - name: tcpdump - path: capture.pcap + - run: docker build . From 93471a89733e0cf73d81898388fce88b4ed96768 Mon Sep 17 00:00:00 2001 From: Weii Wang Date: Fri, 21 Nov 2025 10:38:17 +0800 Subject: [PATCH 6/7] test --- .github/workflows/integration-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index 414632e..65378db 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -7,7 +7,7 @@ on: jobs: integration-test: name: Run Integration Tests - runs-on: [ self-hosted, linux, x64, noble, large ] + runs-on: [ self-hosted, linux, x64, noble ] steps: - uses: actions/checkout@v2 From 517609d1e198f721c4e0dd80c0361db8174dca87 Mon Sep 17 00:00:00 2001 From: Weii Wang Date: Fri, 21 Nov 2025 10:40:38 +0800 Subject: [PATCH 7/7] test --- .github/workflows/integration-tests.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index 65378db..d852939 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -21,3 +21,5 @@ jobs: - run: echo "FROM ubuntu:jammy" > Dockerfile - run: docker build . + + - run: sudo snap logs -n all aproxy \ No newline at end of file