mirror of
https://github.com/whyvl/wireproxy.git
synced 2025-04-29 19:01:42 +02:00
119 lines
2.7 KiB
Go
119 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
|
|
"github.com/akamensky/argparse"
|
|
"github.com/octeep/wireproxy"
|
|
"suah.dev/protect"
|
|
)
|
|
|
|
// an argument to denote that this process was spawned by -d
|
|
const daemonProcess = "daemon-process"
|
|
|
|
// attempts to pledge and panic if it fails
|
|
// this does nothing on non-OpenBSD systems
|
|
func pledgeOrPanic(promises string) {
|
|
err := protect.Pledge(promises)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// attempts to unveil and panic if it fails
|
|
// this does nothing on non-OpenBSD systems
|
|
func unveilOrPanic(path string, flags string) {
|
|
err := protect.Unveil(path, flags)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// get the executable path via syscalls or infer it from argv
|
|
func executablePath() string {
|
|
programPath, err := os.Executable()
|
|
if err != nil {
|
|
return os.Args[0]
|
|
}
|
|
return programPath
|
|
}
|
|
|
|
func main() {
|
|
exePath := executablePath()
|
|
unveilOrPanic("/", "r")
|
|
unveilOrPanic(exePath, "x")
|
|
if err := protect.UnveilBlock(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// only allow standard stdio operation, file reading, networking, and exec
|
|
pledgeOrPanic("stdio rpath inet dns proc exec")
|
|
|
|
isDaemonProcess := len(os.Args) > 1 && os.Args[1] == daemonProcess
|
|
args := os.Args
|
|
if isDaemonProcess {
|
|
// remove proc and exec if they are not needed
|
|
pledgeOrPanic("stdio rpath inet dns")
|
|
args = []string{args[0]}
|
|
args = append(args, os.Args[2:]...)
|
|
}
|
|
parser := argparse.NewParser("wireproxy", "Userspace wireguard client for proxying")
|
|
|
|
config := parser.String("c", "config", &argparse.Options{Required: true, Help: "Path of configuration file"})
|
|
daemon := parser.Flag("d", "daemon", &argparse.Options{Help: "Make wireproxy run in background"})
|
|
configTest := parser.Flag("n", "configtest", &argparse.Options{Help: "Configtest mode. Only check the configuration file for validity."})
|
|
|
|
err := parser.Parse(args)
|
|
if err != nil {
|
|
fmt.Print(parser.Usage(err))
|
|
return
|
|
}
|
|
|
|
if !*daemon {
|
|
// remove proc and exec if they are not needed
|
|
pledgeOrPanic("stdio rpath inet dns")
|
|
}
|
|
|
|
conf, err := wireproxy.ParseConfig(*config)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if *configTest {
|
|
fmt.Println("Config OK")
|
|
return
|
|
}
|
|
|
|
if isDaemonProcess {
|
|
os.Stdout, _ = os.Open(os.DevNull)
|
|
os.Stderr, _ = os.Open(os.DevNull)
|
|
*daemon = false
|
|
}
|
|
|
|
if *daemon {
|
|
args[0] = daemonProcess
|
|
cmd := exec.Command(exePath, args...)
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
}
|
|
return
|
|
}
|
|
|
|
// no file access is allowed from now on, only networking
|
|
pledgeOrPanic("stdio inet dns")
|
|
|
|
tnet, err := wireproxy.StartWireguard(conf.Device)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
for _, spawner := range conf.Routines {
|
|
go spawner.SpawnRoutine(tnet)
|
|
}
|
|
|
|
select {} // sleep eternally
|
|
}
|