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.
This commit is contained in:
CyberMind-FR 2026-06-18 18:36:46 +02:00
parent 364b8c4a30
commit 5acfdb17c6
3 changed files with 59 additions and 14 deletions

View File

@ -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) {

View File

@ -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).

View File

@ -0,0 +1,33 @@
// SPDX-License-Identifier: LicenseRef-CMSD-1.0
// Copyright (c) 2026 CyberMind — Gérald Kerma <devel@cybermind.fr>
//
//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)")
}