1"""
2Shows 802.11 wireless beacons and related information
3"""
4
5from collections import defaultdict
6from datetime import datetime
7
8import dshell.core
9from dshell.output.output import Output
10
11class DshellPlugin(dshell.core.PacketPlugin):
12
13    OUTPUT_FORMAT = "[%(plugin)s]\t%(dt)s\tInterval: %(interval)s TU,\tSSID: %(ssid)s\t%(count)s\n"
14
15    def __init__(self, *args, **kwargs):
16        super().__init__(
17            name="Wi-fi Beacons",
18            description="Show SSIDs of 802.11 wireless beacons",
19            author="dev195",
20            bpf="wlan type mgt subtype beacon",
21            output=Output(label=__name__, format=self.OUTPUT_FORMAT),
22            optiondict={
23                "group": {"action": "store_true", "help": "Group beacons together with counts"},
24            }
25        )
26        self.group_counts = defaultdict(int)
27        self.group_times  = defaultdict(datetime.now)
28
29    def packet_handler(self, pkt):
30        # Extract 802.11 frame from packet
31        try:
32            frame = pkt.pkt.ieee80211
33        except AttributeError:
34            frame = pkt.pkt
35
36        # Confirm that packet is, in fact, a beacon
37        if not frame.is_beacon():
38            return
39
40        # Extract SSID from frame
41        beacon = frame.beacon
42        ssid = ""
43        try:
44            for param in beacon.params:
45                # Find the SSID parameter
46                if param.id == 0:
47                    ssid = param.body_bytes.decode("utf-8")
48                    break
49        except IndexError:
50            # Sometimes pypacker fails to parse a packet
51            return
52
53        if self.group:
54            self.group_counts[(ssid, beacon.interval)] += 1
55            self.group_times[(ssid, beacon.interval)]  = pkt.ts
56        else:
57            self.write(ssid=ssid, interval=beacon.interval, **pkt.info())
58
59        return pkt
60
61    def postfile(self):
62        if self.group:
63            for key, val in self.group_counts.items():
64                ssid, interval = key
65                dt = self.group_times[key]
66                self.write(ssid=ssid, interval=interval, plugin=self.name, dt=dt, count=val)
67