blob: 1e6d7306d9bbe35a2a329b092c1b733c6f3ba611 [file] [log] [blame]
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001#!/usr/bin/env python
2"""
32015-2016
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07004Copyright 2016 Open Networking Foundation (ONF)
Jeremy Songsterae01bba2016-07-11 15:39:17 -07005
6Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
7the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
8or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
Jeremy Songster1f39bf02016-01-20 17:17:25 -08009
10TestON is free software: you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation, either version 2 of the License, or
13( at your option ) any later version.
14
15TestON is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with TestON. If not, see <http://www.gnu.org/licenses/>.
22
23ScapyCliDriver is the basic driver which will handle the Scapy functions
24
25TODO: Add Explanation on how to install scapy
26"""
27import pexpect
28import re
29import sys
Jeremy Songster1f39bf02016-01-20 17:17:25 -080030import os
31from drivers.common.cli.emulatordriver import Emulator
32
33
34class ScapyCliDriver( Emulator ):
35
36 """
37 ScapyCliDriver is the basic driver which will handle
38 the Scapy functions"""
39 def __init__( self ):
Devin Limdc78e202017-06-09 18:30:07 -070040 super( ScapyCliDriver, self ).__init__()
Jeremy Songster1f39bf02016-01-20 17:17:25 -080041 self.handle = self
42 self.name = None
Jon Hall06fd0df2021-01-25 15:50:06 -080043 self.home = "~/"
Jeremy Songster1f39bf02016-01-20 17:17:25 -080044 self.wrapped = sys.modules[ __name__ ]
45 self.flag = 0
46 # TODO: Refactor driver to use these everywhere
You Wangdafb6e22018-01-22 17:01:00 -080047 self.hostPrompt = "\$"
Jeremy Songster1f39bf02016-01-20 17:17:25 -080048 self.scapyPrompt = ">>>"
Jon Hall06fd0df2021-01-25 15:50:06 -080049 self.sudoRequired = True
50 self.ifaceName = None
Jon Hallb0c6ae02021-09-01 10:53:39 -070051 self.scapyPath = "scapy"
Jeremy Songster1f39bf02016-01-20 17:17:25 -080052
53 def connect( self, **connectargs ):
54 """
55 Here the main is the TestON instance after creating
56 all the log handles."""
57 try:
58 for key in connectargs:
59 vars( self )[ key ] = connectargs[ key ]
Jon Hall06fd0df2021-01-25 15:50:06 -080060 for key in self.options:
61 if key == "home":
62 self.home = self.options[ key ]
63 elif key == "name":
64 self.name = self.options[ key ]
65 elif key == "sudo_required":
66 self.sudoRequired = False if self.options[ key ] == "false" else True
67 elif key == "ifaceName":
68 self.ifaceName = self.options[ key ]
Jon Hallb0c6ae02021-09-01 10:53:39 -070069 elif key == "scapy_path":
70 self.scapyPath = self.options[ key ]
Jon Hall06fd0df2021-01-25 15:50:06 -080071 if self.ifaceName is None:
72 self.ifaceName = self.name + "-eth0"
Jon Hall43060f62020-06-23 13:13:33 -070073
74 # Parse route config
75 self.routes = []
76 routes = self.options.get( 'routes' )
77 if routes:
78 for route in routes:
79 route = routes[ route ]
80 iface = route.get( 'interface' )
81 if not iface:
82 iface = None
83 self.routes.append( { 'network': route[ 'network' ],
84 'netmask': route[ 'netmask' ],
85 'gw': route.get( 'gw' ),
86 'interface': iface } )
Jeremy Songster1f39bf02016-01-20 17:17:25 -080087 try:
88 if os.getenv( str( self.ip_address ) ) is not None:
89 self.ip_address = os.getenv( str( self.ip_address ) )
90 else:
91 main.log.info( self.name +
92 ": Trying to connect to " +
93 self.ip_address )
94
95 except KeyError:
Jon Hall43060f62020-06-23 13:13:33 -070096 main.log.info( self.name + ": Invalid host name," +
Jeremy Songster1f39bf02016-01-20 17:17:25 -080097 " connecting to local host instead" )
98 self.ip_address = 'localhost'
99 except Exception as inst:
Jon Hall43060f62020-06-23 13:13:33 -0700100 main.log.error( self.name + ": Uncaught exception: " + str( inst ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800101
102 self.handle = super(
103 ScapyCliDriver,
104 self ).connect(
105 user_name=self.user_name,
106 ip_address=self.ip_address,
107 port=None,
108 pwd=self.pwd )
109
110 if self.handle:
Jon Hall43060f62020-06-23 13:13:33 -0700111 main.log.info( self.name + ": Connection successful to the host " +
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800112 self.user_name +
113 "@" +
114 self.ip_address )
You Wang4cc61912018-08-28 10:10:58 -0700115 return self.handle
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800116 else:
117 main.log.error( "Connection failed to the host " +
118 self.user_name +
119 "@" +
120 self.ip_address )
Jon Hall3a03cad2021-04-07 11:21:55 -0700121 main.log.error( "Failed to connect to the Host" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800122 return main.FALSE
123 except pexpect.EOF:
124 main.log.error( self.name + ": EOF exception found" )
125 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700126 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800127 except Exception:
128 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700129 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800130
131 def disconnect( self ):
132 """
133 Called at the end of the test to stop the scapy component and
134 disconnect the handle.
135 """
Jon Hall43060f62020-06-23 13:13:33 -0700136 main.log.debug( self.name + ": Disconnecting" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800137 response = main.TRUE
You Wangdafb6e22018-01-22 17:01:00 -0800138 try:
139 if self.handle:
140 self.handle.sendline( "exit" )
141 self.handle.expect( "closed" )
142 except pexpect.EOF:
143 main.log.error( self.name + ": EOF exception found" )
144 main.log.error( self.name + ": " + self.handle.before )
145 except Exception:
146 main.log.exception( self.name + ": Connection failed to the host" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800147 response = main.FALSE
148 return response
149
Daniele Moroe0609fb2021-08-30 17:50:20 +0200150 def startScapy( self, mplsPath="", ifaceName=None, enableGtp=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800151 """
152 Start the Scapy cli
153 optional:
154 mplsPath - The path where the MPLS class is located
155 NOTE: This can be a relative path from the user's home dir
Jon Hall43060f62020-06-23 13:13:33 -0700156 ifaceName - the name of the default interface to use.
Daniele Moroe0609fb2021-08-30 17:50:20 +0200157 enableGtp - True if you want to generate GTP traffic
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800158 """
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700159 mplsLines = [ 'import imp',
160 'imp.load_source( "mplsClass", "{}mplsClass.py" )'.format( mplsPath ),
161 'from mplsClass import MPLS',
162 'bind_layers(Ether, MPLS, type = 0x8847)',
163 'bind_layers(MPLS, MPLS, bottom_of_label_stack = 0)',
164 'bind_layers(MPLS, IP)' ]
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800165
Daniele Moroe0609fb2021-08-30 17:50:20 +0200166 # TODO: add GTPPDUSessionContainer when scapy is updated
167 gtpLines = [ 'from scapy.contrib.gtp import GTP_U_Header']
168
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800169 try:
Jon Hall43060f62020-06-23 13:13:33 -0700170 main.log.debug( self.name + ": Starting scapy" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800171 if self.sudoRequired:
Jon Hallb0c6ae02021-09-01 10:53:39 -0700172 self.handle.sendline( "sudo %s" % self.scapyPath )
Jon Hall06fd0df2021-01-25 15:50:06 -0800173 else:
Jon Hallb0c6ae02021-09-01 10:53:39 -0700174 self.handle.sendline( self.scapyPath )
Jon Hall06fd0df2021-01-25 15:50:06 -0800175 i = self.handle.expect( [ "not found", "password for", self.scapyPrompt ] )
176 if i == 1:
177 main.log.debug( "Sudo asking for password" )
Siddeshd9840842021-08-06 19:26:05 +0000178 self.handle.sendline( self.pwd )
Jon Hall06fd0df2021-01-25 15:50:06 -0800179 i = self.handle.expect( [ "not found", self.scapyPrompt ] )
180 if i == 0:
181 output = self.handle.before + self.handle.after
182 self.handle.expect( self.prompt )
183 output += self.handle.before + self.handle.after
184 main.log.debug( self.name + ": Scapy not installed, aborting test. \n" + output )
185 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800186 self.handle.sendline( "conf.color_theme = NoTheme()" )
187 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700188 response = self.cleanOutput( self.handle.before )
189 self.handle.sendline( "conf.fancy_prompt = False" )
190 self.handle.expect( self.scapyPrompt )
191 response = self.cleanOutput( self.handle.before )
192 self.handle.sendline( "conf.interactive = False" )
193 self.handle.expect( "interactive" )
194 self.handle.expect( self.scapyPrompt )
195 response = self.cleanOutput( self.handle.before )
196 self.handle.sendline( "" )
197 self.handle.expect( self.scapyPrompt )
198 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800199 if mplsPath:
Jon Hall43060f62020-06-23 13:13:33 -0700200 main.log.debug( self.name + ": Adding MPLS class" )
201 main.log.debug( self.name + ": MPLS class path: " + mplsPath )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800202 for line in mplsLines:
Jon Hall43060f62020-06-23 13:13:33 -0700203 main.log.debug( self.name + ": sending line: " + line )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800204 self.handle.sendline( line )
205 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700206 response = self.cleanOutput( self.handle.before )
207
Daniele Moroe0609fb2021-08-30 17:50:20 +0200208 if enableGtp:
209 for line in gtpLines:
210 main.log.debug( self.name + ": sending line: " + line )
211 self.handle.sendline( line )
212 self.handle.expect( self.scapyPrompt )
213 response = self.cleanOutput( self.handle.before )
214
Jon Hall43060f62020-06-23 13:13:33 -0700215 # Set interface
216 if ifaceName:
217 self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
218 self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800219 return main.TRUE
220 except pexpect.TIMEOUT:
221 main.log.exception( self.name + ": Command timed out" )
222 return main.FALSE
223 except pexpect.EOF:
224 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700225 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800226 except Exception:
227 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700228 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800229
230 def stopScapy( self ):
231 """
232 Exit the Scapy cli
233 """
234 try:
Jon Hall43060f62020-06-23 13:13:33 -0700235 main.log.debug( self.name + ": Stopping scapy" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800236 self.handle.sendline( "exit()" )
237 self.handle.expect( self.hostPrompt )
238 return main.TRUE
239 except pexpect.TIMEOUT:
240 main.log.exception( self.name + ": Command timed out" )
241 return main.FALSE
242 except pexpect.EOF:
243 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700244 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800245 except Exception:
246 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700247 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800248
Daniele Moroe0609fb2021-08-30 17:50:20 +0200249
250 def buildGTP( self, ipVersion=4, **kwargs ):
251 """
252 Build a GTP frame.
253
254 Will create a frame class with the given options. If a field is
255 left blank it will default to the below value unless it is
256 overwritten by the next frame.
257 Default frame:
258 ###[ GTP_U_Header ]###
259 gtp_type=g_pdu
260
261 Returns main.TRUE or main.FALSE on error
262 """
263
264 try:
265 main.log.debug( self.name + ": Building GTP Frame" )
266 # Set the UDP frame
267 cmd = 'gtp = GTP_U_Header( '
268 options = []
269 for key, value in kwargs.iteritems():
270 options.append( str( key ) + "=" + str( value ) )
271 cmd += ", ".join( options )
272 cmd += ' )'
273 self.handle.sendline( cmd )
274 self.handle.expect( self.scapyPrompt )
275 response = self.cleanOutput( self.handle.before )
276 if "Traceback" in response:
277 # KeyError, SyntaxError, ...
278 main.log.error( "Error in sending command: " + response )
279 return main.FALSE
280 if str( ipVersion ) is '4':
281 self.handle.sendline( "packet = ether/ip/udp/gtp" )
282 elif str( ipVersion ) is '6':
283 self.handle.sendline( "packet = ether/ipv6/udp/gtp" )
284 else:
285 main.log.error( "Unrecognized option for ipVersion, given " +
286 repr( ipVersion ) )
287 return main.FALSE
288 self.handle.expect( self.scapyPrompt )
289 response = self.cleanOutput( self.handle.before )
290 if "Traceback" in response:
291 # KeyError, SyntaxError, ...
292 main.log.error( "Error in sending command: " + response )
293 return main.FALSE
294 return main.TRUE
295 except pexpect.TIMEOUT:
296 main.log.exception( self.name + ": Command timed out" )
297 return main.FALSE
298 except pexpect.EOF:
299 main.log.exception( self.name + ": connection closed." )
300 main.cleanAndExit()
301 except Exception:
302 main.log.exception( self.name + ": Uncaught exception!" )
303 main.cleanAndExit()
304
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800305 def buildEther( self, **kwargs ):
306 """
307 Build an Ethernet frame
308
309 Will create a frame class with the given options. If a field is
310 left blank it will default to the below value unless it is
311 overwritten by the next frame.
312 Default frame:
313 ###[ Ethernet ]###
314 dst= ff:ff:ff:ff:ff:ff
315 src= 00:00:00:00:00:00
316 type= 0x800
317
318 Returns main.TRUE or main.FALSE on error
319 """
320 try:
Jon Hall43060f62020-06-23 13:13:33 -0700321 main.log.debug( self.name + ": Building Ethernet Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800322 # Set the Ethernet frame
323 cmd = 'ether = Ether( '
324 options = []
325 for key, value in kwargs.iteritems():
326 if isinstance( value, str ):
327 value = '"' + value + '"'
328 options.append( str( key ) + "=" + str( value ) )
329 cmd += ", ".join( options )
330 cmd += ' )'
331 self.handle.sendline( cmd )
332 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700333 response = self.cleanOutput( self.handle.before )
334 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800335 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700336 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800337 return main.FALSE
338 self.handle.sendline( "packet = ether" )
339 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700340 response = self.cleanOutput( self.handle.before )
341 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800342 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700343 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800344 return main.FALSE
345 return main.TRUE
346 except pexpect.TIMEOUT:
347 main.log.exception( self.name + ": Command timed out" )
348 return main.FALSE
349 except pexpect.EOF:
350 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700351 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800352 except Exception:
353 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700354 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800355
Daniele Moroe0609fb2021-08-30 17:50:20 +0200356 def buildIP( self, vlan=False, overGtp=False, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800357 """
358 Build an IP frame
359
Daniele Moroe0609fb2021-08-30 17:50:20 +0200360 If overGtp is True, it creates an inner IPv4 frame. The outer IP header
361 must be IPv4.
362
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800363 Will create a frame class with the given options. If a field is
364 left blank it will default to the below value unless it is
365 overwritten by the next frame.
366 Default frame:
367 ###[ IP ]###
368 version= 4
369 ihl= None
370 tos= 0x0
371 len= None
372 id= 1
373 flags=
374 frag= 0
375 ttl= 64
376 proto= hopopt
377 chksum= None
378 src= 127.0.0.1
379 dst= 127.0.0.1
380 \options\
381
382 Returns main.TRUE or main.FALSE on error
383 """
384 try:
Jon Hall43060f62020-06-23 13:13:33 -0700385 main.log.debug( self.name + ": Building IP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800386 # Set the IP frame
Daniele Moroe0609fb2021-08-30 17:50:20 +0200387 if overGtp:
388 cmd = 'inner_ip = IP( '
389 else:
390 cmd = 'ip = IP( '
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800391 options = []
392 for key, value in kwargs.iteritems():
393 if isinstance( value, str ):
394 value = '"' + value + '"'
395 options.append( str( key ) + "=" + str( value ) )
396 cmd += ", ".join( options )
397 cmd += ' )'
398 self.handle.sendline( cmd )
399 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700400 response = self.cleanOutput( self.handle.before )
401 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800402 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700403 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800404 return main.FALSE
Siddeshd9840842021-08-06 19:26:05 +0000405 if vlan:
Daniele Moroe0609fb2021-08-30 17:50:20 +0200406 if overGtp:
407 self.handle.sendline( "packet = ether/vlan/ip/udp/gtp/inner_ip" )
408 else:
409 self.handle.sendline( "packet = ether/vlan/ip" )
Siddeshd9840842021-08-06 19:26:05 +0000410 else:
Daniele Moroe0609fb2021-08-30 17:50:20 +0200411 if overGtp:
412 self.handle.sendline( "packet = ether/ip/udp/gtp/inner_ip" )
413 else:
414 self.handle.sendline( "packet = ether/ip" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800415 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700416 response = self.cleanOutput( self.handle.before )
417 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800418 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700419 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800420 return main.FALSE
421 return main.TRUE
422 except pexpect.TIMEOUT:
423 main.log.exception( self.name + ": Command timed out" )
424 return main.FALSE
425 except pexpect.EOF:
426 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700427 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800428 except Exception:
429 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700430 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800431
Siddesha19e3c82021-06-09 22:45:27 +0000432 def buildVLAN( self, **kwargs ):
433 """
434 Build a VLAN frame
435 """
436 try:
437 main.log.debug( self.name + ": Building VLAN Frame" )
438 # Set the IP frame
439 cmd = 'vlan = Dot1Q( '
440 options = []
441 for key, value in kwargs.iteritems():
442 if isinstance( value, str ):
443 value = '"' + value + '"'
444 options.append( str( key ) + "=" + str( value ) )
445 cmd += ", ".join( options )
446 cmd += ' )'
447 self.handle.sendline( cmd )
448 self.handle.expect( self.scapyPrompt )
449 response = self.cleanOutput( self.handle.before )
450 if "Traceback" in response:
451 # KeyError, SyntaxError, ...
452 main.log.error( "Error in sending command: " + response )
453 return main.FALSE
Siddeshd9840842021-08-06 19:26:05 +0000454 self.handle.sendline( "packet = ether/vlan" )
Siddesha19e3c82021-06-09 22:45:27 +0000455 self.handle.expect( self.scapyPrompt )
456 response = self.cleanOutput( self.handle.before )
457 if "Traceback" in response:
458 # KeyError, SyntaxError, ...
459 main.log.error( "Error in sending command: " + response )
460 return main.FALSE
461 return main.TRUE
462 except pexpect.TIMEOUT:
463 main.log.exception( self.name + ": Command timed out" )
464 return main.FALSE
465 except pexpect.EOF:
466 main.log.exception( self.name + ": connection closed." )
467 main.cleanAndExit()
468 except Exception:
469 main.log.exception( self.name + ": Uncaught exception!" )
470 main.cleanAndExit()
471
Daniele Moroe0609fb2021-08-30 17:50:20 +0200472 def buildIPv6( self, vlan=False, overGtp=False, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800473 """
474 Build an IPv6 frame
475
Daniele Moroe0609fb2021-08-30 17:50:20 +0200476 If overGtp is True, it creates an inner IPv6 frame. The outer ip header
477 must be IPv6.
478
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800479 Will create a frame class with the given options. If a field is
480 left blank it will default to the below value unless it is
481 overwritten by the next frame.
482 Default frame:
483 ###[ IPv6 ]###
484 version= 6
485 tc= 0
486 fl= 0
487 plen= None
488 nh= No Next Header
489 hlim= 64
490 src= ::1
491 dst= ::1
492
493 Returns main.TRUE or main.FALSE on error
494 """
495 try:
Jon Hall43060f62020-06-23 13:13:33 -0700496 main.log.debug( self.name + ": Building IPv6 Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800497 # Set the IPv6 frame
Daniele Moroe0609fb2021-08-30 17:50:20 +0200498 if overGtp:
499 cmd = 'inner_ipv6 = IPv6( '
500 else:
501 cmd = 'ipv6 = IPv6( '
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800502 options = []
503 for key, value in kwargs.iteritems():
504 if isinstance( value, str ):
505 value = '"' + value + '"'
506 options.append( str( key ) + "=" + str( value ) )
507 cmd += ", ".join( options )
508 cmd += ' )'
509 self.handle.sendline( cmd )
510 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700511 response = self.cleanOutput( self.handle.before )
512 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800513 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700514 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800515 return main.FALSE
Siddeshd9840842021-08-06 19:26:05 +0000516 if vlan:
Daniele Moroe0609fb2021-08-30 17:50:20 +0200517 if overGtp:
518 self.handle.sendline( "packet = ether/vlan/ipv6/udp/gtp/inner_ipv6" )
519 else:
520 self.handle.sendline( "packet = ether/vlan/ipv6" )
Siddeshd9840842021-08-06 19:26:05 +0000521 else:
Daniele Moroe0609fb2021-08-30 17:50:20 +0200522 if overGtp:
523 self.handle.sendline( "packet = ether/ipv6/udp/gtp/inner_ipv6" )
524 else:
525 self.handle.sendline( "packet = ether/ipv6" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800526 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700527 response = self.cleanOutput( self.handle.before )
528 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800529 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700530 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800531 return main.FALSE
532 return main.TRUE
533 except pexpect.TIMEOUT:
534 main.log.exception( self.name + ": Command timed out" )
535 return main.FALSE
536 except pexpect.EOF:
537 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700538 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800539 except Exception:
540 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700541 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800542
Daniele Moroe0609fb2021-08-30 17:50:20 +0200543 def buildTCP( self, ipVersion=4, overGtp=False, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800544 """
545 Build an TCP frame
546
Daniele Moroe0609fb2021-08-30 17:50:20 +0200547 If overGtp is True, it creates an inner TCP frame, in this case ipVersion
548 signals the IP version of both outer and inner headers.
549
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800550 Will create a frame class with the given options. If a field is
551 left blank it will default to the below value unless it is
552 overwritten by the next frame.
553
554 NOTE: Some arguments require quotes around them. It's up to you to
555 know which ones and to add them yourself. Arguments with an asterisk
556 do not need quotes.
557
558 Options:
559 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
560 frame to use to encapsulate into
561 Default frame:
562 ###[ TCP ]###
563 sport= ftp_data *
564 dport= http *
565 seq= 0
566 ack= 0
567 dataofs= None
568 reserved= 0
569 flags= S
570 window= 8192
571 chksum= None
572 urgptr= 0
573 options= {}
574
575 Returns main.TRUE or main.FALSE on error
576 """
577 try:
Jon Hall43060f62020-06-23 13:13:33 -0700578 main.log.debug( self.name + ": Building TCP" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800579 # Set the TCP frame
Daniele Moroe0609fb2021-08-30 17:50:20 +0200580 if overGtp:
581 cmd = 'inner_tcp = TCP( '
582 else:
583 cmd = 'tcp = TCP( '
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800584 options = []
585 for key, value in kwargs.iteritems():
586 options.append( str( key ) + "=" + str( value ) )
587 cmd += ", ".join( options )
588 cmd += ' )'
589 self.handle.sendline( cmd )
590 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700591 response = self.cleanOutput( self.handle.before )
592 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800593 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700594 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800595 return main.FALSE
596 if str( ipVersion ) is '4':
Daniele Moroe0609fb2021-08-30 17:50:20 +0200597 if overGtp:
598 self.handle.sendline( "packet = ether/ip/udp/gtp/inner_ip/inner_tcp" )
599 else:
600 self.handle.sendline( "packet = ether/ip/tcp" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800601 elif str( ipVersion ) is '6':
Daniele Moroe0609fb2021-08-30 17:50:20 +0200602 if overGtp:
603 self.handle.sendline( "packet = ether/ipv6/udp/gtp/inner_ipv6/inner_tcp" )
604 else:
605 self.handle.sendline( "packet = ether/ipv6/tcp" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800606 else:
607 main.log.error( "Unrecognized option for ipVersion, given " +
608 repr( ipVersion ) )
609 return main.FALSE
610 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700611 response = self.cleanOutput( self.handle.before )
612 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800613 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700614 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800615 return main.FALSE
616 return main.TRUE
617 except pexpect.TIMEOUT:
618 main.log.exception( self.name + ": Command timed out" )
619 return main.FALSE
620 except pexpect.EOF:
621 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700622 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800623 except Exception:
624 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700625 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800626
Daniele Moroe0609fb2021-08-30 17:50:20 +0200627 def buildUDP( self, ipVersion=4, overGtp=False, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800628 """
629 Build an UDP frame
630
Daniele Moroe0609fb2021-08-30 17:50:20 +0200631 If overGtp is True, it creates an inner UDP frame, in this case ipVersion
632 signals the IP version of both outer and inner headers.
633
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800634 Will create a frame class with the given options. If a field is
635 left blank it will default to the below value unless it is
636 overwritten by the next frame.
637
638 NOTE: Some arguments require quotes around them. It's up to you to
639 know which ones and to add them yourself. Arguments with an asterisk
640 do not need quotes.
641
642 Options:
643 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
644 frame to use to encapsulate into
645 Default frame:
646 ###[ UDP ]###
647 sport= domain *
648 dport= domain *
649 len= None
650 chksum= None
651
652 Returns main.TRUE or main.FALSE on error
653 """
654 try:
Jon Hall43060f62020-06-23 13:13:33 -0700655 main.log.debug( self.name + ": Building UDP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800656 # Set the UDP frame
Daniele Moroe0609fb2021-08-30 17:50:20 +0200657 if overGtp:
658 cmd = 'inner_udp = UDP( '
659 else:
660 cmd = 'udp = UDP( '
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800661 options = []
662 for key, value in kwargs.iteritems():
663 options.append( str( key ) + "=" + str( value ) )
664 cmd += ", ".join( options )
665 cmd += ' )'
666 self.handle.sendline( cmd )
667 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700668 response = self.cleanOutput( self.handle.before )
669 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800670 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700671 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800672 return main.FALSE
673 if str( ipVersion ) is '4':
Daniele Moroe0609fb2021-08-30 17:50:20 +0200674 if overGtp:
675 self.handle.sendline( "packet = ether/ip/udp/gtp/inner_ip/inner_udp" )
676 else:
677 self.handle.sendline( "packet = ether/ip/udp" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800678 elif str( ipVersion ) is '6':
Daniele Moroe0609fb2021-08-30 17:50:20 +0200679 if overGtp:
680 self.handle.sendline( "packet = ether/ipv6/udp/gtp/inner_ipv6/inner_udp" )
681 else:
682 self.handle.sendline( "packet = ether/ipv6/udp" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800683 else:
684 main.log.error( "Unrecognized option for ipVersion, given " +
685 repr( ipVersion ) )
686 return main.FALSE
687 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700688 response = self.cleanOutput( self.handle.before )
689 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800690 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700691 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800692 return main.FALSE
693 return main.TRUE
694 except pexpect.TIMEOUT:
695 main.log.exception( self.name + ": Command timed out" )
696 return main.FALSE
697 except pexpect.EOF:
698 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700699 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800700 except Exception:
701 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700702 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800703
alisone14d7b02016-07-06 10:31:51 -0700704 def buildSCTP( self, ipVersion=4, **kwargs ):
705 """
706 Build an SCTP frame
707
708 Will create a frame class with the given options. If a field is
709 left blank it will default to the below value unless it is
710 overwritten by the next frame.
711
712 NOTE: Some arguments require quotes around them. It's up to you to
713 know which ones and to add them yourself. Arguments with an asterisk
714 do not need quotes.
715
716 Options:
717 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
718 frame to use to encapsulate into
719 Default frame:
720 ###[ SCTP ]###
721 sport= domain *
722 dport= domain *
723 tag = None
724 chksum = None
725
726 Returns main.TRUE or main.FALSE on error
727 """
728 try:
Jon Hall43060f62020-06-23 13:13:33 -0700729 main.log.debug( self.name + ": Building SCTP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700730 # Set the SCTP frame
731 cmd = 'sctp = SCTP( '
732 options = [ ]
733 for key, value in kwargs.iteritems( ):
734 options.append( str( key ) + "=" + str( value ) )
735 cmd += ", ".join( options )
736 cmd += ' )'
737 self.handle.sendline( cmd )
738 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700739 response = self.cleanOutput( self.handle.before )
740 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700741 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700742 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700743 return main.FALSE
744 if str( ipVersion ) is '4':
745 self.handle.sendline( "packet = ether/ip/sctp" )
746 elif str( ipVersion ) is '6':
747 self.handle.sendline( "packet = ether/ipv6/sctp" )
748 else:
749 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700750 repr( ipVersion ) )
alisone14d7b02016-07-06 10:31:51 -0700751 return main.FALSE
752 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700753 response = self.cleanOutput( self.handle.before )
754 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700755 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700756 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700757 return main.FALSE
758 return main.TRUE
759 except pexpect.TIMEOUT:
760 main.log.exception( self.name + ": Command timed out" )
761 return main.FALSE
762 except pexpect.EOF:
763 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700764 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700765 except Exception:
766 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700767 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700768
769 def buildARP( self, **kwargs ):
770 """
771 Build an ARP frame
772
773 Will create a frame class with the given options. If a field is
774 left blank it will default to the below value unless it is
775 overwritten by the next frame.
776
777 NOTE: Some arguments require quotes around them. It's up to you to
778 know which ones and to add them yourself. Arguments with an asterisk
779 do not need quotes.
780
781 Default frame:
782 ###[ ARP ]###
783 hwtype : XShortField = (1)
784 ptype : XShortEnumField = (2048)
785 hwlen : ByteField = (6)
786 plen : ByteField = (4)
787 op : ShortEnumField = (1)
788 hwsrc : ARPSourceMACField = (None)
789 psrc : SourceIPField = (None)
790 hwdst : MACField = ('00:00:00:00:00:00')
791 pdst : IPField = ('0.0.0.0')
792
793 Returns main.TRUE or main.FALSE on error
794 """
795 try:
Jon Hall43060f62020-06-23 13:13:33 -0700796 main.log.debug( self.name + ": Building ARP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700797 # Set the ARP frame
798 cmd = 'arp = ARP( '
799 options = []
800 for key, value in kwargs.iteritems( ):
801 if isinstance( value, str ):
802 value = '"' + value + '"'
803 options.append( str( key ) + "=" + str( value ) )
804 cmd += ", ".join( options )
805 cmd += ' )'
806 self.handle.sendline( cmd )
807 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700808 response = self.cleanOutput( self.handle.before )
809 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700810 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700811 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700812 return main.FALSE
813 self.handle.sendline( "packet = ether/arp" )
814 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700815 response = self.cleanOutput( self.handle.before )
816 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700817 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700818 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700819 return main.FALSE
820 return main.TRUE
821 except pexpect.TIMEOUT:
822 main.log.exception( self.name + ": Command timed out" )
823 return main.FALSE
824 except pexpect.EOF:
825 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700826 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700827 except Exception:
828 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700829 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700830
Siddeshd9840842021-08-06 19:26:05 +0000831 def buildICMP( self, ipVersion=4, vlan=False, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800832 """
833 Build an ICMP frame
834
835 Will create a frame class with the given options. If a field is
836 left blank it will default to the below value unless it is
837 overwritten by the next frame.
838 Default frame:
839 ###[ ICMP ]###
840 type= echo-request
841 code= 0
842 chksum= None
843 id= 0x0
844 seq= 0x0
845
alisone14d7b02016-07-06 10:31:51 -0700846 Options:
847 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
848 frame to use to encapsulate into
849
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800850 Returns main.TRUE or main.FALSE on error
851 """
852 try:
Jon Hall43060f62020-06-23 13:13:33 -0700853 main.log.debug( self.name + ": Building ICMP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800854 # Set the ICMP frame
alisone14d7b02016-07-06 10:31:51 -0700855 if str( ipVersion ) is '4':
856 cmd = 'icmp = ICMP( '
857 elif str( ipVersion ) is '6':
858 cmd = 'icmp6 = ICMPv6EchoReply( '
859 else:
860 main.log.error( "Unrecognized option for ipVersion, given " +
861 repr( ipVersion ) )
862 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800863 options = []
alisone14d7b02016-07-06 10:31:51 -0700864 for key, value in kwargs.iteritems( ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800865 if isinstance( value, str ):
866 value = '"' + value + '"'
867 options.append( str( key ) + "=" + str( value ) )
868 cmd += ", ".join( options )
869 cmd += ' )'
870 self.handle.sendline( cmd )
871 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700872 response = self.cleanOutput( self.handle.before )
873 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800874 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700875 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800876 return main.FALSE
Siddeshd9840842021-08-06 19:26:05 +0000877 if vlan:
878 if str( ipVersion ) is '4':
879 self.handle.sendline( "packet = ether/vlan/ip/icmp" )
880 elif str( ipVersion ) is '6':
881 self.handle.sendline( "packet = ether/vlan/ipv6/icmp6" )
alisone14d7b02016-07-06 10:31:51 -0700882 else:
Siddeshd9840842021-08-06 19:26:05 +0000883 if str( ipVersion ) is '4':
884 self.handle.sendline( "packet = ether/ip/icmp" )
885 elif str( ipVersion ) is '6':
886 self.handle.sendline( "packet = ether/ipv6/icmp6" )
887 else:
888 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700889 repr( ipVersion ) )
Siddeshd9840842021-08-06 19:26:05 +0000890
alisone14d7b02016-07-06 10:31:51 -0700891 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800892 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700893 response = self.cleanOutput( self.handle.before )
894 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800895 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700896 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800897 return main.FALSE
898 return main.TRUE
899 except pexpect.TIMEOUT:
900 main.log.exception( self.name + ": Command timed out" )
901 return main.FALSE
902 except pexpect.EOF:
903 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700904 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800905 except Exception:
906 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700907 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800908
Jon Hall43060f62020-06-23 13:13:33 -0700909 def clearBuffer( self, debug=False ):
910 """
911 Keep reading from buffer until its empty
912 Everything seems to be printed twice in newer versions of
913 scapy, even when turning off fancy output
914 """
915 i = 0
916 response = ''
917 while True:
918 try:
919 i += 1
920 # clear buffer
921 if debug:
922 main.log.warn( "%s expect loop iteration" % i )
Jon Hall627b1572020-12-01 12:01:15 -0800923 self.handle.expect( self.scapyPrompt, timeout=5 )
Jon Hall43060f62020-06-23 13:13:33 -0700924 response += self.cleanOutput( self.handle.before, debug )
925 except pexpect.TIMEOUT:
926 return response
927
928 def sendPacket( self, iface=None, packet=None, timeout=1, debug=True ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800929 """
930 Send a packet with either the given scapy packet command, or use the
931 packet saved in the variable 'packet'.
932
933 Examples of a valid string for packet:
934
935 Simple IP packet
936 packet='Ether(dst="a6:d9:26:df:1d:4b")/IP(dst="10.0.0.2")'
937
938 A Ping with two vlan tags
939 packet='Ether(dst='ff:ff:ff:ff:ff:ff')/Dot1Q(vlan=1)/Dot1Q(vlan=10)/
940 IP(dst='255.255.255.255', src='192.168.0.1')/ICMP()'
941
942 Returns main.TRUE or main.FALSE on error
943 """
944 try:
Jon Hall43060f62020-06-23 13:13:33 -0700945 main.log.debug( self.name + ": Sending Packet" )
946 if debug:
947 self.handle.sendline( "packet.summary()" )
948 self.handle.expect( self.scapyPrompt )
949 self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800950 # TODO: add all params, or use kwargs
Jon Hall43060f62020-06-23 13:13:33 -0700951 sendCmd = 'sendp( '
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800952 if packet:
953 sendCmd += packet
954 else:
955 sendCmd += "packet"
956 if iface:
957 sendCmd += ", iface='{}'".format( iface )
958
Jon Hall43060f62020-06-23 13:13:33 -0700959 if debug:
960 sendCmd += ', return_packets=True).summary()' # show packet(s) sent
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800961 self.handle.sendline( sendCmd )
962 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700963 response = self.cleanOutput( self.handle.before )
964 main.log.debug( self.name + ": Send packet response: {}".format( response ) )
Jon Hall50a00012021-03-08 11:06:11 -0800965 if "Traceback" in response or "Errno" in response or "Error" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800966 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700967 main.log.error( self.name + ": Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800968 return main.FALSE
969 # TODO: Check # of packets sent?
970 return main.TRUE
971 except pexpect.TIMEOUT:
972 main.log.exception( self.name + ": Command timed out" )
973 return main.FALSE
974 except pexpect.EOF:
975 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700976 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800977 except Exception:
978 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700979 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800980
981 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
982 """
983 Listen for packets using the given filters
984
985 Options:
986 ifaceName - the name of the interface to listen on. If none is given,
You Wangdafb6e22018-01-22 17:01:00 -0800987 defaults to self.ifaceName which is <host name>-eth0
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800988 pktFilter - A string in Berkeley Packet Filter (BPF) format which
989 specifies which packets to sniff
990 sniffCount - The number of matching packets to capture before returning
991
992 Returns main.TRUE or main.FALSE on error
993 """
994 try:
Jon Hall43060f62020-06-23 13:13:33 -0700995 main.log.info( self.name + ": Starting filter on interface %s" % ifaceName )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800996 # TODO: add all params, or use kwargs
You Wangdafb6e22018-01-22 17:01:00 -0800997 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800998 # Set interface
You Wangbd848ed2018-03-23 13:57:42 -0700999 self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
Jon Hall43060f62020-06-23 13:13:33 -07001000 self.handle.expect( ifaceName )
1001 self.cleanOutput( self.handle.before + self.handle.after )
1002 self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001003 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001004 response = self.handle.before + self.handle.after
1005 self.cleanOutput( response )
Daniele Moroa9c0d0b2021-09-01 16:56:34 +02001006 cmd = 'pkts = sniff(count = %s, iface="%s", filter = "%s", prn=lambda p: p.summary() )' % ( sniffCount, ifaceName, pktFilter )
Jon Hall43060f62020-06-23 13:13:33 -07001007 main.log.info( self.name + ": Starting filter on " + self.name + ' > ' + cmd )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001008 self.handle.sendline( cmd )
Jon Hall43060f62020-06-23 13:13:33 -07001009 response = self.clearBuffer()
1010
You Wang3a5f74c2018-08-03 14:58:15 -07001011 # Make sure the sniff function didn't exit due to failures
1012 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=3 )
Jon Hall43060f62020-06-23 13:13:33 -07001013 response = self.cleanOutput( self.handle.before + str( self.handle.after ) )
You Wang3a5f74c2018-08-03 14:58:15 -07001014 if i == 0:
1015 # sniff exited
1016 main.log.error( self.name + ": sniff function exited" )
Jon Hall43060f62020-06-23 13:13:33 -07001017 main.log.error( self.name + ": " + response )
You Wang3a5f74c2018-08-03 14:58:15 -07001018 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001019 return main.TRUE
1020 except pexpect.TIMEOUT:
1021 main.log.exception( self.name + ": Command timed out" )
1022 return main.FALSE
1023 except pexpect.EOF:
1024 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001025 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001026 except Exception:
1027 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001028 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001029
1030 def checkFilter( self, timeout=10 ):
1031 """
Jon Hall43060f62020-06-23 13:13:33 -07001032 Check if a filter is still running.
1033 Returns:
1034 main.TRUE if the filter stopped
1035 main.FALSE if the filter is still running
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001036 """
1037 try:
Jon Hall43060f62020-06-23 13:13:33 -07001038 main.log.debug( self.name + ": Checking Filter" )
1039 self.handle.sendline( "" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001040 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=timeout )
Jon Hall43060f62020-06-23 13:13:33 -07001041 response = self.cleanOutput( self.handle.before + str( self.handle.after ), debug=True )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001042 if i == 0:
1043 return main.TRUE
1044 else:
1045 return main.FALSE
1046 except pexpect.EOF:
1047 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001048 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001049 except Exception:
1050 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001051 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001052
1053 def killFilter( self ):
1054 """
1055 Kill a scapy filter
1056 """
1057 try:
Jon Hall43060f62020-06-23 13:13:33 -07001058 main.log.debug( self.name + ": Killing scapy filter" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001059 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
1060 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001061 output = self.cleanOutput( self.handle.before, debug=True )
1062 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001063 except pexpect.TIMEOUT:
1064 main.log.exception( self.name + ": Command timed out" )
1065 return None
1066 except pexpect.EOF:
1067 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001068 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001069 except Exception:
1070 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001071 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001072
You Wang548db382020-08-12 09:17:13 -07001073 def readPackets( self, detailed=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001074 """
1075 Read all the packets captured by the previous filter
1076 """
1077 try:
Jon Hall43060f62020-06-23 13:13:33 -07001078 main.log.debug( self.name + ": Reading Packets" )
1079 main.log.debug( self.name + ": Begin clear buffer" )
1080 self.clearBuffer()
1081 main.log.debug( self.name + ": end clear buffer" )
1082
You Wang548db382020-08-12 09:17:13 -07001083 if detailed:
1084 self.handle.sendline( "[p for p in pkts]")
1085 else:
1086 self.handle.sendline( "pkts.summary()")
Jon Hall43060f62020-06-23 13:13:33 -07001087 output = self.clearBuffer()
Jon Hall50a00012021-03-08 11:06:11 -08001088 if "Traceback" in output or "Errno" in output or "Error" in output:
1089 # KeyError, SyntaxError, IOError, NameError, ...
1090 main.log.error( self.name + ": Error in sending command: " + output )
1091 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001092 except pexpect.TIMEOUT:
1093 main.log.exception( self.name + ": Command timed out" )
1094 return None
1095 except pexpect.EOF:
1096 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001097 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001098 except Exception:
1099 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001100 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -07001101 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001102
alisone14d7b02016-07-06 10:31:51 -07001103 def updateSelf( self, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001104 """
1105 Updates local MAC and IP fields
1106 """
1107 self.hostMac = self.getMac()
alisone14d7b02016-07-06 10:31:51 -07001108 if IPv6:
1109 self.hostIp = self.getIp( IPv6=True )
1110 else:
1111 self.hostIp = self.getIp()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001112
1113 def getMac( self, ifaceName=None ):
1114 """
1115 Save host's MAC address
1116 """
1117 try:
You Wangdafb6e22018-01-22 17:01:00 -08001118 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001119 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
1120 self.handle.sendline( cmd )
1121 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001122 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001123 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
Jon Hall43060f62020-06-23 13:13:33 -07001124 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001125 if match:
1126 return match.group()
1127 else:
1128 # the command will have an exception if iface doesn't exist
1129 return None
1130 except pexpect.TIMEOUT:
1131 main.log.exception( self.name + ": Command timed out" )
1132 return None
1133 except pexpect.EOF:
1134 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001135 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001136 except Exception:
1137 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001138 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001139
alisone14d7b02016-07-06 10:31:51 -07001140 def getIp( self, ifaceName=None, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001141 """
1142 Save host's IP address
1143
1144 Returns the IP of the first interface that is not a loopback device.
1145 If no IP could be found then it will return 0.0.0.0.
alisone14d7b02016-07-06 10:31:51 -07001146
1147 If IPv6 is equal to True, returns IPv6 of the first interface that is not a loopback device.
1148 If no IPv6 could be found then it will return :: .
1149
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001150 """
1151 def getIPofInterface( ifaceName ):
1152 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
alisone14d7b02016-07-06 10:31:51 -07001153 if IPv6:
1154 cmd = 'get_if_raw_addr6("' + str( ifaceName ) + '")'
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001155 self.handle.sendline( cmd )
1156 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001157 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001158
1159 pattern = r'(((2[0-5]|1[0-9]|[0-9])?[0-9]\.){3}((2[0-5]|1[0-9]|[0-9])?[0-9]))'
alisone14d7b02016-07-06 10:31:51 -07001160 if IPv6:
1161 pattern = r'(\\x([0-9]|[a-f]|[A-F])([0-9]|[a-f]|[A-F])){16}'
Jon Hall43060f62020-06-23 13:13:33 -07001162 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001163 if match:
1164 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001165 if IPv6 is not True:
alisone14d7b02016-07-06 10:31:51 -07001166 if match.group() == '0.0.0.0':
1167 main.log.warn( 'iface {0} has no IPv4 address'.format( ifaceName ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001168 return match.group()
1169 else:
1170 return None
1171 try:
1172 if not ifaceName:
1173 # Get list of interfaces
1174 ifList = self.getIfList()
alisone14d7b02016-07-06 10:31:51 -07001175 if IPv6:
1176 for ifaceName in ifList:
1177 if ifaceName == "lo":
1178 continue
1179 ip = getIPofInterface( ifaceName )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001180 if ip is not None:
1181 newip = ip
alisone14d7b02016-07-06 10:31:51 -07001182 tmp = newip.split( "\\x" )
1183 ip = ""
1184 counter = 0
1185 for i in tmp:
1186 if i != "":
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001187 counter = counter + 1
alisone14d7b02016-07-06 10:31:51 -07001188 if counter % 2 == 0 and counter < 16:
1189 ip = ip + i + ":"
1190 else:
1191 ip = ip + i
1192 return ip
1193 return "::"
1194 else:
1195 for ifaceName in ifList:
1196 if ifaceName == "lo":
1197 continue
1198 ip = getIPofInterface( ifaceName )
1199 if ip != "0.0.0.0":
1200 return ip
1201 return "0.0.0.0"
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001202 else:
1203 return getIPofInterface( ifaceName )
1204
1205 except pexpect.TIMEOUT:
1206 main.log.exception( self.name + ": Command timed out" )
1207 return None
1208 except pexpect.EOF:
1209 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001210 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001211 except Exception:
1212 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001213 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001214
Jon Hall43060f62020-06-23 13:13:33 -07001215 def addRoute( self, network, gateway, interface=None ):
1216 """
1217 Add a route to the current scapy session
1218 """
1219 main.log.info( self.name + ": Adding route to scapy session; %s via %s out of interface %s" % ( network, gateway, interface ) )
1220 if gateway is None:
1221 main.log.error( self.name + ": Gateway is None, cannot set route" )
1222 return main.FALSE
Jon Hall06fd0df2021-01-25 15:50:06 -08001223 if network is None or "None" in network:
1224 main.log.error( self.name + ": Network is None, cannot set route" )
1225 return main.FALSE
Jon Hall43060f62020-06-23 13:13:33 -07001226 try:
1227 cmdStr = 'conf.route.add( net="%s", gw="%s"' % ( network, gateway )
1228 if interface:
1229 cmdStr += ', dev="%s"' % interface
1230 cmdStr += ')'
1231 self.handle.sendline( cmdStr )
1232 self.handle.expect( self.scapyPrompt )
1233 response = self.cleanOutput( self.handle.before )
1234 if "Traceback" in response:
1235 main.log.error( self.name + ": Error in adding route to scappy session" )
1236 main.log.debug( response )
1237 return main.FALSE
1238 return main.TRUE
1239 except pexpect.TIMEOUT:
1240 main.log.exception( self.name + ": Command timed out" )
1241 return None
1242 except pexpect.EOF:
1243 main.log.exception( self.name + ": connection closed." )
1244 main.cleanAndExit()
1245 except Exception:
1246 main.log.exception( self.name + ": Uncaught exception!" )
1247 main.cleanAndExit()
1248
1249 def addRoutes( self ):
1250 """
1251 Add any routes configured for the host
1252 """
1253 returnValues = []
1254 for route in self.routes:
1255 gw = route.get( 'gw' )
1256 iface = route.get( 'interface' )
1257 returnValues .append( self.addRoute( "%s/%s" % ( route.get( 'network' ), route.get( 'netmask' ) ),
Jon Hall50a00012021-03-08 11:06:11 -08001258 gw if gw else main.Cluster.active(0).address,
Jon Hall43060f62020-06-23 13:13:33 -07001259 interface=iface if iface else self.interfaces[ 0 ].get( 'name' ) ) )
1260 return returnValues
1261
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001262 def getIfList( self ):
1263 """
1264 Return List of Interfaces
1265 """
1266 try:
1267 self.handle.sendline( 'get_if_list()' )
1268 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001269 response = self.cleanOutput( self.handle.before )
1270 ifList = response.split( '\r\n' )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001271 ifList = ifList[ 1 ].replace( "'", "" )[ 1:-1 ].split( ', ' )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001272 return ifList
1273
1274 except pexpect.TIMEOUT:
1275 main.log.exception( self.name + ": Command timed out" )
1276 return None
1277 except pexpect.EOF:
1278 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001279 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001280 except Exception:
1281 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001282 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001283
1284if __name__ != "__main__":
1285 sys.modules[ __name__ ] = ScapyCliDriver()