blob: db4a7218024f59082c04a19cfc693599de63f31d [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" )
171 main.log.sendline( self.pwd )
172 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
286 def buildIP( self, **kwargs ):
287 """
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
329 self.handle.sendline( "packet = ether/ip" )
330 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700331 response = self.cleanOutput( self.handle.before )
332 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800333 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700334 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800335 return main.FALSE
336 return main.TRUE
337 except pexpect.TIMEOUT:
338 main.log.exception( self.name + ": Command timed out" )
339 return main.FALSE
340 except pexpect.EOF:
341 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700342 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800343 except Exception:
344 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700345 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800346
Siddesha19e3c82021-06-09 22:45:27 +0000347 def buildVLAN( self, **kwargs ):
348 """
349 Build a VLAN frame
350 """
351 try:
352 main.log.debug( self.name + ": Building VLAN Frame" )
353 # Set the IP frame
354 cmd = 'vlan = Dot1Q( '
355 options = []
356 for key, value in kwargs.iteritems():
357 if isinstance( value, str ):
358 value = '"' + value + '"'
359 options.append( str( key ) + "=" + str( value ) )
360 cmd += ", ".join( options )
361 cmd += ' )'
362 self.handle.sendline( cmd )
363 self.handle.expect( self.scapyPrompt )
364 response = self.cleanOutput( self.handle.before )
365 if "Traceback" in response:
366 # KeyError, SyntaxError, ...
367 main.log.error( "Error in sending command: " + response )
368 return main.FALSE
369 self.handle.sendline( "packet = ether/ip/vlan" )
370 self.handle.expect( self.scapyPrompt )
371 response = self.cleanOutput( self.handle.before )
372 if "Traceback" in response:
373 # KeyError, SyntaxError, ...
374 main.log.error( "Error in sending command: " + response )
375 return main.FALSE
376 return main.TRUE
377 except pexpect.TIMEOUT:
378 main.log.exception( self.name + ": Command timed out" )
379 return main.FALSE
380 except pexpect.EOF:
381 main.log.exception( self.name + ": connection closed." )
382 main.cleanAndExit()
383 except Exception:
384 main.log.exception( self.name + ": Uncaught exception!" )
385 main.cleanAndExit()
386
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800387 def buildIPv6( self, **kwargs ):
388 """
389 Build an IPv6 frame
390
391 Will create a frame class with the given options. If a field is
392 left blank it will default to the below value unless it is
393 overwritten by the next frame.
394 Default frame:
395 ###[ IPv6 ]###
396 version= 6
397 tc= 0
398 fl= 0
399 plen= None
400 nh= No Next Header
401 hlim= 64
402 src= ::1
403 dst= ::1
404
405 Returns main.TRUE or main.FALSE on error
406 """
407 try:
Jon Hall43060f62020-06-23 13:13:33 -0700408 main.log.debug( self.name + ": Building IPv6 Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800409 # Set the IPv6 frame
410 cmd = 'ipv6 = IPv6( '
411 options = []
412 for key, value in kwargs.iteritems():
413 if isinstance( value, str ):
414 value = '"' + value + '"'
415 options.append( str( key ) + "=" + str( value ) )
416 cmd += ", ".join( options )
417 cmd += ' )'
418 self.handle.sendline( cmd )
419 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700420 response = self.cleanOutput( self.handle.before )
421 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800422 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700423 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800424 return main.FALSE
425 self.handle.sendline( "packet = ether/ipv6" )
426 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700427 response = self.cleanOutput( self.handle.before )
428 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800429 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700430 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800431 return main.FALSE
432 return main.TRUE
433 except pexpect.TIMEOUT:
434 main.log.exception( self.name + ": Command timed out" )
435 return main.FALSE
436 except pexpect.EOF:
437 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700438 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800439 except Exception:
440 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700441 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800442
443 def buildTCP( self, ipVersion=4, **kwargs ):
444 """
445 Build an TCP frame
446
447 Will create a frame class with the given options. If a field is
448 left blank it will default to the below value unless it is
449 overwritten by the next frame.
450
451 NOTE: Some arguments require quotes around them. It's up to you to
452 know which ones and to add them yourself. Arguments with an asterisk
453 do not need quotes.
454
455 Options:
456 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
457 frame to use to encapsulate into
458 Default frame:
459 ###[ TCP ]###
460 sport= ftp_data *
461 dport= http *
462 seq= 0
463 ack= 0
464 dataofs= None
465 reserved= 0
466 flags= S
467 window= 8192
468 chksum= None
469 urgptr= 0
470 options= {}
471
472 Returns main.TRUE or main.FALSE on error
473 """
474 try:
Jon Hall43060f62020-06-23 13:13:33 -0700475 main.log.debug( self.name + ": Building TCP" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800476 # Set the TCP frame
477 cmd = 'tcp = TCP( '
478 options = []
479 for key, value in kwargs.iteritems():
480 options.append( str( key ) + "=" + str( value ) )
481 cmd += ", ".join( options )
482 cmd += ' )'
483 self.handle.sendline( cmd )
484 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700485 response = self.cleanOutput( self.handle.before )
486 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800487 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700488 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800489 return main.FALSE
490 if str( ipVersion ) is '4':
491 self.handle.sendline( "packet = ether/ip/tcp" )
492 elif str( ipVersion ) is '6':
493 self.handle.sendline( "packet = ether/ipv6/tcp" )
494 else:
495 main.log.error( "Unrecognized option for ipVersion, given " +
496 repr( ipVersion ) )
497 return main.FALSE
498 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700499 response = self.cleanOutput( self.handle.before )
500 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800501 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700502 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800503 return main.FALSE
504 return main.TRUE
505 except pexpect.TIMEOUT:
506 main.log.exception( self.name + ": Command timed out" )
507 return main.FALSE
508 except pexpect.EOF:
509 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700510 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800511 except Exception:
512 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700513 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800514
515 def buildUDP( self, ipVersion=4, **kwargs ):
516 """
517 Build an UDP frame
518
519 Will create a frame class with the given options. If a field is
520 left blank it will default to the below value unless it is
521 overwritten by the next frame.
522
523 NOTE: Some arguments require quotes around them. It's up to you to
524 know which ones and to add them yourself. Arguments with an asterisk
525 do not need quotes.
526
527 Options:
528 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
529 frame to use to encapsulate into
530 Default frame:
531 ###[ UDP ]###
532 sport= domain *
533 dport= domain *
534 len= None
535 chksum= None
536
537 Returns main.TRUE or main.FALSE on error
538 """
539 try:
Jon Hall43060f62020-06-23 13:13:33 -0700540 main.log.debug( self.name + ": Building UDP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800541 # Set the UDP frame
542 cmd = 'udp = UDP( '
543 options = []
544 for key, value in kwargs.iteritems():
545 options.append( str( key ) + "=" + str( value ) )
546 cmd += ", ".join( options )
547 cmd += ' )'
548 self.handle.sendline( cmd )
549 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700550 response = self.cleanOutput( self.handle.before )
551 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800552 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700553 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800554 return main.FALSE
555 if str( ipVersion ) is '4':
556 self.handle.sendline( "packet = ether/ip/udp" )
557 elif str( ipVersion ) is '6':
558 self.handle.sendline( "packet = ether/ipv6/udp" )
559 else:
560 main.log.error( "Unrecognized option for ipVersion, given " +
561 repr( ipVersion ) )
562 return main.FALSE
563 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700564 response = self.cleanOutput( self.handle.before )
565 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800566 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700567 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800568 return main.FALSE
569 return main.TRUE
570 except pexpect.TIMEOUT:
571 main.log.exception( self.name + ": Command timed out" )
572 return main.FALSE
573 except pexpect.EOF:
574 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700575 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800576 except Exception:
577 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700578 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800579
alisone14d7b02016-07-06 10:31:51 -0700580 def buildSCTP( self, ipVersion=4, **kwargs ):
581 """
582 Build an SCTP frame
583
584 Will create a frame class with the given options. If a field is
585 left blank it will default to the below value unless it is
586 overwritten by the next frame.
587
588 NOTE: Some arguments require quotes around them. It's up to you to
589 know which ones and to add them yourself. Arguments with an asterisk
590 do not need quotes.
591
592 Options:
593 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
594 frame to use to encapsulate into
595 Default frame:
596 ###[ SCTP ]###
597 sport= domain *
598 dport= domain *
599 tag = None
600 chksum = None
601
602 Returns main.TRUE or main.FALSE on error
603 """
604 try:
Jon Hall43060f62020-06-23 13:13:33 -0700605 main.log.debug( self.name + ": Building SCTP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700606 # Set the SCTP frame
607 cmd = 'sctp = SCTP( '
608 options = [ ]
609 for key, value in kwargs.iteritems( ):
610 options.append( str( key ) + "=" + str( value ) )
611 cmd += ", ".join( options )
612 cmd += ' )'
613 self.handle.sendline( cmd )
614 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700615 response = self.cleanOutput( self.handle.before )
616 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700617 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700618 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700619 return main.FALSE
620 if str( ipVersion ) is '4':
621 self.handle.sendline( "packet = ether/ip/sctp" )
622 elif str( ipVersion ) is '6':
623 self.handle.sendline( "packet = ether/ipv6/sctp" )
624 else:
625 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700626 repr( ipVersion ) )
alisone14d7b02016-07-06 10:31:51 -0700627 return main.FALSE
628 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700629 response = self.cleanOutput( self.handle.before )
630 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700631 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700632 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700633 return main.FALSE
634 return main.TRUE
635 except pexpect.TIMEOUT:
636 main.log.exception( self.name + ": Command timed out" )
637 return main.FALSE
638 except pexpect.EOF:
639 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700640 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700641 except Exception:
642 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700643 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700644
645 def buildARP( self, **kwargs ):
646 """
647 Build an ARP frame
648
649 Will create a frame class with the given options. If a field is
650 left blank it will default to the below value unless it is
651 overwritten by the next frame.
652
653 NOTE: Some arguments require quotes around them. It's up to you to
654 know which ones and to add them yourself. Arguments with an asterisk
655 do not need quotes.
656
657 Default frame:
658 ###[ ARP ]###
659 hwtype : XShortField = (1)
660 ptype : XShortEnumField = (2048)
661 hwlen : ByteField = (6)
662 plen : ByteField = (4)
663 op : ShortEnumField = (1)
664 hwsrc : ARPSourceMACField = (None)
665 psrc : SourceIPField = (None)
666 hwdst : MACField = ('00:00:00:00:00:00')
667 pdst : IPField = ('0.0.0.0')
668
669 Returns main.TRUE or main.FALSE on error
670 """
671 try:
Jon Hall43060f62020-06-23 13:13:33 -0700672 main.log.debug( self.name + ": Building ARP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700673 # Set the ARP frame
674 cmd = 'arp = ARP( '
675 options = []
676 for key, value in kwargs.iteritems( ):
677 if isinstance( value, str ):
678 value = '"' + value + '"'
679 options.append( str( key ) + "=" + str( value ) )
680 cmd += ", ".join( options )
681 cmd += ' )'
682 self.handle.sendline( cmd )
683 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700684 response = self.cleanOutput( self.handle.before )
685 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700686 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700687 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700688 return main.FALSE
689 self.handle.sendline( "packet = ether/arp" )
690 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700691 response = self.cleanOutput( self.handle.before )
692 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700693 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700694 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700695 return main.FALSE
696 return main.TRUE
697 except pexpect.TIMEOUT:
698 main.log.exception( self.name + ": Command timed out" )
699 return main.FALSE
700 except pexpect.EOF:
701 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700702 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700703 except Exception:
704 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700705 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700706
707 def buildICMP( self, ipVersion=4, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800708 """
709 Build an ICMP frame
710
711 Will create a frame class with the given options. If a field is
712 left blank it will default to the below value unless it is
713 overwritten by the next frame.
714 Default frame:
715 ###[ ICMP ]###
716 type= echo-request
717 code= 0
718 chksum= None
719 id= 0x0
720 seq= 0x0
721
alisone14d7b02016-07-06 10:31:51 -0700722 Options:
723 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
724 frame to use to encapsulate into
725
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800726 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 ICMP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800730 # Set the ICMP frame
alisone14d7b02016-07-06 10:31:51 -0700731 if str( ipVersion ) is '4':
732 cmd = 'icmp = ICMP( '
733 elif str( ipVersion ) is '6':
734 cmd = 'icmp6 = ICMPv6EchoReply( '
735 else:
736 main.log.error( "Unrecognized option for ipVersion, given " +
737 repr( ipVersion ) )
738 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800739 options = []
alisone14d7b02016-07-06 10:31:51 -0700740 for key, value in kwargs.iteritems( ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800741 if isinstance( value, str ):
742 value = '"' + value + '"'
743 options.append( str( key ) + "=" + str( value ) )
744 cmd += ", ".join( options )
745 cmd += ' )'
746 self.handle.sendline( cmd )
747 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700748 response = self.cleanOutput( self.handle.before )
749 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800750 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700751 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800752 return main.FALSE
alisone14d7b02016-07-06 10:31:51 -0700753
754 if str( ipVersion ) is '4':
755 self.handle.sendline( "packet = ether/ip/icmp" )
756 elif str( ipVersion ) is '6':
757 self.handle.sendline( "packet = ether/ipv6/icmp6" )
758 else:
759 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700760 repr( ipVersion ) )
alisone14d7b02016-07-06 10:31:51 -0700761 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800762 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700763 response = self.cleanOutput( self.handle.before )
764 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800765 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700766 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800767 return main.FALSE
768 return main.TRUE
769 except pexpect.TIMEOUT:
770 main.log.exception( self.name + ": Command timed out" )
771 return main.FALSE
772 except pexpect.EOF:
773 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700774 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800775 except Exception:
776 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700777 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800778
Jon Hall43060f62020-06-23 13:13:33 -0700779 def clearBuffer( self, debug=False ):
780 """
781 Keep reading from buffer until its empty
782 Everything seems to be printed twice in newer versions of
783 scapy, even when turning off fancy output
784 """
785 i = 0
786 response = ''
787 while True:
788 try:
789 i += 1
790 # clear buffer
791 if debug:
792 main.log.warn( "%s expect loop iteration" % i )
Jon Hall627b1572020-12-01 12:01:15 -0800793 self.handle.expect( self.scapyPrompt, timeout=5 )
Jon Hall43060f62020-06-23 13:13:33 -0700794 response += self.cleanOutput( self.handle.before, debug )
795 except pexpect.TIMEOUT:
796 return response
797
798 def sendPacket( self, iface=None, packet=None, timeout=1, debug=True ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800799 """
800 Send a packet with either the given scapy packet command, or use the
801 packet saved in the variable 'packet'.
802
803 Examples of a valid string for packet:
804
805 Simple IP packet
806 packet='Ether(dst="a6:d9:26:df:1d:4b")/IP(dst="10.0.0.2")'
807
808 A Ping with two vlan tags
809 packet='Ether(dst='ff:ff:ff:ff:ff:ff')/Dot1Q(vlan=1)/Dot1Q(vlan=10)/
810 IP(dst='255.255.255.255', src='192.168.0.1')/ICMP()'
811
812 Returns main.TRUE or main.FALSE on error
813 """
814 try:
Jon Hall43060f62020-06-23 13:13:33 -0700815 main.log.debug( self.name + ": Sending Packet" )
816 if debug:
817 self.handle.sendline( "packet.summary()" )
818 self.handle.expect( self.scapyPrompt )
819 self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800820 # TODO: add all params, or use kwargs
Jon Hall43060f62020-06-23 13:13:33 -0700821 sendCmd = 'sendp( '
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800822 if packet:
823 sendCmd += packet
824 else:
825 sendCmd += "packet"
826 if iface:
827 sendCmd += ", iface='{}'".format( iface )
828
Jon Hall43060f62020-06-23 13:13:33 -0700829 if debug:
830 sendCmd += ', return_packets=True).summary()' # show packet(s) sent
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800831 self.handle.sendline( sendCmd )
832 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700833 response = self.cleanOutput( self.handle.before )
834 main.log.debug( self.name + ": Send packet response: {}".format( response ) )
Jon Hall50a00012021-03-08 11:06:11 -0800835 if "Traceback" in response or "Errno" in response or "Error" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800836 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700837 main.log.error( self.name + ": Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800838 return main.FALSE
839 # TODO: Check # of packets sent?
840 return main.TRUE
841 except pexpect.TIMEOUT:
842 main.log.exception( self.name + ": Command timed out" )
843 return main.FALSE
844 except pexpect.EOF:
845 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700846 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800847 except Exception:
848 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700849 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800850
851 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
852 """
853 Listen for packets using the given filters
854
855 Options:
856 ifaceName - the name of the interface to listen on. If none is given,
You Wangdafb6e22018-01-22 17:01:00 -0800857 defaults to self.ifaceName which is <host name>-eth0
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800858 pktFilter - A string in Berkeley Packet Filter (BPF) format which
859 specifies which packets to sniff
860 sniffCount - The number of matching packets to capture before returning
861
862 Returns main.TRUE or main.FALSE on error
863 """
864 try:
Jon Hall43060f62020-06-23 13:13:33 -0700865 main.log.info( self.name + ": Starting filter on interface %s" % ifaceName )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800866 # TODO: add all params, or use kwargs
You Wangdafb6e22018-01-22 17:01:00 -0800867 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800868 # Set interface
You Wangbd848ed2018-03-23 13:57:42 -0700869 self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
Jon Hall43060f62020-06-23 13:13:33 -0700870 self.handle.expect( ifaceName )
871 self.cleanOutput( self.handle.before + self.handle.after )
872 self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800873 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700874 response = self.handle.before + self.handle.after
875 self.cleanOutput( response )
876 cmd = 'pkts = sniff(count = %s, filter = "%s", prn=lambda p: p.summary() )' % ( sniffCount, pktFilter )
877 main.log.info( self.name + ": Starting filter on " + self.name + ' > ' + cmd )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800878 self.handle.sendline( cmd )
Jon Hall43060f62020-06-23 13:13:33 -0700879 response = self.clearBuffer()
880
You Wang3a5f74c2018-08-03 14:58:15 -0700881 # Make sure the sniff function didn't exit due to failures
882 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=3 )
Jon Hall43060f62020-06-23 13:13:33 -0700883 response = self.cleanOutput( self.handle.before + str( self.handle.after ) )
You Wang3a5f74c2018-08-03 14:58:15 -0700884 if i == 0:
885 # sniff exited
886 main.log.error( self.name + ": sniff function exited" )
Jon Hall43060f62020-06-23 13:13:33 -0700887 main.log.error( self.name + ": " + response )
You Wang3a5f74c2018-08-03 14:58:15 -0700888 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800889 return main.TRUE
890 except pexpect.TIMEOUT:
891 main.log.exception( self.name + ": Command timed out" )
892 return main.FALSE
893 except pexpect.EOF:
894 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700895 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800896 except Exception:
897 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700898 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800899
900 def checkFilter( self, timeout=10 ):
901 """
Jon Hall43060f62020-06-23 13:13:33 -0700902 Check if a filter is still running.
903 Returns:
904 main.TRUE if the filter stopped
905 main.FALSE if the filter is still running
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800906 """
907 try:
Jon Hall43060f62020-06-23 13:13:33 -0700908 main.log.debug( self.name + ": Checking Filter" )
909 self.handle.sendline( "" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800910 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=timeout )
Jon Hall43060f62020-06-23 13:13:33 -0700911 response = self.cleanOutput( self.handle.before + str( self.handle.after ), debug=True )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800912 if i == 0:
913 return main.TRUE
914 else:
915 return main.FALSE
916 except pexpect.EOF:
917 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700918 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800919 except Exception:
920 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700921 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800922
923 def killFilter( self ):
924 """
925 Kill a scapy filter
926 """
927 try:
Jon Hall43060f62020-06-23 13:13:33 -0700928 main.log.debug( self.name + ": Killing scapy filter" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800929 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
930 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700931 output = self.cleanOutput( self.handle.before, debug=True )
932 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800933 except pexpect.TIMEOUT:
934 main.log.exception( self.name + ": Command timed out" )
935 return None
936 except pexpect.EOF:
937 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700938 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800939 except Exception:
940 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700941 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800942
You Wang548db382020-08-12 09:17:13 -0700943 def readPackets( self, detailed=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800944 """
945 Read all the packets captured by the previous filter
946 """
947 try:
Jon Hall43060f62020-06-23 13:13:33 -0700948 main.log.debug( self.name + ": Reading Packets" )
949 main.log.debug( self.name + ": Begin clear buffer" )
950 self.clearBuffer()
951 main.log.debug( self.name + ": end clear buffer" )
952
You Wang548db382020-08-12 09:17:13 -0700953 if detailed:
954 self.handle.sendline( "[p for p in pkts]")
955 else:
956 self.handle.sendline( "pkts.summary()")
Jon Hall43060f62020-06-23 13:13:33 -0700957 output = self.clearBuffer()
Jon Hall50a00012021-03-08 11:06:11 -0800958 if "Traceback" in output or "Errno" in output or "Error" in output:
959 # KeyError, SyntaxError, IOError, NameError, ...
960 main.log.error( self.name + ": Error in sending command: " + output )
961 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800962 except pexpect.TIMEOUT:
963 main.log.exception( self.name + ": Command timed out" )
964 return None
965 except pexpect.EOF:
966 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700967 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800968 except Exception:
969 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700970 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700971 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800972
alisone14d7b02016-07-06 10:31:51 -0700973 def updateSelf( self, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800974 """
975 Updates local MAC and IP fields
976 """
977 self.hostMac = self.getMac()
alisone14d7b02016-07-06 10:31:51 -0700978 if IPv6:
979 self.hostIp = self.getIp( IPv6=True )
980 else:
981 self.hostIp = self.getIp()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800982
983 def getMac( self, ifaceName=None ):
984 """
985 Save host's MAC address
986 """
987 try:
You Wangdafb6e22018-01-22 17:01:00 -0800988 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800989 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
990 self.handle.sendline( cmd )
991 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700992 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800993 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
Jon Hall43060f62020-06-23 13:13:33 -0700994 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800995 if match:
996 return match.group()
997 else:
998 # the command will have an exception if iface doesn't exist
999 return None
1000 except pexpect.TIMEOUT:
1001 main.log.exception( self.name + ": Command timed out" )
1002 return None
1003 except pexpect.EOF:
1004 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001005 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001006 except Exception:
1007 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001008 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001009
alisone14d7b02016-07-06 10:31:51 -07001010 def getIp( self, ifaceName=None, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001011 """
1012 Save host's IP address
1013
1014 Returns the IP of the first interface that is not a loopback device.
1015 If no IP could be found then it will return 0.0.0.0.
alisone14d7b02016-07-06 10:31:51 -07001016
1017 If IPv6 is equal to True, returns IPv6 of the first interface that is not a loopback device.
1018 If no IPv6 could be found then it will return :: .
1019
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001020 """
1021 def getIPofInterface( ifaceName ):
1022 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
alisone14d7b02016-07-06 10:31:51 -07001023 if IPv6:
1024 cmd = 'get_if_raw_addr6("' + str( ifaceName ) + '")'
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001025 self.handle.sendline( cmd )
1026 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001027 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001028
1029 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 -07001030 if IPv6:
1031 pattern = r'(\\x([0-9]|[a-f]|[A-F])([0-9]|[a-f]|[A-F])){16}'
Jon Hall43060f62020-06-23 13:13:33 -07001032 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001033 if match:
1034 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001035 if IPv6 is not True:
alisone14d7b02016-07-06 10:31:51 -07001036 if match.group() == '0.0.0.0':
1037 main.log.warn( 'iface {0} has no IPv4 address'.format( ifaceName ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001038 return match.group()
1039 else:
1040 return None
1041 try:
1042 if not ifaceName:
1043 # Get list of interfaces
1044 ifList = self.getIfList()
alisone14d7b02016-07-06 10:31:51 -07001045 if IPv6:
1046 for ifaceName in ifList:
1047 if ifaceName == "lo":
1048 continue
1049 ip = getIPofInterface( ifaceName )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001050 if ip is not None:
1051 newip = ip
alisone14d7b02016-07-06 10:31:51 -07001052 tmp = newip.split( "\\x" )
1053 ip = ""
1054 counter = 0
1055 for i in tmp:
1056 if i != "":
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001057 counter = counter + 1
alisone14d7b02016-07-06 10:31:51 -07001058 if counter % 2 == 0 and counter < 16:
1059 ip = ip + i + ":"
1060 else:
1061 ip = ip + i
1062 return ip
1063 return "::"
1064 else:
1065 for ifaceName in ifList:
1066 if ifaceName == "lo":
1067 continue
1068 ip = getIPofInterface( ifaceName )
1069 if ip != "0.0.0.0":
1070 return ip
1071 return "0.0.0.0"
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001072 else:
1073 return getIPofInterface( ifaceName )
1074
1075 except pexpect.TIMEOUT:
1076 main.log.exception( self.name + ": Command timed out" )
1077 return None
1078 except pexpect.EOF:
1079 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001080 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001081 except Exception:
1082 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001083 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001084
Jon Hall43060f62020-06-23 13:13:33 -07001085 def addRoute( self, network, gateway, interface=None ):
1086 """
1087 Add a route to the current scapy session
1088 """
1089 main.log.info( self.name + ": Adding route to scapy session; %s via %s out of interface %s" % ( network, gateway, interface ) )
1090 if gateway is None:
1091 main.log.error( self.name + ": Gateway is None, cannot set route" )
1092 return main.FALSE
Jon Hall06fd0df2021-01-25 15:50:06 -08001093 if network is None or "None" in network:
1094 main.log.error( self.name + ": Network is None, cannot set route" )
1095 return main.FALSE
Jon Hall43060f62020-06-23 13:13:33 -07001096 try:
1097 cmdStr = 'conf.route.add( net="%s", gw="%s"' % ( network, gateway )
1098 if interface:
1099 cmdStr += ', dev="%s"' % interface
1100 cmdStr += ')'
1101 self.handle.sendline( cmdStr )
1102 self.handle.expect( self.scapyPrompt )
1103 response = self.cleanOutput( self.handle.before )
1104 if "Traceback" in response:
1105 main.log.error( self.name + ": Error in adding route to scappy session" )
1106 main.log.debug( response )
1107 return main.FALSE
1108 return main.TRUE
1109 except pexpect.TIMEOUT:
1110 main.log.exception( self.name + ": Command timed out" )
1111 return None
1112 except pexpect.EOF:
1113 main.log.exception( self.name + ": connection closed." )
1114 main.cleanAndExit()
1115 except Exception:
1116 main.log.exception( self.name + ": Uncaught exception!" )
1117 main.cleanAndExit()
1118
1119 def addRoutes( self ):
1120 """
1121 Add any routes configured for the host
1122 """
1123 returnValues = []
1124 for route in self.routes:
1125 gw = route.get( 'gw' )
1126 iface = route.get( 'interface' )
1127 returnValues .append( self.addRoute( "%s/%s" % ( route.get( 'network' ), route.get( 'netmask' ) ),
Jon Hall50a00012021-03-08 11:06:11 -08001128 gw if gw else main.Cluster.active(0).address,
Jon Hall43060f62020-06-23 13:13:33 -07001129 interface=iface if iface else self.interfaces[ 0 ].get( 'name' ) ) )
1130 return returnValues
1131
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001132 def getIfList( self ):
1133 """
1134 Return List of Interfaces
1135 """
1136 try:
1137 self.handle.sendline( 'get_if_list()' )
1138 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001139 response = self.cleanOutput( self.handle.before )
1140 ifList = response.split( '\r\n' )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001141 ifList = ifList[ 1 ].replace( "'", "" )[ 1:-1 ].split( ', ' )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001142 return ifList
1143
1144 except pexpect.TIMEOUT:
1145 main.log.exception( self.name + ": Command timed out" )
1146 return None
1147 except pexpect.EOF:
1148 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001149 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001150 except Exception:
1151 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001152 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001153
1154if __name__ != "__main__":
1155 sys.modules[ __name__ ] = ScapyCliDriver()