extcap: Documentation for the new features
[metze/wireshark/wip.git] / doc / extcap_example.py
1 #!/usr/bin/env python
2
3 # Copyright 2014 Roland Knall <rknall [AT] gmail.com>
4 #
5 # Wireshark - Network traffic analyzer
6 # By Gerald Combs <gerald@wireshark.org>
7 # Copyright 1998 Gerald Combs
8 #
9 # This program is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU General Public License
11 # as published by the Free Software Foundation; either version 2
12 # of the License, or (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23 """
24 This is a generic example, which produces pcap packages every n seconds, and
25 is configurable via extcap options.
26
27 @note
28 {
29 To use this script on Windows, please generate an extcap_example.bat inside
30 the extcap folder, with the following content:
31
32 -------
33 @echo off
34 <Path to python interpreter> <Path to script file> %*
35 -------
36
37 Windows is not able to execute Python scripts directly, which also goes for all
38 other script-based formates beside VBScript
39 }
40
41 """
42
43 import os
44 import sys
45 import signal
46 import re
47 import argparse
48 import time
49 import struct
50 import binascii
51 from threading import Thread
52
53 ERROR_USAGE             = 0
54 ERROR_ARG               = 1
55 ERROR_INTERFACE = 2
56 ERROR_FIFO              = 3
57
58 doExit = False
59 globalinterface = 0
60
61 def signalHandler(signal, frame):
62         global doExit
63         doExit = True
64
65 #### EXTCAP FUNCTIONALITY
66
67 """@brief Extcap configuration
68 This method prints the extcap configuration, which will be picked up by the
69 interface in Wireshark to present a interface specific configuration for
70 this extcap plugin
71 """
72 def extcap_config(interface):
73         args = []
74         values = []
75
76         args.append ( (0, '--delay', 'Time delay', 'Time delay between packages', 'integer', '{range=1,15}') )
77         args.append ( (1, '--message', 'Message', 'Package message content', 'string', '{required=true}') )
78         args.append ( (2, '--verify', 'Verify', 'Verify package content', 'boolflag', '') )
79         args.append ( (3, '--remote', 'Remote Channel', 'Remote Channel Selector', 'selector', ''))
80         args.append ( (4, '--fake_ip', 'Fake IP Address', 'Use this ip address as sender', 'string', '{validation=\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b}'))
81
82         values.append ( (3, "if1", "Remote1", "true" ) )
83         values.append ( (3, "if2", "Remote2", "false" ) )
84
85         for arg in args:
86                 print ("arg {number=%d}{call=%s}{display=%s}{tooltip=%s}{type=%s}%s" % arg)
87
88         for value in values:
89                 print ("value {arg=%d}{value=%s}{display=%s}{default=%s}" % value)
90
91
92 def extcap_interfaces():
93         print ("interface {value=example1}{display=Example interface usage for extcap}")
94
95 def extcap_dlts(interface):
96         if ( interface == '1' ):
97                 print ("dlt {number=147}{name=USER0}{display=Demo Implementation for Extcap}")
98
99 """
100
101 ### FAKE DATA GENERATOR
102
103 Extcap capture routine
104  This routine simulates a capture by any kind of user defined device. The parameters
105  are user specified and must be handled by the extcap.
106
107  The data captured inside this routine is fake, so change this routine to present
108  your own input data, or call your own capture program via Popen for example. See
109
110  for more details.
111
112 """
113 def unsigned(n):
114         return int(n) & 0xFFFFFFFF
115
116 def append_bytes(ba, blist):
117         for c in range(0, len(blist)):
118                 ba.append(blist[c])
119         return ba
120
121 def pcap_fake_header():
122
123         header = bytearray()
124         header = append_bytes(header, struct.pack('<L', int ('a1b2c3d4', 16) ))
125         header = append_bytes(header, struct.pack('<H', unsigned(2)) ) # Pcap Major Version
126         header = append_bytes(header, struct.pack('<H', unsigned(4)) ) # Pcap Minor Version
127         header = append_bytes(header, struct.pack('<I', int(0))) # Timezone
128         header = append_bytes(header, struct.pack('<I', int(0))) # Accurancy of timestamps
129         header = append_bytes(header, struct.pack('<L', int ('0000ffff', 16) )) # Max Length of capture frame
130         header = append_bytes(header, struct.pack('<L', unsigned(1))) # Ethernet
131         return header
132
133 # Calculates and returns the IP checksum based on the given IP Header
134 def ip_checksum(iph):
135         #split into bytes
136         words = splitN(''.join(iph.split()),4)
137         csum = 0;
138         for word in words:
139                 csum += int(word, base=16)
140         csum += (csum >> 16)
141         csum = csum & 0xFFFF ^ 0xFFFF
142         return csum
143
144 def pcap_fake_package ( message, fake_ip ):
145
146         pcap = bytearray()
147         #length = 14 bytes [ eth ] + 20 bytes [ ip ] + messagelength
148
149         caplength = len(message) + 14 + 20
150         timestamp = int(time.time())
151
152         pcap = append_bytes(pcap, struct.pack('<L', unsigned(timestamp) ) ) # timestamp seconds
153         pcap = append_bytes(pcap, struct.pack('<L', 0x00 ) ) # timestamp nanoseconds
154         pcap = append_bytes(pcap, struct.pack('<L', unsigned(caplength) ) ) # length captured
155         pcap = append_bytes(pcap, struct.pack('<L', unsigned(caplength) ) ) # length in frame
156
157 # ETH
158         pcap = append_bytes(pcap, struct.pack('h', 0 )) # source mac
159         pcap = append_bytes(pcap, struct.pack('h', 0 )) # source mac
160         pcap = append_bytes(pcap, struct.pack('h', 0 )) # source mac
161         pcap = append_bytes(pcap, struct.pack('h', 0 )) # dest mac
162         pcap = append_bytes(pcap, struct.pack('h', 0 )) # dest mac
163         pcap = append_bytes(pcap, struct.pack('h', 0 )) # dest mac
164         pcap = append_bytes(pcap, struct.pack('<h', unsigned(8) )) # protocol (ip)
165
166 # IP
167         pcap = append_bytes(pcap, struct.pack('b', int ( '45', 16) )) # IP version
168         pcap = append_bytes(pcap, struct.pack('b', int ( '0', 16) )) #
169         pcap = append_bytes(pcap, struct.pack('>H', unsigned(len(message)+20) )) # length of data + payload
170         pcap = append_bytes(pcap, struct.pack('<H', int ( '0', 16) )) # Identification
171         pcap = append_bytes(pcap, struct.pack('b', int ( '40', 16) )) # Don't fragment
172         pcap = append_bytes(pcap, struct.pack('b', int ( '0', 16) )) # Fragment Offset
173         pcap = append_bytes(pcap, struct.pack('b', int ( '40', 16) ))
174         pcap = append_bytes(pcap, struct.pack('B', 0xFE )) # Protocol (2 = unspecified)
175         pcap = append_bytes(pcap, struct.pack('<H', int ( '0000', 16) )) # Checksum
176
177         parts = fake_ip.split('.')
178         ipadr = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3])
179         pcap = append_bytes(pcap, struct.pack('>L', ipadr )) # Source IP
180         pcap = append_bytes(pcap, struct.pack('>L', int ( '7F000001', 16) )) # Dest IP
181
182         pcap = append_bytes(pcap, message)
183         return pcap
184
185 def extcap_capture(interface, fifo, delay, verify, message, remote, fake_ip):
186         global doExit
187
188         signal.signal(signal.SIGINT, signalHandler)
189         signal.signal(signal.SIGTERM , signalHandler)
190
191         tdelay = delay if delay != 0 else 5
192
193         try:
194                 os.stat(fifo)
195         except OSError:
196                 doExit = True
197                 print ( "Fifo does not exist, exiting!" )
198
199         fh = open(fifo, 'w+b', 0 )
200         fh.write (pcap_fake_header())
201
202         while doExit == False:
203                 out = str( "%s|%04X%s|%s" % ( remote.strip(), len(message), message, verify ) )
204                 try:
205                         fh.write (pcap_fake_package(out, fake_ip))
206                         time.sleep(tdelay)
207                 except IOError:
208                         doExit = True
209
210         fh.close()
211
212 ####
213
214 def usage():
215         print ( "Usage: %s <--extcap-interfaces | --extcap-dlts | --extcap-interface | --extcap-config | --capture | --extcap-capture-filter | --fifo>" % sys.argv[0] )
216
217 if __name__ == '__main__':
218         interface = ""
219
220         # Capture options
221         delay = 0
222         message = ""
223         fake_ip = ""
224
225         parser = argparse.ArgumentParser(
226                 prog="Extcap Example",
227                 description="Extcap example program for python"
228                 )
229
230         # Extcap Arguments
231         parser.add_argument("--capture", help="Start the capture routine", action="store_true" )
232         parser.add_argument("--extcap-interfaces", help="Provide a list of interfaces to capture from", action="store_true")
233         parser.add_argument("--extcap-interface", help="Provide the interface to capture from")
234         parser.add_argument("--extcap-dlts", help="Provide a list of dlts for the given interface", action="store_true")
235         parser.add_argument("--extcap-config", help="Provide a list of configurations for the given interface", action="store_true")
236         parser.add_argument("--extcap-capture-filter", help="Used together with capture to provide a capture filter")
237         parser.add_argument("--fifo", help="Use together with capture to provide the fifo to dump data to")
238
239         # Interface Arguments
240         parser.add_argument("--verify", help="Demonstrates a verification bool flag", action="store_true" )
241         parser.add_argument("--delay", help="Demonstrates an integer variable", type=int, default=0, choices=[0, 1, 2, 3, 4, 5] )
242         parser.add_argument("--remote", help="Demonstrates a selector choice", default="if1", choices=["if1", "if2"] )
243         parser.add_argument("--message", help="Demonstrates string variable", nargs='?', default="" )
244         parser.add_argument("--fake_ip", help="Add a fake sender IP adress", nargs='?', default="127.0.0.1" )
245
246         args, unknown = parser.parse_known_args()
247         if ( len(sys.argv) <= 1 ):
248                 parser.exit("No arguments given!")
249
250         if ( args.extcap_interfaces == False and args.extcap_interface == None ):
251                 parser.exit("An interface must be provided or the selection must be displayed")
252
253         if ( args.extcap_interfaces == True or args.extcap_interface == None ):
254                 extcap_interfaces()
255                 sys.exit(0)
256
257         if ( len(unknown) > 1 ):
258                 print("Extcap Example %d unknown arguments given" % len(unknown) )
259
260         m = re.match ( 'example(\d+)', args.extcap_interface )
261         if not m:
262                 sys.exit(ERROR_INTERFACE)
263         interface = m.group(1)
264
265         message = args.message
266         if ( args.message == None or len(args.message) == 0 ):
267                 message = "Extcap Test"
268
269         fake_ip = args.fake_ip
270         if ( args.fake_ip == None or len(args.fake_ip) < 7 or len(args.fake_ip.split('.')) != 4 ):
271                 fake_ip = "127.0.0.1"
272
273         if args.extcap_config:
274                 extcap_config(interface)
275         elif args.extcap_dlts:
276                 extcap_dlts(interface)
277         elif args.capture:
278                 if args.fifo is None:
279                         sys.exit(ERROR_FIFO)
280                 extcap_capture(interface, args.fifo, args.delay, args.verify, message, args.remote, fake_ip)
281         else:
282                 usage()
283                 sys.exit(ERROR_USAGE)