示例#1
0
    def detect_pairing_feature(self, paddr, patype, timeout:int=10):
        """
        """
        # TODO Mac OS 会弹窗,需要解决。
        hci = HCI(self.hci)
        logger.info("Detecting SMP pairing feature of %s, using %s\n"%(blue(paddr), blue(self.hci)))

        pairing_req = SM_Hdr(sm_command=btsmp.CmdCode.PAIRING_REQUEST) / \
            SM_Pairing_Request(iocap="NoInputNoOutput", oob='Not Present', 
                authentication=(0b00 << AUTHREQ_RFU_POS) | (0 << CT2_POS) | \
                    (0 << KEYPRESS_POS) | (1 << SC_POS) | (0 << MITM_POS) | \
                    (BONDING << BONDING_FLAGS_POS), max_key_size=16,
                initiator_key_distribution=(0b0000 << INIT_RESP_KEY_DIST_RFU_POS) \
                    | (1 << LINKKEY_POS) | (1 << SIGNKEY_POS) | (1 << IDKEY_POS) \
                    | (1 << ENCKEY_POS),
                responder_key_distribution=(0b0000 << INIT_RESP_KEY_DIST_RFU_POS) \
                    | (1 << LINKKEY_POS) | (1 << SIGNKEY_POS) | (1 << IDKEY_POS) \
                    | (1 << ENCKEY_POS))

        event_params = None
        
        spinner = Halo(text="Scanning", spinner={'interval': 200,
                                                 'frames': ['', '.', '.'*2, '.'*3]},
                       placement='right')
        hci = HCI(self.hci)
        logger.info('Scanning LE LL Features of %s, using %s\n'%(blue(paddr), blue(self.hci)))
        
        spinner.start()
        
        try:
            event_params = hci.le_create_connection(paddr, patype, timeout=timeout)
            logger.debug(event_params)

            result = btsmp.send_pairing_request(event_params['Connection_Handle'], pairing_req, self.hci)
            logger.debug("detect_pairing_feature(), result: {}".format(result))

            rsp = btsmp.recv_pairing_response(timeout, self.hci)
            logger.debug("detect_pairing_feature(), rsp: {}".format(rsp))
            
            spinner.stop()

            pp_smp_pkt(rsp)
        except RuntimeError as e:
            logger.error(str(e))
        except TimeoutError as e:
            output = subprocess.check_output(' '.join(['hciconfig', self.hci, 'reset']), 
                stderr=STDOUT, timeout=60, shell=True)
            event_params = None
            logger.info("Timeout")
            # logger.error("detect_pairing_feature(), TimeoutError {}".format(e))

        if event_params != None:
            hci.disconnect(event_params['Connection_Handle'],
                           ControllerErrorCodes.UNSUPPORTED_REMOTE_FEATURE)

        return
