• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3#  Copyright (c) 2022, The OpenThread Authors.
4#  All rights reserved.
5#
6#  Redistribution and use in source and binary forms, with or without
7#  modification, are permitted provided that the following conditions are met:
8#  1. Redistributions of source code must retain the above copyright
9#     notice, this list of conditions and the following disclaimer.
10#  2. Redistributions in binary form must reproduce the above copyright
11#     notice, this list of conditions and the following disclaimer in the
12#     documentation and/or other materials provided with the distribution.
13#  3. Neither the name of the copyright holder nor the
14#     names of its contributors may be used to endorse or promote products
15#     derived from this software without specific prior written permission.
16#
17#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27#  POSSIBILITY OF SUCH DAMAGE.
28#
29
30import argparse
31import logging
32import signal
33import time
34import pcap_codec
35import sys
36import threading
37
38import sniffer_transport
39
40
41class Sniffer:
42    """ Class representing the Sniffing node, whose main task is listening.
43    """
44
45    logger = logging.getLogger('sniffer.Sniffer')
46
47    RECV_BUFFER_SIZE = 4096
48
49    def __init__(self, filename, channel):
50        self._pcap = pcap_codec.PcapCodec(filename, channel)
51
52        # Create transport
53        transport_factory = sniffer_transport.SnifferTransportFactory()
54        self._transport = transport_factory.create_transport()
55
56        self._thread = None
57        self._thread_alive = threading.Event()
58        self._thread_alive.clear()
59
60    def _sniffer_main_loop(self):
61        """ Sniffer main loop. """
62
63        self.logger.debug('Sniffer started.')
64
65        while self._thread_alive.is_set():
66            data, nodeid = self._transport.recv(self.RECV_BUFFER_SIZE)
67            self._pcap.append(data)
68
69        self.logger.debug('Sniffer stopped.')
70
71    def start(self):
72        """ Start sniffing. """
73
74        self._thread = threading.Thread(target=self._sniffer_main_loop)
75        self._thread.daemon = True
76
77        self._transport.open()
78
79        self._thread_alive.set()
80        self._thread.start()
81
82    def stop(self):
83        """ Stop sniffing. """
84
85        self._thread_alive.clear()
86
87        self._transport.close()
88
89        self._thread.join(timeout=1)
90        self._thread = None
91
92    def close(self):
93        """ Close the pcap file. """
94
95        self._pcap.close()
96
97
98def run_sniffer():
99    parser = argparse.ArgumentParser()
100    parser.add_argument('-o',
101                        '--output',
102                        dest='output',
103                        type=str,
104                        required=True,
105                        help='the path of the output .pcap file')
106    parser.add_argument('-c',
107                        '--channel',
108                        dest='channel',
109                        type=int,
110                        required=True,
111                        help='the channel which is sniffered')
112    args = parser.parse_args()
113
114    sniffer = Sniffer(args.output, args.channel)
115    sniffer.start()
116
117    def atexit(signum, frame):
118        sniffer.stop()
119        sniffer.close()
120        sys.exit(0)
121
122    signal.signal(signal.SIGTERM, atexit)
123
124    while sniffer._thread_alive.is_set():
125        time.sleep(0.5)
126
127    sniffer.stop()
128    sniffer.close()
129
130
131if __name__ == '__main__':
132    run_sniffer()
133