package main import ( "bytes" "crypto/ed25519" "crypto/sha512" "flag" "io/ioutil" "log" "math/rand" "os" "os/signal" "path" "syscall" "time" "gopkg.in/fsnotify.v1" ) var ( myprivkey ed25519.PrivateKey collectorpubkey ed25519.PublicKey ) func main() { var tokenfile = flag.String("token-file", "/etc/wireguard/adlin.token", "Path to your token file") var wgfile = flag.String("wg-file", "/etc/wireguard/adlin.conf", "Path to your wireguard configuration file") var interval = flag.Duration("check-interval", 30*time.Second, "Interval between two checks") flag.StringVar(&test_name, "test-name", "", "Name of the test to report") flag.StringVar(&target, "target", "https://adlin.nemunai.re", "HTTP server to contact") flag.BoolVar(&verbose, "verbose", verbose, "Enable verbose mode") flag.Parse() if test_name == "" { test_name, _ = os.Hostname() } // First load token if it exists if _, err := os.Stat(*tokenfile); !os.IsNotExist(err) { if err := loadToken(*tokenfile); err != nil { log.Fatal("ERROR: Unable to read token file:", err) } } else { log.Fatal("Unable to find token file:", err) } // Load of configuration if it exists if _, err := os.Stat(*wgfile); !os.IsNotExist(err) { if err := loadSettings(*wgfile); err != nil { log.Println("ERROR: Unable to read wg settings:", err) } } // Register SIGHUP c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGHUP) go func() { for range c { log.Println("SIGHUP received, reloading settings...") if err := loadSettings(*wgfile); err != nil { log.Println("ERROR: Unable to read wg settings:", err) } } }() // Watch the configuration file if watcher, err := fsnotify.NewWatcher(); err != nil { log.Fatal(err) } else { if err := watcher.Add(path.Dir(*wgfile)); err != nil { log.Fatal("Unable to watch: ", path.Dir(*wgfile), ": ", err) } go func() { defer watcher.Close() for { select { case ev := <-watcher.Events: if path.Base(ev.Name) == *wgfile && ev.Op&(fsnotify.Write|fsnotify.Create) != 0 { log.Println("Settings file changes, reloading it!") if err := loadSettings(*wgfile); err != nil { log.Println("ERROR: Unable to read wg settings:", err) } } case err := <-watcher.Errors: log.Println("watcher error:", err) } } }() } // Prepare graceful shutdown interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) // Delay first check randomly rand.Seed(time.Now().UnixNano()) n := rand.Intn(10) time.Sleep(time.Duration(n) * time.Second) ticker := time.NewTicker(*interval) defer ticker.Stop() // Launch checker //wksChecker() loop: for { select { case <-interrupt: break loop case <-ticker.C: wksChecker() } } } func loadToken(filename string) error { if fd, err := os.Open(filename); err != nil { return err } else { defer fd.Close() if b, err := ioutil.ReadAll(fd); err != nil { return err } else { seed := sha512.Sum512(bytes.TrimSpace(b)) myprivkey = ed25519.NewKeyFromSeed(seed[:ed25519.SeedSize]) } return nil } } func loadSettings(filename string) error { if fd, err := os.Open(filename); err != nil { return err } else { defer fd.Close() if b, err := ioutil.ReadAll(fd); err != nil { return err } else if wgConf, err := FromWgQuick(string(b), "wg0"); err != nil { return err } else { Login = wgConf.Interface.MyLogin KeySign = wgConf.Interface.KeySign } return nil } }