示例#2
0
文件: lmp_scan.py 项目: qemm/bluescan
    def scan(self, remote_bd_addr:str):
        hci = HCI(self.iface)
        event_params = hci.create_connection({
            'BD_ADDR': remote_bd_addr,
            'Packet_Type': 0xcc18,
            'Page_Scan_Repetition_Mode': 0x02,
            'Reserved': 0x00,
            'Clock_Offset': 0x0000,
            'Allow_Role_Switch': 0x01
        })

        if event_params['Status'] != 0:
            print(ERROR, 'Failed to create ACL connection')
            sys.exit(1)

        event_params = hci.read_remote_version_information(cmd_params={
            'Connection_Handle': event_params['Connection_Handle']
        })

        if event_params['Status'] != 0:
            print(ERROR, 'Failed to read remote version')
            sys.exit(1)

        print(blue('Version'))
        print('    Version:')
        print(' '*8+lm_vers[event_params['Version']], '(LMP)')
        print(' '*8+ll_vers[event_params['Version']], '(LL)')
        print('    Manufacturer name:', event_params['Manufacturer_Name'])
        print('    Subversion:', event_params['Subversion'], '\n')

        event_params = hci.read_remote_supported_features({
            'Connection_Handle': event_params['Connection_Handle']
        })
        if event_params['Status'] != 0:
            print(ERROR, 'Failed to read remote supported features')
        else:
            print(blue('LMP features'))
            pp_lmp_features(event_params['LMP_Features'])
            print()

        if not True if (event_params['LMP_Features'][7] >> 7) & 0x01 else False:
            sys.exit(1)

        print(blue('Extended LMP features'))
        event_params = hci.read_remote_extended_features({
            'Connection_Handle': event_params['Connection_Handle'],
            'Page_Number': 0x00
        })
        if event_params['Status'] != 0:
            print(ERROR, 'Failed to read remote extented features')
        else:
            pp_ext_lmp_features(event_params['Extended_LMP_Features'], 0)
            for i in range(1, event_params['Maximum_Page_Number']+1):
                event_params = hci.read_remote_extended_features({
                    'Connection_Handle': event_params['Connection_Handle'],
                    'Page_Number': i})
                if event_params['Status'] != 0:
                    print(ERROR, 'Failed to read remote extented features, page', i)
                else:
                    pp_ext_lmp_features(event_params['Extended_LMP_Features'], i)
示例#3
0
    def scan_ll_feature(self, paddr, patype, timeout: int=10):
        """LL feature scanning

        paddr   - Peer addresss for scanning LL features.
        patype  - Peer address type, public or random.
        timeout - sec
        """
        spinner = Halo(text="Scanning", spinner={'interval': 200,
                                                 'frames': ['', '.', '.'*2, '.'*3]},
                       placement='right')
        hci = HCI(self.hci)
        logger.info('Scanning LE LL Features of %s, using %s\n'%(blue(paddr), blue(self.hci)))
        
        spinner.start()

        try:
            event_params = hci.le_create_connection(paddr, patype, timeout=timeout)
            logger.debug(event_params)
        except RuntimeError as e:
            logger.error(str(e))
            return
        except TimeoutError as e:
            logger.info("Timeout")
            # logger.error("TimeoutError {}".format(e))
            return

        event_params = hci.le_read_remote_features(event_params['Connection_Handle'])
        spinner.stop()
        logger.debug(event_params)
        print(blue('LE LL Features:'))
        pp_le_features(event_params['LE_Features'])

        event_params = hci.disconnect(event_params['Connection_Handle'], ControllerErrorCodes.REMOTE_USER_TERM_CONN)
        logger.debug(event_params)
        return
示例#4
0
    def scan_ll_feature(self, paddr, patype):
        """LL feature scanning

        paddr  - Peer addresss for scanning LL features.
        patype - Peer address type, public or random.
        """
        hci = HCI(self.hci)
        logger.info('Scanning LE LL Features of %s, using %s\n' %
                    (blue(paddr), blue(self.hci)))

        try:
            event_params = hci.le_create_connection(
                HCI_Cmd_LE_Create_Connection(paddr=bytes.fromhex(
                    paddr.replace(':', ''))[::-1],
                                             patype=patype))
            logger.debug(event_params)
        except RuntimeError as e:
            logger.error(e)
            return

        event_params = hci.le_read_remote_features(
            HCI_Cmd_LE_Read_Remote_Features(
                handle=event_params['Connection_Handle']))
        logger.debug(event_params)
        print(blue('LE LL Features:'))
        pp_le_features(event_params['LE_Features'])

        event_params = hci.disconnect({
            'Connection_Handle':
            event_params['Connection_Handle'],
            'Reason':
            ERR_REMOTE_USER_TERMINATED_CONNECTION
        })
        logger.debug(event_params)
        return
示例#5
0
 def __init__(self, iface='hci0'):
     self.iface = iface
     self.devid = HCI.hcistr2devid(self.iface)
     try:
         self.hci_bdaddr = HCI(iface).read_bdaddr()['BD_ADDR'].upper()
     except Exception as e:
         logger.error("{}".format(e))
         exit(1)
