mirror of
https://github.com/bettercap/bettercap
synced 2025-08-19 13:09:49 -07:00
refact: big refactoring and improvements of wifi.* modules
This commit is contained in:
parent
d0d3ce3ec7
commit
da5d1d46d4
6 changed files with 266 additions and 123 deletions
|
@ -19,31 +19,30 @@ func (s EventsStream) viewLogEvent(e session.Event) {
|
||||||
e.Data.(session.LogMessage).Message)
|
e.Data.(session.LogMessage).Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s EventsStream) viewStationEvent(e session.Event) {
|
func (s EventsStream) viewApEvent(e session.Event) {
|
||||||
st := e.Data.(*network.Station)
|
ap := e.Data.(*network.AccessPoint)
|
||||||
vend := ""
|
vend := ""
|
||||||
if st.Vendor != "" {
|
if ap.Vendor != "" {
|
||||||
vend = fmt.Sprintf(" (%s)", st.Vendor)
|
vend = fmt.Sprintf(" (%s)", ap.Vendor)
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Tag == "wifi.station.new" {
|
if e.Tag == "wifi.ap.new" {
|
||||||
fmt.Printf("[%s] WiFi station %s detected as %s%s.\n",
|
fmt.Printf("[%s] WiFi access point %s detected as %s%s.\n",
|
||||||
e.Time.Format(eventTimeFormat),
|
e.Time.Format(eventTimeFormat),
|
||||||
core.Bold(st.ESSID()),
|
core.Bold(ap.ESSID()),
|
||||||
core.Green(st.BSSID()),
|
core.Green(ap.BSSID()),
|
||||||
vend)
|
vend)
|
||||||
} else if e.Tag == "wifi.station.lost" {
|
} else if e.Tag == "wifi.ap.lost" {
|
||||||
fmt.Printf("[%s] WiFi station %s (%s) lost.\n",
|
fmt.Printf("[%s] WiFi access point %s (%s) lost.\n",
|
||||||
e.Time.Format(eventTimeFormat),
|
e.Time.Format(eventTimeFormat),
|
||||||
core.Red(st.ESSID()),
|
core.Red(ap.ESSID()),
|
||||||
st.BSSID())
|
ap.BSSID())
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("[%s] [%s] %s\n",
|
fmt.Printf("[%s] [%s] %s\n",
|
||||||
e.Time.Format(eventTimeFormat),
|
e.Time.Format(eventTimeFormat),
|
||||||
core.Green(e.Tag),
|
core.Green(e.Tag),
|
||||||
st)
|
ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s EventsStream) viewEndpointEvent(e session.Event) {
|
func (s EventsStream) viewEndpointEvent(e session.Event) {
|
||||||
|
@ -101,8 +100,8 @@ func (s *EventsStream) View(e session.Event, refresh bool) {
|
||||||
s.viewLogEvent(e)
|
s.viewLogEvent(e)
|
||||||
} else if strings.HasPrefix(e.Tag, "endpoint.") {
|
} else if strings.HasPrefix(e.Tag, "endpoint.") {
|
||||||
s.viewEndpointEvent(e)
|
s.viewEndpointEvent(e)
|
||||||
} else if strings.HasPrefix(e.Tag, "wifi.station.") {
|
} else if strings.HasPrefix(e.Tag, "wifi.ap.") {
|
||||||
s.viewStationEvent(e)
|
s.viewApEvent(e)
|
||||||
} else if strings.HasPrefix(e.Tag, "mod.") {
|
} else if strings.HasPrefix(e.Tag, "mod.") {
|
||||||
s.viewModuleEvent(e)
|
s.viewModuleEvent(e)
|
||||||
} else if strings.HasPrefix(e.Tag, "net.sniff.") {
|
} else if strings.HasPrefix(e.Tag, "net.sniff.") {
|
||||||
|
|
|
@ -31,14 +31,16 @@ type WiFiRecon struct {
|
||||||
handle *pcap.Handle
|
handle *pcap.Handle
|
||||||
channel int
|
channel int
|
||||||
frequencies []int
|
frequencies []int
|
||||||
apBSSID net.HardwareAddr
|
ap *network.AccessPoint
|
||||||
|
stickChan int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWiFiRecon(s *session.Session) *WiFiRecon {
|
func NewWiFiRecon(s *session.Session) *WiFiRecon {
|
||||||
w := &WiFiRecon{
|
w := &WiFiRecon{
|
||||||
SessionModule: session.NewSessionModule("wifi.recon", s),
|
SessionModule: session.NewSessionModule("wifi.recon", s),
|
||||||
channel: 0,
|
channel: 0,
|
||||||
apBSSID: nil,
|
stickChan: 0,
|
||||||
|
ap: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
w.AddHandler(session.NewModuleHandler("wifi.recon on", "",
|
w.AddHandler(session.NewModuleHandler("wifi.recon on", "",
|
||||||
|
@ -56,41 +58,33 @@ func NewWiFiRecon(s *session.Session) *WiFiRecon {
|
||||||
w.AddHandler(session.NewModuleHandler("wifi.recon MAC", "wifi.recon ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2}))",
|
w.AddHandler(session.NewModuleHandler("wifi.recon MAC", "wifi.recon ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2}))",
|
||||||
"Set 802.11 base station address to filter for.",
|
"Set 802.11 base station address to filter for.",
|
||||||
func(args []string) error {
|
func(args []string) error {
|
||||||
var err error
|
bssid, err := net.ParseMAC(args[0])
|
||||||
w.Session.WiFi.Clear()
|
if err != nil {
|
||||||
w.apBSSID, err = net.ParseMAC(args[0])
|
|
||||||
return err
|
return err
|
||||||
|
} else if ap, found := w.Session.WiFi.Get(bssid.String()); found == true {
|
||||||
|
w.ap = ap
|
||||||
|
w.stickChan = mhz2chan(ap.Frequency)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Could not find station with BSSID %s", args[0])
|
||||||
}))
|
}))
|
||||||
|
|
||||||
w.AddHandler(session.NewModuleHandler("wifi.recon clear", "",
|
w.AddHandler(session.NewModuleHandler("wifi.recon clear", "",
|
||||||
"Remove the 802.11 base station filter.",
|
"Remove the 802.11 base station filter.",
|
||||||
func(args []string) error {
|
func(args []string) error {
|
||||||
w.Session.WiFi.Clear()
|
w.ap = nil
|
||||||
w.apBSSID = nil
|
w.stickChan = 0
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
w.AddHandler(session.NewModuleHandler("wifi.deauth AP-BSSID TARGET-BSSID", `wifi\.deauth ([a-fA-F0-9\s:]+)`,
|
w.AddHandler(session.NewModuleHandler("wifi.deauth AP-BSSID TARGET-BSSID", `wifi\.deauth ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2}))`,
|
||||||
"Start a 802.11 deauth attack, while the AP-BSSID is mandatory, if no TARGET-BSSID is specified the deauth will be executed against every connected client.",
|
"Start a 802.11 deauth attack, if an access point BSSID is provided, every client will be deauthenticated, otherwise only the selected client.",
|
||||||
func(args []string) error {
|
func(args []string) error {
|
||||||
err := (error)(nil)
|
bssid, err := net.ParseMAC(args[0])
|
||||||
apMac := (net.HardwareAddr)(nil)
|
if err != nil {
|
||||||
clMac := (net.HardwareAddr)(nil)
|
|
||||||
parts := strings.SplitN(args[0], " ", 2)
|
|
||||||
|
|
||||||
if len(parts) == 2 {
|
|
||||||
if apMac, err = net.ParseMAC(parts[0]); err != nil {
|
|
||||||
return err
|
|
||||||
} else if clMac, err = net.ParseMAC(parts[1]); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
return w.startDeauth(bssid)
|
||||||
if apMac, err = net.ParseMAC(parts[0]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.startDeauth(apMac, clMac)
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
w.AddHandler(session.NewModuleHandler("wifi.show", "",
|
w.AddHandler(session.NewModuleHandler("wifi.show", "",
|
||||||
|
@ -115,7 +109,7 @@ func (w WiFiRecon) Description() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w WiFiRecon) Author() string {
|
func (w WiFiRecon) Author() string {
|
||||||
return "Gianluca Braga <matrix86@protonmail.com>"
|
return "Gianluca Braga <matrix86@protonmail.com> && Simone Margaritelli <evilsocket@protonmail.com>>"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFiRecon) getRow(station *network.Station) []string {
|
func (w *WiFiRecon) getRow(station *network.Station) []string {
|
||||||
|
@ -164,6 +158,11 @@ func (w *WiFiRecon) getRow(station *network.Station) []string {
|
||||||
seen,
|
seen,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// this is ugly, but necessary in order to have this
|
||||||
|
// method handle both access point and clients
|
||||||
|
// transparently
|
||||||
|
ap, _ := w.Session.WiFi.Get(station.HwAddress)
|
||||||
|
|
||||||
return []string{
|
return []string{
|
||||||
fmt.Sprintf("%d dBm", station.RSSI),
|
fmt.Sprintf("%d dBm", station.RSSI),
|
||||||
bssid,
|
bssid,
|
||||||
|
@ -171,6 +170,7 @@ func (w *WiFiRecon) getRow(station *network.Station) []string {
|
||||||
station.Vendor,
|
station.Vendor,
|
||||||
encryption,
|
encryption,
|
||||||
strconv.Itoa(mhz2chan(station.Frequency)),
|
strconv.Itoa(mhz2chan(station.Frequency)),
|
||||||
|
strconv.Itoa(ap.NumClients()),
|
||||||
sent,
|
sent,
|
||||||
recvd,
|
recvd,
|
||||||
seen,
|
seen,
|
||||||
|
@ -200,11 +200,23 @@ func (w *WiFiRecon) showTable(header []string, rows [][]string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFiRecon) isApSelected() bool {
|
func (w *WiFiRecon) isApSelected() bool {
|
||||||
return w.apBSSID != nil
|
return w.ap != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFiRecon) Show(by string) error {
|
func (w *WiFiRecon) Show(by string) error {
|
||||||
stations := w.Session.WiFi.List()
|
var stations []*network.Station
|
||||||
|
|
||||||
|
apSelected := w.isApSelected()
|
||||||
|
if apSelected {
|
||||||
|
if ap, found := w.Session.WiFi.Get(w.ap.HwAddress); found == true {
|
||||||
|
stations = ap.Clients()
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Could not find station %s", w.ap.HwAddress)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stations = w.Session.WiFi.Stations()
|
||||||
|
}
|
||||||
|
|
||||||
if by == "seen" {
|
if by == "seen" {
|
||||||
sort.Sort(ByWiFiSeenSorter(stations))
|
sort.Sort(ByWiFiSeenSorter(stations))
|
||||||
} else if by == "essid" {
|
} else if by == "essid" {
|
||||||
|
@ -221,15 +233,15 @@ func (w *WiFiRecon) Show(by string) error {
|
||||||
}
|
}
|
||||||
nrows := len(rows)
|
nrows := len(rows)
|
||||||
|
|
||||||
columns := []string{"RSSI", "BSSID", "SSID", "Vendor", "Encryption", "Channel", "Sent", "Recvd", "Last Seen"}
|
columns := []string{"RSSI", "BSSID", "SSID", "Vendor", "Encryption", "Channel", "Clients", "Sent", "Recvd", "Last Seen"}
|
||||||
if w.isApSelected() {
|
if apSelected {
|
||||||
// these are clients
|
// these are clients
|
||||||
columns = []string{"RSSI", "MAC", "Vendor", "Channel", "Sent", "Received", "Last Seen"}
|
columns = []string{"RSSI", "MAC", "Vendor", "Channel", "Sent", "Received", "Last Seen"}
|
||||||
|
|
||||||
if nrows == 0 {
|
if nrows == 0 {
|
||||||
fmt.Printf("\nNo authenticated clients detected for %s.\n", w.apBSSID.String())
|
fmt.Printf("\nNo authenticated clients detected for %s.\n", w.ap.HwAddress)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\n%s clients:\n", w.apBSSID.String())
|
fmt.Printf("\n%s clients:\n", w.ap.HwAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +317,20 @@ func (w *WiFiRecon) sendDeauthPacket(ap net.HardwareAddr, client net.HardwareAdd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFiRecon) startDeauth(apMac net.HardwareAddr, clMac net.HardwareAddr) error {
|
func (w *WiFiRecon) onChannel(channel int, cb func()) {
|
||||||
|
prev := w.stickChan
|
||||||
|
w.stickChan = channel
|
||||||
|
|
||||||
|
if err := network.SetInterfaceChannel(w.Session.Interface.Name(), channel); err != nil {
|
||||||
|
log.Warning("Error while hopping to channel %d: %s", channel, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cb()
|
||||||
|
|
||||||
|
w.stickChan = prev
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WiFiRecon) startDeauth(to net.HardwareAddr) error {
|
||||||
// if not already running, temporarily enable the pcap handle
|
// if not already running, temporarily enable the pcap handle
|
||||||
// for packet injection
|
// for packet injection
|
||||||
if w.Running() == false {
|
if w.Running() == false {
|
||||||
|
@ -315,21 +340,34 @@ func (w *WiFiRecon) startDeauth(apMac net.HardwareAddr, clMac net.HardwareAddr)
|
||||||
defer w.handle.Close()
|
defer w.handle.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// deauth a specific client
|
bssid := to.String()
|
||||||
if clMac != nil {
|
|
||||||
log.Info("Deauthing client %s from AP %s ...", clMac.String(), apMac.String())
|
// are we deauthing every client of a given access point?
|
||||||
w.sendDeauthPacket(apMac, clMac)
|
if ap, found := w.Session.WiFi.Get(bssid); found == true {
|
||||||
} else {
|
clients := ap.Clients()
|
||||||
log.Info("Deauthing clients from AP %s ...", apMac.String())
|
log.Info("Deauthing %d clients from AP %s ...", len(clients), ap.ESSID())
|
||||||
// deauth every authenticated client
|
w.onChannel(mhz2chan(ap.Frequency), func() {
|
||||||
for _, station := range w.Session.WiFi.List() {
|
for _, c := range clients {
|
||||||
if station.IsAP == false {
|
w.sendDeauthPacket(ap.HW, c.HW)
|
||||||
w.sendDeauthPacket(apMac, station.HW)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// search for a client
|
||||||
|
aps := w.Session.WiFi.List()
|
||||||
|
for _, ap := range aps {
|
||||||
|
if c, found := ap.Get(bssid); found == true {
|
||||||
|
log.Info("Deauthing client %s from AP %s ...", c.HwAddress, ap.ESSID())
|
||||||
|
w.onChannel(mhz2chan(ap.Frequency), func() {
|
||||||
|
w.sendDeauthPacket(ap.HW, c.HW)
|
||||||
|
})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return fmt.Errorf("%s is an unknown BSSID.", bssid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFiRecon) discoverAccessPoints(radiotap *layers.RadioTap, dot11 *layers.Dot11, packet gopacket.Packet) {
|
func (w *WiFiRecon) discoverAccessPoints(radiotap *layers.RadioTap, dot11 *layers.Dot11, packet gopacket.Packet) {
|
||||||
|
@ -337,17 +375,17 @@ func (w *WiFiRecon) discoverAccessPoints(radiotap *layers.RadioTap, dot11 *layer
|
||||||
if ok, ssid := packets.Dot11ParseIDSSID(packet); ok == true {
|
if ok, ssid := packets.Dot11ParseIDSSID(packet); ok == true {
|
||||||
bssid := dot11.Address3.String()
|
bssid := dot11.Address3.String()
|
||||||
frequency := int(radiotap.ChannelFrequency)
|
frequency := int(radiotap.ChannelFrequency)
|
||||||
w.Session.WiFi.AddIfNew(ssid, bssid, true, frequency, radiotap.DBMAntennaSignal)
|
w.Session.WiFi.AddIfNew(ssid, bssid, frequency, radiotap.DBMAntennaSignal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFiRecon) discoverClients(radiotap *layers.RadioTap, dot11 *layers.Dot11, ap net.HardwareAddr, packet gopacket.Packet) {
|
func (w *WiFiRecon) discoverClients(radiotap *layers.RadioTap, dot11 *layers.Dot11, packet gopacket.Packet) {
|
||||||
|
w.Session.WiFi.EachAccessPoint(func(bssid string, ap *network.AccessPoint) {
|
||||||
// packet going to this specific BSSID?
|
// packet going to this specific BSSID?
|
||||||
if packets.Dot11IsDataFor(dot11, ap) == true {
|
if packets.Dot11IsDataFor(dot11, ap.HW) == true {
|
||||||
src := dot11.Address2
|
ap.AddClient(dot11.Address2.String(), int(radiotap.ChannelFrequency), radiotap.DBMAntennaSignal)
|
||||||
frequency := int(radiotap.ChannelFrequency)
|
|
||||||
w.Session.WiFi.AddIfNew("", src.String(), false, frequency, radiotap.DBMAntennaSignal)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFiRecon) updateStats(dot11 *layers.Dot11, packet gopacket.Packet) {
|
func (w *WiFiRecon) updateStats(dot11 *layers.Dot11, packet gopacket.Packet) {
|
||||||
|
@ -387,6 +425,12 @@ func (w *WiFiRecon) channelHopper() {
|
||||||
|
|
||||||
for _, frequency := range w.frequencies {
|
for _, frequency := range w.frequencies {
|
||||||
channel := mhz2chan(frequency)
|
channel := mhz2chan(frequency)
|
||||||
|
// stick to the access point channel as long as it's selected
|
||||||
|
// or as long as we're deauthing on it
|
||||||
|
if w.stickChan != 0 {
|
||||||
|
channel = w.stickChan
|
||||||
|
}
|
||||||
|
|
||||||
if err := network.SetInterfaceChannel(w.Session.Interface.Name(), channel); err != nil {
|
if err := network.SetInterfaceChannel(w.Session.Interface.Name(), channel); err != nil {
|
||||||
log.Warning("Error while hopping to channel %d: %s", channel, err)
|
log.Warning("Error while hopping to channel %d: %s", channel, err)
|
||||||
}
|
}
|
||||||
|
@ -438,15 +482,9 @@ func (w *WiFiRecon) Start() error {
|
||||||
|
|
||||||
// perform initial dot11 parsing and layers validation
|
// perform initial dot11 parsing and layers validation
|
||||||
if ok, radiotap, dot11 := packets.Dot11Parse(packet); ok == true {
|
if ok, radiotap, dot11 := packets.Dot11Parse(packet); ok == true {
|
||||||
// keep collecting traffic statistics
|
|
||||||
w.updateStats(dot11, packet)
|
w.updateStats(dot11, packet)
|
||||||
// no access point bssid selected, keep scanning for other aps
|
|
||||||
if w.isApSelected() == false {
|
|
||||||
w.discoverAccessPoints(radiotap, dot11, packet)
|
w.discoverAccessPoints(radiotap, dot11, packet)
|
||||||
} else {
|
w.discoverClients(radiotap, dot11, packet)
|
||||||
// discover stations connected to the selected access point bssid
|
|
||||||
w.discoverClients(radiotap, dot11, w.apBSSID, packet)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,25 +6,25 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StationNewCallback func(s *Station)
|
type APNewCallback func(ap *AccessPoint)
|
||||||
type StationLostCallback func(s *Station)
|
type APLostCallback func(ap *AccessPoint)
|
||||||
|
|
||||||
type WiFi struct {
|
type WiFi struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
stations map[string]*Station
|
aps map[string]*AccessPoint
|
||||||
iface *Endpoint
|
iface *Endpoint
|
||||||
newCb StationNewCallback
|
newCb APNewCallback
|
||||||
lostCb StationLostCallback
|
lostCb APLostCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
type wifiJSON struct {
|
type wifiJSON struct {
|
||||||
Stations []*Station `json:"stations"`
|
AccessPoints []*AccessPoint `json:"aps"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWiFi(iface *Endpoint, newcb StationNewCallback, lostcb StationLostCallback) *WiFi {
|
func NewWiFi(iface *Endpoint, newcb APNewCallback, lostcb APLostCallback) *WiFi {
|
||||||
return &WiFi{
|
return &WiFi{
|
||||||
stations: make(map[string]*Station),
|
aps: make(map[string]*AccessPoint),
|
||||||
iface: iface,
|
iface: iface,
|
||||||
newCb: newcb,
|
newCb: newcb,
|
||||||
lostCb: lostcb,
|
lostCb: lostcb,
|
||||||
|
@ -33,23 +33,43 @@ func NewWiFi(iface *Endpoint, newcb StationNewCallback, lostcb StationLostCallba
|
||||||
|
|
||||||
func (w *WiFi) MarshalJSON() ([]byte, error) {
|
func (w *WiFi) MarshalJSON() ([]byte, error) {
|
||||||
doc := wifiJSON{
|
doc := wifiJSON{
|
||||||
Stations: make([]*Station, 0),
|
AccessPoints: make([]*AccessPoint, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range w.stations {
|
for _, ap := range w.aps {
|
||||||
doc.Stations = append(doc.Stations, s)
|
doc.AccessPoints = append(doc.AccessPoints, ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(doc)
|
return json.Marshal(doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFi) List() (list []*Station) {
|
func (w *WiFi) EachAccessPoint(cb func(mac string, ap *AccessPoint)) {
|
||||||
|
w.Lock()
|
||||||
|
defer w.Unlock()
|
||||||
|
|
||||||
|
for m, ap := range w.aps {
|
||||||
|
cb(m, ap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WiFi) Stations() (list []*Station) {
|
||||||
w.Lock()
|
w.Lock()
|
||||||
defer w.Unlock()
|
defer w.Unlock()
|
||||||
|
|
||||||
list = make([]*Station, 0)
|
list = make([]*Station, 0)
|
||||||
for _, t := range w.stations {
|
for _, ap := range w.aps {
|
||||||
list = append(list, t)
|
list = append(list, ap.Station)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WiFi) List() (list []*AccessPoint) {
|
||||||
|
w.Lock()
|
||||||
|
defer w.Unlock()
|
||||||
|
|
||||||
|
list = make([]*AccessPoint, 0)
|
||||||
|
for _, ap := range w.aps {
|
||||||
|
list = append(list, ap)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -58,45 +78,45 @@ func (w *WiFi) Remove(mac string) {
|
||||||
w.Lock()
|
w.Lock()
|
||||||
defer w.Unlock()
|
defer w.Unlock()
|
||||||
|
|
||||||
if s, found := w.stations[mac]; found {
|
if ap, found := w.aps[mac]; found {
|
||||||
delete(w.stations, mac)
|
delete(w.aps, mac)
|
||||||
if w.lostCb != nil {
|
if w.lostCb != nil {
|
||||||
w.lostCb(s)
|
w.lostCb(ap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFi) AddIfNew(ssid, mac string, isAp bool, frequency int, rssi int8) *Station {
|
func (w *WiFi) AddIfNew(ssid, mac string, frequency int, rssi int8) *AccessPoint {
|
||||||
w.Lock()
|
w.Lock()
|
||||||
defer w.Unlock()
|
defer w.Unlock()
|
||||||
|
|
||||||
mac = NormalizeMac(mac)
|
mac = NormalizeMac(mac)
|
||||||
if station, found := w.stations[mac]; found {
|
if ap, found := w.aps[mac]; found {
|
||||||
station.LastSeen = time.Now()
|
ap.LastSeen = time.Now()
|
||||||
station.RSSI = rssi
|
ap.RSSI = rssi
|
||||||
return station
|
return ap
|
||||||
}
|
}
|
||||||
|
|
||||||
newStation := NewStation(ssid, mac, isAp, frequency, rssi)
|
newAp := NewAccessPoint(ssid, mac, frequency, rssi)
|
||||||
w.stations[mac] = newStation
|
w.aps[mac] = newAp
|
||||||
|
|
||||||
if w.newCb != nil {
|
if w.newCb != nil {
|
||||||
w.newCb(newStation)
|
w.newCb(newAp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFi) Get(mac string) (*Station, bool) {
|
func (w *WiFi) Get(mac string) (*AccessPoint, bool) {
|
||||||
w.Lock()
|
w.Lock()
|
||||||
defer w.Unlock()
|
defer w.Unlock()
|
||||||
|
|
||||||
mac = NormalizeMac(mac)
|
mac = NormalizeMac(mac)
|
||||||
station, found := w.stations[mac]
|
ap, found := w.aps[mac]
|
||||||
return station, found
|
return ap, found
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WiFi) Clear() error {
|
func (w *WiFi) Clear() error {
|
||||||
w.stations = make(map[string]*Station)
|
w.aps = make(map[string]*AccessPoint)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
88
network/wifi_ap.go
Normal file
88
network/wifi_ap.go
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccessPoint struct {
|
||||||
|
*Station
|
||||||
|
sync.Mutex
|
||||||
|
|
||||||
|
clients map[string]*Station
|
||||||
|
}
|
||||||
|
|
||||||
|
type apJSON struct {
|
||||||
|
*Station
|
||||||
|
Clients []*Station `json:"clients"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAccessPoint(essid, bssid string, frequency int, rssi int8) *AccessPoint {
|
||||||
|
return &AccessPoint{
|
||||||
|
Station: NewStation(essid, bssid, frequency, rssi),
|
||||||
|
clients: make(map[string]*Station),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AccessPoint) MarshalJSON() ([]byte, error) {
|
||||||
|
doc := apJSON{
|
||||||
|
Station: ap.Station,
|
||||||
|
Clients: make([]*Station, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range ap.clients {
|
||||||
|
doc.Clients = append(doc.Clients, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(doc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AccessPoint) Get(bssid string) (*Station, bool) {
|
||||||
|
ap.Lock()
|
||||||
|
defer ap.Unlock()
|
||||||
|
|
||||||
|
bssid = NormalizeMac(bssid)
|
||||||
|
if s, found := ap.clients[bssid]; found == true {
|
||||||
|
return s, true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AccessPoint) AddClient(bssid string, frequency int, rssi int8) *Station {
|
||||||
|
ap.Lock()
|
||||||
|
defer ap.Unlock()
|
||||||
|
|
||||||
|
bssid = NormalizeMac(bssid)
|
||||||
|
|
||||||
|
if s, found := ap.clients[bssid]; found == true {
|
||||||
|
// update
|
||||||
|
s.Frequency = frequency
|
||||||
|
s.RSSI = rssi
|
||||||
|
s.LastSeen = time.Now()
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
s := NewStation("", bssid, frequency, rssi)
|
||||||
|
ap.clients[bssid] = s
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AccessPoint) NumClients() int {
|
||||||
|
ap.Lock()
|
||||||
|
defer ap.Unlock()
|
||||||
|
return len(ap.clients)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AccessPoint) Clients() (list []*Station) {
|
||||||
|
ap.Lock()
|
||||||
|
defer ap.Unlock()
|
||||||
|
|
||||||
|
list = make([]*Station, 0)
|
||||||
|
for _, c := range ap.clients {
|
||||||
|
list = append(list, c)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -2,18 +2,16 @@ package network
|
||||||
|
|
||||||
type Station struct {
|
type Station struct {
|
||||||
*Endpoint
|
*Endpoint
|
||||||
IsAP bool
|
Frequency int `json:"frequency"`
|
||||||
Frequency int
|
RSSI int8 `json:"rssi"`
|
||||||
RSSI int8
|
Sent uint64 `json:"sent"`
|
||||||
Sent uint64
|
Received uint64 `json:"received"`
|
||||||
Received uint64
|
Encryption string `json:"encryption"`
|
||||||
Encryption string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStation(essid, bssid string, isAp bool, frequency int, rssi int8) *Station {
|
func NewStation(essid, bssid string, frequency int, rssi int8) *Station {
|
||||||
return &Station{
|
return &Station{
|
||||||
Endpoint: NewEndpointNoResolve(MonitorModeAddress, bssid, essid, 0),
|
Endpoint: NewEndpointNoResolve(MonitorModeAddress, bssid, essid, 0),
|
||||||
IsAP: isAp,
|
|
||||||
Frequency: frequency,
|
Frequency: frequency,
|
||||||
RSSI: rssi,
|
RSSI: rssi,
|
||||||
}
|
}
|
||||||
|
|
|
@ -378,10 +378,10 @@ func (s *Session) Start() error {
|
||||||
|
|
||||||
s.Firewall = firewall.Make(s.Interface)
|
s.Firewall = firewall.Make(s.Interface)
|
||||||
|
|
||||||
s.WiFi = network.NewWiFi(s.Interface, func(st *network.Station) {
|
s.WiFi = network.NewWiFi(s.Interface, func(ap *network.AccessPoint) {
|
||||||
s.Events.Add("wifi.station.new", st)
|
s.Events.Add("wifi.ap.new", ap)
|
||||||
}, func(st *network.Station) {
|
}, func(ap *network.AccessPoint) {
|
||||||
s.Events.Add("wifi.station.lost", st)
|
s.Events.Add("wifi.ap.lost", ap)
|
||||||
})
|
})
|
||||||
|
|
||||||
s.Lan = network.NewLAN(s.Interface, s.Gateway, func(e *network.Endpoint) {
|
s.Lan = network.NewLAN(s.Interface, s.Gateway, func(e *network.Endpoint) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue