Scan routine

This commit is contained in:
aceberg 2024-08-21 22:29:31 +07:00
parent 73db704cf7
commit 3a3bc5da09
11 changed files with 142 additions and 50 deletions

View file

@ -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)

View file

@ -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)
}

View file

@ -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)

View file

@ -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
}

View file

@ -11,6 +11,9 @@ var (
appConfig models.Conf
allHosts []models.Host
// histHosts []models.Host
quitScan chan bool
)
// templFS - html templates

View file

@ -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;
}

View file

@ -11,10 +11,18 @@ function createHTML(addr, i) {
now = `<i class="bi bi-check-circle-fill" style="color:var(--bs-success);"></i>`;
}
let known = '';
if (addr.Known == 1) {
known = `<button type="button" class="btn btn-success">Yes</button>`;
} else {
known = `<button type="button" class="btn btn-warning" disabled>No</button>`;
}
let html = `
<tr>
<td style="opacity: 45%;">${i}.</td>
<td>${addr.Name}</td>
<td><input name="name" type="text" class="form-control" value="${addr.Name}"></td>
<td>${addr.Iface}</td>
<td>
<a href="http://${addr.IP}">${addr.IP}</a>
@ -22,7 +30,7 @@ function createHTML(addr, i) {
<td>${addr.Mac}</td>
<td>${addr.Hw}</td>
<td>${addr.Date}</td>
<td>${addr.Known}</td>
<td>${known}</td>
<td>${now}</td>
</tr>
`;

80
internal/web/scan.go Normal file
View file

@ -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)
}
}

View file

@ -20,6 +20,8 @@
<link href="{{ .Config.NodePath }}/node_modules/bootswatch/dist/{{ .Config.Theme }}/bootstrap.min.css" rel="stylesheet">
<script src="{{ .Config.NodePath }}/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
{{ end }}
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="/fs/public/css/index.css" />
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-primary">

View file

@ -11,14 +11,14 @@
<table class="table table-striped">
<thead>
<th style="width: 3em;"></th>
<th>Name <i class="bi bi-sort-down-alt" onclick="sortBy('Name')"></i></th>
<th>Iface <i class="bi bi-sort-down-alt" onclick="sortBy('Iface')"></i></th>
<th>IP <i class="bi bi-sort-down-alt" onclick="sortBy('IP')"></i></th>
<th>MAC <i class="bi bi-sort-down-alt" onclick="sortBy('Mac')"></i></th>
<th>Hardware <i class="bi bi-sort-down-alt" onclick="sortBy('Hw')"></i></th>
<th>Date <i class="bi bi-sort-down-alt" onclick="sortBy('Date')"></i></th>
<th>Known <i class="bi bi-sort-down-alt" onclick="sortBy('Known')"></i></th>
<th>Online <i class="bi bi-sort-down-alt" onclick="sortBy('Now')"></i></th>
<th>Name <i class="bi bi-sort-down-alt my-btn" onclick="sortBy('Name')"></i></th>
<th>Iface <i class="bi bi-sort-down-alt my-btn" onclick="sortBy('Iface')"></i></th>
<th>IP <i class="bi bi-sort-down-alt my-btn" onclick="sortBy('IP')"></i></th>
<th>MAC <i class="bi bi-sort-down-alt my-btn" onclick="sortBy('Mac')"></i></th>
<th>Hardware <i class="bi bi-sort-down-alt my-btn" onclick="sortBy('Hw')"></i></th>
<th>Date <i class="bi bi-sort-down-alt my-btn" onclick="sortBy('Date')"></i></th>
<th>Known <i class="bi bi-sort-down-alt my-btn" onclick="sortBy('Known')"></i></th>
<th>Online <i class="bi bi-sort-down-alt my-btn" onclick="sortBy('Now')"></i></th>
</thead>
<tbody id="tBody"></tbody>
<!-- index.js -->

View file

@ -7,10 +7,8 @@ import (
"github.com/gin-gonic/gin"
"github.com/aceberg/WatchYourLAN/internal/arp"
"github.com/aceberg/WatchYourLAN/internal/check"
"github.com/aceberg/WatchYourLAN/internal/conf"
"github.com/aceberg/WatchYourLAN/internal/db"
)
// Gui - start web server
@ -26,6 +24,8 @@ func Gui(dirPath, nodePath string) {
appConfig.DBPath = dirPath + "/scan.db"
appConfig.NodePath = nodePath
updateScan() // scan.go
slog.Info("config", "path", appConfig.DirPath)
address := appConfig.Host + ":" + appConfig.Port
@ -34,11 +34,6 @@ func Gui(dirPath, nodePath string) {
slog.Info("Web GUI at http://" + address)
slog.Info("=================================== ")
updateAllHosts()
// Run scan
allHosts = arp.Scan(appConfig.Ifaces)
slog.Info("ARPSCAN:", "found", allHosts)
gin.SetMode(gin.ReleaseMode)
router := gin.Default()
@ -57,7 +52,3 @@ func Gui(dirPath, nodePath string) {
err := router.Run(address)
check.IfError(err)
}
func updateAllHosts() {
allHosts = db.Select(appConfig.DBPath)
}