示例#6
0
    def detect_pairing_feature(self, paddr, patype, timeout: int = 10):
        """ """
        hci = HCI(self.hci)
        logger.info("Detecting SMP pairing feature of %s, using %s\n" %
                    (blue(paddr), blue(self.hci)))

        pairing_req = SM_Hdr(sm_command=btsmp.CmdCode.PAIRING_REQUEST) / \
            SM_Pairing_Request(iocap="NoInputNoOutput", oob='Not Present',
                authentication=(0b00 << AUTHREQ_RFU_POS) | (0 << CT2_POS) | \
                    (0 << KEYPRESS_POS) | (1 << SC_POS) | (0 << MITM_POS) | \
                    (BONDING << BONDING_FLAGS_POS), max_key_size=16,
                initiator_key_distribution=(0b0000 << INIT_RESP_KEY_DIST_RFU_POS) \
                    | (1 << LINKKEY_POS) | (1 << SIGNKEY_POS) | (1 << IDKEY_POS) \
                    | (1 << ENCKEY_POS),
                responder_key_distribution=(0b0000 << INIT_RESP_KEY_DIST_RFU_POS) \
                    | (1 << LINKKEY_POS) | (1 << SIGNKEY_POS) | (1 << IDKEY_POS) \
                    | (1 << ENCKEY_POS))

        event_params = None
        try:
            event_params = hci.le_create_connection(
                HCI_Cmd_LE_Create_Connection(paddr=bytes.fromhex(
                    paddr.replace(':', ''))[::-1],
                                             patype=patype), timeout)
            logger.debug(event_params)

            result = btsmp.send_pairing_request(
                event_params['Connection_Handle'], pairing_req, self.hci)
            logger.debug("detect_pairing_feature(), result: {}".format(result))

            rsp = btsmp.recv_pairing_response(timeout, self.hci)
            logger.debug("detect_pairing_feature(), rsp: {}".format(rsp))

            pp_smp_pkt(rsp)
        except RuntimeError as e:
            logger.error(e)
        except TimeoutError as e:
            output = subprocess.check_output(' '.join(
                ['hciconfig', self.hci, 'reset']),
                                             stderr=STDOUT,
                                             timeout=60,
                                             shell=True)
            event_params = None
            logger.info("Timeout")
            # logger.error("detect_pairing_feature(), TimeoutError {}".format(e))

        if event_params != None:
            hci.disconnect({
                'Connection_Handle':
                event_params['Connection_Handle'],
                'Reason':
                0x1A
            })

        return
示例#7
0
    def inquiry(self, inquiry_len=0x08):
        logger.info('BR scanning on ' + blue("hci%d"%self.devid) + \
              ' with timeout ' + blue("%.2f sec\n"%(inquiry_len*1.28))+'\n')

        self.scanned_dev = []
        self.remote_name_req_flag = True
        hci = HCI(self.iface)

        def inquiry_result_handler(result: bytes):
            event_code = result[0]

            logger.debug("Entered inquiry(), inquiry_result_handler()\n"
                         "{}".format(HciEventCodes[event_code].name))

            if event_code == HCI_Inquiry_Result.evt_code:
                self.pp_inquiry_result(result[2:])
            elif event_code == HCI_Inquiry_Result_with_RSSI.evt_code:
                self.pp_inquiry_result_with_rssi(result[2:])
            elif event_code == HCI_Extended_Inquiry_Result.evt_code:
                self.pp_extended_inquiry_result(result[2:])
            else:
                logger.warning('Unknow inquiry result: {}'.format(result))

        try:
            hci.inquiry(inquiry_len=inquiry_len,
                        inquiry_result_handler=inquiry_result_handler)
            logger.info('Inquiry completed\n')

            if self.remote_name_req_flag and len(self.scanned_dev) != 0:
                logger.info('Requesting the name of the scanned devices...')
                for bd_addr in self.scanned_dev:
                    try:
                        name = hci.remote_name_request({
                            'BD_ADDR':
                            bytes.fromhex(bd_addr.replace(':', '')),
                            'Page_Scan_Repetition_Mode':
                            0x01,
                            'Reserved':
                            0x00,
                            'Clock_Offset':
                            0x0000
                        })['Remote_Name'].decode().strip()
                    except Exception as e:
                        print(e)
                        name = ''

                    print(bd_addr + ':', blue(name))
        except HciRuntimeError as e:
            logger.error("{}".format(e))
        except KeyboardInterrupt as e:
            logger.info('BR/EDR devices scan canceled\n')
            hci.inquiry_cancel()

        hci.close()
