mirror of
https://github.com/bettercap/bettercap.git
synced 2024-11-07 22:20:11 -08:00
155 lines
3.4 KiB
Go
155 lines
3.4 KiB
Go
//go:build !windows && !freebsd && !openbsd && !netbsd
|
|
// +build !windows,!freebsd,!openbsd,!netbsd
|
|
|
|
package ble
|
|
|
|
import (
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/bettercap/bettercap/v2/network"
|
|
|
|
"github.com/evilsocket/islazy/ops"
|
|
"github.com/evilsocket/islazy/tui"
|
|
)
|
|
|
|
var (
|
|
bleAliveInterval = time.Duration(5) * time.Second
|
|
)
|
|
|
|
func (mod *BLERecon) getRow(dev *network.BLEDevice, withName bool) []string {
|
|
rssi := network.ColorRSSI(dev.RSSI)
|
|
address := network.NormalizeMac(dev.Device.ID())
|
|
vendor := tui.Dim(ops.Ternary(dev.Vendor == "", dev.Advertisement.Company, dev.Vendor).(string))
|
|
isConnectable := ops.Ternary(dev.Advertisement.Connectable, tui.Green("✔"), tui.Red("✖")).(string)
|
|
sinceSeen := time.Since(dev.LastSeen)
|
|
lastSeen := dev.LastSeen.Format("15:04:05")
|
|
|
|
blePresentInterval := time.Duration(mod.devTTL) * time.Second
|
|
if sinceSeen <= bleAliveInterval {
|
|
lastSeen = tui.Bold(lastSeen)
|
|
} else if sinceSeen > blePresentInterval {
|
|
lastSeen = tui.Dim(lastSeen)
|
|
address = tui.Dim(address)
|
|
}
|
|
|
|
if withName {
|
|
return []string{
|
|
rssi,
|
|
address,
|
|
tui.Yellow(dev.Name()),
|
|
vendor,
|
|
dev.Advertisement.Flags.String(),
|
|
isConnectable,
|
|
lastSeen,
|
|
}
|
|
} else {
|
|
return []string{
|
|
rssi,
|
|
address,
|
|
vendor,
|
|
dev.Advertisement.Flags.String(),
|
|
isConnectable,
|
|
lastSeen,
|
|
}
|
|
}
|
|
}
|
|
|
|
func (mod *BLERecon) doFilter(dev *network.BLEDevice) bool {
|
|
if mod.selector.Expression == nil {
|
|
return true
|
|
}
|
|
return mod.selector.Expression.MatchString(dev.Device.ID()) ||
|
|
mod.selector.Expression.MatchString(dev.Device.Name()) ||
|
|
mod.selector.Expression.MatchString(dev.Vendor)
|
|
}
|
|
|
|
func (mod *BLERecon) doSelection() (devices []*network.BLEDevice, err error) {
|
|
if err = mod.selector.Update(); err != nil {
|
|
return
|
|
}
|
|
|
|
devices = mod.Session.BLE.Devices()
|
|
filtered := []*network.BLEDevice{}
|
|
for _, dev := range devices {
|
|
if mod.doFilter(dev) {
|
|
filtered = append(filtered, dev)
|
|
}
|
|
}
|
|
devices = filtered
|
|
|
|
switch mod.selector.SortField {
|
|
case "mac":
|
|
sort.Sort(ByBLEMacSorter(devices))
|
|
case "seen":
|
|
sort.Sort(ByBLESeenSorter(devices))
|
|
default:
|
|
sort.Sort(ByBLERSSISorter(devices))
|
|
}
|
|
|
|
// default is asc
|
|
if mod.selector.Sort == "desc" {
|
|
// from https://github.com/golang/go/wiki/SliceTricks
|
|
for i := len(devices)/2 - 1; i >= 0; i-- {
|
|
opp := len(devices) - 1 - i
|
|
devices[i], devices[opp] = devices[opp], devices[i]
|
|
}
|
|
}
|
|
|
|
if mod.selector.Limit > 0 {
|
|
limit := mod.selector.Limit
|
|
max := len(devices)
|
|
if limit > max {
|
|
limit = max
|
|
}
|
|
devices = devices[0:limit]
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (mod *BLERecon) colNames(withName bool) []string {
|
|
colNames := []string{"RSSI", "MAC", "Vendor", "Flags", "Connect", "Seen"}
|
|
seenIdx := 5
|
|
if withName {
|
|
colNames = []string{"RSSI", "MAC", "Name", "Vendor", "Flags", "Connect", "Seen"}
|
|
seenIdx = 6
|
|
}
|
|
switch mod.selector.SortField {
|
|
case "rssi":
|
|
colNames[0] += " " + mod.selector.SortSymbol
|
|
case "mac":
|
|
colNames[1] += " " + mod.selector.SortSymbol
|
|
case "seen":
|
|
colNames[seenIdx] += " " + mod.selector.SortSymbol
|
|
}
|
|
return colNames
|
|
}
|
|
|
|
func (mod *BLERecon) Show() error {
|
|
devices, err := mod.doSelection()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hasName := false
|
|
for _, dev := range devices {
|
|
if dev.Name() != "" {
|
|
hasName = true
|
|
break
|
|
}
|
|
}
|
|
|
|
rows := make([][]string, 0)
|
|
for _, dev := range devices {
|
|
rows = append(rows, mod.getRow(dev, hasName))
|
|
}
|
|
|
|
if len(rows) > 0 {
|
|
tui.Table(mod.Session.Events.Stdout, mod.colNames(hasName), rows)
|
|
mod.Session.Refresh()
|
|
}
|
|
|
|
return nil
|
|
}
|