156 lines
2.9 KiB
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...")
|
|
}
|