示例#8
0
    def scan_lmp_feature(self, paddr):
        hci = HCI(self.iface)
        conn_complete_evt = hci.create_connection(
            paddr, page_scan_repetition_mode=0x02)

        if conn_complete_evt.status != 0:
            logger.error('Failed to create ACL connection')
            sys.exit(1)

        event_params = hci.read_remote_version_information(
            cmd_params={'Connection_Handle': conn_complete_evt.conn_handle})

        if event_params['Status'] != 0:
            logger.error('Failed to read remote version')
            sys.exit(1)

        print(blue('Version'))
        print('    Version:')
        print(' ' * 8 + lmp_vers[event_params['Version']], '(LMP)')
        print(' ' * 8 + ll_vers[event_params['Version']], '(LL)')
        print('    Manufacturer name:',
              green(company_identfiers[event_params['Manufacturer_Name']]))
        print('    Subversion:', event_params['Subversion'], '\n')

        complete_evt = hci.read_remote_supported_features(
            event_params['Connection_Handle'])
        if complete_evt.status != ControllerErrorCodes.SUCCESS:
            logger.error('Failed to read remote supported features')
        else:
            print(blue('LMP features'))
            pp_lmp_features(complete_evt.lmp_features)
            print()

        if not True if (complete_evt.lmp_features[7] >> 7) & 0x01 else False:
            sys.exit(1)

        print(blue('Extended LMP features'))
        complete_evt = hci.read_remote_extended_features(
            event_params['Connection_Handle'], 0x00)
        if complete_evt.status != ControllerErrorCodes.SUCCESS:
            logger.error('Failed to read remote extented features')
        else:
            pp_ext_lmp_features(complete_evt.ext_lmp_features, 0)
            for i in range(1, complete_evt.max_page_num + 1):
                complete_evt = hci.read_remote_extended_features(
                    event_params['Connection_Handle'], i)
                if complete_evt.status != ControllerErrorCodes.SUCCESS:
                    logger.error(
                        'Failed to read remote extented features, page {}'.
                        format(i))
                else:
                    pp_ext_lmp_features(complete_evt.ext_lmp_features, i)
示例#9
0
def init_hci(iface: str = 'hci0'):
    # hciconfig <hci> up 的前提是 rfkill 先 unblock
    subprocess.check_output('rfkill unblock %d' % find_rfkill_devid(iface),
                            stderr=STDOUT,
                            timeout=5,
                            shell=True)
    subprocess.check_output('hciconfig {} up'.format(iface),
                            stderr=STDOUT,
                            timeout=5,
                            shell=True)
    subprocess.check_output('systemctl restart bluetooth.service',
                            stderr=STDOUT,
                            timeout=5,
                            shell=True)

    hci = HCI(iface)

    # 下面在发送各种 HCI command 时,如果出现如下异常:
    #     BlockingIOError: [Errno 11] Resource temporarily unavailable
    # 那么可能是 hci socket 被设为了 non-blocking mode。
    hci.inquiry_cancel()
    hci.exit_periodic_inquiry_mode()
    hci.write_scan_enable()  # No scan enabled
    event_params = hci.le_set_advertising_enable()  # Advertising is disabled
    if event_params['Status'] != 0x00:
        #print(WARNING, 'Status of HCI_LE_Set_Advertising_Enable command: 0x%02x'%event_params['Status'])
        pass

    try:
        hci.le_set_scan_enable({
            'LE_Scan_Enable': 0x00,  # Scanning disabled
            'Filter_Duplicates': 0x01  # Ignored
        })
    except RuntimeError as e:
        #print(WARNING, e)
        pass

    hci.set_event_filter({'Filter_Type': 0x00})  # Clear All Filters

    event_params = hci.read_bdaddr()
    if event_params['Status'] != 0:
        raise RuntimeError
    else:
        local_bd_addr = event_params['BD_ADDR'].upper()

    # Clear bluetoothd cache
    cache_path = PosixPath('/var/lib/bluetooth/') / local_bd_addr / 'cache'
    if cache_path.exists():
        for file in cache_path.iterdir():
            os.remove(file)

    hci.close()
