esp32_bluetooth_classic_sni.../libs/scapy/contrib/altbeacon.py

83 lines
2.8 KiB
Python
Raw Normal View History

# -*- mode: python3; indent-tabs-mode: nil; tab-width: 4 -*-
# altbeacon.py - protocol handlers for AltBeacon
#
# This file is part of Scapy
# See http://www.secdev.org/projects/scapy for more information
# Copyright (C) Michael Farrell <micolous+git@gmail.com>
# This program is published under a GPLv2 (or later) license
#
# scapy.contrib.description = AltBeacon BLE proximity beacon
# scapy.contrib.status = loads
"""
scapy.contrib.altbeacon - AltBeacon Bluetooth LE proximity beacons.
The AltBeacon specification can be found at: https://github.com/AltBeacon/spec
"""
from scapy.fields import ByteField, ShortField, SignedByteField, \
StrFixedLenField
from scapy.layers.bluetooth import EIR_Hdr, EIR_Manufacturer_Specific_Data, \
UUIDField, LowEnergyBeaconHelper
from scapy.packet import Packet
# When building beacon frames, one should use their own manufacturer ID.
#
# However, most software (including the AltBeacon SDK) requires explicitly
# registering particular manufacturer IDs to listen to, and the only ID used is
# that of Radius Networks (the developer of the specification).
#
# To maximise compatibility, Scapy's implementation of
# LowEnergyBeaconHelper.build_eir (for constructing frames) uses Radius
# Networks' manufacturer ID.
#
# Scapy's implementation of AltBeacon **does not** require a specific
# manufacturer ID to detect AltBeacons - it uses
# EIR_Manufacturer_Specific_Data.register_magic_payload.
RADIUS_NETWORKS_MFG = 0x0118
class AltBeacon(Packet, LowEnergyBeaconHelper):
"""
AltBeacon broadcast frame type.
https://github.com/AltBeacon/spec
"""
name = "AltBeacon"
magic = b"\xBE\xAC"
fields_desc = [
StrFixedLenField("header", magic, len(magic)),
# The spec says this is 20 bytes, with >=16 bytes being an
# organisational unit-specific identifier. However, the Android library
# treats this as UUID + uint16 + uint16.
UUIDField("id1", None),
# Local identifier
ShortField("id2", None),
ShortField("id3", None),
SignedByteField("tx_power", None),
ByteField("mfg_reserved", None),
]
@classmethod
def magic_check(cls, payload):
"""
Checks if the given payload is for us (starts with our magic string).
"""
return payload.startswith(cls.magic)
def build_eir(self):
"""Builds a list of EIR messages to wrap this frame."""
# Note: Company ID is not required by spec, but most tools only look
# for manufacturer-specific data with Radius Networks' manufacturer ID.
return LowEnergyBeaconHelper.base_eir + [
EIR_Hdr() / EIR_Manufacturer_Specific_Data(
company_id=RADIUS_NETWORKS_MFG) / self
]
EIR_Manufacturer_Specific_Data.register_magic_payload(AltBeacon)