From 5acfdb17c6b4a081fc2118a718b12aadf4e33e09 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Thu, 18 Jun 2026 18:36:46 +0200 Subject: [PATCH] fix(toolbox-ng): non-linux build regression in transparent dispatch (ref #662) main.go (untagged) referenced px.handleTransparent + the transparent accept loop unconditionally, so the linux-only transparent.go made `GOOS=darwin go build ./...` fail. Move the accept loop into a linux-tagged runTransparent helper and add a non-linux transparent_stub.go that log.Fatals; main.go now calls runTransparent only when --transparent. Verified GOOS=linux/arm64, linux/amd64 and darwin all build. --- .../secubox-toolbox-ng/cmd/sbxmitm/main.go | 19 +++-------- .../cmd/sbxmitm/transparent.go | 21 ++++++++++++ .../cmd/sbxmitm/transparent_stub.go | 33 +++++++++++++++++++ 3 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 packages/secubox-toolbox-ng/cmd/sbxmitm/transparent_stub.go diff --git a/packages/secubox-toolbox-ng/cmd/sbxmitm/main.go b/packages/secubox-toolbox-ng/cmd/sbxmitm/main.go index 44214660..3cd3f20f 100644 --- a/packages/secubox-toolbox-ng/cmd/sbxmitm/main.go +++ b/packages/secubox-toolbox-ng/cmd/sbxmitm/main.go @@ -352,20 +352,11 @@ func main() { } if *transparent { // Transparent R3 mode: raw accept loop, each conn carries its pre-DNAT - // destination via SO_ORIGINAL_DST (recovered in handleTransparent). - ln, err := net.Listen("tcp", *addr) - if err != nil { - log.Fatalf("transparent listen: %v", err) - } - log.Printf("sbxmitm TRANSPARENT listening on %s (CA %s)", *addr, *caCert) - for { - conn, err := ln.Accept() - if err != nil { - log.Printf("accept: %v", err) - continue - } - go px.handleTransparent(conn) - } + // destination via SO_ORIGINAL_DST (recovered in handleTransparent). The + // accept loop lives in runTransparent — linux-tagged, with a non-linux + // stub so the package still builds (and `darwin go build`) off-target. + runTransparent(px, *addr) + return } srv := &http.Server{Addr: *addr, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/packages/secubox-toolbox-ng/cmd/sbxmitm/transparent.go b/packages/secubox-toolbox-ng/cmd/sbxmitm/transparent.go index e480c0b9..16f4a37b 100644 --- a/packages/secubox-toolbox-ng/cmd/sbxmitm/transparent.go +++ b/packages/secubox-toolbox-ng/cmd/sbxmitm/transparent.go @@ -26,11 +26,32 @@ import ( "encoding/binary" "fmt" "io" + "log" "net" "syscall" "unsafe" ) +// runTransparent runs the transparent (SO_ORIGINAL_DST) accept loop: listen on +// addr, and for each nft-DNAT'd connection recover its pre-DNAT destination and +// dispatch to handleTransparent. Linux-only (build-tagged); a non-linux stub in +// transparent_stub.go keeps the package building off-target. +func runTransparent(px *Proxy, addr string) { + ln, err := net.Listen("tcp", addr) + if err != nil { + log.Fatalf("transparent listen: %v", err) + } + log.Printf("sbxmitm TRANSPARENT listening on %s", addr) + for { + conn, err := ln.Accept() + if err != nil { + log.Printf("accept: %v", err) + continue + } + go px.handleTransparent(conn) + } +} + // SO_ORIGINAL_DST is the Netfilter getsockopt that returns the pre-DNAT // destination sockaddr. Same value (80) for IPv4 (SOL_IP) and IPv6 // (SOL_IPV6, where it is named IP6T_SO_ORIGINAL_DST). diff --git a/packages/secubox-toolbox-ng/cmd/sbxmitm/transparent_stub.go b/packages/secubox-toolbox-ng/cmd/sbxmitm/transparent_stub.go new file mode 100644 index 00000000..d389e388 --- /dev/null +++ b/packages/secubox-toolbox-ng/cmd/sbxmitm/transparent_stub.go @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: LicenseRef-CMSD-1.0 +// Copyright (c) 2026 CyberMind — Gérald Kerma +// +//go:build !linux + +// SecuBox-Deb :: toolbox-ng :: transparent mode non-linux stub (#662). +// +// SO_ORIGINAL_DST recovery is Netfilter-specific (Linux-only). The real +// transparent accept path lives in transparent.go behind //go:build linux. This +// stub lets the package still compile (and `GOOS=darwin go build ./...`) on +// non-linux: invoking transparent mode there is a hard error, never silently +// degraded. handleTransparent is stubbed too in case it is referenced. +package main + +import ( + "log" + "net" +) + +// runTransparent is the non-linux counterpart of the linux accept loop: it +// refuses to start, because transparent SO_ORIGINAL_DST capture requires Linux. +func runTransparent(px *Proxy, addr string) { + _ = px + _ = addr + log.Fatal("transparent mode requires linux (SO_ORIGINAL_DST)") +} + +// handleTransparent is a non-linux stub; it can never be reached because +// runTransparent log.Fatals first. Present so any reference still links. +func (px *Proxy) handleTransparent(client net.Conn) { + _ = client + log.Fatal("transparent mode requires linux (SO_ORIGINAL_DST)") +}