83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
|
# -*- 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)
|