| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- // WiFi Scanner - captures WiFi probe requests and publishes events via ZMQ
- package main
- import (
- "context"
- "encoding/json"
- "flag"
- "log"
- "os"
- "os/signal"
- "syscall"
- "time"
- "mybeacon/internal/protocol"
- "mybeacon/internal/wifi"
- "github.com/go-zeromq/zmq4"
- )
- const (
- defaultZMQAddr = "tcp://127.0.0.1:5556"
- defaultIface = "wlan0"
- )
- var defaultChannels = []int{1, 6, 11}
- func main() {
- var (
- zmqAddr = flag.String("zmq", defaultZMQAddr, "ZMQ PUB address")
- iface = flag.String("iface", defaultIface, "WiFi interface")
- dwellMs = flag.Int("dwell", 400, "Channel dwell time in ms")
- debug = flag.Bool("debug", false, "Enable debug logging")
- noMonitor = flag.Bool("no-monitor", false, "Skip monitor mode setup")
- )
- flag.Parse()
- log.SetFlags(log.Ltime | log.Lmicroseconds)
- log.Printf("WiFi Scanner starting (iface=%s, zmq=%s)", *iface, *zmqAddr)
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
- // Create ZMQ publisher socket
- publisher := zmq4.NewPub(ctx)
- defer publisher.Close()
- if err := publisher.Listen(*zmqAddr); err != nil {
- log.Fatalf("ZMQ listen: %v", err)
- }
- log.Printf("ZMQ PUB listening on %s", *zmqAddr)
- time.Sleep(100 * time.Millisecond)
- // Enable monitor mode
- if !*noMonitor {
- log.Printf("Enabling monitor mode on %s...", *iface)
- if err := wifi.SetMonitorMode(*iface); err != nil {
- log.Fatalf("Monitor mode: %v", err)
- }
- log.Printf("Monitor mode enabled on %s", *iface)
- }
- // Create capture socket
- capture, err := wifi.NewCaptureSocket(*iface)
- if err != nil {
- log.Fatalf("Capture socket: %v", err)
- }
- defer capture.Close()
- // Start channel hopper
- hopper := wifi.NewChannelHopper(*iface, defaultChannels, time.Duration(*dwellMs)*time.Millisecond)
- hopper.Start()
- defer hopper.Stop()
- log.Printf("Channel hopping: %v (dwell=%dms)", defaultChannels, *dwellMs)
- // Handle shutdown
- sigChan := make(chan os.Signal, 1)
- signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
- go func() {
- <-sigChan
- log.Println("Shutting down...")
- hopper.Stop()
- capture.Close()
- if !*noMonitor {
- wifi.SetManagedMode(*iface)
- }
- cancel()
- os.Exit(0)
- }()
- // Main capture loop
- buf := make([]byte, 65536)
- var eventCount uint64
- for {
- n, err := capture.Read(buf)
- if err != nil {
- log.Printf("Read error: %v", err)
- continue
- }
- probe, ok := wifi.ParseProbeRequest(buf[:n])
- if !ok {
- continue
- }
- ev := protocol.WiFiProbeEvent{
- Type: protocol.EventWiFiProbe,
- MAC: probe.SourceMAC,
- RSSI: probe.RSSI,
- TsMs: probe.Timestamp.UnixMilli(),
- SSID: probe.SSID,
- }
- jsonData, err := json.Marshal(ev)
- if err != nil {
- continue
- }
- topic := "wifi.probe"
- msg := zmq4.NewMsgString(topic + " " + string(jsonData))
- if err := publisher.Send(msg); err != nil {
- log.Printf("ZMQ send error: %v", err)
- continue
- }
- eventCount++
- if *debug {
- log.Printf("[%s] %s", topic, string(jsonData))
- } else if eventCount%100 == 0 {
- log.Printf("Published %d probe requests", eventCount)
- }
- }
- }
|