Download
103 lines 2.5 KiBGoModified 2026-10-31 raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
package sandbox

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"syscall"

	"blinker/internal/proxy"
)

// BridgeCommand is the hidden subcommand that runs inside a Linux sandbox
// to give a command its proxy: "blinker __bridge <socket> <port> -- argv...".
// ApplyCommand (apply.go) is another, run in place of a command.
const BridgeCommand = "__bridge"

// RunHidden runs the hidden subcommand args (a program's os.Args) name, if
// they name one, and reports whether they did, with its exit status. Each
// program that can be the sandbox's, blinker's and the tests', calls it
// first thing.
func RunHidden(args []string) (int, bool) {
	if len(args) < 2 {
		return 0, false
	}
	switch args[1] {
	case BridgeCommand:
		return runBridge(args[2:]), true
	case ApplyCommand:
		return runApply(args[2:]), true
	}
	return 0, false
}

// runBridge listens on 127.0.0.1:<port>, forwards each connection to the
// Unix socket, and runs argv until it exits, returning its exit status.
func runBridge(args []string) int {
	if len(args) < 4 || args[2] != "--" {
		fmt.Fprintln(os.Stderr, "usage: blinker __bridge <socket> <port> -- command...")
		return 2
	}
	socket, argv := args[0], args[3:]
	port, err := strconv.Atoi(args[1])
	if err != nil {
		fmt.Fprintln(os.Stderr, "blinker bridge: bad port:", args[1])
		return 2
	}
	l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
	if err != nil {
		fmt.Fprintln(os.Stderr, "blinker bridge:", err)
		return 1
	}
	go func() {
		for {
			c, err := l.Accept()
			if err != nil {
				return
			}
			go forward(c, socket)
		}
	}()

	cmd := exec.Command(argv[0], argv[1:]...)
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	sigs := make(chan os.Signal, 4)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
	if err := cmd.Start(); err != nil {
		fmt.Fprintln(os.Stderr, "blinker bridge:", err)
		return 127
	}
	go func() {
		for s := range sigs {
			// Fails only once the command has exited, when there is
			// nothing left to signal.
			if err := cmd.Process.Signal(s); err != nil && !errors.Is(err, os.ErrProcessDone) {
				fmt.Fprintln(os.Stderr, "blinker bridge:", err)
			}
		}
	}()
	err = cmd.Wait()
	if ee := (*exec.ExitError)(nil); errors.As(err, &ee) {
		return exitCode(ee)
	}
	if err != nil {
		return 1
	}
	return 0
}

func forward(c net.Conn, socket string) {
	defer c.Close()
	u, err := net.Dial("unix", socket)
	if err != nil {
		return
	}
	defer u.Close()
	// Either side failing just ends the connection: there is no one to
	// tell.
	proxy.Splice(c, c, u)
}