// The forticlient module's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): the FortiClient // VPN client's tray in the operator's session and the vendor's service behind it, served by the node's // runtime as the operator account, and its adapter to the machine's own resolver (splitdns.go, hq ADR // 0247). The module holds no seat, so every tool is its own. The tools // report running and connected state only: never a profile, a credential, a gateway or a certificate. package main import ( "context" "fmt" "os" "os/signal" "syscall" stdio "git.novox.be/novox/mesh-sdk/go" ) func main() { // Started as `forticlient-tools split-dns` it is the module's adapter to the machine's own resolver, // a long-running process as root (splitdns.go). With no argument, the runtime's tools bundle. if len(os.Args) > 1 { if os.Args[1] != "split-dns" || len(os.Args) != 2 { fmt.Fprintln(os.Stderr, "usage: forticlient-tools [split-dns]") os.Exit(2) } ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) defer stop() NewAdapter().Run(ctx) return } if err := stdio.Serve("", tools()); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } var machine = NewMachine() func tools() []stdio.Tool { return []stdio.Tool{ { Name: "forticlient_status", Description: "The VPN client: the installed version and whether it came from outside the official " + "repositories, the vendor's service (active, enabled), whether the tray and its launcher run " + "(pid, since, scope or unit), what starts the tray at login, and whether a tunnel is up (a " + "count; never a name, an address, a gateway or a profile). (r)", Run: func(map[string]any) (any, error) { return machine.Status() }, }, { Name: "forticlient_restart", Description: "End the tray and its launcher (asked first, then forced after 5 s) and start the " + "launcher again in the operator's desktop session, under the account's service manager. The " + "tunnel is the service's and is not touched. Needs someone logged in to the desktop. (a)", Run: func(map[string]any) (any, error) { return machine.Restart() }, }, { Name: "forticlient_check", Description: "Check what the module promises and relies on: the package is installed (by hand: it is " + "outside the official repositories); the service runs and is enabled; the tray has exactly one " + "start (the vendor's XDG autostart entry, which the session's dex runs; no window-manager exec); " + "and the tray and its launcher run once in a desktop session. Being connected is not checked. (r)", Run: func(map[string]any) (any, error) { return machine.Check() }, }, } }