示例#10
0
def init_hci(iface='hci0'):
    hci = HCI(iface)

    exitcode, output = subprocess.getstatusoutput('rfkill unblock %d' %
                                                  find_rfkill_devid(iface))
    if exitcode != 0:
        logger.error('rfkill: ' + output)
        sys.exit(exitcode)

    exitcode, output = subprocess.getstatusoutput("hciconfig up " + iface)
    if exitcode != 0:
        logger.error("Failed to up " + iface)
        sys.exit(exitcode)
    else:
        time.sleep(0.5)

    # hci.reset()
    hci.inquiry_cancel()
    hci.exit_periodic_inquiry_mode()

    hci.write_scan_enable()  # No scan enabled

    event_params = hci.le_set_advertising_enable()  # Advertising is disabled
    if event_params['Status'] != 0x00:
        #print(WARNING, 'Status of HCI_LE_Set_Advertising_Enable command: 0x%02x'%event_params['Status'])
        pass

    try:
        hci.le_set_scan_enable({
            'LE_Scan_Enable': 0x00,  # Scanning disabled
            'Filter_Duplicates': 0x01  # Ignored
        })
    except RuntimeError as e:
        #print(WARNING, e)
        pass

    hci.set_event_filter({'Filter_Type': 0x00})  # Clear All Filters

    event_params = hci.read_bdaddr()
    if event_params['Status'] != 0:
        raise RuntimeError
    else:
        local_bd_addr = event_params['BD_ADDR'].upper()

    # Clear bluetoothd cache
    cache_path = PosixPath('/var/lib/bluetooth/') / local_bd_addr / 'cache'
    if cache_path.exists():
        for file in cache_path.iterdir():
            os.remove(file)
示例#11
0
    def inquiry(self, lap=0x9e8b33, inquiry_len=0x08, num_rsp=0x00):
        print(INFO, "BR scanning on " + blue("hci%d"%self.devid) + \
              " with timeout " + blue("%.2f sec\n"%(inquiry_len*1.28))+'\n')

        self.scanned_dev = []

        cmd_params = lap.to_bytes(3, 'little') + \
            inquiry_len.to_bytes(1, 'little') + num_rsp.to_bytes(1, 'little')

        # If no filter is set, we can't receive any inquiry result.
        flt = hci_filter_new()
        hci_filter_set_ptype(flt, HCI_EVENT_PKT)
        hci_filter_all_events(flt)

        dd = hci_open_dev(self.devid)
        dd.setsockopt(SOL_HCI, HCI_FILTER, flt)

        hci_send_cmd(dd, OGF_LINK_CTL, OCF_INQUIRY, cmd_params)

        try:
            while True:
                data = dd.recv(300)
                if len(data) >= 4:
                    event_code = data[1]
                    if event_code == EVT_CMD_STATUS:
                        # print(DEBUG, 'HCI_Command_Status')
                        pass
                    elif event_code == EVT_INQUIRY_RESULT:
                        print(DEBUG, 'HCI_Inquiry_Result')
                        self.pp_inquiry_result(data[3:])
                    elif event_code == EVT_INQUIRY_RESULT_WITH_RSSI:
                        # print(DEBUG, 'HCI_Inquiry_Result_with_RSSI')
                        self.pp_inquiry_result_with_rssi(data[3:])
                    elif event_code == EVT_EXTENDED_INQUIRY_RESULT:
                        # print(DEBUG, 'HCI_Extended_Inquiry_Result')
                        self.pp_extended_inquiry_result(data[3:])
                    elif event_code == EVT_INQUIRY_COMPLETE:
                        # print(DEBUG, 'HCI_Inquiry_Complete')
                        print(INFO, 'Inquiry completed')
                        break
                    else:
                        print(DEBUG, "Unknow:", data)
        except KeyboardInterrupt as e:
            print(INFO, "BR/EDR devices scan canceled\n")
            HCI(self.iface).inquiry_cancel()

        hci_close_dev(dd.fileno())
