package iwlist import ( "fmt" "os/exec" "regexp" "strconv" "strings" "sync" ) var ( newCellRegexp = regexp.MustCompile(`^Cell\s+(?P.+)\s+-\s+Address:\s(?P.+)$`) 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.*)\"$`), regexp.MustCompile(`^Mode:(?P.+)$`), regexp.MustCompile(`^Frequency:(?P[\d.]+) (?P.+) \(Channel (?P\d+)\)$`), regexp.MustCompile(`^Encryption key:(?P.+)$`), regexp.MustCompile(`^IE:\ WPA\ Version\ (?P.+)$`), regexp.MustCompile(`^IE:\ IEEE\ 802\.11i/WPA2\ Version\ (?P)$`), regexp.MustCompile(`^Quality=(?P\d+)/(?P\d+)\s+Signal level=(?P.+) 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:"" // 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() } }