database
This commit is contained in:
parent
39ff9a43b0
commit
3b98fb36cb
|
@ -51,17 +51,17 @@ func (msg *SocketMSG) Marshal() ([]byte, error) {
|
|||
pos += 4
|
||||
|
||||
if msg.Types.Is(SocketMSGTypeClient) {
|
||||
obj[pos] = msg.Client.Addr.HardwareAddr[0]
|
||||
obj[pos] = msg.Client.Addr[0]
|
||||
pos++
|
||||
obj[pos] = msg.Client.Addr.HardwareAddr[1]
|
||||
obj[pos] = msg.Client.Addr[1]
|
||||
pos++
|
||||
obj[pos] = msg.Client.Addr.HardwareAddr[2]
|
||||
obj[pos] = msg.Client.Addr[2]
|
||||
pos++
|
||||
obj[pos] = msg.Client.Addr.HardwareAddr[3]
|
||||
obj[pos] = msg.Client.Addr[3]
|
||||
pos++
|
||||
obj[pos] = msg.Client.Addr.HardwareAddr[4]
|
||||
obj[pos] = msg.Client.Addr[4]
|
||||
pos++
|
||||
obj[pos] = msg.Client.Addr.HardwareAddr[5]
|
||||
obj[pos] = msg.Client.Addr[5]
|
||||
pos++
|
||||
binary.BigEndian.PutUint32(obj[pos:(pos+4)], uint32(msg.Client.Time.Unix()))
|
||||
pos += 4
|
||||
|
@ -100,7 +100,7 @@ func (msg *SocketMSG) Unmarshal(obj []byte) error {
|
|||
|
||||
if msg.Types.Is(SocketMSGTypeClient) {
|
||||
msg.Client = &WifiClient{
|
||||
Addr: data.HardwareAddr{HardwareAddr: obj[pos:(pos + 6)]},
|
||||
Addr: data.HardwareAddr(obj[pos:(pos + 6)]),
|
||||
Time: time.Unix(int64(binary.BigEndian.Uint32(obj[(pos+6):(pos+10)])), 0),
|
||||
TryProbe: binary.BigEndian.Uint16(obj[(pos + 10):(pos + 12)]),
|
||||
TryAuth: binary.BigEndian.Uint16(obj[(pos + 12):(pos + 14)]),
|
||||
|
|
|
@ -6,18 +6,18 @@ import (
|
|||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
"dev.sum7.eu/genofire/golang-lib/file"
|
||||
"github.com/bdlm/log"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/capture"
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/controller"
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/database"
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/web"
|
||||
)
|
||||
|
||||
type ControllerConfig struct {
|
||||
Database string `toml:"database"`
|
||||
Database database.Config `toml:"database"`
|
||||
Answer bool `toml:"answer"`
|
||||
Webserver *web.Config `toml:"webserver"`
|
||||
Interfaces []*capture.IFaceConfig `toml:"interfaces"`
|
||||
|
@ -34,9 +34,12 @@ var controllerCmd = &cobra.Command{
|
|||
|
||||
file.ReadTOML(args[0], config)
|
||||
|
||||
db := database.NewDB(config.Database)
|
||||
if err := database.Open(config.Database); err != nil {
|
||||
log.Panicf("no database connection: %s", err)
|
||||
}
|
||||
defer database.Close()
|
||||
|
||||
ctr := controller.NewController(db)
|
||||
ctr := controller.NewController()
|
||||
defer ctr.Close()
|
||||
|
||||
var handlers []capture.Handler
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
database = "/tmp/wifictld.json"
|
||||
answer = false
|
||||
|
||||
[database]
|
||||
type = "sqlite3"
|
||||
logging = true
|
||||
connection = "file:/tmp/wifictld.db"
|
||||
# For Master-Slave cluster
|
||||
# read_connection = ""
|
||||
|
||||
[webserver]
|
||||
enable = true
|
||||
|
|
|
@ -2,24 +2,38 @@ package controller
|
|||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
// "github.com/bdlm/log"
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/capture"
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/data"
|
||||
)
|
||||
|
||||
func (c *Controller) Handler(addr *net.UDPAddr, msg *capture.SocketMSG) (*capture.SocketMSG, error) {
|
||||
ignore := false
|
||||
if msg.Types.Is(capture.SocketMSGTypeClient) && msg.Client != nil {
|
||||
ignore = c.db.LearnClient(addr.IP, msg.Client)
|
||||
ignore = c.LearnClient(addr.IP, msg.Client)
|
||||
}
|
||||
if !msg.Types.Is(capture.SocketMSGTypeRequest) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
client := &data.Client{Addr: msg.Client.Addr}
|
||||
|
||||
if result := database.Read.Select([]string{"try_probe", "try_auth"}).First(client); result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
msg = &capture.SocketMSG{
|
||||
Types: (capture.SocketMSGTypeResponse | capture.SocketMSGTypeClient),
|
||||
Client: c.db.GetClient(msg.Client.Addr),
|
||||
Client: &capture.WifiClient{
|
||||
Addr: msg.Client.Addr,
|
||||
Time: time.Now(),
|
||||
TryProbe: client.TryProbe,
|
||||
TryAuth: client.TryAuth,
|
||||
},
|
||||
}
|
||||
|
||||
if !ignore {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
// "github.com/bdlm/log"
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/capture"
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/data"
|
||||
)
|
||||
|
||||
func (c *Controller) LearnClient(apIP net.IP, clientWifictl *capture.WifiClient) bool {
|
||||
ret := false
|
||||
|
||||
// learn ap
|
||||
ap := &data.AP{
|
||||
IP: apIP,
|
||||
Lastseen: time.Now(),
|
||||
}
|
||||
result := database.Read.First(ap)
|
||||
if result.RowsAffected > 0 {
|
||||
database.Write.Save(ap)
|
||||
} else {
|
||||
database.Write.Create(ap)
|
||||
}
|
||||
|
||||
// learn client
|
||||
client := &data.Client{
|
||||
Addr: clientWifictl.Addr,
|
||||
Lastseen: time.Now(),
|
||||
APAddr: apIP,
|
||||
Connected: clientWifictl.Connected,
|
||||
SignalLowFreq: clientWifictl.SignalLowFreq,
|
||||
SignalHighFreq: clientWifictl.SignalHighFreq,
|
||||
}
|
||||
|
||||
database.Write.FirstOrCreate(client)
|
||||
|
||||
if clientWifictl.TryAuth > client.TryAuth {
|
||||
client.TryAuth = clientWifictl.TryAuth
|
||||
}
|
||||
if clientWifictl.TryProbe > client.TryProbe {
|
||||
client.TryProbe = clientWifictl.TryProbe
|
||||
}
|
||||
|
||||
if client.FreqHighest < clientWifictl.FreqHighest {
|
||||
ret = (client.FreqHighest != 0)
|
||||
client.FreqHighest = clientWifictl.FreqHighest
|
||||
}
|
||||
if clientWifictl.Authed {
|
||||
client.Authed = clientWifictl.Authed
|
||||
}
|
||||
database.Write.Save(client)
|
||||
return ret
|
||||
}
|
|
@ -4,23 +4,22 @@ import (
|
|||
"net"
|
||||
"time"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
"github.com/bdlm/log"
|
||||
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/capture"
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/database"
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/data"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
SendTo func(addr *net.UDPAddr, msg *capture.SocketMSG)
|
||||
Send func(msg *capture.SocketMSG)
|
||||
db *database.DB
|
||||
ticker *time.Ticker
|
||||
}
|
||||
|
||||
func NewController(db *database.DB) *Controller {
|
||||
func NewController() *Controller {
|
||||
ctl := &Controller{
|
||||
ticker: time.NewTicker(time.Minute),
|
||||
db: db,
|
||||
}
|
||||
go ctl.Repeated()
|
||||
return ctl
|
||||
|
@ -31,7 +30,12 @@ func (c *Controller) Close() {
|
|||
}
|
||||
|
||||
func (c *Controller) Repeated() {
|
||||
aps := 0
|
||||
clients := 0
|
||||
|
||||
for range c.ticker.C {
|
||||
log.Debugf("lerned: %d APs, %d Clients", len(c.db.APs), len(c.db.Clients))
|
||||
database.Read.Model(&data.AP{}).Count(&aps)
|
||||
database.Read.Model(&data.Client{}).Count(&clients)
|
||||
log.Debugf("learned: %d APs, %d Clients", aps, clients)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"time"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
)
|
||||
|
||||
type AP struct {
|
||||
IP net.IP `json:"ip" gorm:"PRIMARY_KEY"`
|
||||
Lastseen time.Time `json:"lastseen"`
|
||||
Clients []Client `gorm:"foreignkey:APAddr" json:"-"`
|
||||
}
|
||||
|
||||
// Function to initialize the database
|
||||
func init() {
|
||||
database.AddModel(&AP{})
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
Addr HardwareAddr `gorm:"PRIMARY_KEY" json:"addr"`
|
||||
APAddr net.IP `gorm:"column:ap" json:"ap"`
|
||||
TryProbe uint16 `json:"try_probe"`
|
||||
TryAuth uint16 `json:"try_auth"`
|
||||
Connected bool `json:"connected"`
|
||||
Authed bool `json:"authed"`
|
||||
FreqHighest uint16 `json:"freq_highest"`
|
||||
SignalLowFreq int16 `json:"signal_low_freq"`
|
||||
SignalHighFreq int16 `json:"signal_high_freq"`
|
||||
Lastseen time.Time `json:"lastseen"`
|
||||
}
|
||||
|
||||
// Function to initialize the database
|
||||
func init() {
|
||||
database.AddModel(&Client{})
|
||||
}
|
|
@ -2,7 +2,12 @@ package data
|
|||
|
||||
import "net"
|
||||
|
||||
type HardwareAddr struct{ net.HardwareAddr }
|
||||
type HardwareAddr net.HardwareAddr
|
||||
|
||||
//MarshalJSON to bytearray
|
||||
func (a HardwareAddr) String() string {
|
||||
return net.HardwareAddr(a).String()
|
||||
}
|
||||
|
||||
//MarshalJSON to bytearray
|
||||
func (a HardwareAddr) MarshalText() ([]byte, error) {
|
||||
|
@ -10,7 +15,11 @@ func (a HardwareAddr) MarshalText() ([]byte, error) {
|
|||
}
|
||||
|
||||
// UnmarshalJSON from bytearray
|
||||
func (a HardwareAddr) UnmarshalText(data []byte) (err error) {
|
||||
a.HardwareAddr, err = net.ParseMAC(string(data))
|
||||
return
|
||||
func (a HardwareAddr) UnmarshalText(data []byte) error {
|
||||
b, err := net.ParseMAC(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a = HardwareAddr(b)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/FreifunkBremen/yanic/lib/jsontime"
|
||||
)
|
||||
|
||||
type AP struct {
|
||||
IP *net.IP `json:"ip"`
|
||||
Lastseen jsontime.Time `json:"lastseen"`
|
||||
}
|
||||
|
||||
func (db *DB) GetClients(ap *AP) []*Client {
|
||||
var clients []*Client
|
||||
for _, client := range db.Clients {
|
||||
if client.AP == ap {
|
||||
clients = append(clients, client)
|
||||
}
|
||||
}
|
||||
return clients
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
// "github.com/bdlm/log"
|
||||
"github.com/FreifunkBremen/yanic/lib/jsontime"
|
||||
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/capture"
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/data"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
AP *AP `json:"-"`
|
||||
APAddr string `json:"ap"`
|
||||
Addr data.HardwareAddr `json:"-"`
|
||||
TryProbe uint16 `json:"try_probe"`
|
||||
TryAuth uint16 `json:"try_auth"`
|
||||
Connected bool `json:"connected"`
|
||||
Authed bool `json:"authed"`
|
||||
FreqHighest uint16 `json:"freq_highest"`
|
||||
SignalLowFreq int16 `json:"signal_low_freq"`
|
||||
SignalHighFreq int16 `json:"signal_high_freq"`
|
||||
Lastseen jsontime.Time `json:"lastseen"`
|
||||
}
|
||||
|
||||
func (db *DB) LearnClient(apIP net.IP, clientWifictl *capture.WifiClient) bool {
|
||||
ret := false
|
||||
|
||||
// learn ap
|
||||
apAddr := apIP.String()
|
||||
ap, ok := db.APs[apAddr]
|
||||
if !ok {
|
||||
ap = &AP{}
|
||||
db.APs[apAddr] = ap
|
||||
}
|
||||
ap.IP = &apIP
|
||||
ap.Lastseen = jsontime.Now()
|
||||
|
||||
// learn client
|
||||
clientAddr := clientWifictl.Addr.String()
|
||||
client, ok := db.Clients[clientAddr]
|
||||
if !ok {
|
||||
client = &Client{
|
||||
Addr: clientWifictl.Addr,
|
||||
}
|
||||
db.Clients[clientAddr] = client
|
||||
}
|
||||
client.Lastseen = jsontime.Now()
|
||||
client.AP = ap
|
||||
client.APAddr = apAddr
|
||||
client.Connected = clientWifictl.Connected
|
||||
client.SignalLowFreq = clientWifictl.SignalLowFreq
|
||||
client.SignalHighFreq = clientWifictl.SignalHighFreq
|
||||
|
||||
if clientWifictl.TryAuth > client.TryAuth {
|
||||
client.TryAuth = clientWifictl.TryAuth
|
||||
}
|
||||
if clientWifictl.TryProbe > client.TryProbe {
|
||||
client.TryProbe = clientWifictl.TryProbe
|
||||
}
|
||||
|
||||
if client.FreqHighest < clientWifictl.FreqHighest {
|
||||
ret = (client.FreqHighest != 0)
|
||||
client.FreqHighest = clientWifictl.FreqHighest
|
||||
}
|
||||
if clientWifictl.Authed {
|
||||
client.Authed = clientWifictl.Authed
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (db *DB) GetClient(addr data.HardwareAddr) *capture.WifiClient {
|
||||
client, ok := db.Clients[addr.String()]
|
||||
wClient := &capture.WifiClient{
|
||||
Addr: addr,
|
||||
Time: time.Now(),
|
||||
}
|
||||
if ok {
|
||||
wClient.TryProbe = client.TryProbe
|
||||
}
|
||||
return wClient
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/bdlm/log"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/file"
|
||||
"dev.sum7.eu/genofire/golang-lib/worker"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
Clients map[string]*Client `json:"client"`
|
||||
APs map[string]*AP `json:"ap"`
|
||||
worker *worker.Worker
|
||||
}
|
||||
|
||||
func NewDB(path string) *DB {
|
||||
db := &DB{
|
||||
Clients: make(map[string]*Client),
|
||||
APs: make(map[string]*AP),
|
||||
}
|
||||
|
||||
file.ReadJSON(path, db)
|
||||
|
||||
for addr, client := range db.Clients {
|
||||
client.Addr.UnmarshalText([]byte(addr))
|
||||
if ap, ok := db.APs[client.APAddr]; ok {
|
||||
client.AP = ap
|
||||
}
|
||||
}
|
||||
|
||||
db.worker = worker.NewWorker(time.Minute, func() {
|
||||
file.SaveJSON(path, db)
|
||||
log.Debug("save db state")
|
||||
})
|
||||
|
||||
db.worker.Start()
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func (db *DB) Close() {
|
||||
if db.worker != nil {
|
||||
db.worker.Close()
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package database
|
|
@ -7,9 +7,12 @@ import (
|
|||
"github.com/NYTimes/gziphandler"
|
||||
"github.com/bdlm/log"
|
||||
|
||||
"dev.sum7.eu/genofire/golang-lib/database"
|
||||
lib "dev.sum7.eu/genofire/golang-lib/http"
|
||||
"dev.sum7.eu/genofire/golang-lib/websocket"
|
||||
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/capture"
|
||||
"dev.sum7.eu/genofire/wifictld-analyzer/data"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
|
@ -22,6 +25,26 @@ func New(config *Config) *Server {
|
|||
ws := websocket.NewWebsocketHandlerService()
|
||||
ws.Listen("/ws")
|
||||
|
||||
http.HandleFunc("/data.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
type dataResponse struct {
|
||||
APs []data.AP `json:"aps"`
|
||||
Clients []data.Client `json:"clients"`
|
||||
}
|
||||
data := &dataResponse{}
|
||||
if result := database.Read.Find(&data.APs); result.Error != nil {
|
||||
log.WithField("error", result.Error.Error()).Warn("not possible to read APs")
|
||||
http.Error(w, "not possible to read APs", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if result := database.Read.Find(&data.Clients); result.Error != nil {
|
||||
log.WithField("error", result.Error.Error()).Warn("not possible to read Clients")
|
||||
http.Error(w, "not possible to read Clients", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
lib.Write(w, data)
|
||||
log.Info("fetch data")
|
||||
})
|
||||
|
||||
http.Handle("/", gziphandler.GzipHandler(http.FileServer(http.Dir(config.Webroot))))
|
||||
return &Server{
|
||||
web: &http.Server{
|
||||
|
|
Loading…
Reference in New Issue