dissertation-2-code/main.go

156 lines
2.9 KiB
Go

package main
import (
"context"
"errors"
"fmt"
"log"
"mpbl3p/config"
"mpbl3p/flags"
"mpbl3p/tun"
"os"
"os/signal"
"strconv"
"syscall"
)
const (
ENV_NC_TUN_FD = "NC_TUN_FD"
ENV_NC_CONFIG_PATH = "NC_CONFIG_PATH"
)
func main() {
log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)
if _, exists := os.LookupEnv(ENV_NC_TUN_FD); !exists {
// we are the parent process
// 1) process arguments
// 2) validate config
// 2) create a tun adapter
// 3) spawn a child
// 4) exit
o, err := flags.ParseFlags()
if err != nil {
if errors.Is(err, flags.PrintedHelpErr) {
return
}
panic(err)
}
log.Println("loading config...")
c, err := config.LoadConfig(o.ConfigFile)
if err != nil {
log.Fatalf("error validating config: %s", err.Error())
return
}
log.Println("creating tun adapter...")
t, err := tun.NewTun(o.Positional.InterfaceName, int(c.Host.MTU))
if err != nil {
panic(err)
}
if o.Foreground {
if err := os.Setenv(ENV_NC_TUN_FD, fmt.Sprintf("%d", t.File().Fd())); err != nil {
panic(err)
}
if err := os.Setenv(ENV_NC_CONFIG_PATH, o.ConfigFile); err != nil {
panic(err)
}
log.Println("switching to foreground")
goto FOREGROUND
}
files := make([]*os.File, 4)
files[0], _ = os.Open(os.DevNull) // stdin
files[1], _ = os.Open(os.DevNull) // stderr
files[2], _ = os.Open(os.DevNull) // stdout
files[3] = t.File()
env := os.Environ()
env = append(env, fmt.Sprintf("%s=3", ENV_NC_TUN_FD))
env = append(env, fmt.Sprintf("%s=%s", ENV_NC_CONFIG_PATH, o.ConfigFile))
attr := os.ProcAttr{
Env: env,
Files: files,
}
path, err := os.Executable()
if err != nil {
panic(err)
}
process, err := os.StartProcess(
path,
os.Args,
&attr,
)
if err != nil {
panic(err)
}
pidFile, err := os.Create(o.PidFile)
if err != nil {
panic(err)
}
if _, err := fmt.Fprintf(pidFile, "%d", process.Pid); err != nil {
panic(err)
}
_ = process.Release()
return
}
// we are the child process
// 1) recreate tun adapter from file descriptor
// 2) launch proxy
FOREGROUND:
log.Println("loading config...")
c, err := config.LoadConfig(os.Getenv(ENV_NC_CONFIG_PATH))
if err != nil {
panic(err)
}
log.Println("connecting tun adapter...")
tunFd, err := strconv.ParseUint(os.Getenv(ENV_NC_TUN_FD), 10, 64)
if err != nil {
panic(err)
}
t, err := tun.NewFromFile(uintptr(tunFd), int(c.Host.MTU))
if err != nil {
panic(err)
}
defer func() {
if err := t.Close(); err != nil {
panic(err)
}
}()
log.Println("building config...")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
p, err := c.Build(ctx, t, t)
if err != nil {
panic(err)
}
log.Println("starting proxy...")
p.Start()
log.Println("proxy started")
signals := make(chan os.Signal)
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
<-signals
log.Println("exiting...")
}