package binder import ( "fmt" "io" "net" "os" "os/user" "strconv" "syscall" g "euandre.org/gobang/src" ) type CLIArgs struct { FromAddr string ToAddr string } const USER = "nobody" var EmitActiveConnection = g.MakeGauge("active-connections") func dropPrivileges(username string) { g.Info("Dropping privileges", "drop-root-init") user, err := user.Lookup(username) g.FatalIf(err) gid, err := strconv.Atoi(user.Gid) g.FatalIf(err) uid, err := strconv.Atoi(user.Uid) g.FatalIf(err) err = syscall.Setgid(gid) g.FatalIf(err) err = syscall.Setgroups([]int{}) g.FatalIf(err) err = syscall.Setuid(uid) g.FatalIf(err) g.Info("Privileges dropped", "drop-root-end") } func isRunningAsRoot() bool { return os.Geteuid() == 0 } func copyData(closer chan struct{}, from io.Reader, to io.Writer) { io.Copy(to, from) closer <- struct{}{} } func ParseArgs(args []string) CLIArgs { if len(args) != 3 { fmt.Fprintf( os.Stderr, "Usage: %s FROM-ADDRESS TO-ADDRESS\n", args[0], ) os.Exit(2) } return CLIArgs { FromAddr: args[1], ToAddr: args[2], } } func Listen(fromAddr string) net.Listener { listener, err := net.Listen("tcp", fromAddr) g.FatalIf(err) g.Info("Started listening", "listen-start", "from-address", fromAddr) return listener } func DropRoot() { if isRunningAsRoot() { dropPrivileges(USER) if isRunningAsRoot() { panic("Failed to drop privileges") } } } func Start(toAddr string, listener net.Listener) { for { connFrom, err := listener.Accept() if err != nil { g.Warning( "Error accepting connection", "accept-connection", "err", err, ) continue } defer connFrom.Close() EmitActiveConnection.Inc() connTo, err := net.Dial("unix", toAddr) if err != nil { g.Error( "Error dialing connection", "dial-connection", "err", err, ) os.Exit(1) } defer connTo.Close() closer := make(chan struct{}, 2) go copyData(closer, connFrom, connTo) go copyData(closer, connTo, connFrom) go func() { <-closer EmitActiveConnection.Dec() }() } } func Main() { g.Init() args := ParseArgs(os.Args) listener := Listen(args.FromAddr) DropRoot() Start(args.ToAddr, listener) }