package main import ( "bytes" _ "embed" "fmt" "log" "net" "net/http" "os" "os/signal" "strings" "syscall" "text/template" "time" ) //go:embed index.html var tmpl string var report = template.Must(template.New("").Parse(tmpl)) var write_report chan bool var interval = time.Second * 2 type Network struct { Name string IP string OnFail string } var Networks = []*Network{ { Name: "DSL", IP: "220.135.85.67", OnFail: "nmcli connection up DSL", }, { Name: "Asus", IP: "192.168.50.48", }, } func main() { write_report = make(chan bool, 1) file, err := os.OpenFile("network.log", os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModePerm) if err != nil { log.Panicln(err) } defer file.Close() log.Println("starting network monitor") go func() { perr := false derr := false for reducer := 0; ; reducer++ { now := time.Now().Format("2006-01-02 15:04:05") // Public go func(print bool) { _, err = net.LookupIP("google.com") if err != nil { if !perr { perr = true log.Println(err) } fmt.Fprintf(file, `{"x": "%s", "y": "%s", "name": "%s"},`, now, "failed", "Public") fmt.Fprintf(file, "\n") } else { perr = false if print { fmt.Fprintf(file, `{"x": "%s", "y": "%s", "name": "%s"},`, now, "ok", "Public") fmt.Fprintf(file, "\n") } } }(reducer == 0) // devices go func(print bool) { for i := range Networks { _, err = GetOutboundIP(Networks[i].IP + ":0") if err != nil { if !derr { derr = true log.Println(err) } fmt.Fprintf(file, `{"x": "%s", "y": "%s", "name": "%s"},`, now, "failed", Networks[i].Name) fmt.Fprintf(file, "\n") // fmt.Fprintf(file, "%s\t%s\t%s\n", now, Networks[i].Name, "failed") } else { derr = false if print { fmt.Fprintf(file, `{"x": "%s", "y": "%s", "name": "%s"},`, now, "ok", Networks[i].Name) fmt.Fprintf(file, "\n") } } } }(reducer == 0) <-time.After(interval) if reducer >= 9 { reducer = -1 } } }() go func() { for { <-time.After(time.Minute * 10) WriteReport() } }() go func() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, strings.TrimPrefix(r.URL.Path, "/")) }) if err := http.ListenAndServe("0.0.0.0:1080", nil); err != nil { log.Fatalln(err) } }() wait := make(chan os.Signal, 1) signal.Notify(wait, syscall.SIGINT, syscall.SIGTERM) <-wait WriteReport() } func WriteReport() { select { case write_report <- true: default: return } defer func() { <-write_report }() f, err := os.OpenFile("report.html", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) if err != nil { log.Println(err) return } defer f.Close() data, err := os.ReadFile("network.log") if err != nil { log.Println(err) return } content := &bytes.Buffer{} if err = report.Execute(content, map[string]string{"Data": string(data)}); err != nil { log.Println(err) return } content.WriteTo(f) } // Get preferred outbound ip of this machine func GetOutboundIP(addr string) (net.IP, error) { iface, err := net.ResolveUDPAddr("udp", addr) if err != nil { return nil, err } dialer := &net.Dialer{LocalAddr: iface} conn, err := dialer.Dial("udp", "8.8.8.8:80") if err != nil { return nil, err } defer conn.Close() localAddr := conn.LocalAddr().(*net.UDPAddr) return localAddr.IP, nil }