From 3a3bc5da09a79917b963f274d8a89023a0fc7540 Mon Sep 17 00:00:00 2001 From: aceberg <1502200+aceberg@users.noreply.github.com> Date: Wed, 21 Aug 2024 22:29:31 +0700 Subject: [PATCH] Scan routine --- internal/conf/getconfig.go | 6 +++ internal/db/edit.go | 36 ++++++++++---- internal/db/sqlite.go | 4 +- internal/models/models.go | 16 +----- internal/web/const-var.go | 3 ++ internal/web/public/css/index.css | 4 +- internal/web/public/js/index.js | 12 ++++- internal/web/scan.go | 80 ++++++++++++++++++++++++++++++ internal/web/templates/header.html | 2 + internal/web/templates/index.html | 16 +++--- internal/web/webgui.go | 13 +---- 11 files changed, 142 insertions(+), 50 deletions(-) create mode 100644 internal/web/scan.go diff --git a/internal/conf/getconfig.go b/internal/conf/getconfig.go index 8ca0805..979a47d 100644 --- a/internal/conf/getconfig.go +++ b/internal/conf/getconfig.go @@ -18,6 +18,8 @@ func Get(path string) (config models.Conf) { viper.SetDefault("SCANER", "arpscan") viper.SetDefault("ARPARGS", "") viper.SetDefault("IFACES", "") + viper.SetDefault("TIMEOUT", 60) + viper.SetDefault("IGNOREIP", "no") viper.SetConfigFile(path) viper.SetConfigType("yaml") @@ -34,6 +36,8 @@ func Get(path string) (config models.Conf) { config.Scaner = viper.Get("SCANER").(string) config.ArpArgs = viper.Get("ARPARGS").(string) config.Ifaces = viper.Get("IFACES").(string) + config.Timeout = viper.GetInt("TIMEOUT") + config.IgnoreIP = viper.Get("IGNOREIP").(string) return config } @@ -52,6 +56,8 @@ func Write(config models.Conf) { viper.Set("SCANER", config.Scaner) viper.Set("ARPARGS", config.ArpArgs) viper.Set("IFACES", config.Ifaces) + viper.Set("TIMEOUT", config.Timeout) + viper.Set("IGNOREIP", config.IgnoreIP) err := viper.WriteConfig() check.IfError(err) diff --git a/internal/db/edit.go b/internal/db/edit.go index adbd190..a6cfe8a 100644 --- a/internal/db/edit.go +++ b/internal/db/edit.go @@ -21,41 +21,55 @@ func Create(path string) { "NOW" INTEGER DEFAULT 0 );` dbExec(path, sqlStatement) + + sqlStatement = `CREATE TABLE IF NOT EXISTS "history" ( + "ID" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, + "NAME" TEXT NOT NULL, + "IFACE" TEXT, + "IP" TEXT, + "MAC" TEXT, + "HW" TEXT, + "DATE" TEXT, + "KNOWN" INTEGER DEFAULT 0, + "NOW" INTEGER DEFAULT 0 + );` + dbExec(path, sqlStatement) } // Insert - insert host into table -func Insert(path string, oneHost models.Host) { +func Insert(path, table string, oneHost models.Host) { oneHost.Name = quoteStr(oneHost.Name) oneHost.Hw = quoteStr(oneHost.Hw) - sqlStatement := `INSERT INTO "now" (NAME, IFACE, IP, MAC, HW, DATE, KNOWN, NOW) + sqlStatement := `INSERT INTO '%s' (NAME, IFACE, IP, MAC, HW, DATE, KNOWN, NOW) VALUES ('%s','%s','%s','%s','%s','%s','%d','%d');` - sqlStatement = fmt.Sprintf(sqlStatement, oneHost.Name, oneHost.Iface, oneHost.IP, oneHost.Mac, oneHost.Hw, oneHost.Date, oneHost.Known, oneHost.Now) + sqlStatement = fmt.Sprintf(sqlStatement, table, oneHost.Name, oneHost.Iface, oneHost.IP, oneHost.Mac, oneHost.Hw, oneHost.Date, oneHost.Known, oneHost.Now) dbExec(path, sqlStatement) } // Update - update host -func Update(path string, oneHost models.Host) { +func Update(path, table string, oneHost models.Host) { oneHost.Name = quoteStr(oneHost.Name) oneHost.Hw = quoteStr(oneHost.Hw) - sqlStatement := `UPDATE "now" set + sqlStatement := `UPDATE '%s' set NAME = '%s', IFACE = '%s', IP = '%s', MAC = '%s', HW = '%s', DATE = '%s', KNOWN = '%d', NOW = '%d' WHERE ID = '%d';` - sqlStatement = fmt.Sprintf(sqlStatement, oneHost.Name, oneHost.Iface, oneHost.IP, oneHost.Mac, oneHost.Hw, oneHost.Date, oneHost.Known, oneHost.Now, oneHost.ID) + sqlStatement = fmt.Sprintf(sqlStatement, table, oneHost.Name, oneHost.Iface, oneHost.IP, oneHost.Mac, oneHost.Hw, oneHost.Date, oneHost.Known, oneHost.Now, oneHost.ID) dbExec(path, sqlStatement) } // Delete - delete host from DB -func Delete(path string, id int) { - sqlStatement := `DELETE FROM "now" WHERE ID='%d';` - sqlStatement = fmt.Sprintf(sqlStatement, id) +func Delete(path, table string, id int) { + sqlStatement := `DELETE FROM '%s' WHERE ID='%d';` + sqlStatement = fmt.Sprintf(sqlStatement, table, id) dbExec(path, sqlStatement) } // Clear - delete all hosts from table -func Clear(path string) { - sqlStatement := `DELETE FROM "now";` +func Clear(path, table string) { + sqlStatement := `DELETE FROM '%s';` + sqlStatement = fmt.Sprintf(sqlStatement, table) dbExec(path, sqlStatement) } diff --git a/internal/db/sqlite.go b/internal/db/sqlite.go index 66a4f0a..1cbba43 100644 --- a/internal/db/sqlite.go +++ b/internal/db/sqlite.go @@ -28,9 +28,9 @@ func dbExec(path, sqlStatement string) { } // Select - select all hosts -func Select(path string) (dbHosts []models.Host) { +func Select(path, table string) (dbHosts []models.Host) { - sqlStatement := `SELECT * FROM "now" ORDER BY DATE DESC` + sqlStatement := "SELECT * FROM " + table + " ORDER BY DATE DESC" mu.Lock() db, _ := sqlx.Connect("sqlite", path) diff --git a/internal/models/models.go b/internal/models/models.go index 80eca48..4d3697a 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -13,6 +13,8 @@ type Conf struct { Ifaces string Scaner string ArpArgs string + Timeout int + IgnoreIP string } // Host - one host @@ -28,24 +30,10 @@ type Host struct { Now int `db:"NOW"` } -// History for hosts -type History struct { - ID int `db:"ID"` - Host int `db:"HOST"` - Name string `db:"NAME"` - IP string `db:"IP"` - Mac string `db:"MAC"` - Hw string `db:"HW"` - Date string `db:"DATE"` - Known int `db:"KNOWN"` - State int `db:"STATE"` -} - // GuiData - all data sent to html page type GuiData struct { Config Conf Hosts []Host Themes []string Version string - Hist []History } diff --git a/internal/web/const-var.go b/internal/web/const-var.go index c175c77..e8cbf92 100644 --- a/internal/web/const-var.go +++ b/internal/web/const-var.go @@ -11,6 +11,9 @@ var ( appConfig models.Conf allHosts []models.Host + // histHosts []models.Host + + quitScan chan bool ) // templFS - html templates diff --git a/internal/web/public/css/index.css b/internal/web/public/css/index.css index 27bc4cf..979ee5e 100644 --- a/internal/web/public/css/index.css +++ b/internal/web/public/css/index.css @@ -1,9 +1,9 @@ -.my-button { +.my-btn { height: 100%; background-color: #00000000; color: var(--bs-primary); text-align: center; } -.my-button:hover { +.my-btn:hover { background-color: #0000001a; } \ No newline at end of file diff --git a/internal/web/public/js/index.js b/internal/web/public/js/index.js index 84f701f..a2901bc 100644 --- a/internal/web/public/js/index.js +++ b/internal/web/public/js/index.js @@ -11,10 +11,18 @@ function createHTML(addr, i) { now = ``; } + let known = ''; + + if (addr.Known == 1) { + known = ``; + } else { + known = ``; + } + let html = ` ${i}. - ${addr.Name} + ${addr.Iface} ${addr.IP} @@ -22,7 +30,7 @@ function createHTML(addr, i) { ${addr.Mac} ${addr.Hw} ${addr.Date} - ${addr.Known} + ${known} ${now} `; diff --git a/internal/web/scan.go b/internal/web/scan.go new file mode 100644 index 0000000..e018016 --- /dev/null +++ b/internal/web/scan.go @@ -0,0 +1,80 @@ +package web + +import ( + // "log/slog" + "time" + + "github.com/aceberg/WatchYourLAN/internal/arp" + "github.com/aceberg/WatchYourLAN/internal/db" + "github.com/aceberg/WatchYourLAN/internal/models" +) + +func updateScan() { + db.Create(appConfig.DBPath) + + allHosts = db.Select(appConfig.DBPath, "now") + // histHosts = db.Select(appConfig.DBPath, "history") + + quitScan = make(chan bool) + go startScan() +} + +func startScan() { + var lastDate time.Time + + for { + select { + case <-quitScan: + return + default: + nowDate := time.Now() + plusDate := lastDate.Add(time.Duration(appConfig.Timeout) * time.Second) + + if nowDate.After(plusDate) { + + foundHosts := arp.Scan(appConfig.Ifaces) + compareHosts(foundHosts) + allHosts = db.Select(appConfig.DBPath, "now") + // histHosts = db.Select(appConfig.DBPath, "history") + + lastDate = time.Now() + } + + time.Sleep(time.Duration(1) * time.Second) + } + } +} + +func compareHosts(foundHosts []models.Host) { + + // Make map and Insert history + foundHostsMap := make(map[string]models.Host) + for _, fHost := range foundHosts { + foundHostsMap[fHost.Mac] = fHost + db.Insert(appConfig.DBPath, "history", fHost) + } + + for _, aHost := range allHosts { + + fHost, exists := foundHostsMap[aHost.Mac] + if exists && (appConfig.IgnoreIP == "yes" || aHost.IP == fHost.IP) { + + aHost.Iface = fHost.Iface + aHost.IP = fHost.IP + aHost.Date = fHost.Date + aHost.Now = 1 + + delete(foundHostsMap, aHost.Mac) + + } else { + aHost.Now = 0 + } + db.Update(appConfig.DBPath, "now", aHost) + } + + for _, fHost := range foundHostsMap { + + // NOTIFY, LOG + db.Insert(appConfig.DBPath, "now", fHost) + } +} diff --git a/internal/web/templates/header.html b/internal/web/templates/header.html index 1d2cd2a..5008d2d 100644 --- a/internal/web/templates/header.html +++ b/internal/web/templates/header.html @@ -20,6 +20,8 @@ {{ end }} + +