package iwlist
|
|
import (
|
"fmt"
|
"os/exec"
|
"regexp"
|
"strconv"
|
"strings"
|
"sync"
|
)
|
|
var (
|
newCellRegexp = regexp.MustCompile(`^Cell\s+(?P<cell_number>.+)\s+-\s+Address:\s(?P<mac>.+)$`)
|
regxp [7]*regexp.Regexp
|
)
|
|
type Cell struct {
|
CellNumber string `json:"cell_number"`
|
MAC string `json:"mac"`
|
ESSID string `json:"essid"`
|
Mode string `json:"mode"`
|
Frequency float32 `json:"frequency"`
|
FrequencyUnits string `json:"frequency_units"`
|
Channel int `json:"channel"`
|
EncryptionKey bool `json:"encryption_key"`
|
Encryption string `json:"encryption"`
|
SignalQuality int `json:"signal_quality"`
|
SignalTotal int `json:"signal_total"`
|
SignalLevel int `json:"signal_level"`
|
Connected bool `json:"connected"`
|
}
|
|
func init() {
|
// precompile regexp
|
regxp = [7]*regexp.Regexp{
|
regexp.MustCompile(`^ESSID:\"(?P<essid>.*)\"$`),
|
regexp.MustCompile(`^Mode:(?P<mode>.+)$`),
|
regexp.MustCompile(`^Frequency:(?P<frequency>[\d.]+) (?P<frequency_units>.+) \(Channel (?P<channel>\d+)\)$`),
|
regexp.MustCompile(`^Encryption key:(?P<encryption_key>.+)$`),
|
regexp.MustCompile(`^IE:\ WPA\ Version\ (?P<wpa>.+)$`),
|
regexp.MustCompile(`^IE:\ IEEE\ 802\.11i/WPA2\ Version\ (?P<wpa2>)$`),
|
regexp.MustCompile(`^Quality=(?P<signal_quality>\d+)/(?P<signal_total>\d+)\s+Signal level=(?P<signal_level>.+) d.+$`),
|
}
|
}
|
|
func Scan(interfaceName string) ([]Cell, error) {
|
// execute iwlist for scanning wireless networks
|
// 博通网卡不加sudo扫描不到网络
|
cmdStr := fmt.Sprintf("sudo iwlist %s scan", interfaceName)
|
cmd := exec.Command("/bin/bash", "-c", cmdStr)
|
out, err := cmd.CombinedOutput()
|
if err != nil {
|
return nil, err
|
}
|
|
wifiList, err := parse(string(out))
|
if err != nil {
|
return wifiList, err
|
}
|
|
// 获取当前连接的wifi
|
// 使用iwconfig 获取当前接口的连接状态, 过滤出连接的wifi名称
|
// 忽略了Mode的判断,连接后应该是Managed
|
//wlan0 IEEE 802.11AC ESSID:"Basic" Nickname:"<WIFI@REALTEK>"
|
// Mode:Managed Frequency:5.22 GHz Access Point: 82:45:58:18:17:E6
|
// Bit Rate:200 Mb/s Sensitivity:0/0
|
// Retry:off RTS thr:off Fragment thr:off
|
// Power Management:off
|
// Link Quality=75/100 Signal level=-53 dBm Noise level=0 dBm
|
// Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
|
// Tx excessive retries:0 Invalid misc:0 Missed beacon:0
|
|
reg, _ := regexp.Compile(`ESSID:\"(\w+)\".*\n\s+Mode:(\w+).*Point:\s?(\S+)`)
|
cmd = exec.Command("iwconfig", interfaceName)
|
out, _ = cmd.CombinedOutput()
|
|
res := reg.FindStringSubmatch(string(out))
|
if len(res) == 4 {
|
for i, v := range wifiList {
|
if v.MAC == res[3] {
|
wifiList[i].Connected = true
|
wifiList[0], wifiList[i] = wifiList[i], wifiList[0]
|
}
|
}
|
}
|
|
return wifiList, nil
|
}
|
|
func parse(input string) (cells []Cell, err error) {
|
lines := strings.Split(input, "\n")
|
|
var cell *Cell
|
var wg sync.WaitGroup
|
var m sync.Mutex
|
for _, line := range lines {
|
line = strings.TrimSpace(line)
|
|
// check new cell value
|
if cellValues := newCellRegexp.FindStringSubmatch(line); len(cellValues) > 0 {
|
cells = append(cells, Cell{
|
CellNumber: cellValues[1],
|
MAC: cellValues[2],
|
})
|
cell = &cells[len(cells)-1]
|
|
continue
|
}
|
|
// compare lines to regexps
|
wg.Add(len(regxp))
|
for _, reg := range regxp {
|
go compare(line, &wg, &m, cell, reg)
|
}
|
wg.Wait()
|
}
|
|
return
|
}
|
|
func compare(line string, wg *sync.WaitGroup, m *sync.Mutex, cell *Cell, reg *regexp.Regexp) {
|
defer wg.Done()
|
|
if values := reg.FindStringSubmatch(line); len(values) > 0 {
|
keys := reg.SubexpNames()
|
|
m.Lock()
|
|
for i := 1; i < len(keys); i++ {
|
switch keys[i] {
|
case "essid":
|
cell.ESSID = values[i]
|
case "mode":
|
cell.Mode = values[i]
|
case "frequency":
|
if frequency, err := strconv.ParseFloat(values[i], 32); err == nil {
|
cell.Frequency = float32(frequency)
|
}
|
case "frequency_units":
|
cell.FrequencyUnits = values[i]
|
case "channel":
|
if channel, err := strconv.ParseInt(values[i], 10, 32); err == nil {
|
cell.Channel = int(channel)
|
}
|
case "encryption_key":
|
if cell.EncryptionKey = values[i] == "on"; cell.EncryptionKey {
|
cell.Encryption = "wep"
|
} else {
|
cell.Encryption = "off"
|
}
|
case "wpa":
|
cell.Encryption = "wpa"
|
case "wpa2":
|
cell.Encryption = "wpa2"
|
case "signal_quality":
|
if quality, err := strconv.ParseInt(values[i], 10, 32); err == nil {
|
cell.SignalQuality = int(quality)
|
}
|
case "signal_total":
|
if total, err := strconv.ParseInt(values[i], 10, 32); err == nil {
|
cell.SignalTotal = int(total)
|
}
|
case "signal_level":
|
if level, err := strconv.ParseInt(values[i], 10, 32); err == nil {
|
cell.SignalLevel = int(level)
|
}
|
}
|
}
|
|
m.Unlock()
|
}
|
}
|