mirror of
https://github.com/taigrr/golang-wpasupplicant
synced 2025-01-18 04:43:18 -08:00
Initial interface to wpa_supplicant scan results
This code connects to wpa_supplicant's control interface using a UNIX datagram socket. It can ping the daemon and fetch wifi network scan results. Documentation, tests, and additional functionality is forthcoming.
This commit is contained in:
commit
8a251ea4ef
187
unixgram.go
Normal file
187
unixgram.go
Normal file
@ -0,0 +1,187 @@
|
||||
package wpasupplicant
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type message struct {
|
||||
priority int
|
||||
data []byte
|
||||
err error
|
||||
}
|
||||
|
||||
type unixgramConn struct {
|
||||
c *net.UnixConn
|
||||
fd uintptr
|
||||
solicited, unsolicited chan message
|
||||
}
|
||||
|
||||
func Unixgram(ifName string) (Conn, error) {
|
||||
var err error
|
||||
uc := &unixgramConn{}
|
||||
|
||||
local, err := ioutil.TempFile("/tmp", "wpa_supplicant")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
os.Remove(local.Name())
|
||||
|
||||
uc.c, err = net.DialUnix("unixgram",
|
||||
&net.UnixAddr{Name: local.Name(), Net: "unixgram"},
|
||||
&net.UnixAddr{Name: path.Join("/run/wpa_supplicant", ifName), Net: "unixgram"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file, err := uc.c.File()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uc.fd = file.Fd()
|
||||
|
||||
uc.solicited = make(chan message)
|
||||
uc.unsolicited = make(chan message)
|
||||
|
||||
go uc.readLoop()
|
||||
|
||||
return uc, nil
|
||||
}
|
||||
|
||||
func (uc *unixgramConn) readLoop() {
|
||||
for {
|
||||
n, _, err := syscall.Recvfrom(int(uc.fd), []byte{}, syscall.MSG_PEEK|syscall.MSG_TRUNC)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
buf := make([]byte, n)
|
||||
_, err = uc.c.Read(buf[:])
|
||||
if err != nil {
|
||||
uc.solicited <- message{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
var p int
|
||||
var c chan message
|
||||
if len(buf) >= 3 && buf[0] == '<' && buf[2] == '>' {
|
||||
switch buf[1] {
|
||||
case '0', '1', '2', '3', '4':
|
||||
c = uc.unsolicited
|
||||
p, _ = strconv.Atoi(string(buf[1]))
|
||||
buf = buf[3:]
|
||||
default:
|
||||
c = uc.solicited
|
||||
p = 2
|
||||
}
|
||||
} else {
|
||||
c = uc.solicited
|
||||
p = 2
|
||||
}
|
||||
|
||||
c <- message{
|
||||
priority: p,
|
||||
data: buf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (uc *unixgramConn) cmd(cmd string) ([]byte, error) {
|
||||
// TODO: block if any other commands are running
|
||||
|
||||
_, err := uc.c.Write([]byte(cmd))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg := <-uc.solicited
|
||||
return msg.data, msg.err
|
||||
}
|
||||
|
||||
func (uc *unixgramConn) Ping() error {
|
||||
resp, err := uc.cmd("PING")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Compare(resp, []byte("PONG\n")) == 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("expected %q, got %q", "PONG", resp)
|
||||
}
|
||||
|
||||
func (uc *unixgramConn) ScanResults() ([]ScanResult, error) {
|
||||
resp, err := uc.cmd("SCAN_RESULTS")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := bufio.NewScanner(bytes.NewBuffer(resp))
|
||||
if !s.Scan() {
|
||||
return nil, errors.New("failed to parse scan results")
|
||||
}
|
||||
var bssidCol, freqCol, rssiCol, flagsCol, ssidCol, maxCol int
|
||||
for n, col := range strings.Split(s.Text(), " / ") {
|
||||
switch col {
|
||||
case "bssid":
|
||||
bssidCol = n
|
||||
case "frequency":
|
||||
freqCol = n
|
||||
case "signal level":
|
||||
rssiCol = n
|
||||
case "flags":
|
||||
flagsCol = n
|
||||
case "ssid":
|
||||
ssidCol = n
|
||||
}
|
||||
maxCol = n
|
||||
}
|
||||
|
||||
var res []ScanResult
|
||||
for s.Scan() {
|
||||
fields := strings.Split(s.Text(), "\t")
|
||||
if len(fields) < maxCol {
|
||||
continue // TODO: log error
|
||||
}
|
||||
|
||||
bssid, err := net.ParseMAC(fields[bssidCol])
|
||||
if err != nil {
|
||||
continue // TODO: log error
|
||||
}
|
||||
|
||||
freq, err := strconv.Atoi(fields[freqCol])
|
||||
if err != nil {
|
||||
continue // TODO: log error
|
||||
}
|
||||
|
||||
rssi, err := strconv.Atoi(fields[rssiCol])
|
||||
if err != nil {
|
||||
continue // TODO: log error
|
||||
}
|
||||
|
||||
var flags []string
|
||||
if len(fields[flagsCol]) >= 2 && fields[flagsCol][0] != '[' && fields[flagsCol][len(fields[flagsCol])-1] != ']' {
|
||||
flags = strings.Split(fields[flagsCol][1:len(fields[flagsCol])-2], "][")
|
||||
}
|
||||
|
||||
res = append(res, &scanResult{
|
||||
bssid: bssid,
|
||||
frequency: freq,
|
||||
rssi: rssi,
|
||||
flags: flags,
|
||||
ssid: fields[ssidCol],
|
||||
})
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
78
wpasupplicant.go
Normal file
78
wpasupplicant.go
Normal file
@ -0,0 +1,78 @@
|
||||
package wpasupplicant
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
type Cipher int
|
||||
|
||||
const (
|
||||
CIPHER_NONE Cipher = 1 << iota
|
||||
WEP40
|
||||
WEP104
|
||||
TKIP
|
||||
CCMP
|
||||
AES_128_CMAC
|
||||
GCMP
|
||||
SMS4
|
||||
GCMP_256
|
||||
CCMP_256
|
||||
_
|
||||
BIP_GMAC_128
|
||||
BIP_GMAC_256
|
||||
BIP_CMAC_256
|
||||
GTK_NOT_USED
|
||||
)
|
||||
|
||||
type KeyMgmt int
|
||||
|
||||
const (
|
||||
IEEE8021X KeyMgmt = 1 << iota
|
||||
PSK
|
||||
KEY_MGMT_NONE
|
||||
IEEE8021X_NO_WPA
|
||||
WPA_NONE
|
||||
FT_IEEE8021X
|
||||
FT_PSK
|
||||
IEEE8021X_SHA256
|
||||
PSK_SHA256
|
||||
WPS
|
||||
SAE
|
||||
FT_SAE
|
||||
WAPI_PSK
|
||||
WAPI_CERT
|
||||
CCKM
|
||||
OSEN
|
||||
IEEE8021X_SUITE_B
|
||||
IEEE8021X_SUITE_B_192
|
||||
)
|
||||
|
||||
type Algorithm int
|
||||
|
||||
type ScanResult interface {
|
||||
BSSID() net.HardwareAddr
|
||||
SSID() string
|
||||
Frequency() int
|
||||
RSSI() int
|
||||
Flags() []string
|
||||
}
|
||||
|
||||
type scanResult struct {
|
||||
bssid net.HardwareAddr
|
||||
ssid string
|
||||
frequency int
|
||||
rssi int
|
||||
flags []string
|
||||
}
|
||||
|
||||
func (r *scanResult) BSSID() net.HardwareAddr { return r.bssid }
|
||||
func (r *scanResult) SSID() string { return r.ssid }
|
||||
func (r *scanResult) Frequency() int { return r.frequency }
|
||||
func (r *scanResult) RSSI() int { return r.rssi }
|
||||
func (r *scanResult) Flags() []string { return r.flags }
|
||||
|
||||
type Conn interface {
|
||||
Ping() error
|
||||
|
||||
ScanResults() ([]ScanResult, error)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user