blob: 79a19563d09b74496a78f097fc3d9b4420b92515 [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 )
118 main.log.error( "Failed to connect to the Mininet Host" )
119 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
347 def buildIPv6( self, **kwargs ):
348 """
349 Build an IPv6 frame
350
351 Will create a frame class with the given options. If a field is
352 left blank it will default to the below value unless it is
353 overwritten by the next frame.
354 Default frame:
355 ###[ IPv6 ]###
356 version= 6
357 tc= 0
358 fl= 0
359 plen= None
360 nh= No Next Header
361 hlim= 64
362 src= ::1
363 dst= ::1
364
365 Returns main.TRUE or main.FALSE on error
366 """
367 try:
Jon Hall43060f62020-06-23 13:13:33 -0700368 main.log.debug( self.name + ": Building IPv6 Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800369 # Set the IPv6 frame
370 cmd = 'ipv6 = IPv6( '
371 options = []
372 for key, value in kwargs.iteritems():
373 if isinstance( value, str ):
374 value = '"' + value + '"'
375 options.append( str( key ) + "=" + str( value ) )
376 cmd += ", ".join( options )
377 cmd += ' )'
378 self.handle.sendline( cmd )
379 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700380 response = self.cleanOutput( self.handle.before )
381 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800382 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700383 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800384 return main.FALSE
385 self.handle.sendline( "packet = ether/ipv6" )
386 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700387 response = self.cleanOutput( self.handle.before )
388 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800389 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700390 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800391 return main.FALSE
392 return main.TRUE
393 except pexpect.TIMEOUT:
394 main.log.exception( self.name + ": Command timed out" )
395 return main.FALSE
396 except pexpect.EOF:
397 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700398 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800399 except Exception:
400 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700401 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800402
403 def buildTCP( self, ipVersion=4, **kwargs ):
404 """
405 Build an TCP frame
406
407 Will create a frame class with the given options. If a field is
408 left blank it will default to the below value unless it is
409 overwritten by the next frame.
410
411 NOTE: Some arguments require quotes around them. It's up to you to
412 know which ones and to add them yourself. Arguments with an asterisk
413 do not need quotes.
414
415 Options:
416 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
417 frame to use to encapsulate into
418 Default frame:
419 ###[ TCP ]###
420 sport= ftp_data *
421 dport= http *
422 seq= 0
423 ack= 0
424 dataofs= None
425 reserved= 0
426 flags= S
427 window= 8192
428 chksum= None
429 urgptr= 0
430 options= {}
431
432 Returns main.TRUE or main.FALSE on error
433 """
434 try:
Jon Hall43060f62020-06-23 13:13:33 -0700435 main.log.debug( self.name + ": Building TCP" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800436 # Set the TCP frame
437 cmd = 'tcp = TCP( '
438 options = []
439 for key, value in kwargs.iteritems():
440 options.append( str( key ) + "=" + str( value ) )
441 cmd += ", ".join( options )
442 cmd += ' )'
443 self.handle.sendline( cmd )
444 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700445 response = self.cleanOutput( self.handle.before )
446 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800447 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700448 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800449 return main.FALSE
450 if str( ipVersion ) is '4':
451 self.handle.sendline( "packet = ether/ip/tcp" )
452 elif str( ipVersion ) is '6':
453 self.handle.sendline( "packet = ether/ipv6/tcp" )
454 else:
455 main.log.error( "Unrecognized option for ipVersion, given " +
456 repr( ipVersion ) )
457 return main.FALSE
458 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700459 response = self.cleanOutput( self.handle.before )
460 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800461 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700462 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800463 return main.FALSE
464 return main.TRUE
465 except pexpect.TIMEOUT:
466 main.log.exception( self.name + ": Command timed out" )
467 return main.FALSE
468 except pexpect.EOF:
469 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700470 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800471 except Exception:
472 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700473 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800474
475 def buildUDP( self, ipVersion=4, **kwargs ):
476 """
477 Build an UDP frame
478
479 Will create a frame class with the given options. If a field is
480 left blank it will default to the below value unless it is
481 overwritten by the next frame.
482
483 NOTE: Some arguments require quotes around them. It's up to you to
484 know which ones and to add them yourself. Arguments with an asterisk
485 do not need quotes.
486
487 Options:
488 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
489 frame to use to encapsulate into
490 Default frame:
491 ###[ UDP ]###
492 sport= domain *
493 dport= domain *
494 len= None
495 chksum= None
496
497 Returns main.TRUE or main.FALSE on error
498 """
499 try:
Jon Hall43060f62020-06-23 13:13:33 -0700500 main.log.debug( self.name + ": Building UDP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800501 # Set the UDP frame
502 cmd = 'udp = UDP( '
503 options = []
504 for key, value in kwargs.iteritems():
505 options.append( str( key ) + "=" + str( value ) )
506 cmd += ", ".join( options )
507 cmd += ' )'
508 self.handle.sendline( cmd )
509 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700510 response = self.cleanOutput( self.handle.before )
511 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800512 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700513 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800514 return main.FALSE
515 if str( ipVersion ) is '4':
516 self.handle.sendline( "packet = ether/ip/udp" )
517 elif str( ipVersion ) is '6':
518 self.handle.sendline( "packet = ether/ipv6/udp" )
519 else:
520 main.log.error( "Unrecognized option for ipVersion, given " +
521 repr( ipVersion ) )
522 return main.FALSE
523 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700524 response = self.cleanOutput( self.handle.before )
525 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800526 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700527 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800528 return main.FALSE
529 return main.TRUE
530 except pexpect.TIMEOUT:
531 main.log.exception( self.name + ": Command timed out" )
532 return main.FALSE
533 except pexpect.EOF:
534 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700535 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800536 except Exception:
537 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700538 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800539
alisone14d7b02016-07-06 10:31:51 -0700540 def buildSCTP( self, ipVersion=4, **kwargs ):
541 """
542 Build an SCTP frame
543
544 Will create a frame class with the given options. If a field is
545 left blank it will default to the below value unless it is
546 overwritten by the next frame.
547
548 NOTE: Some arguments require quotes around them. It's up to you to
549 know which ones and to add them yourself. Arguments with an asterisk
550 do not need quotes.
551
552 Options:
553 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
554 frame to use to encapsulate into
555 Default frame:
556 ###[ SCTP ]###
557 sport= domain *
558 dport= domain *
559 tag = None
560 chksum = None
561
562 Returns main.TRUE or main.FALSE on error
563 """
564 try:
Jon Hall43060f62020-06-23 13:13:33 -0700565 main.log.debug( self.name + ": Building SCTP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700566 # Set the SCTP frame
567 cmd = 'sctp = SCTP( '
568 options = [ ]
569 for key, value in kwargs.iteritems( ):
570 options.append( str( key ) + "=" + str( value ) )
571 cmd += ", ".join( options )
572 cmd += ' )'
573 self.handle.sendline( cmd )
574 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700575 response = self.cleanOutput( self.handle.before )
576 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700577 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700578 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700579 return main.FALSE
580 if str( ipVersion ) is '4':
581 self.handle.sendline( "packet = ether/ip/sctp" )
582 elif str( ipVersion ) is '6':
583 self.handle.sendline( "packet = ether/ipv6/sctp" )
584 else:
585 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700586 repr( ipVersion ) )
alisone14d7b02016-07-06 10:31:51 -0700587 return main.FALSE
588 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700589 response = self.cleanOutput( self.handle.before )
590 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700591 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700592 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700593 return main.FALSE
594 return main.TRUE
595 except pexpect.TIMEOUT:
596 main.log.exception( self.name + ": Command timed out" )
597 return main.FALSE
598 except pexpect.EOF:
599 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700600 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700601 except Exception:
602 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700603 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700604
605 def buildARP( self, **kwargs ):
606 """
607 Build an ARP frame
608
609 Will create a frame class with the given options. If a field is
610 left blank it will default to the below value unless it is
611 overwritten by the next frame.
612
613 NOTE: Some arguments require quotes around them. It's up to you to
614 know which ones and to add them yourself. Arguments with an asterisk
615 do not need quotes.
616
617 Default frame:
618 ###[ ARP ]###
619 hwtype : XShortField = (1)
620 ptype : XShortEnumField = (2048)
621 hwlen : ByteField = (6)
622 plen : ByteField = (4)
623 op : ShortEnumField = (1)
624 hwsrc : ARPSourceMACField = (None)
625 psrc : SourceIPField = (None)
626 hwdst : MACField = ('00:00:00:00:00:00')
627 pdst : IPField = ('0.0.0.0')
628
629 Returns main.TRUE or main.FALSE on error
630 """
631 try:
Jon Hall43060f62020-06-23 13:13:33 -0700632 main.log.debug( self.name + ": Building ARP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700633 # Set the ARP frame
634 cmd = 'arp = ARP( '
635 options = []
636 for key, value in kwargs.iteritems( ):
637 if isinstance( value, str ):
638 value = '"' + value + '"'
639 options.append( str( key ) + "=" + str( value ) )
640 cmd += ", ".join( options )
641 cmd += ' )'
642 self.handle.sendline( cmd )
643 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700644 response = self.cleanOutput( self.handle.before )
645 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700646 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700647 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700648 return main.FALSE
649 self.handle.sendline( "packet = ether/arp" )
650 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700651 response = self.cleanOutput( self.handle.before )
652 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700653 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700654 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700655 return main.FALSE
656 return main.TRUE
657 except pexpect.TIMEOUT:
658 main.log.exception( self.name + ": Command timed out" )
659 return main.FALSE
660 except pexpect.EOF:
661 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700662 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700663 except Exception:
664 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700665 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700666
667 def buildICMP( self, ipVersion=4, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800668 """
669 Build an ICMP frame
670
671 Will create a frame class with the given options. If a field is
672 left blank it will default to the below value unless it is
673 overwritten by the next frame.
674 Default frame:
675 ###[ ICMP ]###
676 type= echo-request
677 code= 0
678 chksum= None
679 id= 0x0
680 seq= 0x0
681
alisone14d7b02016-07-06 10:31:51 -0700682 Options:
683 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
684 frame to use to encapsulate into
685
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800686 Returns main.TRUE or main.FALSE on error
687 """
688 try:
Jon Hall43060f62020-06-23 13:13:33 -0700689 main.log.debug( self.name + ": Building ICMP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800690 # Set the ICMP frame
alisone14d7b02016-07-06 10:31:51 -0700691 if str( ipVersion ) is '4':
692 cmd = 'icmp = ICMP( '
693 elif str( ipVersion ) is '6':
694 cmd = 'icmp6 = ICMPv6EchoReply( '
695 else:
696 main.log.error( "Unrecognized option for ipVersion, given " +
697 repr( ipVersion ) )
698 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800699 options = []
alisone14d7b02016-07-06 10:31:51 -0700700 for key, value in kwargs.iteritems( ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800701 if isinstance( value, str ):
702 value = '"' + value + '"'
703 options.append( str( key ) + "=" + str( value ) )
704 cmd += ", ".join( options )
705 cmd += ' )'
706 self.handle.sendline( cmd )
707 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700708 response = self.cleanOutput( self.handle.before )
709 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800710 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700711 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800712 return main.FALSE
alisone14d7b02016-07-06 10:31:51 -0700713
714 if str( ipVersion ) is '4':
715 self.handle.sendline( "packet = ether/ip/icmp" )
716 elif str( ipVersion ) is '6':
717 self.handle.sendline( "packet = ether/ipv6/icmp6" )
718 else:
719 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700720 repr( ipVersion ) )
alisone14d7b02016-07-06 10:31:51 -0700721 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800722 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700723 response = self.cleanOutput( self.handle.before )
724 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800725 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700726 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800727 return main.FALSE
728 return main.TRUE
729 except pexpect.TIMEOUT:
730 main.log.exception( self.name + ": Command timed out" )
731 return main.FALSE
732 except pexpect.EOF:
733 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700734 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800735 except Exception:
736 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700737 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800738
Jon Hall43060f62020-06-23 13:13:33 -0700739 def clearBuffer( self, debug=False ):
740 """
741 Keep reading from buffer until its empty
742 Everything seems to be printed twice in newer versions of
743 scapy, even when turning off fancy output
744 """
745 i = 0
746 response = ''
747 while True:
748 try:
749 i += 1
750 # clear buffer
751 if debug:
752 main.log.warn( "%s expect loop iteration" % i )
Jon Hall627b1572020-12-01 12:01:15 -0800753 self.handle.expect( self.scapyPrompt, timeout=5 )
Jon Hall43060f62020-06-23 13:13:33 -0700754 response += self.cleanOutput( self.handle.before, debug )
755 except pexpect.TIMEOUT:
756 return response
757
758 def sendPacket( self, iface=None, packet=None, timeout=1, debug=True ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800759 """
760 Send a packet with either the given scapy packet command, or use the
761 packet saved in the variable 'packet'.
762
763 Examples of a valid string for packet:
764
765 Simple IP packet
766 packet='Ether(dst="a6:d9:26:df:1d:4b")/IP(dst="10.0.0.2")'
767
768 A Ping with two vlan tags
769 packet='Ether(dst='ff:ff:ff:ff:ff:ff')/Dot1Q(vlan=1)/Dot1Q(vlan=10)/
770 IP(dst='255.255.255.255', src='192.168.0.1')/ICMP()'
771
772 Returns main.TRUE or main.FALSE on error
773 """
774 try:
Jon Hall43060f62020-06-23 13:13:33 -0700775 main.log.debug( self.name + ": Sending Packet" )
776 if debug:
777 self.handle.sendline( "packet.summary()" )
778 self.handle.expect( self.scapyPrompt )
779 self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800780 # TODO: add all params, or use kwargs
Jon Hall43060f62020-06-23 13:13:33 -0700781 sendCmd = 'sendp( '
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800782 if packet:
783 sendCmd += packet
784 else:
785 sendCmd += "packet"
786 if iface:
787 sendCmd += ", iface='{}'".format( iface )
788
Jon Hall43060f62020-06-23 13:13:33 -0700789 if debug:
790 sendCmd += ', return_packets=True).summary()' # show packet(s) sent
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800791 self.handle.sendline( sendCmd )
792 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700793 response = self.cleanOutput( self.handle.before )
794 main.log.debug( self.name + ": Send packet response: {}".format( response ) )
795 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800796 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700797 main.log.error( self.name + ": Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800798 return main.FALSE
799 # TODO: Check # of packets sent?
800 return main.TRUE
801 except pexpect.TIMEOUT:
802 main.log.exception( self.name + ": Command timed out" )
803 return main.FALSE
804 except pexpect.EOF:
805 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700806 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800807 except Exception:
808 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700809 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800810
811 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
812 """
813 Listen for packets using the given filters
814
815 Options:
816 ifaceName - the name of the interface to listen on. If none is given,
You Wangdafb6e22018-01-22 17:01:00 -0800817 defaults to self.ifaceName which is <host name>-eth0
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800818 pktFilter - A string in Berkeley Packet Filter (BPF) format which
819 specifies which packets to sniff
820 sniffCount - The number of matching packets to capture before returning
821
822 Returns main.TRUE or main.FALSE on error
823 """
824 try:
Jon Hall43060f62020-06-23 13:13:33 -0700825 main.log.info( self.name + ": Starting filter on interface %s" % ifaceName )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800826 # TODO: add all params, or use kwargs
You Wangdafb6e22018-01-22 17:01:00 -0800827 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800828 # Set interface
You Wangbd848ed2018-03-23 13:57:42 -0700829 self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
Jon Hall43060f62020-06-23 13:13:33 -0700830 self.handle.expect( ifaceName )
831 self.cleanOutput( self.handle.before + self.handle.after )
832 self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800833 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700834 response = self.handle.before + self.handle.after
835 self.cleanOutput( response )
836 cmd = 'pkts = sniff(count = %s, filter = "%s", prn=lambda p: p.summary() )' % ( sniffCount, pktFilter )
837 main.log.info( self.name + ": Starting filter on " + self.name + ' > ' + cmd )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800838 self.handle.sendline( cmd )
Jon Hall43060f62020-06-23 13:13:33 -0700839 response = self.clearBuffer()
840
You Wang3a5f74c2018-08-03 14:58:15 -0700841 # Make sure the sniff function didn't exit due to failures
842 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=3 )
Jon Hall43060f62020-06-23 13:13:33 -0700843 response = self.cleanOutput( self.handle.before + str( self.handle.after ) )
You Wang3a5f74c2018-08-03 14:58:15 -0700844 if i == 0:
845 # sniff exited
846 main.log.error( self.name + ": sniff function exited" )
Jon Hall43060f62020-06-23 13:13:33 -0700847 main.log.error( self.name + ": " + response )
You Wang3a5f74c2018-08-03 14:58:15 -0700848 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800849 return main.TRUE
850 except pexpect.TIMEOUT:
851 main.log.exception( self.name + ": Command timed out" )
852 return main.FALSE
853 except pexpect.EOF:
854 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700855 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800856 except Exception:
857 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700858 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800859
860 def checkFilter( self, timeout=10 ):
861 """
Jon Hall43060f62020-06-23 13:13:33 -0700862 Check if a filter is still running.
863 Returns:
864 main.TRUE if the filter stopped
865 main.FALSE if the filter is still running
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800866 """
867 try:
Jon Hall43060f62020-06-23 13:13:33 -0700868 main.log.debug( self.name + ": Checking Filter" )
869 self.handle.sendline( "" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800870 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=timeout )
Jon Hall43060f62020-06-23 13:13:33 -0700871 response = self.cleanOutput( self.handle.before + str( self.handle.after ), debug=True )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800872 if i == 0:
873 return main.TRUE
874 else:
875 return main.FALSE
876 except pexpect.EOF:
877 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700878 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800879 except Exception:
880 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700881 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800882
883 def killFilter( self ):
884 """
885 Kill a scapy filter
886 """
887 try:
Jon Hall43060f62020-06-23 13:13:33 -0700888 main.log.debug( self.name + ": Killing scapy filter" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800889 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
890 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700891 output = self.cleanOutput( self.handle.before, debug=True )
892 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800893 except pexpect.TIMEOUT:
894 main.log.exception( self.name + ": Command timed out" )
895 return None
896 except pexpect.EOF:
897 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700898 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800899 except Exception:
900 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700901 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800902
You Wang548db382020-08-12 09:17:13 -0700903 def readPackets( self, detailed=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800904 """
905 Read all the packets captured by the previous filter
906 """
907 try:
Jon Hall43060f62020-06-23 13:13:33 -0700908 main.log.debug( self.name + ": Reading Packets" )
909 main.log.debug( self.name + ": Begin clear buffer" )
910 self.clearBuffer()
911 main.log.debug( self.name + ": end clear buffer" )
912
You Wang548db382020-08-12 09:17:13 -0700913 if detailed:
914 self.handle.sendline( "[p for p in pkts]")
915 else:
916 self.handle.sendline( "pkts.summary()")
Jon Hall43060f62020-06-23 13:13:33 -0700917 output = self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800918 except pexpect.TIMEOUT:
919 main.log.exception( self.name + ": Command timed out" )
920 return None
921 except pexpect.EOF:
922 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700923 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800924 except Exception:
925 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700926 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700927 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800928
alisone14d7b02016-07-06 10:31:51 -0700929 def updateSelf( self, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800930 """
931 Updates local MAC and IP fields
932 """
933 self.hostMac = self.getMac()
alisone14d7b02016-07-06 10:31:51 -0700934 if IPv6:
935 self.hostIp = self.getIp( IPv6=True )
936 else:
937 self.hostIp = self.getIp()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800938
939 def getMac( self, ifaceName=None ):
940 """
941 Save host's MAC address
942 """
943 try:
You Wangdafb6e22018-01-22 17:01:00 -0800944 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800945 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
946 self.handle.sendline( cmd )
947 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700948 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800949 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
Jon Hall43060f62020-06-23 13:13:33 -0700950 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800951 if match:
952 return match.group()
953 else:
954 # the command will have an exception if iface doesn't exist
955 return None
956 except pexpect.TIMEOUT:
957 main.log.exception( self.name + ": Command timed out" )
958 return None
959 except pexpect.EOF:
960 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700961 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800962 except Exception:
963 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700964 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800965
alisone14d7b02016-07-06 10:31:51 -0700966 def getIp( self, ifaceName=None, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800967 """
968 Save host's IP address
969
970 Returns the IP of the first interface that is not a loopback device.
971 If no IP could be found then it will return 0.0.0.0.
alisone14d7b02016-07-06 10:31:51 -0700972
973 If IPv6 is equal to True, returns IPv6 of the first interface that is not a loopback device.
974 If no IPv6 could be found then it will return :: .
975
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800976 """
977 def getIPofInterface( ifaceName ):
978 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
alisone14d7b02016-07-06 10:31:51 -0700979 if IPv6:
980 cmd = 'get_if_raw_addr6("' + str( ifaceName ) + '")'
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800981 self.handle.sendline( cmd )
982 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700983 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800984
985 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 -0700986 if IPv6:
987 pattern = r'(\\x([0-9]|[a-f]|[A-F])([0-9]|[a-f]|[A-F])){16}'
Jon Hall43060f62020-06-23 13:13:33 -0700988 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800989 if match:
990 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700991 if IPv6 is not True:
alisone14d7b02016-07-06 10:31:51 -0700992 if match.group() == '0.0.0.0':
993 main.log.warn( 'iface {0} has no IPv4 address'.format( ifaceName ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800994 return match.group()
995 else:
996 return None
997 try:
998 if not ifaceName:
999 # Get list of interfaces
1000 ifList = self.getIfList()
alisone14d7b02016-07-06 10:31:51 -07001001 if IPv6:
1002 for ifaceName in ifList:
1003 if ifaceName == "lo":
1004 continue
1005 ip = getIPofInterface( ifaceName )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001006 if ip is not None:
1007 newip = ip
alisone14d7b02016-07-06 10:31:51 -07001008 tmp = newip.split( "\\x" )
1009 ip = ""
1010 counter = 0
1011 for i in tmp:
1012 if i != "":
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001013 counter = counter + 1
alisone14d7b02016-07-06 10:31:51 -07001014 if counter % 2 == 0 and counter < 16:
1015 ip = ip + i + ":"
1016 else:
1017 ip = ip + i
1018 return ip
1019 return "::"
1020 else:
1021 for ifaceName in ifList:
1022 if ifaceName == "lo":
1023 continue
1024 ip = getIPofInterface( ifaceName )
1025 if ip != "0.0.0.0":
1026 return ip
1027 return "0.0.0.0"
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001028 else:
1029 return getIPofInterface( ifaceName )
1030
1031 except pexpect.TIMEOUT:
1032 main.log.exception( self.name + ": Command timed out" )
1033 return None
1034 except pexpect.EOF:
1035 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001036 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001037 except Exception:
1038 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001039 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001040
Jon Hall43060f62020-06-23 13:13:33 -07001041 def addRoute( self, network, gateway, interface=None ):
1042 """
1043 Add a route to the current scapy session
1044 """
1045 main.log.info( self.name + ": Adding route to scapy session; %s via %s out of interface %s" % ( network, gateway, interface ) )
1046 if gateway is None:
1047 main.log.error( self.name + ": Gateway is None, cannot set route" )
1048 return main.FALSE
Jon Hall06fd0df2021-01-25 15:50:06 -08001049 if network is None or "None" in network:
1050 main.log.error( self.name + ": Network is None, cannot set route" )
1051 return main.FALSE
Jon Hall43060f62020-06-23 13:13:33 -07001052 try:
1053 cmdStr = 'conf.route.add( net="%s", gw="%s"' % ( network, gateway )
1054 if interface:
1055 cmdStr += ', dev="%s"' % interface
1056 cmdStr += ')'
1057 self.handle.sendline( cmdStr )
1058 self.handle.expect( self.scapyPrompt )
1059 response = self.cleanOutput( self.handle.before )
1060 if "Traceback" in response:
1061 main.log.error( self.name + ": Error in adding route to scappy session" )
1062 main.log.debug( response )
1063 return main.FALSE
1064 return main.TRUE
1065 except pexpect.TIMEOUT:
1066 main.log.exception( self.name + ": Command timed out" )
1067 return None
1068 except pexpect.EOF:
1069 main.log.exception( self.name + ": connection closed." )
1070 main.cleanAndExit()
1071 except Exception:
1072 main.log.exception( self.name + ": Uncaught exception!" )
1073 main.cleanAndExit()
1074
1075 def addRoutes( self ):
1076 """
1077 Add any routes configured for the host
1078 """
1079 returnValues = []
1080 for route in self.routes:
1081 gw = route.get( 'gw' )
1082 iface = route.get( 'interface' )
1083 returnValues .append( self.addRoute( "%s/%s" % ( route.get( 'network' ), route.get( 'netmask' ) ),
1084 gw if gw else main.Cluster.active(0).ipAddress,
1085 interface=iface if iface else self.interfaces[ 0 ].get( 'name' ) ) )
1086 return returnValues
1087
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001088 def getIfList( self ):
1089 """
1090 Return List of Interfaces
1091 """
1092 try:
1093 self.handle.sendline( 'get_if_list()' )
1094 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001095 response = self.cleanOutput( self.handle.before )
1096 ifList = response.split( '\r\n' )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001097 ifList = ifList[ 1 ].replace( "'", "" )[ 1:-1 ].split( ', ' )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001098 return ifList
1099
1100 except pexpect.TIMEOUT:
1101 main.log.exception( self.name + ": Command timed out" )
1102 return None
1103 except pexpect.EOF:
1104 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001105 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001106 except Exception:
1107 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001108 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001109
1110if __name__ != "__main__":
1111 sys.modules[ __name__ ] = ScapyCliDriver()