root/umpa/branches/link-layer-integration/umit/umpa/sniffing/__init__.py @ 5734

Revision 5734, 9.0 kB (checked in by kosma, 3 years ago)

sniffing: check next() return value more carefully

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (C) 2009 Adriano Monteiro Marques.
5#
6# Author: Bartosz SKOWRON <getxsick at gmail dot com>
7#
8# This library is free software; you can redistribute it and/or modify
9# it under the terms of the GNU Lesser General Public License as published
10# by the Free Software Foundation; either version 2.1 of the License, or
11# (at your option) any later version.
12#
13# This library is distributed in the hope that it will be useful, but
14# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16# License for more details.
17#
18# You should have received a copy of the GNU Lesser General Public License
19# along with this library; if not, write to the Free Software Foundation,
20# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22import os.path
23
24import umit.umpa
25from umit.umpa.protocols._decoder import decode
26from umit.umpa.utils.exceptions import UMPASniffingException
27from umit.umpa.utils.libpcap import lpcap
28
29def get_available_devices():
30    """
31    Return list of network devices.
32
33    These devices are suitable for packets capturing.
34
35    @note: There may be network devices that cannot be used for capturing
36    because e.g. that process might not have sufficient privileges.
37   
38    @return: list of network devices
39    """
40
41    return lpcap.findalldevs()
42
43def get_default_device():
44    """
45    Return the first (default) network device, which is usually 'eth0' under
46    Linux and Windows and varies under BSD.
47
48    @return: name of the first device.
49    """
50
51    return lpcap.lookupdev()
52
53def sniff(count, filter=None, device=None, timeout=0, snaplen=1024,
54                                            promisc=True, dump=None):
55    """
56    Sniff packets and return list of them. May return less than `count' packets
57    if timeout is reached.
58
59    @type count: C{int}
60    @param count: number of sniffing packets
61
62    @type filter: C{str}
63    @param filter: BPF filter
64
65    @type device: C{str}
66    @param device: interface for sniffing
67
68    @type timeout: C{int}
69    @param timeout: timeout for sniffing
70
71    @type snaplen: C{int}
72    @param snaplen: maximum number of bytes to capture of each packet
73                    (default: I{1024})
74
75    @type promisc: C{bool}
76    @param promisc: promiscous mode sniffing
77
78    @type dump: C{str}
79    @param dump: path to file where store the result
80    """
81
82    session = lpcap.open_pcap(device, snaplen, promisc, timeout, immediate=True)
83    if filter:
84        session.setfilter(filter)
85    d = None
86    if dump is not None:
87        d = lpcap.dumper(session, dump)
88    captured = []
89    for i in xrange(count):
90        packet = session.next()
91        # handle timeout
92        if packet is None or packet[1] is None:
93            break
94        p = decode(packet[1], session.datalink())
95        captured.append(p)
96        if d is not None:
97            d.dump()
98    if d is not None:
99        d.flush()
100    return captured
101
102def sniff_next(filter=None, device=None, timeout=0, snaplen=1024,promisc=True,
103                                                                    dump=None):
104    """
105    Sniff one packet and return it. May return None if timeout is reached.
106
107    @type filter: C{str}
108    @param filter: BPF filter
109
110    @type device: C{str}
111    @param device: interface for sniffing
112
113    @type timeout: C{int}
114    @param timeout: timeout for sniffing
115
116    @type snaplen: C{int}
117    @param snaplen: maximum number of bytes to capture of each packet
118                    (default: I{1024})
119
120    @type promisc: C{bool}
121    @param promisc: promiscous mode sniffing
122
123    @type dump: C{str}
124    @param dump: path to file where store the result
125    """
126
127    packets = sniff(1, filter, device, timeout, snaplen, promisc, dump)
128
129    if len(packets) > 0:
130        return packets[0]
131    else:
132        return None
133
134def sniff_loop(count=0, filter=None, device=None, timeout=0, snaplen=1024,
135                promisc=True, dump=None, callback=None, callback_args=None):
136    """
137    Sniff packets and call a callback function for each. May process less than
138    `count' packets if timeout is reached.
139   
140    @type count: C{int}
141    @param count: number of sniffing packets; 0 means infinity (default: I{0})
142
143    @type filter: C{str}
144    @param filter: BPF filter
145
146    @type device: C{str}
147    @param device: interface for sniffing
148
149    @type timeout: C{int}
150    @param timeout: timeout for sniffing
151
152    @type snaplen: C{int}
153    @param snaplen: maximum number of bytes to capture of each packet
154                    (default: I{1024})
155
156    @type promisc: C{bool}
157    @param promisc: promiscous mode sniffing
158
159    @type dump: C{str}
160    @param dump: path to file where store the result
161
162    @type callback: C{func}
163    @param callback: function with (timestamp, pkt, *callback_args) prototype
164
165    @type callback_args: C{list}
166    @param callback_args: additional arguments for callback function
167    """
168   
169    if callback is None:
170        raise UMPASniffingException("no callback function is passed.")
171
172    if callback_args is None:
173        callback_args = []
174
175    session = lpcap.open_pcap(device, snaplen, promisc, timeout, immediate=True)
176    if filter:
177        session.setfilter(filter)
178    d = None
179    if dump is not None:
180        d = lpcap.dumper(session, dump)
181
182    i = 0
183    while 1:
184        if i == count and count > 0:
185            break
186        packet = session.next()
187        # handle timeout
188        if packet is None or packet[1] is None:
189            break
190        ts, pkt = packet
191        decoded_pkt = decode(pkt, session.datalink())
192        if d is not None:
193            d.dump()
194        callback(ts, decoded_pkt, *callback_args)
195        i += 1
196    if d is not None:
197        d.flush()
198
199def sniff_any(dump=None):
200    """
201    Sniff any first upcoming packet and return it.
202
203    Note: this function is Linux-specific. Don't use it in portable code.
204
205    @type dump: C{str}
206    @param dump: path to file where store the result
207    """
208
209    return sniff(1, device='any', dump=dump)
210
211def from_file(filename, count=0, filter=None):
212    """
213    Load data from pcap file instead of sniffing online.
214
215    Call callback for each or return list of packets.
216
217    @type filename: C{str}
218    @param filename: path to a file in pcap format
219
220    @type count: C{int}
221    @param count: number of sniffing packets; 0 means infinity (default: I{0})
222
223    @type filter: C{str}
224    @param filter: BPF filter
225    """
226
227    if os.path.isfile(filename):
228        f = lpcap.open_pcap(filename)
229    else:
230        raise UMPASniffingException("can't open file: %s" % filename)
231
232    if filter:
233        f.setfilter(filter)
234
235    packets = []
236    for i, pkt in enumerate(f):
237        if i == count and count > 0:
238            break
239        p = decode(pkt[1], f.datalink())
240        packets.append(p)
241    return packets
242
243def from_file_loop(filename, count=0, filter=None, callback=None,
244                                                callback_args=None):
245    """
246    Load data from pcap file instead of sniffing online.
247
248    Call callback for each or return list of packets.
249
250    @note: sniffed packets in callback function is not decoded.
251    To get decoded packets use umit.umpa.protocols._decoder.decode() function
252    or other sniff's functions (without a loop feature).
253
254    @type filename: C{str}
255    @param filename: path to a file in pcap format
256
257    @type count: C{int}
258    @param count: number of sniffing packets; 0 means infinity (default: I{0})
259
260    @type filter: C{str}
261    @param filter: BPF filter
262
263    @type callback: C{func}
264    @param callback: function with (timestamp, pkt, *callback_args) prototype
265
266    @type callback_args: C{list}
267    @param callback_args: additional arguments for callback function
268    """
269
270    if callback is None:
271        raise UMPASniffingException("no callback function is passed.")
272
273    if callback_args is None:
274        callback_args = []
275
276    if os.path.isfile(filename):
277        f = lpcap.open_pcap(filename)
278    else:
279        raise UMPASniffingException("can't open file: %s" % filename)
280
281    if filter:
282        f.setfilter(filter)
283
284    for i, p in enumerate(f):
285        if i == count and count > 0:
286            break
287        ts, pkt = p
288        decoded_pkt = decode(pkt, f.datalink())
289        callback(ts, decoded_pkt, *callback_args)
290
291def to_file(fname, count, filter=None, device=None, timeout=0, snaplen=1024,
292                                                                promisc=True):
293    """
294    Sniff packets and store them into a file.
295
296    @type fname: C{str}
297    @param fname: path to a file
298
299    @type count: C{int}
300    @param count: number of sniffing packets
301
302    @type filter: C{str}
303    @param filter: BPF filter
304
305    @type device: C{str}
306    @param device: interface for sniffing
307
308    @type timeout: C{int}
309    @param timeout: timeout for sniffing
310
311    @type snaplen: C{int}
312    @param snaplen: maximum number of bytes to capture of each packet
313                    (default: I{1024})
314
315    @type promisc: C{bool}
316    @param promisc: promiscous mode sniffing
317    """
318    sniff(count, filter, device, timeout, snaplen, promisc, fname)
Note: See TracBrowser for help on using the browser.