blob: e5d2deb50f3c37308bc1a61211c1770e75688728 [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
Jeremy Songster1f39bf02016-01-20 17:17:25 -080051
52 def connect( self, **connectargs ):
53 """
54 Here the main is the TestON instance after creating
55 all the log handles."""
56 try:
57 for key in connectargs:
58 vars( self )[ key ] = connectargs[ key ]
Jon Hall06fd0df2021-01-25 15:50:06 -080059 for key in self.options:
60 if key == "home":
61 self.home = self.options[ key ]
62 elif key == "name":
63 self.name = self.options[ key ]
64 elif key == "sudo_required":
65 self.sudoRequired = False if self.options[ key ] == "false" else True
66 elif key == "ifaceName":
67 self.ifaceName = self.options[ key ]
68 if self.ifaceName is None:
69 self.ifaceName = self.name + "-eth0"
Jon Hall43060f62020-06-23 13:13:33 -070070
71 # Parse route config
72 self.routes = []
73 routes = self.options.get( 'routes' )
74 if routes:
75 for route in routes:
76 route = routes[ route ]
77 iface = route.get( 'interface' )
78 if not iface:
79 iface = None
80 self.routes.append( { 'network': route[ 'network' ],
81 'netmask': route[ 'netmask' ],
82 'gw': route.get( 'gw' ),
83 'interface': iface } )
Jeremy Songster1f39bf02016-01-20 17:17:25 -080084 try:
85 if os.getenv( str( self.ip_address ) ) is not None:
86 self.ip_address = os.getenv( str( self.ip_address ) )
87 else:
88 main.log.info( self.name +
89 ": Trying to connect to " +
90 self.ip_address )
91
92 except KeyError:
Jon Hall43060f62020-06-23 13:13:33 -070093 main.log.info( self.name + ": Invalid host name," +
Jeremy Songster1f39bf02016-01-20 17:17:25 -080094 " connecting to local host instead" )
95 self.ip_address = 'localhost'
96 except Exception as inst:
Jon Hall43060f62020-06-23 13:13:33 -070097 main.log.error( self.name + ": Uncaught exception: " + str( inst ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -080098
99 self.handle = super(
100 ScapyCliDriver,
101 self ).connect(
102 user_name=self.user_name,
103 ip_address=self.ip_address,
104 port=None,
105 pwd=self.pwd )
106
107 if self.handle:
Jon Hall43060f62020-06-23 13:13:33 -0700108 main.log.info( self.name + ": Connection successful to the host " +
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800109 self.user_name +
110 "@" +
111 self.ip_address )
You Wang4cc61912018-08-28 10:10:58 -0700112 return self.handle
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800113 else:
114 main.log.error( "Connection failed to the host " +
115 self.user_name +
116 "@" +
117 self.ip_address )
Jon Hall3a03cad2021-04-07 11:21:55 -0700118 main.log.error( "Failed to connect to the Host" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800119 return main.FALSE
120 except pexpect.EOF:
121 main.log.error( self.name + ": EOF exception found" )
122 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700123 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800124 except Exception:
125 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700126 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800127
128 def disconnect( self ):
129 """
130 Called at the end of the test to stop the scapy component and
131 disconnect the handle.
132 """
Jon Hall43060f62020-06-23 13:13:33 -0700133 main.log.debug( self.name + ": Disconnecting" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800134 response = main.TRUE
You Wangdafb6e22018-01-22 17:01:00 -0800135 try:
136 if self.handle:
137 self.handle.sendline( "exit" )
138 self.handle.expect( "closed" )
139 except pexpect.EOF:
140 main.log.error( self.name + ": EOF exception found" )
141 main.log.error( self.name + ": " + self.handle.before )
142 except Exception:
143 main.log.exception( self.name + ": Connection failed to the host" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800144 response = main.FALSE
145 return response
146
Jon Hall43060f62020-06-23 13:13:33 -0700147 def startScapy( self, mplsPath="", ifaceName=None ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800148 """
149 Start the Scapy cli
150 optional:
151 mplsPath - The path where the MPLS class is located
152 NOTE: This can be a relative path from the user's home dir
Jon Hall43060f62020-06-23 13:13:33 -0700153 ifaceName - the name of the default interface to use.
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800154 """
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700155 mplsLines = [ 'import imp',
156 'imp.load_source( "mplsClass", "{}mplsClass.py" )'.format( mplsPath ),
157 'from mplsClass import MPLS',
158 'bind_layers(Ether, MPLS, type = 0x8847)',
159 'bind_layers(MPLS, MPLS, bottom_of_label_stack = 0)',
160 'bind_layers(MPLS, IP)' ]
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800161
162 try:
Jon Hall43060f62020-06-23 13:13:33 -0700163 main.log.debug( self.name + ": Starting scapy" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800164 if self.sudoRequired:
165 self.handle.sendline( "sudo scapy" )
166 else:
167 self.handle.sendline( "scapy" )
168 i = self.handle.expect( [ "not found", "password for", self.scapyPrompt ] )
169 if i == 1:
170 main.log.debug( "Sudo asking for password" )
Siddeshd9840842021-08-06 19:26:05 +0000171 self.handle.sendline( self.pwd )
Jon Hall06fd0df2021-01-25 15:50:06 -0800172 i = self.handle.expect( [ "not found", self.scapyPrompt ] )
173 if i == 0:
174 output = self.handle.before + self.handle.after
175 self.handle.expect( self.prompt )
176 output += self.handle.before + self.handle.after
177 main.log.debug( self.name + ": Scapy not installed, aborting test. \n" + output )
178 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800179 self.handle.sendline( "conf.color_theme = NoTheme()" )
180 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700181 response = self.cleanOutput( self.handle.before )
182 self.handle.sendline( "conf.fancy_prompt = False" )
183 self.handle.expect( self.scapyPrompt )
184 response = self.cleanOutput( self.handle.before )
185 self.handle.sendline( "conf.interactive = False" )
186 self.handle.expect( "interactive" )
187 self.handle.expect( self.scapyPrompt )
188 response = self.cleanOutput( self.handle.before )
189 self.handle.sendline( "" )
190 self.handle.expect( self.scapyPrompt )
191 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800192 if mplsPath:
Jon Hall43060f62020-06-23 13:13:33 -0700193 main.log.debug( self.name + ": Adding MPLS class" )
194 main.log.debug( self.name + ": MPLS class path: " + mplsPath )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800195 for line in mplsLines:
Jon Hall43060f62020-06-23 13:13:33 -0700196 main.log.debug( self.name + ": sending line: " + line )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800197 self.handle.sendline( line )
198 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700199 response = self.cleanOutput( self.handle.before )
200
201 # Set interface
202 if ifaceName:
203 self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
204 self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800205 return main.TRUE
206 except pexpect.TIMEOUT:
207 main.log.exception( self.name + ": Command timed out" )
208 return main.FALSE
209 except pexpect.EOF:
210 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700211 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800212 except Exception:
213 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700214 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800215
216 def stopScapy( self ):
217 """
218 Exit the Scapy cli
219 """
220 try:
Jon Hall43060f62020-06-23 13:13:33 -0700221 main.log.debug( self.name + ": Stopping scapy" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800222 self.handle.sendline( "exit()" )
223 self.handle.expect( self.hostPrompt )
224 return main.TRUE
225 except pexpect.TIMEOUT:
226 main.log.exception( self.name + ": Command timed out" )
227 return main.FALSE
228 except pexpect.EOF:
229 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700230 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800231 except Exception:
232 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700233 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800234
235 def buildEther( self, **kwargs ):
236 """
237 Build an Ethernet frame
238
239 Will create a frame class with the given options. If a field is
240 left blank it will default to the below value unless it is
241 overwritten by the next frame.
242 Default frame:
243 ###[ Ethernet ]###
244 dst= ff:ff:ff:ff:ff:ff
245 src= 00:00:00:00:00:00
246 type= 0x800
247
248 Returns main.TRUE or main.FALSE on error
249 """
250 try:
Jon Hall43060f62020-06-23 13:13:33 -0700251 main.log.debug( self.name + ": Building Ethernet Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800252 # Set the Ethernet frame
253 cmd = 'ether = Ether( '
254 options = []
255 for key, value in kwargs.iteritems():
256 if isinstance( value, str ):
257 value = '"' + value + '"'
258 options.append( str( key ) + "=" + str( value ) )
259 cmd += ", ".join( options )
260 cmd += ' )'
261 self.handle.sendline( cmd )
262 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700263 response = self.cleanOutput( self.handle.before )
264 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800265 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700266 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800267 return main.FALSE
268 self.handle.sendline( "packet = ether" )
269 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700270 response = self.cleanOutput( self.handle.before )
271 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800272 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700273 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800274 return main.FALSE
275 return main.TRUE
276 except pexpect.TIMEOUT:
277 main.log.exception( self.name + ": Command timed out" )
278 return main.FALSE
279 except pexpect.EOF:
280 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700281 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800282 except Exception:
283 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700284 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800285
Siddeshd9840842021-08-06 19:26:05 +0000286 def buildIP( self, vlan=False, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800287 """
288 Build an IP frame
289
290 Will create a frame class with the given options. If a field is
291 left blank it will default to the below value unless it is
292 overwritten by the next frame.
293 Default frame:
294 ###[ IP ]###
295 version= 4
296 ihl= None
297 tos= 0x0
298 len= None
299 id= 1
300 flags=
301 frag= 0
302 ttl= 64
303 proto= hopopt
304 chksum= None
305 src= 127.0.0.1
306 dst= 127.0.0.1
307 \options\
308
309 Returns main.TRUE or main.FALSE on error
310 """
311 try:
Jon Hall43060f62020-06-23 13:13:33 -0700312 main.log.debug( self.name + ": Building IP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800313 # Set the IP frame
314 cmd = 'ip = IP( '
315 options = []
316 for key, value in kwargs.iteritems():
317 if isinstance( value, str ):
318 value = '"' + value + '"'
319 options.append( str( key ) + "=" + str( value ) )
320 cmd += ", ".join( options )
321 cmd += ' )'
322 self.handle.sendline( cmd )
323 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700324 response = self.cleanOutput( self.handle.before )
325 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800326 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700327 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800328 return main.FALSE
Siddeshd9840842021-08-06 19:26:05 +0000329 if vlan:
330 self.handle.sendline( "packet = ether/vlan/ip" )
331 else:
332 self.handle.sendline( "packet = ether/ip" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800333 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700334 response = self.cleanOutput( self.handle.before )
335 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800336 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700337 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800338 return main.FALSE
339 return main.TRUE
340 except pexpect.TIMEOUT:
341 main.log.exception( self.name + ": Command timed out" )
342 return main.FALSE
343 except pexpect.EOF:
344 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700345 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800346 except Exception:
347 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700348 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800349
Siddesha19e3c82021-06-09 22:45:27 +0000350 def buildVLAN( self, **kwargs ):
351 """
352 Build a VLAN frame
353 """
354 try:
355 main.log.debug( self.name + ": Building VLAN Frame" )
356 # Set the IP frame
357 cmd = 'vlan = Dot1Q( '
358 options = []
359 for key, value in kwargs.iteritems():
360 if isinstance( value, str ):
361 value = '"' + value + '"'
362 options.append( str( key ) + "=" + str( value ) )
363 cmd += ", ".join( options )
364 cmd += ' )'
365 self.handle.sendline( cmd )
366 self.handle.expect( self.scapyPrompt )
367 response = self.cleanOutput( self.handle.before )
368 if "Traceback" in response:
369 # KeyError, SyntaxError, ...
370 main.log.error( "Error in sending command: " + response )
371 return main.FALSE
Siddeshd9840842021-08-06 19:26:05 +0000372 self.handle.sendline( "packet = ether/vlan" )
Siddesha19e3c82021-06-09 22:45:27 +0000373 self.handle.expect( self.scapyPrompt )
374 response = self.cleanOutput( self.handle.before )
375 if "Traceback" in response:
376 # KeyError, SyntaxError, ...
377 main.log.error( "Error in sending command: " + response )
378 return main.FALSE
379 return main.TRUE
380 except pexpect.TIMEOUT:
381 main.log.exception( self.name + ": Command timed out" )
382 return main.FALSE
383 except pexpect.EOF:
384 main.log.exception( self.name + ": connection closed." )
385 main.cleanAndExit()
386 except Exception:
387 main.log.exception( self.name + ": Uncaught exception!" )
388 main.cleanAndExit()
389
Siddeshd9840842021-08-06 19:26:05 +0000390 def buildIPv6( self, vlan=False, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800391 """
392 Build an IPv6 frame
393
394 Will create a frame class with the given options. If a field is
395 left blank it will default to the below value unless it is
396 overwritten by the next frame.
397 Default frame:
398 ###[ IPv6 ]###
399 version= 6
400 tc= 0
401 fl= 0
402 plen= None
403 nh= No Next Header
404 hlim= 64
405 src= ::1
406 dst= ::1
407
408 Returns main.TRUE or main.FALSE on error
409 """
410 try:
Jon Hall43060f62020-06-23 13:13:33 -0700411 main.log.debug( self.name + ": Building IPv6 Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800412 # Set the IPv6 frame
413 cmd = 'ipv6 = IPv6( '
414 options = []
415 for key, value in kwargs.iteritems():
416 if isinstance( value, str ):
417 value = '"' + value + '"'
418 options.append( str( key ) + "=" + str( value ) )
419 cmd += ", ".join( options )
420 cmd += ' )'
421 self.handle.sendline( cmd )
422 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700423 response = self.cleanOutput( self.handle.before )
424 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800425 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700426 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800427 return main.FALSE
Siddeshd9840842021-08-06 19:26:05 +0000428 if vlan:
429 self.handle.sendline( "packet = ether/vlan/ipv6" )
430 else:
431 self.handle.sendline( "packet = ether/ipv6" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800432 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700433 response = self.cleanOutput( self.handle.before )
434 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800435 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700436 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800437 return main.FALSE
438 return main.TRUE
439 except pexpect.TIMEOUT:
440 main.log.exception( self.name + ": Command timed out" )
441 return main.FALSE
442 except pexpect.EOF:
443 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700444 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800445 except Exception:
446 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700447 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800448
449 def buildTCP( self, ipVersion=4, **kwargs ):
450 """
451 Build an TCP frame
452
453 Will create a frame class with the given options. If a field is
454 left blank it will default to the below value unless it is
455 overwritten by the next frame.
456
457 NOTE: Some arguments require quotes around them. It's up to you to
458 know which ones and to add them yourself. Arguments with an asterisk
459 do not need quotes.
460
461 Options:
462 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
463 frame to use to encapsulate into
464 Default frame:
465 ###[ TCP ]###
466 sport= ftp_data *
467 dport= http *
468 seq= 0
469 ack= 0
470 dataofs= None
471 reserved= 0
472 flags= S
473 window= 8192
474 chksum= None
475 urgptr= 0
476 options= {}
477
478 Returns main.TRUE or main.FALSE on error
479 """
480 try:
Jon Hall43060f62020-06-23 13:13:33 -0700481 main.log.debug( self.name + ": Building TCP" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800482 # Set the TCP frame
483 cmd = 'tcp = TCP( '
484 options = []
485 for key, value in kwargs.iteritems():
486 options.append( str( key ) + "=" + str( value ) )
487 cmd += ", ".join( options )
488 cmd += ' )'
489 self.handle.sendline( cmd )
490 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700491 response = self.cleanOutput( self.handle.before )
492 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800493 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700494 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800495 return main.FALSE
496 if str( ipVersion ) is '4':
497 self.handle.sendline( "packet = ether/ip/tcp" )
498 elif str( ipVersion ) is '6':
499 self.handle.sendline( "packet = ether/ipv6/tcp" )
500 else:
501 main.log.error( "Unrecognized option for ipVersion, given " +
502 repr( ipVersion ) )
503 return main.FALSE
504 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700505 response = self.cleanOutput( self.handle.before )
506 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800507 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700508 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800509 return main.FALSE
510 return main.TRUE
511 except pexpect.TIMEOUT:
512 main.log.exception( self.name + ": Command timed out" )
513 return main.FALSE
514 except pexpect.EOF:
515 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700516 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800517 except Exception:
518 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700519 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800520
521 def buildUDP( self, ipVersion=4, **kwargs ):
522 """
523 Build an UDP frame
524
525 Will create a frame class with the given options. If a field is
526 left blank it will default to the below value unless it is
527 overwritten by the next frame.
528
529 NOTE: Some arguments require quotes around them. It's up to you to
530 know which ones and to add them yourself. Arguments with an asterisk
531 do not need quotes.
532
533 Options:
534 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
535 frame to use to encapsulate into
536 Default frame:
537 ###[ UDP ]###
538 sport= domain *
539 dport= domain *
540 len= None
541 chksum= None
542
543 Returns main.TRUE or main.FALSE on error
544 """
545 try:
Jon Hall43060f62020-06-23 13:13:33 -0700546 main.log.debug( self.name + ": Building UDP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800547 # Set the UDP frame
548 cmd = 'udp = UDP( '
549 options = []
550 for key, value in kwargs.iteritems():
551 options.append( str( key ) + "=" + str( value ) )
552 cmd += ", ".join( options )
553 cmd += ' )'
554 self.handle.sendline( cmd )
555 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700556 response = self.cleanOutput( self.handle.before )
557 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800558 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700559 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800560 return main.FALSE
561 if str( ipVersion ) is '4':
562 self.handle.sendline( "packet = ether/ip/udp" )
563 elif str( ipVersion ) is '6':
564 self.handle.sendline( "packet = ether/ipv6/udp" )
565 else:
566 main.log.error( "Unrecognized option for ipVersion, given " +
567 repr( ipVersion ) )
568 return main.FALSE
569 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700570 response = self.cleanOutput( self.handle.before )
571 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800572 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700573 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800574 return main.FALSE
575 return main.TRUE
576 except pexpect.TIMEOUT:
577 main.log.exception( self.name + ": Command timed out" )
578 return main.FALSE
579 except pexpect.EOF:
580 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700581 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800582 except Exception:
583 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700584 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800585
alisone14d7b02016-07-06 10:31:51 -0700586 def buildSCTP( self, ipVersion=4, **kwargs ):
587 """
588 Build an SCTP frame
589
590 Will create a frame class with the given options. If a field is
591 left blank it will default to the below value unless it is
592 overwritten by the next frame.
593
594 NOTE: Some arguments require quotes around them. It's up to you to
595 know which ones and to add them yourself. Arguments with an asterisk
596 do not need quotes.
597
598 Options:
599 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
600 frame to use to encapsulate into
601 Default frame:
602 ###[ SCTP ]###
603 sport= domain *
604 dport= domain *
605 tag = None
606 chksum = None
607
608 Returns main.TRUE or main.FALSE on error
609 """
610 try:
Jon Hall43060f62020-06-23 13:13:33 -0700611 main.log.debug( self.name + ": Building SCTP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700612 # Set the SCTP frame
613 cmd = 'sctp = SCTP( '
614 options = [ ]
615 for key, value in kwargs.iteritems( ):
616 options.append( str( key ) + "=" + str( value ) )
617 cmd += ", ".join( options )
618 cmd += ' )'
619 self.handle.sendline( cmd )
620 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700621 response = self.cleanOutput( self.handle.before )
622 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700623 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700624 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700625 return main.FALSE
626 if str( ipVersion ) is '4':
627 self.handle.sendline( "packet = ether/ip/sctp" )
628 elif str( ipVersion ) is '6':
629 self.handle.sendline( "packet = ether/ipv6/sctp" )
630 else:
631 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700632 repr( ipVersion ) )
alisone14d7b02016-07-06 10:31:51 -0700633 return main.FALSE
634 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700635 response = self.cleanOutput( self.handle.before )
636 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700637 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700638 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700639 return main.FALSE
640 return main.TRUE
641 except pexpect.TIMEOUT:
642 main.log.exception( self.name + ": Command timed out" )
643 return main.FALSE
644 except pexpect.EOF:
645 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700646 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700647 except Exception:
648 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700649 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700650
651 def buildARP( self, **kwargs ):
652 """
653 Build an ARP frame
654
655 Will create a frame class with the given options. If a field is
656 left blank it will default to the below value unless it is
657 overwritten by the next frame.
658
659 NOTE: Some arguments require quotes around them. It's up to you to
660 know which ones and to add them yourself. Arguments with an asterisk
661 do not need quotes.
662
663 Default frame:
664 ###[ ARP ]###
665 hwtype : XShortField = (1)
666 ptype : XShortEnumField = (2048)
667 hwlen : ByteField = (6)
668 plen : ByteField = (4)
669 op : ShortEnumField = (1)
670 hwsrc : ARPSourceMACField = (None)
671 psrc : SourceIPField = (None)
672 hwdst : MACField = ('00:00:00:00:00:00')
673 pdst : IPField = ('0.0.0.0')
674
675 Returns main.TRUE or main.FALSE on error
676 """
677 try:
Jon Hall43060f62020-06-23 13:13:33 -0700678 main.log.debug( self.name + ": Building ARP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700679 # Set the ARP frame
680 cmd = 'arp = ARP( '
681 options = []
682 for key, value in kwargs.iteritems( ):
683 if isinstance( value, str ):
684 value = '"' + value + '"'
685 options.append( str( key ) + "=" + str( value ) )
686 cmd += ", ".join( options )
687 cmd += ' )'
688 self.handle.sendline( cmd )
689 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700690 response = self.cleanOutput( self.handle.before )
691 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700692 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700693 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700694 return main.FALSE
695 self.handle.sendline( "packet = ether/arp" )
696 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700697 response = self.cleanOutput( self.handle.before )
698 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700699 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700700 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700701 return main.FALSE
702 return main.TRUE
703 except pexpect.TIMEOUT:
704 main.log.exception( self.name + ": Command timed out" )
705 return main.FALSE
706 except pexpect.EOF:
707 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700708 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700709 except Exception:
710 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700711 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700712
Siddeshd9840842021-08-06 19:26:05 +0000713 def buildICMP( self, ipVersion=4, vlan=False, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800714 """
715 Build an ICMP frame
716
717 Will create a frame class with the given options. If a field is
718 left blank it will default to the below value unless it is
719 overwritten by the next frame.
720 Default frame:
721 ###[ ICMP ]###
722 type= echo-request
723 code= 0
724 chksum= None
725 id= 0x0
726 seq= 0x0
727
alisone14d7b02016-07-06 10:31:51 -0700728 Options:
729 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
730 frame to use to encapsulate into
731
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800732 Returns main.TRUE or main.FALSE on error
733 """
734 try:
Jon Hall43060f62020-06-23 13:13:33 -0700735 main.log.debug( self.name + ": Building ICMP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800736 # Set the ICMP frame
alisone14d7b02016-07-06 10:31:51 -0700737 if str( ipVersion ) is '4':
738 cmd = 'icmp = ICMP( '
739 elif str( ipVersion ) is '6':
740 cmd = 'icmp6 = ICMPv6EchoReply( '
741 else:
742 main.log.error( "Unrecognized option for ipVersion, given " +
743 repr( ipVersion ) )
744 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800745 options = []
alisone14d7b02016-07-06 10:31:51 -0700746 for key, value in kwargs.iteritems( ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800747 if isinstance( value, str ):
748 value = '"' + value + '"'
749 options.append( str( key ) + "=" + str( value ) )
750 cmd += ", ".join( options )
751 cmd += ' )'
752 self.handle.sendline( cmd )
753 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700754 response = self.cleanOutput( self.handle.before )
755 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800756 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700757 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800758 return main.FALSE
Siddeshd9840842021-08-06 19:26:05 +0000759 if vlan:
760 if str( ipVersion ) is '4':
761 self.handle.sendline( "packet = ether/vlan/ip/icmp" )
762 elif str( ipVersion ) is '6':
763 self.handle.sendline( "packet = ether/vlan/ipv6/icmp6" )
alisone14d7b02016-07-06 10:31:51 -0700764 else:
Siddeshd9840842021-08-06 19:26:05 +0000765 if str( ipVersion ) is '4':
766 self.handle.sendline( "packet = ether/ip/icmp" )
767 elif str( ipVersion ) is '6':
768 self.handle.sendline( "packet = ether/ipv6/icmp6" )
769 else:
770 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700771 repr( ipVersion ) )
Siddeshd9840842021-08-06 19:26:05 +0000772
alisone14d7b02016-07-06 10:31:51 -0700773 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800774 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700775 response = self.cleanOutput( self.handle.before )
776 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800777 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700778 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800779 return main.FALSE
780 return main.TRUE
781 except pexpect.TIMEOUT:
782 main.log.exception( self.name + ": Command timed out" )
783 return main.FALSE
784 except pexpect.EOF:
785 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700786 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800787 except Exception:
788 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700789 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800790
Jon Hall43060f62020-06-23 13:13:33 -0700791 def clearBuffer( self, debug=False ):
792 """
793 Keep reading from buffer until its empty
794 Everything seems to be printed twice in newer versions of
795 scapy, even when turning off fancy output
796 """
797 i = 0
798 response = ''
799 while True:
800 try:
801 i += 1
802 # clear buffer
803 if debug:
804 main.log.warn( "%s expect loop iteration" % i )
Jon Hall627b1572020-12-01 12:01:15 -0800805 self.handle.expect( self.scapyPrompt, timeout=5 )
Jon Hall43060f62020-06-23 13:13:33 -0700806 response += self.cleanOutput( self.handle.before, debug )
807 except pexpect.TIMEOUT:
808 return response
809
810 def sendPacket( self, iface=None, packet=None, timeout=1, debug=True ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800811 """
812 Send a packet with either the given scapy packet command, or use the
813 packet saved in the variable 'packet'.
814
815 Examples of a valid string for packet:
816
817 Simple IP packet
818 packet='Ether(dst="a6:d9:26:df:1d:4b")/IP(dst="10.0.0.2")'
819
820 A Ping with two vlan tags
821 packet='Ether(dst='ff:ff:ff:ff:ff:ff')/Dot1Q(vlan=1)/Dot1Q(vlan=10)/
822 IP(dst='255.255.255.255', src='192.168.0.1')/ICMP()'
823
824 Returns main.TRUE or main.FALSE on error
825 """
826 try:
Jon Hall43060f62020-06-23 13:13:33 -0700827 main.log.debug( self.name + ": Sending Packet" )
828 if debug:
829 self.handle.sendline( "packet.summary()" )
830 self.handle.expect( self.scapyPrompt )
831 self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800832 # TODO: add all params, or use kwargs
Jon Hall43060f62020-06-23 13:13:33 -0700833 sendCmd = 'sendp( '
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800834 if packet:
835 sendCmd += packet
836 else:
837 sendCmd += "packet"
838 if iface:
839 sendCmd += ", iface='{}'".format( iface )
840
Jon Hall43060f62020-06-23 13:13:33 -0700841 if debug:
842 sendCmd += ', return_packets=True).summary()' # show packet(s) sent
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800843 self.handle.sendline( sendCmd )
844 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700845 response = self.cleanOutput( self.handle.before )
846 main.log.debug( self.name + ": Send packet response: {}".format( response ) )
Jon Hall50a00012021-03-08 11:06:11 -0800847 if "Traceback" in response or "Errno" in response or "Error" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800848 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700849 main.log.error( self.name + ": Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800850 return main.FALSE
851 # TODO: Check # of packets sent?
852 return main.TRUE
853 except pexpect.TIMEOUT:
854 main.log.exception( self.name + ": Command timed out" )
855 return main.FALSE
856 except pexpect.EOF:
857 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700858 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800859 except Exception:
860 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700861 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800862
863 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
864 """
865 Listen for packets using the given filters
866
867 Options:
868 ifaceName - the name of the interface to listen on. If none is given,
You Wangdafb6e22018-01-22 17:01:00 -0800869 defaults to self.ifaceName which is <host name>-eth0
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800870 pktFilter - A string in Berkeley Packet Filter (BPF) format which
871 specifies which packets to sniff
872 sniffCount - The number of matching packets to capture before returning
873
874 Returns main.TRUE or main.FALSE on error
875 """
876 try:
Jon Hall43060f62020-06-23 13:13:33 -0700877 main.log.info( self.name + ": Starting filter on interface %s" % ifaceName )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800878 # TODO: add all params, or use kwargs
You Wangdafb6e22018-01-22 17:01:00 -0800879 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800880 # Set interface
You Wangbd848ed2018-03-23 13:57:42 -0700881 self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
Jon Hall43060f62020-06-23 13:13:33 -0700882 self.handle.expect( ifaceName )
883 self.cleanOutput( self.handle.before + self.handle.after )
884 self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800885 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700886 response = self.handle.before + self.handle.after
887 self.cleanOutput( response )
888 cmd = 'pkts = sniff(count = %s, filter = "%s", prn=lambda p: p.summary() )' % ( sniffCount, pktFilter )
889 main.log.info( self.name + ": Starting filter on " + self.name + ' > ' + cmd )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800890 self.handle.sendline( cmd )
Jon Hall43060f62020-06-23 13:13:33 -0700891 response = self.clearBuffer()
892
You Wang3a5f74c2018-08-03 14:58:15 -0700893 # Make sure the sniff function didn't exit due to failures
894 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=3 )
Jon Hall43060f62020-06-23 13:13:33 -0700895 response = self.cleanOutput( self.handle.before + str( self.handle.after ) )
You Wang3a5f74c2018-08-03 14:58:15 -0700896 if i == 0:
897 # sniff exited
898 main.log.error( self.name + ": sniff function exited" )
Jon Hall43060f62020-06-23 13:13:33 -0700899 main.log.error( self.name + ": " + response )
You Wang3a5f74c2018-08-03 14:58:15 -0700900 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800901 return main.TRUE
902 except pexpect.TIMEOUT:
903 main.log.exception( self.name + ": Command timed out" )
904 return main.FALSE
905 except pexpect.EOF:
906 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700907 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800908 except Exception:
909 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700910 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800911
912 def checkFilter( self, timeout=10 ):
913 """
Jon Hall43060f62020-06-23 13:13:33 -0700914 Check if a filter is still running.
915 Returns:
916 main.TRUE if the filter stopped
917 main.FALSE if the filter is still running
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800918 """
919 try:
Jon Hall43060f62020-06-23 13:13:33 -0700920 main.log.debug( self.name + ": Checking Filter" )
921 self.handle.sendline( "" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800922 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=timeout )
Jon Hall43060f62020-06-23 13:13:33 -0700923 response = self.cleanOutput( self.handle.before + str( self.handle.after ), debug=True )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800924 if i == 0:
925 return main.TRUE
926 else:
927 return main.FALSE
928 except pexpect.EOF:
929 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700930 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800931 except Exception:
932 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700933 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800934
935 def killFilter( self ):
936 """
937 Kill a scapy filter
938 """
939 try:
Jon Hall43060f62020-06-23 13:13:33 -0700940 main.log.debug( self.name + ": Killing scapy filter" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800941 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
942 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700943 output = self.cleanOutput( self.handle.before, debug=True )
944 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800945 except pexpect.TIMEOUT:
946 main.log.exception( self.name + ": Command timed out" )
947 return None
948 except pexpect.EOF:
949 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700950 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800951 except Exception:
952 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700953 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800954
You Wang548db382020-08-12 09:17:13 -0700955 def readPackets( self, detailed=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800956 """
957 Read all the packets captured by the previous filter
958 """
959 try:
Jon Hall43060f62020-06-23 13:13:33 -0700960 main.log.debug( self.name + ": Reading Packets" )
961 main.log.debug( self.name + ": Begin clear buffer" )
962 self.clearBuffer()
963 main.log.debug( self.name + ": end clear buffer" )
964
You Wang548db382020-08-12 09:17:13 -0700965 if detailed:
966 self.handle.sendline( "[p for p in pkts]")
967 else:
968 self.handle.sendline( "pkts.summary()")
Jon Hall43060f62020-06-23 13:13:33 -0700969 output = self.clearBuffer()
Jon Hall50a00012021-03-08 11:06:11 -0800970 if "Traceback" in output or "Errno" in output or "Error" in output:
971 # KeyError, SyntaxError, IOError, NameError, ...
972 main.log.error( self.name + ": Error in sending command: " + output )
973 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800974 except pexpect.TIMEOUT:
975 main.log.exception( self.name + ": Command timed out" )
976 return None
977 except pexpect.EOF:
978 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700979 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800980 except Exception:
981 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700982 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700983 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800984
alisone14d7b02016-07-06 10:31:51 -0700985 def updateSelf( self, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800986 """
987 Updates local MAC and IP fields
988 """
989 self.hostMac = self.getMac()
alisone14d7b02016-07-06 10:31:51 -0700990 if IPv6:
991 self.hostIp = self.getIp( IPv6=True )
992 else:
993 self.hostIp = self.getIp()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800994
995 def getMac( self, ifaceName=None ):
996 """
997 Save host's MAC address
998 """
999 try:
You Wangdafb6e22018-01-22 17:01:00 -08001000 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001001 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
1002 self.handle.sendline( cmd )
1003 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001004 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001005 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
Jon Hall43060f62020-06-23 13:13:33 -07001006 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001007 if match:
1008 return match.group()
1009 else:
1010 # the command will have an exception if iface doesn't exist
1011 return None
1012 except pexpect.TIMEOUT:
1013 main.log.exception( self.name + ": Command timed out" )
1014 return None
1015 except pexpect.EOF:
1016 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001017 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001018 except Exception:
1019 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001020 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001021
alisone14d7b02016-07-06 10:31:51 -07001022 def getIp( self, ifaceName=None, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001023 """
1024 Save host's IP address
1025
1026 Returns the IP of the first interface that is not a loopback device.
1027 If no IP could be found then it will return 0.0.0.0.
alisone14d7b02016-07-06 10:31:51 -07001028
1029 If IPv6 is equal to True, returns IPv6 of the first interface that is not a loopback device.
1030 If no IPv6 could be found then it will return :: .
1031
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001032 """
1033 def getIPofInterface( ifaceName ):
1034 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
alisone14d7b02016-07-06 10:31:51 -07001035 if IPv6:
1036 cmd = 'get_if_raw_addr6("' + str( ifaceName ) + '")'
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001037 self.handle.sendline( cmd )
1038 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001039 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001040
1041 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 -07001042 if IPv6:
1043 pattern = r'(\\x([0-9]|[a-f]|[A-F])([0-9]|[a-f]|[A-F])){16}'
Jon Hall43060f62020-06-23 13:13:33 -07001044 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001045 if match:
1046 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001047 if IPv6 is not True:
alisone14d7b02016-07-06 10:31:51 -07001048 if match.group() == '0.0.0.0':
1049 main.log.warn( 'iface {0} has no IPv4 address'.format( ifaceName ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001050 return match.group()
1051 else:
1052 return None
1053 try:
1054 if not ifaceName:
1055 # Get list of interfaces
1056 ifList = self.getIfList()
alisone14d7b02016-07-06 10:31:51 -07001057 if IPv6:
1058 for ifaceName in ifList:
1059 if ifaceName == "lo":
1060 continue
1061 ip = getIPofInterface( ifaceName )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001062 if ip is not None:
1063 newip = ip
alisone14d7b02016-07-06 10:31:51 -07001064 tmp = newip.split( "\\x" )
1065 ip = ""
1066 counter = 0
1067 for i in tmp:
1068 if i != "":
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001069 counter = counter + 1
alisone14d7b02016-07-06 10:31:51 -07001070 if counter % 2 == 0 and counter < 16:
1071 ip = ip + i + ":"
1072 else:
1073 ip = ip + i
1074 return ip
1075 return "::"
1076 else:
1077 for ifaceName in ifList:
1078 if ifaceName == "lo":
1079 continue
1080 ip = getIPofInterface( ifaceName )
1081 if ip != "0.0.0.0":
1082 return ip
1083 return "0.0.0.0"
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001084 else:
1085 return getIPofInterface( ifaceName )
1086
1087 except pexpect.TIMEOUT:
1088 main.log.exception( self.name + ": Command timed out" )
1089 return None
1090 except pexpect.EOF:
1091 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001092 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001093 except Exception:
1094 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001095 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001096
Jon Hall43060f62020-06-23 13:13:33 -07001097 def addRoute( self, network, gateway, interface=None ):
1098 """
1099 Add a route to the current scapy session
1100 """
1101 main.log.info( self.name + ": Adding route to scapy session; %s via %s out of interface %s" % ( network, gateway, interface ) )
1102 if gateway is None:
1103 main.log.error( self.name + ": Gateway is None, cannot set route" )
1104 return main.FALSE
Jon Hall06fd0df2021-01-25 15:50:06 -08001105 if network is None or "None" in network:
1106 main.log.error( self.name + ": Network is None, cannot set route" )
1107 return main.FALSE
Jon Hall43060f62020-06-23 13:13:33 -07001108 try:
1109 cmdStr = 'conf.route.add( net="%s", gw="%s"' % ( network, gateway )
1110 if interface:
1111 cmdStr += ', dev="%s"' % interface
1112 cmdStr += ')'
1113 self.handle.sendline( cmdStr )
1114 self.handle.expect( self.scapyPrompt )
1115 response = self.cleanOutput( self.handle.before )
1116 if "Traceback" in response:
1117 main.log.error( self.name + ": Error in adding route to scappy session" )
1118 main.log.debug( response )
1119 return main.FALSE
1120 return main.TRUE
1121 except pexpect.TIMEOUT:
1122 main.log.exception( self.name + ": Command timed out" )
1123 return None
1124 except pexpect.EOF:
1125 main.log.exception( self.name + ": connection closed." )
1126 main.cleanAndExit()
1127 except Exception:
1128 main.log.exception( self.name + ": Uncaught exception!" )
1129 main.cleanAndExit()
1130
1131 def addRoutes( self ):
1132 """
1133 Add any routes configured for the host
1134 """
1135 returnValues = []
1136 for route in self.routes:
1137 gw = route.get( 'gw' )
1138 iface = route.get( 'interface' )
1139 returnValues .append( self.addRoute( "%s/%s" % ( route.get( 'network' ), route.get( 'netmask' ) ),
Jon Hall50a00012021-03-08 11:06:11 -08001140 gw if gw else main.Cluster.active(0).address,
Jon Hall43060f62020-06-23 13:13:33 -07001141 interface=iface if iface else self.interfaces[ 0 ].get( 'name' ) ) )
1142 return returnValues
1143
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001144 def getIfList( self ):
1145 """
1146 Return List of Interfaces
1147 """
1148 try:
1149 self.handle.sendline( 'get_if_list()' )
1150 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001151 response = self.cleanOutput( self.handle.before )
1152 ifList = response.split( '\r\n' )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001153 ifList = ifList[ 1 ].replace( "'", "" )[ 1:-1 ].split( ', ' )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001154 return ifList
1155
1156 except pexpect.TIMEOUT:
1157 main.log.exception( self.name + ": Command timed out" )
1158 return None
1159 except pexpect.EOF:
1160 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001161 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001162 except Exception:
1163 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001164 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001165
1166if __name__ != "__main__":
1167 sys.modules[ __name__ ] = ScapyCliDriver()