示例#12
0
    def inquiry(self, lap=0x9e8b33, inquiry_len=0x08, num_rsp=0x00):
        logger.info('BR scanning on ' + blue("hci%d"%self.devid) + \
              ' with timeout ' + blue("%.2f sec\n"%(inquiry_len*1.28))+'\n')

        self.scanned_dev = []
        self.remote_name_req_flag = True

        cmd_params = lap.to_bytes(3, 'little') + \
            inquiry_len.to_bytes(1, 'little') + num_rsp.to_bytes(1, 'little')

        # If no filter is set, we can't receive any inquiry result.
        flt = hci_filter_new()
        hci_filter_set_ptype(flt, HCI_EVENT_PKT)
        hci_filter_all_events(flt)

        dd = hci_open_dev(self.devid)
        dd.setsockopt(SOL_HCI, HCI_FILTER, flt)

        hci_send_cmd(dd, OGF_LINK_CTL, OCF_INQUIRY, cmd_params)

        try:
            while True:
                data = dd.recv(300)
                if len(data) >= 4:
                    event_code = data[1]
                    if event_code == EVT_CMD_STATUS:
                        logger.debug('HCI_Command_Status')
                        pass
                    elif event_code == EVT_INQUIRY_RESULT:
                        logger.debug('HCI_Inquiry_Result')
                        self.pp_inquiry_result(data[3:])
                    elif event_code == EVT_INQUIRY_RESULT_WITH_RSSI:
                        logger.debug('HCI_Inquiry_Result_with_RSSI')
                        self.pp_inquiry_result_with_rssi(data[3:])
                    elif event_code == EVT_EXTENDED_INQUIRY_RESULT:
                        logger.debug('HCI_Extended_Inquiry_Result')
                        self.pp_extended_inquiry_result(data[3:])
                    elif event_code == EVT_INQUIRY_COMPLETE:
                        logger.debug('HCI_Inquiry_Complete')
                        logger.info('Inquiry completed\n')

                        if self.remote_name_req_flag and len(
                                self.scanned_dev) != 0:
                            logger.info(
                                'Requesting the name of the scanned devices...'
                            )
                            for bd_addr in self.scanned_dev:
                                try:
                                    name = HCI(self.iface).remote_name_request(
                                        {
                                            'BD_ADDR':
                                            bytes.fromhex(
                                                bd_addr.replace(':', '')),
                                            'Page_Scan_Repetition_Mode':
                                            0x01,
                                            'Reserved':
                                            0x00,
                                            'Clock_Offset':
                                            0x0000
                                        })['Remote_Name'].decode().strip()
                                except Exception as e:
                                    print(e)
                                    name = ''

                                print(bd_addr + ':', blue(name))
                        break
                    else:
                        logger.debug('Unknow: {}'.format(data))
        except KeyboardInterrupt as e:
            logger.info('BR/EDR devices scan canceled\n')
            HCI(self.iface).inquiry_cancel()

        hci_close_dev(dd.fileno())