You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
2.2 KiB
115 lines
2.2 KiB
package main |
|
|
|
import ( |
|
"flag" |
|
"fmt" |
|
"log" |
|
"os" |
|
"os/signal" |
|
"path" |
|
"strings" |
|
"sync" |
|
"syscall" |
|
|
|
"git.sr.ht/~tslocum/sshtargate/pkg/gate" |
|
"github.com/anmitsu/go-shlex" |
|
) |
|
|
|
const ( |
|
version = "0.0.0" |
|
|
|
versionInfo = `sshtargate - Host SSH portals to applications - v` + version + ` |
|
https://git.sr.ht/~tslocum/sshtargate |
|
The MIT License (MIT) |
|
Copyright (c) 2020 Trevor Slocum <trevor@rocketnine.space> |
|
` |
|
) |
|
|
|
var ( |
|
printVersionInfo bool |
|
configPath string |
|
|
|
portals []*gate.Portal |
|
portalsLock = new(sync.Mutex) |
|
|
|
done = make(chan bool) |
|
) |
|
|
|
func main() { |
|
flag.BoolVar(&printVersionInfo, "version", false, "print version information and exit") |
|
flag.StringVar(&configPath, "config", "", "path to configuration file") |
|
flag.Parse() |
|
|
|
if printVersionInfo { |
|
fmt.Print(versionInfo) |
|
return |
|
} |
|
|
|
// TODO: Allow portals to be specified via arguments |
|
|
|
// TODO: Catch SIGHUP |
|
sigc := make(chan os.Signal, 1) |
|
signal.Notify(sigc, |
|
syscall.SIGINT, |
|
syscall.SIGTERM) |
|
go func() { |
|
<-sigc |
|
|
|
done <- true |
|
}() |
|
|
|
log.Println("Initializing sshtargate...") |
|
|
|
if configPath == "" { |
|
homedir, err := os.UserHomeDir() |
|
if err == nil && homedir != "" { |
|
configPath = path.Join(homedir, ".config", "sshtargate", "config.yaml") |
|
} |
|
} |
|
|
|
err := readConfig(configPath) |
|
if err != nil { |
|
log.Fatalf("failed to read configuration file %s: %s", configPath, err) |
|
} |
|
|
|
for pname, pcfg := range config.Portals { |
|
cs, err := shlex.Split(pcfg.Command, true) |
|
if err != nil { |
|
log.Fatalf("failed to split command %s", pcfg.Command) |
|
} |
|
|
|
pname, pcfg := pname, pcfg // Capture |
|
go func() { |
|
wg := new(sync.WaitGroup) |
|
|
|
for _, address := range pcfg.Host { |
|
wg.Add(1) |
|
address := address // Capture |
|
|
|
go func() { |
|
p, err := gate.NewPortal(pname, address, cs) |
|
if err != nil { |
|
log.Fatalf("failed to start portal %s on %s: %s", pname, address, err) |
|
} |
|
|
|
portalsLock.Lock() |
|
portals = append(portals, p) |
|
portalsLock.Unlock() |
|
|
|
wg.Done() |
|
}() |
|
} |
|
|
|
wg.Wait() |
|
log.Printf("Opened portal %s on %s to %s", pname, strings.Join(pcfg.Host, ","), pcfg.Command) |
|
}() |
|
} |
|
|
|
<-done |
|
|
|
portalsLock.Lock() |
|
for _, p := range portals { |
|
p.Shutdown() |
|
} |
|
portalsLock.Unlock() |
|
}
|
|
|