fix: fixed a bug in the gatt library which prevented ble.recon/ble.enum to work multiple times (fixes #471)

This commit is contained in:
evilsocket 2019-03-13 15:35:46 +01:00
commit 120db4db3d
No known key found for this signature in database
GPG key ID: 1564D7F30393A456
7 changed files with 75 additions and 13 deletions

4
Gopkg.lock generated
View file

@ -27,7 +27,7 @@
[[projects]]
branch = "master"
digest = "1:c309b41787813f80ec393023471014b0be16346bba6e16bf5fa01ce1d310a4ea"
digest = "1:a2c142e6c2aa1c71796c748bbe42d224e23d6638fd5b3ae153e70a4b08a8da4e"
name = "github.com/bettercap/gatt"
packages = [
".",
@ -40,7 +40,7 @@
"xpc",
]
pruneopts = "UT"
revision = "1353e80bee488dc02d1f7e42759c1352492bf18b"
revision = "277ee0d0ef94d26e3190252c59fa34dde0df4f26"
[[projects]]
branch = "master"

View file

@ -6,7 +6,6 @@ package ble
import (
"encoding/hex"
"fmt"
"io/ioutil"
golog "log"
"time"
@ -15,6 +14,8 @@ import (
"github.com/bettercap/bettercap/session"
"github.com/bettercap/gatt"
"github.com/evilsocket/islazy/str"
)
type BLERecon struct {
@ -126,15 +127,25 @@ func (mod *BLERecon) isEnumerating() bool {
return mod.currDevice != nil
}
type dummyWriter struct {
mod *BLERecon
}
func (w dummyWriter) Write(p []byte) (n int, err error) {
w.mod.Debug("[gatt.log] %s", str.Trim(string(p)))
return len(p), nil
}
func (mod *BLERecon) Configure() (err error) {
if mod.Running() {
return session.ErrAlreadyStarted
} else if mod.gattDevice == nil {
mod.Debug("initializing device ...")
// hey Paypal GATT library, could you please just STFU?!
golog.SetOutput(ioutil.Discard)
golog.SetFlags(0)
golog.SetOutput(dummyWriter{mod})
if mod.gattDevice, err = gatt.NewDevice(defaultBLEClientOptions...); err != nil {
mod.Debug("error while creating new gatt device: %v", err)
return err
}
@ -162,7 +173,17 @@ func (mod *BLERecon) Start() error {
mod.Info("stopping scan ...")
mod.gattDevice.StopScanning()
if mod.currDevice != nil && mod.currDevice.Device != nil && mod.gattDevice != nil {
mod.Debug("resetting connection with %v", mod.currDevice.Device)
mod.gattDevice.CancelConnection(mod.currDevice.Device)
}
mod.Debug("stopping device")
if err := mod.gattDevice.Stop(); err != nil {
mod.Warning("error while stopping device: %v", err)
} else {
mod.Debug("gatt device closed")
}
mod.done <- true
})
@ -172,6 +193,9 @@ func (mod *BLERecon) Stop() error {
return mod.SetRunning(false, func() {
mod.quit <- true
<-mod.done
mod.Debug("module stopped, cleaning state")
mod.gattDevice = nil
mod.setCurrentDevice(nil)
})
}

View file

@ -15,8 +15,12 @@ func (mod *BLERecon) onStateChanged(dev gatt.Device, s gatt.State) {
if mod.currDevice == nil {
mod.Info("starting discovery ...")
dev.Scan([]gatt.UUID{}, true)
} else {
mod.Debug("current device was not cleaned: %v", mod.currDevice)
}
case gatt.StatePoweredOff:
mod.Debug("resetting device instance")
mod.gattDevice.StopScanning()
mod.setCurrentDevice(nil)
mod.gattDevice = nil
@ -51,6 +55,7 @@ func (mod *BLERecon) onPeriphConnected(p gatt.Peripheral, err error) {
defer func(per gatt.Peripheral) {
mod.Info("disconnecting from %s ...", per.ID())
per.Device().CancelConnection(per)
mod.setCurrentDevice(nil)
}(p)
mod.Session.Events.Add("ble.device.connected", mod.currDevice)

View file

@ -22,6 +22,7 @@ type device struct {
func newDevice(n int, chk bool) (*device, error) {
fd, err := socket.Socket(socket.AF_BLUETOOTH, syscall.SOCK_RAW, socket.BTPROTO_HCI)
if err != nil {
log.Printf("could not create AF_BLUETOOTH raw socket")
return nil, err
}
if n != -1 {
@ -30,13 +31,17 @@ func newDevice(n int, chk bool) (*device, error) {
req := devListRequest{devNum: hciMaxDevices}
if err := gioctl.Ioctl(uintptr(fd), hciGetDeviceList, uintptr(unsafe.Pointer(&req))); err != nil {
log.Printf("hciGetDeviceList failed")
return nil, err
}
log.Printf("got %d devices", req.devNum)
for i := 0; i < int(req.devNum); i++ {
d, err := newSocket(fd, i, chk)
if err == nil {
log.Printf("dev: %s opened", d.name)
return d, err
} else {
log.Printf("error while opening device %d: %v", i, err)
}
}
return nil, errors.New("no supported devices available")
@ -45,6 +50,7 @@ func newDevice(n int, chk bool) (*device, error) {
func newSocket(fd, n int, chk bool) (*device, error) {
i := hciDevInfo{id: uint16(n)}
if err := gioctl.Ioctl(uintptr(fd), hciGetDeviceInfo, uintptr(unsafe.Pointer(&i))); err != nil {
log.Printf("hciGetDeviceInfo failed")
return nil, err
}
name := string(i.name[:])
@ -61,6 +67,7 @@ func newSocket(fd, n int, chk bool) (*device, error) {
}
log.Printf("dev: %s reset", name)
if err := gioctl.Ioctl(uintptr(fd), hciResetDevice, uintptr(n)); err != nil {
log.Printf("hciResetDevice failed")
return nil, err
}
}
@ -105,5 +112,6 @@ func (d device) Write(b []byte) (int, error) {
}
func (d device) Close() error {
log.Printf("linux.device.Close()")
return syscall.Close(d.fd)
}

View file

@ -26,7 +26,8 @@ type HCI struct {
bufCnt chan struct{}
bufSize int
pool *util.BytePool
pool *util.BytePool
loopDone chan bool
maxConn int
connsmu *sync.Mutex
@ -68,7 +69,8 @@ func NewHCI(devID int, chk bool, maxConn int) (*HCI, error) {
bufCnt: make(chan struct{}, 15-1),
bufSize: 27,
pool: util.NewBytePool(4096, 16),
pool: util.NewBytePool(4096, 16),
loopDone: make(chan bool),
maxConn: maxConn,
connsmu: &sync.Mutex{},
@ -89,9 +91,15 @@ func NewHCI(devID int, chk bool, maxConn int) (*HCI, error) {
}
func (h *HCI) Close() error {
log.Printf("hci.Close()")
h.pool.Put(nil)
<-h.loopDone
log.Printf("mainLoop exited")
for _, c := range h.conns {
log.Printf("closing connection %v", c)
c.Close()
}
log.Printf("closing %v", h.d)
return h.d.Close()
}
@ -151,7 +159,10 @@ func (h *HCI) Connect(pd *PlatData) error {
}
func (h *HCI) CancelConnection(pd *PlatData) error {
return pd.Conn.Close()
if pd != nil && pd.Conn != nil {
return pd.Conn.Close()
}
return nil
}
func (h *HCI) SendRawCommand(c cmd.CmdParam) ([]byte, error) {
@ -166,19 +177,33 @@ func btoi(b bool) uint8 {
}
func (h *HCI) mainLoop() {
log.Printf("hci.mainLoop started")
defer func() {
h.loopDone <- true
}()
for {
// log.Printf("hci.mainLoop pool.Get")
b := h.pool.Get()
if b == nil {
log.Printf("got nil buffer, breaking mainLoop")
break
}
// log.Printf("hci.mainLoop Read(%d)", len(b))
n, err := h.d.Read(b)
if err != nil {
fmt.Sprintf("mainloop err: %v\n", err)
log.Printf("mainloop err: %v", err)
return
}
if n == 0 {
println("mainLoop failed to read")
log.Printf("mainLoop failed to read")
return
}
// log.Printf("hci.mainLoop -> handlePacket")
h.handlePacket(b, n)
}
log.Printf("hci.mainLoop stopped")
}
func (h *HCI) handlePacket(buf []byte, n int) {

View file

@ -156,7 +156,7 @@ func (c *conn) Close() error {
defer h.connsmu.Unlock()
_, found := h.conns[hh]
if !found {
// log.Printf("l2conn: 0x%04x already disconnected", hh)
log.Printf("l2conn: 0x%04x already disconnected", hh)
return nil
}
if err, _ := h.c.Send(cmd.Disconnect{ConnectionHandle: hh, Reason: 0x13}); err != nil {

View file

@ -407,7 +407,6 @@ func (p *peripheral) loop() {
if rspOp == attRspFor[reqOp] || (rspOp == attOpError && r[1] == reqOp) {
req.rspc <- r
break
}
log.Printf("Request 0x%02x got a mismatched response: 0x%02x", reqOp, rspOp)
p.l2c.Write(attErrorRsp(rspOp, 0x0000, AttEcodeReqNotSupp))
@ -434,6 +433,7 @@ func (p *peripheral) loop() {
copy(b, buf)
if (b[0] != attOpHandleNotify) && (b[0] != attOpHandleInd) {
log.Printf("response 0x%x", b[0])
rspc <- b
continue
}