#!/usr/bin/python ############################################################################# # Copyright (C) 2011 Spidcom # # Beacon description in a VS_SNIFFER.IND MME # # See scpay/layers/inet.py for IPOptions construction. # # To add a new beacon entry in the script, you need to create a new class # which derives Bentry class. # In this new class, the header must be filled as class attribute. ############################################################################# from scapy.all import Packet, SourceMACField from scapy.fields import * from common import ETHER_TYPES, HPAV_CCO_LEVEL from commonfields import * BENTRY_HDR = { "NON_PERSISTENT_SCHEDULE": 0x00, "PERSISTENT_SCHEDULE": 0x01, "REGIONS": 0x02, "MAC_ADDRESS": 0x03, "DISCOVER": 0x04, "DISCOVERED_INFO": 0x05, "BEACON_PERIOD_START_TIME_OFFSET": 0x06, "ENCRYPTION_KEY_CHANGE": 0x07, "CCO_HANDOVER": 0x08, "BEACON_RELOCATION": 0x09, "AC_LINE_SYNC_COUNTDOWN": 0x0A, "CHANGE_NUMSLOTS": 0x0B, "CHANGE_HM": 0x0C, "CHANGE_SNID": 0x0D, } class BEntryHDR (Packet): """Beacon entry header.""" # Use the BENTRY_HDR dict to compose a new dict with the keyword # inverted. i.e. bentry['CHANHE_SNID'] will be _bentry[0xd]. _bentry = {} for i in BENTRY_HDR: _bentry[BENTRY_HDR[i]] = i fields_desc = [ ByteEnumField ("header", 0, _bentry), ByteField ("length", 0) ] class BEntry (Packet): """Beacon entries are different depending on the Beacon Entry Header. So we need to parse each header to know to which beacon entry it corresponds.""" fields_desc = [ BEntryHDR, ] registered_bentry = {} @classmethod def register_variant(cls): cls.registered_bentry [cls.header.default] = cls @classmethod def dispatch_hook(cls, pkt=None, *args, **kargs): if pkt: header = struct.unpack ('B', pkt[0])[0] if header in cls.registered_bentry: return cls.registered_bentry [header] return cls def extract_padding(self, s): return "",s class BEntrySchedulesAllocations (Packet): """Session Allocation Information.""" # The stpf flag indicates if there is a start time in the allocation or # not. fields_desc = [ LEBitField ("stpf", 0, 1), LEBitField ("glid", 0, 7), ConditionalField (LEBitField ("st_atu", 0, 12), lambda p: p.stpf), LEBitField ("et_atu", 0, 12), ConditionalField (LEBitField("pad", 0, 4), lambda p: not p.stpf), ] def extract_padding(self, s): return "",s class BEntryNonPersistentSchedule (BEntry): """Beacon entry Non Persistent Schedule.""" header = BENTRY_HDR['NON_PERSISTENT_SCHEDULE'] fields_desc = [ BEntryHDR, LEBitField ("ns", 0, 6), LEBitField ("benpsf_rsvd1", 0, 2), PacketListField ("sai", None, BEntrySchedulesAllocations, count_from=lambda p:p.ns), ] class BEntryPersistentSchedule (BEntry): """Beacon entry Non Persistent Schedule.""" header = BENTRY_HDR['PERSISTENT_SCHEDULE'] fields_desc = [ BEntryHDR, LEBitField ("pscd", 0, 3), LEBitField ("cscd", 0, 3), LEBitField ("bepsf_rsvd1", 0, 2), LEBitField ("ns", 0, 6), LEBitField ("bepsf_rsvd2", 0, 2), PacketListField ("sai", None, BEntrySchedulesAllocations, count_from=lambda p:p.ns), ] class BEntryRegionsDesc (Packet): """Region definition.""" fields_desc = [ LEBitField ("rt", 0, 4), LEBitField ("ret", 0, 12), ] def extract_padding(self, s): return "",s class BEntryRegions (BEntry): """Region beacon entry.""" header = BENTRY_HDR['REGIONS'] fields_desc = [ BEntryHDR, LEBitField ("nr", 0, 6), LEBitField ("ber_rvsd", 0, 2), PacketListField ("rlist", None, BEntryRegionsDesc, count_from=lambda p:p.nr), ] class BEntryMacAddress (BEntry): """Beacon entry for the mac address.""" header = BENTRY_HDR['MAC_ADDRESS'] fields_desc = [ BEntryHDR, MACField("mac", ETHER_ANY), ] class BEntryDiscover (BEntry): """Discover beacon entry.""" header = BENTRY_HDR['DISCOVER'] fields_desc = [ BEntryHDR, ByteField ("tei", 0), ] class BEntryDiscoveredInfo (BEntry): """Discover info beacon entry.""" header = BENTRY_HDR['DISCOVERED_INFO'] fields_desc = [ BEntryHDR, LEBitField ("updated", 0, 1), LEBitField ("cco_cap", 0, 2), LEBitField ("proxy_networking_cap", 0, 1), LEBitField ("backup_cco_cap", 0, 1), LEBitField ("cco_status", 0, 1), LEBitField ("pco_status", 0, 1), LEBitField ("backup_cco_status", 0, 1), ByteField ("numdissta", 0), ByteField ("numdisnet", 0), LEBitField ("authentication_status", 0, 1), LEBitField ("user_appointed", 0, 1), LEBitField ("bedi_rsvd", 0, 6), ] class BEntryBeaconPeriodStartTimeOffset (BEntry): """Beacon Period Start Time Offset.""" header = BENTRY_HDR['BEACON_PERIOD_START_TIME_OFFSET'] fields_desc = [ BEntryHDR, LEBitField ("bpsto", 0, 24), ] class BEntryEncryptionKeyChange (BEntry): """Encryption Key change.""" header = BENTRY_HDR['ENCRYPTION_KEY_CHANGE'] fields_desc = [ BEntryHDR, LEBitField ("kccd", 0, 6), LEBitField ("kbc", 0, 1), LEBitField ("beckc_rsvd", 0, 1), LEBitField ("neweks", 0, 4), LEBitField ("beckc_rsvd2", 0, 4), ] class BEntryCcoHandover (BEntry): """CCo Handover.""" header = BENTRY_HDR['CCO_HANDOVER'] fields_desc = [ BEntryHDR, LEBitField ("hcd", 0, 6), LEBitField ("bech_rsvd", 0, 2), ByteField ("nctei", 0), ] class BEntryBeaconRelocation (BEntry): """Beacon Relocation""" header = BENTRY_HDR['BEACON_RELOCATION'] fields_desc = [ BEntryHDR, LEBitField ("rcd", 0, 6), LEBitField ("rlt", 0, 1), LEBitField ("lgf", 0, 1), LEBitField ("rlo", 0, 17), LEBitField ("rlslotid", 0, 3), LEBitField ("bebr_rsvd", 0, 4), ] class BEntryAcLineSyncCountdown (BEntry): """AC Line Sync Countdown.""" header = BENTRY_HDR['AC_LINE_SYNC_COUNTDOWN'] fields_desc = [ BEntryHDR, LEBitField ("countdown", 0, 6), LEBitField ("beaclsc_rsvd1", 0, 2), LEBitField ("reasoncode", 0, 2), LEBitField ("beaclsc_rsvd2", 0, 6), ] class BEntryChangeNumslots (BEntry): """Change NumSlots.""" header = BENTRY_HDR['CHANGE_NUMSLOTS'] fields_desc = [ BEntryHDR, LEBitField ("nsccd", 0, 6), LEBitField ("becns_rsvd1", 0, 2), LEBitField ("newnumslot", 0, 3), LEBitField ("becns_rsvd2", 0, 5), ] class BEntryChangeHm (BEntry): """Change Hybrid Mode.""" header = BENTRY_HDR['CHANGE_HM'] fields_desc = [ BEntryHDR, LEBitField ("hmccd", 0, 6), LEBitField ("newhm", 0, 2), ] class BEntryChangeSnid (BEntry): """Change SNID.""" header = BENTRY_HDR['CHANGE_SNID'] fields_desc = [ BEntryHDR, LEBitField ("sccd", 0, 4), LEBitField ("newsnid", 0, 4), ] class BeaconSniff (Packet): """Beacon description inside a VS_SNIFFER.IND MME""" name = "Beacon description inside a VS_SNIFFER.IND MME" fields_desc = [ XLEBitField ("nid", 0, 54), XLEBitField ("hm", 0, 2), XByteField ("stei", 0), XLEBitField ("bt", 0, 3), XLEBitField ("ncnr", 0, 1), XLEBitField ("npsm", 0, 1), XLEBitField ("numslots", 0, 3), XLEBitField ("slotusage", 7, 8), XLEBitField ("slotid", 0, 3), XLEBitField ("aclss", 0, 3), XLEBitField ("hoip", 0, 1), XLEBitField ("rtsbf", 0, 1), XLEBitField ("nm", 0, 2), XLEBitField ("ccocap", 0, 2), XLEBitField ("rsvd", 0, 4), FieldLenField("nbe", None, count_of="bentry",fmt="B"), # From here the beacon entry are like Header, Length (in bytes), # entry. # Entries may have N repeated structure i.e. schedules, regions... # So entries does not have the same length, all we know is that # the beacon entries are ordered and there is nbe beacon entries # in the beacon. PacketListField("bentry", None, BEntry, count_from=lambda p:p.nbe), ] if __name__ == '__main__': """Create a beacon to check if the dissector is correct.""" from scapy.utils import str2mac mac = '00:13:d7:00:00:%02x' # Non Persistent schedules. non_peristent_sais = [ BEntrySchedulesAllocations (stpf = False , glid = 1, et_atu=50), BEntrySchedulesAllocations (stpf = True, glid = 2, st_atu=50, et_atu=1500), ] bnps = BEntryNonPersistentSchedule ( header=BENTRY_HDR['NON_PERSISTENT_SCHEDULE'], length=11 ,ns=3, sai=non_peristent_sais) # Persistent schedules. persistent_sais = [ BEntrySchedulesAllocations (stpf = True, glid = 3, st_atu=1500, et_atu=3907) ] bps = BEntryPersistentSchedule ( header=BENTRY_HDR['PERSISTENT_SCHEDULE'], length=5, pscd=7, cscd=7, ns=1, sai=persistent_sais) # Create regions. r = BEntryRegions ( header = BENTRY_HDR['REGIONS'], length = 4, nr = 2, rlist = [ BEntryRegionsDesc (rt=0, ret=50), BEntryRegionsDesc (rt=1, ret=3907) ]) # Store the mac address. m = BEntryMacAddress ( header = BENTRY_HDR['MAC_ADDRESS'], length = 6, mac = mac % 5) # Discover entry. d = BEntryDiscover ( header = BENTRY_HDR['DISCOVER'], length = 1, tei = 0xA) # Discover info entry. di = BEntryDiscoveredInfo ( header = BENTRY_HDR['DISCOVERED_INFO'], length = 4, updated = False, cco_cap = 1, proxy_networking_cap = False, backup_cco_cap = True, cco_status = True, pco_status = False, backup_cco_status = False, numdissta = 4, numdisnet = 3, authentication_status = True, user_appointed = False) # Beacon period start time offset. bpsto = BEntryBeaconPeriodStartTimeOffset ( header = BENTRY_HDR['BEACON_PERIOD_START_TIME_OFFSET'], length = 3, bpsto = 1204) # Encryption key change. ekc = BEntryEncryptionKeyChange ( header = BENTRY_HDR['ENCRYPTION_KEY_CHANGE'], length = 2, kccd = 4, kbc = 1, neweks = 2) # CCo handover. ccoh = BEntryCcoHandover ( header = BENTRY_HDR['CCO_HANDOVER'], length = 2, hcd = 3, nctei = 0xb) # Beacon relocation. br = BEntryBeaconRelocation ( header = BENTRY_HDR['BEACON_RELOCATION'], length = 4, rcd = 4, rlt = 1, lgf = 1, rlo = 1240, rlslotid = 2) # Ac Line Sync Countdown alsc = BEntryAcLineSyncCountdown ( header = BENTRY_HDR['AC_LINE_SYNC_COUNTDOWN'], length = 2, countdown = 3, reasoncode = 1) # Change num slots. cn = BEntryChangeNumslots ( header = BENTRY_HDR['CHANGE_NUMSLOTS'], length = 2, nsccd = 3, newnumslot = 2) # Change Hybrid mode. chm = BEntryChangeHm ( header = BENTRY_HDR['CHANGE_HM'], length = 1, hmccd = 2, newhm = 1) # Change snid. csnid = BEntryChangeSnid ( header = BENTRY_HDR['CHANGE_SNID'], length = 1, sccd = 3, newsnid = 2) # Create the beacon. m = BeaconSniff (nid=0x12345789abc, hm=0, stei=1, bt=1, ncnr=0, npsm=0, numslots=7, slotusage=1, slotid=1, aclss=0, hoip=0, rtsbf=0, nm=2, ccocap=1, rsvd=0, bentry=[bnps, bps, r, m, d, di, bpsto, ekc, ccoh, br, alsc, cn, chm, csnid]) m.show ()