update
commit
d51ccc456b
|
@ -0,0 +1,2 @@
|
||||||
|
nwm
|
||||||
|
runtime
|
|
@ -0,0 +1,62 @@
|
||||||
|
<div>
|
||||||
|
<canvas id="myChart"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@^3"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/moment@^2"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const ctx = document.getElementById('myChart');
|
||||||
|
|
||||||
|
const fails = [
|
||||||
|
{{.Data}}
|
||||||
|
]
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Public Network',
|
||||||
|
data: fails.filter(el=>el.name=='Public'),
|
||||||
|
borderColor: 'rgb(255, 99, 132)',
|
||||||
|
backgroundColor: 'rgb(255, 99, 132)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'DSL',
|
||||||
|
data: fails.filter(el=>el.name=='DSL'),
|
||||||
|
borderColor: 'rgb(75, 192, 192)',
|
||||||
|
backgroundColor: 'rgb(75, 192, 192)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Asus Router',
|
||||||
|
data: fails.filter(el=>el.name=='Asus'),
|
||||||
|
borderColor: 'rgb(255, 205, 86)',
|
||||||
|
backgroundColor: 'rgb(255, 205, 86)'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
type: 'time',
|
||||||
|
time: {
|
||||||
|
unit: 'second'
|
||||||
|
},
|
||||||
|
position: 'bottom'
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
type: 'category',
|
||||||
|
labels: ['', 'ok','failed','']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
decimation: {
|
||||||
|
enabled: true,
|
||||||
|
algorithm: 'lttb'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,184 @@
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Evan Network Monitor
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
WorkingDirectory=/home/evan/Documents/network-monitor/runtime
|
||||||
|
ExecStart=/home/evan/Documents/network-monitor/nwm
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
StandardOutput=append:/home/evan/Documents/network-monitor/runtime/service.log
|
||||||
|
StandardError=append:/home/evan/Documents/network-monitor/runtime/service.log
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
sudo systemctl stop nwm
|
||||||
|
|
||||||
|
go build -o nwm main.go
|
||||||
|
|
||||||
|
sudo systemctl start nwm
|
Loading…
Reference in New Issue