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