commit d86999ed18ff3e72e928be94992175ccd70c166c Author: restitux Date: Wed Nov 22 20:41:41 2023 -0700 Initial commit diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f32c67a --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module git.ohea.xyz/restitux/nmcli-vpn-activator + +go 1.21.4 + +require git.ohea.xyz/golang/config v0.0.0-20230225082310-91f0f601076e + +require github.com/pelletier/go-toml/v2 v2.0.5 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d7c5cbb --- /dev/null +++ b/go.sum @@ -0,0 +1,14 @@ +git.ohea.xyz/golang/config v0.0.0-20230225082310-91f0f601076e h1:Hwv4cSg2+VG7vk7uOS/WqGIGySmW1xpjs0blo6dfHYc= +git.ohea.xyz/golang/config v0.0.0-20230225082310-91f0f601076e/go.mod h1:86PbXJ2WdqQ+3hYqrnv3ukgKNRK9nQfThnlY03FAO0g= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..556f4fb --- /dev/null +++ b/main.go @@ -0,0 +1,165 @@ +package main + +import ( + "fmt" + "os/exec" + "regexp" + + "git.ohea.xyz/golang/config" +) + +type Config struct { + IgnoreDevices bool + Devices []string + IgnoreConnections bool + Connections []string + VPNConnection string +} + +func isMatch(ignoreStrings bool, strings []string, match string) bool { + if ignoreStrings { + for _, s := range strings { + if match == s { + return false + } + } + return true + } else { + for _, s := range strings { + if match == s { + return true + } + } + return false + } +} + +func PrintArray(message string, items []string) { + fmt.Printf("%s: ", message) + for i, s := range items { + fmt.Print(s) + if i < len(items)-1 { + fmt.Print(", ") + } + } + fmt.Printf("\n") +} + +func enableVPN(vpnCon string) error { + cmd := exec.Command("nmcli", "con", "up", vpnCon) + if err := cmd.Run(); err != nil { + return fmt.Errorf("could not launch VPN: %w\n", err) + } + return nil +} + +func disableVPN(vpnCon string) error { + cmd := exec.Command("nmcli", "con", "down", vpnCon) + if err := cmd.Run(); err != nil { + return fmt.Errorf("could not stop VPN: %w\n", err) + } + return nil +} + +func main() { + configData := config.Config[Config]{ + Name: "nmcli-vpn-activator", + Filename: "config", + Config: Config{ + IgnoreDevices: false, + Devices: []string{}, + IgnoreConnections: true, + Connections: []string{}, + VPNConnection: "", + }, + } + new, err := configData.Get() + if err != nil { + fmt.Printf("Could not get config: %w\n", err) + return + } + + if new { + fmt.Println("New config created, please update and restart.") + return + } + + if configData.Config.IgnoreDevices { + PrintArray("Ignoring the following devices", configData.Config.Devices) + } else { + PrintArray("Enabling the VPN on the following devices", configData.Config.Devices) + } + + if configData.Config.IgnoreConnections { + PrintArray("Ignoring the following connections", configData.Config.Connections) + } else { + PrintArray("Enabling the VPN on the following connections", configData.Config.Connections) + } + + nmcli_monitor := exec.Command("nmcli", "monitor") + + stdout, err := nmcli_monitor.StdoutPipe() + if err != nil { + fmt.Printf("could not get stdout: %w\n", err) + return + } + + err = nmcli_monitor.Start() + if err != nil { + fmt.Printf("Could not start process: %w\n", err) + return + } + + buf := make([]byte, 1024) + connectingEnable := false + connectingDisable := false + + for { + n, err := stdout.Read(buf) + if err != nil { + fmt.Printf("could not read stdout: %w\n, err") + return + } + logLine := string(buf[:n]) + + usingConnection := regexp.MustCompile(`(?P\S+?): using connection \'(?P.+?)\'`) + results := usingConnection.FindStringSubmatch(logLine) + if len(results) > 0 { + if !isMatch(configData.Config.IgnoreDevices, configData.Config.Devices, results[1]) { + continue + } + if !isMatch(configData.Config.IgnoreConnections, configData.Config.Connections, results[2]) { + fmt.Printf("Monitored device %s has started connecting to VPN disabled network %s.\n", results[1], results[2]) + connectingDisable = true + connectingEnable = false + } else { + fmt.Printf("Monitored device %s has started connecting to VPN enabled network %s.\n", results[1], results[2]) + connectingEnable = true + connectingDisable = false + } + continue + } + + deviceConnected := regexp.MustCompile(`(?P\S+?): connected`) + results = deviceConnected.FindStringSubmatch(logLine) + if len(results) > 0 { + if connectingEnable { + fmt.Printf("Monitored device %s has connected to VPN enabled network, enabling VPN.\n", results[1]) + err = enableVPN(configData.Config.VPNConnection) + if err != nil { + fmt.Printf("Could not enable VPN: %w\n", err) + } + connectingEnable = false + } + if connectingDisable { + fmt.Printf("Monitored device %s has connected to VPN disabled network, disabling VPN.\n", results[1]) + err = disableVPN(configData.Config.VPNConnection) + if err != nil { + fmt.Printf("Could not disable VPN: %w\n", err) + } + connectingDisable = false + } + } + + } +}