blob: d340d5c467f5a8fb53f84914cd19356127dc2298 [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
43 self.home = None
44 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 = ">>>"
49
50 def connect( self, **connectargs ):
51 """
52 Here the main is the TestON instance after creating
53 all the log handles."""
54 try:
55 for key in connectargs:
56 vars( self )[ key ] = connectargs[ key ]
You Wangdafb6e22018-01-22 17:01:00 -080057 self.home = self.options[ 'home' ] if 'home' in self.options.keys() else "~/"
Jeremy Songster1f39bf02016-01-20 17:17:25 -080058 self.name = self.options[ 'name' ]
You Wangdafb6e22018-01-22 17:01:00 -080059 self.ifaceName = self.options[ 'ifaceName' ] if 'ifaceName' in self.options.keys() else self.name + "-eth0"
Jon Hall43060f62020-06-23 13:13:33 -070060
61 # Parse route config
62 self.routes = []
63 routes = self.options.get( 'routes' )
64 if routes:
65 for route in routes:
66 route = routes[ route ]
67 iface = route.get( 'interface' )
68 if not iface:
69 iface = None
70 self.routes.append( { 'network': route[ 'network' ],
71 'netmask': route[ 'netmask' ],
72 'gw': route.get( 'gw' ),
73 'interface': iface } )
Jeremy Songster1f39bf02016-01-20 17:17:25 -080074 try:
75 if os.getenv( str( self.ip_address ) ) is not None:
76 self.ip_address = os.getenv( str( self.ip_address ) )
77 else:
78 main.log.info( self.name +
79 ": Trying to connect to " +
80 self.ip_address )
81
82 except KeyError:
Jon Hall43060f62020-06-23 13:13:33 -070083 main.log.info( self.name + ": Invalid host name," +
Jeremy Songster1f39bf02016-01-20 17:17:25 -080084 " connecting to local host instead" )
85 self.ip_address = 'localhost'
86 except Exception as inst:
Jon Hall43060f62020-06-23 13:13:33 -070087 main.log.error( self.name + ": Uncaught exception: " + str( inst ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -080088
89 self.handle = super(
90 ScapyCliDriver,
91 self ).connect(
92 user_name=self.user_name,
93 ip_address=self.ip_address,
94 port=None,
95 pwd=self.pwd )
96
97 if self.handle:
Jon Hall43060f62020-06-23 13:13:33 -070098 main.log.info( self.name + ": Connection successful to the host " +
Jeremy Songster1f39bf02016-01-20 17:17:25 -080099 self.user_name +
100 "@" +
101 self.ip_address )
You Wang4cc61912018-08-28 10:10:58 -0700102 return self.handle
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800103 else:
104 main.log.error( "Connection failed to the host " +
105 self.user_name +
106 "@" +
107 self.ip_address )
108 main.log.error( "Failed to connect to the Mininet Host" )
109 return main.FALSE
110 except pexpect.EOF:
111 main.log.error( self.name + ": EOF exception found" )
112 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -0700113 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800114 except Exception:
115 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700116 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800117
118 def disconnect( self ):
119 """
120 Called at the end of the test to stop the scapy component and
121 disconnect the handle.
122 """
Jon Hall43060f62020-06-23 13:13:33 -0700123 main.log.debug( self.name + ": Disconnecting" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800124 response = main.TRUE
You Wangdafb6e22018-01-22 17:01:00 -0800125 try:
126 if self.handle:
127 self.handle.sendline( "exit" )
128 self.handle.expect( "closed" )
129 except pexpect.EOF:
130 main.log.error( self.name + ": EOF exception found" )
131 main.log.error( self.name + ": " + self.handle.before )
132 except Exception:
133 main.log.exception( self.name + ": Connection failed to the host" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800134 response = main.FALSE
135 return response
136
Jon Hall43060f62020-06-23 13:13:33 -0700137 def startScapy( self, mplsPath="", ifaceName=None ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800138 """
139 Start the Scapy cli
140 optional:
141 mplsPath - The path where the MPLS class is located
142 NOTE: This can be a relative path from the user's home dir
Jon Hall43060f62020-06-23 13:13:33 -0700143 ifaceName - the name of the default interface to use.
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800144 """
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700145 mplsLines = [ 'import imp',
146 'imp.load_source( "mplsClass", "{}mplsClass.py" )'.format( mplsPath ),
147 'from mplsClass import MPLS',
148 'bind_layers(Ether, MPLS, type = 0x8847)',
149 'bind_layers(MPLS, MPLS, bottom_of_label_stack = 0)',
150 'bind_layers(MPLS, IP)' ]
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800151
152 try:
Jon Hall43060f62020-06-23 13:13:33 -0700153 main.log.debug( self.name + ": Starting scapy" )
You Wang4cc61912018-08-28 10:10:58 -0700154 self.handle.sendline( "sudo scapy" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800155 self.handle.expect( self.scapyPrompt )
156 self.handle.sendline( "conf.color_theme = NoTheme()" )
157 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700158 response = self.cleanOutput( self.handle.before )
159 self.handle.sendline( "conf.fancy_prompt = False" )
160 self.handle.expect( self.scapyPrompt )
161 response = self.cleanOutput( self.handle.before )
162 self.handle.sendline( "conf.interactive = False" )
163 self.handle.expect( "interactive" )
164 self.handle.expect( self.scapyPrompt )
165 response = self.cleanOutput( self.handle.before )
166 self.handle.sendline( "" )
167 self.handle.expect( self.scapyPrompt )
168 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800169 if mplsPath:
Jon Hall43060f62020-06-23 13:13:33 -0700170 main.log.debug( self.name + ": Adding MPLS class" )
171 main.log.debug( self.name + ": MPLS class path: " + mplsPath )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800172 for line in mplsLines:
Jon Hall43060f62020-06-23 13:13:33 -0700173 main.log.debug( self.name + ": sending line: " + line )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800174 self.handle.sendline( line )
175 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700176 response = self.cleanOutput( self.handle.before )
177
178 # Set interface
179 if ifaceName:
180 self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
181 self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800182 return main.TRUE
183 except pexpect.TIMEOUT:
184 main.log.exception( self.name + ": Command timed out" )
185 return main.FALSE
186 except pexpect.EOF:
187 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700188 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800189 except Exception:
190 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700191 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800192
193 def stopScapy( self ):
194 """
195 Exit the Scapy cli
196 """
197 try:
Jon Hall43060f62020-06-23 13:13:33 -0700198 main.log.debug( self.name + ": Stopping scapy" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800199 self.handle.sendline( "exit()" )
200 self.handle.expect( self.hostPrompt )
201 return main.TRUE
202 except pexpect.TIMEOUT:
203 main.log.exception( self.name + ": Command timed out" )
204 return main.FALSE
205 except pexpect.EOF:
206 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700207 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800208 except Exception:
209 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700210 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800211
212 def buildEther( self, **kwargs ):
213 """
214 Build an Ethernet frame
215
216 Will create a frame class with the given options. If a field is
217 left blank it will default to the below value unless it is
218 overwritten by the next frame.
219 Default frame:
220 ###[ Ethernet ]###
221 dst= ff:ff:ff:ff:ff:ff
222 src= 00:00:00:00:00:00
223 type= 0x800
224
225 Returns main.TRUE or main.FALSE on error
226 """
227 try:
Jon Hall43060f62020-06-23 13:13:33 -0700228 main.log.debug( self.name + ": Building Ethernet Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800229 # Set the Ethernet frame
230 cmd = 'ether = Ether( '
231 options = []
232 for key, value in kwargs.iteritems():
233 if isinstance( value, str ):
234 value = '"' + value + '"'
235 options.append( str( key ) + "=" + str( value ) )
236 cmd += ", ".join( options )
237 cmd += ' )'
238 self.handle.sendline( cmd )
239 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700240 response = self.cleanOutput( self.handle.before )
241 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800242 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700243 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800244 return main.FALSE
245 self.handle.sendline( "packet = ether" )
246 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700247 response = self.cleanOutput( self.handle.before )
248 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800249 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700250 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800251 return main.FALSE
252 return main.TRUE
253 except pexpect.TIMEOUT:
254 main.log.exception( self.name + ": Command timed out" )
255 return main.FALSE
256 except pexpect.EOF:
257 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700258 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800259 except Exception:
260 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700261 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800262
263 def buildIP( self, **kwargs ):
264 """
265 Build an IP frame
266
267 Will create a frame class with the given options. If a field is
268 left blank it will default to the below value unless it is
269 overwritten by the next frame.
270 Default frame:
271 ###[ IP ]###
272 version= 4
273 ihl= None
274 tos= 0x0
275 len= None
276 id= 1
277 flags=
278 frag= 0
279 ttl= 64
280 proto= hopopt
281 chksum= None
282 src= 127.0.0.1
283 dst= 127.0.0.1
284 \options\
285
286 Returns main.TRUE or main.FALSE on error
287 """
288 try:
Jon Hall43060f62020-06-23 13:13:33 -0700289 main.log.debug( self.name + ": Building IP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800290 # Set the IP frame
291 cmd = 'ip = IP( '
292 options = []
293 for key, value in kwargs.iteritems():
294 if isinstance( value, str ):
295 value = '"' + value + '"'
296 options.append( str( key ) + "=" + str( value ) )
297 cmd += ", ".join( options )
298 cmd += ' )'
299 self.handle.sendline( cmd )
300 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700301 response = self.cleanOutput( self.handle.before )
302 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800303 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700304 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800305 return main.FALSE
306 self.handle.sendline( "packet = ether/ip" )
307 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700308 response = self.cleanOutput( self.handle.before )
309 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800310 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700311 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800312 return main.FALSE
313 return main.TRUE
314 except pexpect.TIMEOUT:
315 main.log.exception( self.name + ": Command timed out" )
316 return main.FALSE
317 except pexpect.EOF:
318 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700319 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800320 except Exception:
321 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700322 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800323
324 def buildIPv6( self, **kwargs ):
325 """
326 Build an IPv6 frame
327
328 Will create a frame class with the given options. If a field is
329 left blank it will default to the below value unless it is
330 overwritten by the next frame.
331 Default frame:
332 ###[ IPv6 ]###
333 version= 6
334 tc= 0
335 fl= 0
336 plen= None
337 nh= No Next Header
338 hlim= 64
339 src= ::1
340 dst= ::1
341
342 Returns main.TRUE or main.FALSE on error
343 """
344 try:
Jon Hall43060f62020-06-23 13:13:33 -0700345 main.log.debug( self.name + ": Building IPv6 Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800346 # Set the IPv6 frame
347 cmd = 'ipv6 = IPv6( '
348 options = []
349 for key, value in kwargs.iteritems():
350 if isinstance( value, str ):
351 value = '"' + value + '"'
352 options.append( str( key ) + "=" + str( value ) )
353 cmd += ", ".join( options )
354 cmd += ' )'
355 self.handle.sendline( cmd )
356 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700357 response = self.cleanOutput( self.handle.before )
358 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800359 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700360 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800361 return main.FALSE
362 self.handle.sendline( "packet = ether/ipv6" )
363 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700364 response = self.cleanOutput( self.handle.before )
365 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800366 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700367 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800368 return main.FALSE
369 return main.TRUE
370 except pexpect.TIMEOUT:
371 main.log.exception( self.name + ": Command timed out" )
372 return main.FALSE
373 except pexpect.EOF:
374 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700375 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800376 except Exception:
377 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700378 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800379
380 def buildTCP( self, ipVersion=4, **kwargs ):
381 """
382 Build an TCP frame
383
384 Will create a frame class with the given options. If a field is
385 left blank it will default to the below value unless it is
386 overwritten by the next frame.
387
388 NOTE: Some arguments require quotes around them. It's up to you to
389 know which ones and to add them yourself. Arguments with an asterisk
390 do not need quotes.
391
392 Options:
393 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
394 frame to use to encapsulate into
395 Default frame:
396 ###[ TCP ]###
397 sport= ftp_data *
398 dport= http *
399 seq= 0
400 ack= 0
401 dataofs= None
402 reserved= 0
403 flags= S
404 window= 8192
405 chksum= None
406 urgptr= 0
407 options= {}
408
409 Returns main.TRUE or main.FALSE on error
410 """
411 try:
Jon Hall43060f62020-06-23 13:13:33 -0700412 main.log.debug( self.name + ": Building TCP" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800413 # Set the TCP frame
414 cmd = 'tcp = TCP( '
415 options = []
416 for key, value in kwargs.iteritems():
417 options.append( str( key ) + "=" + str( value ) )
418 cmd += ", ".join( options )
419 cmd += ' )'
420 self.handle.sendline( cmd )
421 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700422 response = self.cleanOutput( self.handle.before )
423 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800424 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700425 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800426 return main.FALSE
427 if str( ipVersion ) is '4':
428 self.handle.sendline( "packet = ether/ip/tcp" )
429 elif str( ipVersion ) is '6':
430 self.handle.sendline( "packet = ether/ipv6/tcp" )
431 else:
432 main.log.error( "Unrecognized option for ipVersion, given " +
433 repr( ipVersion ) )
434 return main.FALSE
435 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700436 response = self.cleanOutput( self.handle.before )
437 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800438 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700439 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800440 return main.FALSE
441 return main.TRUE
442 except pexpect.TIMEOUT:
443 main.log.exception( self.name + ": Command timed out" )
444 return main.FALSE
445 except pexpect.EOF:
446 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700447 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800448 except Exception:
449 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700450 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800451
452 def buildUDP( self, ipVersion=4, **kwargs ):
453 """
454 Build an UDP frame
455
456 Will create a frame class with the given options. If a field is
457 left blank it will default to the below value unless it is
458 overwritten by the next frame.
459
460 NOTE: Some arguments require quotes around them. It's up to you to
461 know which ones and to add them yourself. Arguments with an asterisk
462 do not need quotes.
463
464 Options:
465 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
466 frame to use to encapsulate into
467 Default frame:
468 ###[ UDP ]###
469 sport= domain *
470 dport= domain *
471 len= None
472 chksum= None
473
474 Returns main.TRUE or main.FALSE on error
475 """
476 try:
Jon Hall43060f62020-06-23 13:13:33 -0700477 main.log.debug( self.name + ": Building UDP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800478 # Set the UDP frame
479 cmd = 'udp = UDP( '
480 options = []
481 for key, value in kwargs.iteritems():
482 options.append( str( key ) + "=" + str( value ) )
483 cmd += ", ".join( options )
484 cmd += ' )'
485 self.handle.sendline( cmd )
486 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700487 response = self.cleanOutput( self.handle.before )
488 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800489 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700490 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800491 return main.FALSE
492 if str( ipVersion ) is '4':
493 self.handle.sendline( "packet = ether/ip/udp" )
494 elif str( ipVersion ) is '6':
495 self.handle.sendline( "packet = ether/ipv6/udp" )
496 else:
497 main.log.error( "Unrecognized option for ipVersion, given " +
498 repr( ipVersion ) )
499 return main.FALSE
500 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700501 response = self.cleanOutput( self.handle.before )
502 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800503 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700504 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800505 return main.FALSE
506 return main.TRUE
507 except pexpect.TIMEOUT:
508 main.log.exception( self.name + ": Command timed out" )
509 return main.FALSE
510 except pexpect.EOF:
511 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700512 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800513 except Exception:
514 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700515 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800516
alisone14d7b02016-07-06 10:31:51 -0700517 def buildSCTP( self, ipVersion=4, **kwargs ):
518 """
519 Build an SCTP frame
520
521 Will create a frame class with the given options. If a field is
522 left blank it will default to the below value unless it is
523 overwritten by the next frame.
524
525 NOTE: Some arguments require quotes around them. It's up to you to
526 know which ones and to add them yourself. Arguments with an asterisk
527 do not need quotes.
528
529 Options:
530 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
531 frame to use to encapsulate into
532 Default frame:
533 ###[ SCTP ]###
534 sport= domain *
535 dport= domain *
536 tag = None
537 chksum = None
538
539 Returns main.TRUE or main.FALSE on error
540 """
541 try:
Jon Hall43060f62020-06-23 13:13:33 -0700542 main.log.debug( self.name + ": Building SCTP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700543 # Set the SCTP frame
544 cmd = 'sctp = SCTP( '
545 options = [ ]
546 for key, value in kwargs.iteritems( ):
547 options.append( str( key ) + "=" + str( value ) )
548 cmd += ", ".join( options )
549 cmd += ' )'
550 self.handle.sendline( cmd )
551 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700552 response = self.cleanOutput( self.handle.before )
553 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700554 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700555 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700556 return main.FALSE
557 if str( ipVersion ) is '4':
558 self.handle.sendline( "packet = ether/ip/sctp" )
559 elif str( ipVersion ) is '6':
560 self.handle.sendline( "packet = ether/ipv6/sctp" )
561 else:
562 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700563 repr( ipVersion ) )
alisone14d7b02016-07-06 10:31:51 -0700564 return main.FALSE
565 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700566 response = self.cleanOutput( self.handle.before )
567 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700568 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700569 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700570 return main.FALSE
571 return main.TRUE
572 except pexpect.TIMEOUT:
573 main.log.exception( self.name + ": Command timed out" )
574 return main.FALSE
575 except pexpect.EOF:
576 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700577 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700578 except Exception:
579 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700580 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700581
582 def buildARP( self, **kwargs ):
583 """
584 Build an ARP frame
585
586 Will create a frame class with the given options. If a field is
587 left blank it will default to the below value unless it is
588 overwritten by the next frame.
589
590 NOTE: Some arguments require quotes around them. It's up to you to
591 know which ones and to add them yourself. Arguments with an asterisk
592 do not need quotes.
593
594 Default frame:
595 ###[ ARP ]###
596 hwtype : XShortField = (1)
597 ptype : XShortEnumField = (2048)
598 hwlen : ByteField = (6)
599 plen : ByteField = (4)
600 op : ShortEnumField = (1)
601 hwsrc : ARPSourceMACField = (None)
602 psrc : SourceIPField = (None)
603 hwdst : MACField = ('00:00:00:00:00:00')
604 pdst : IPField = ('0.0.0.0')
605
606 Returns main.TRUE or main.FALSE on error
607 """
608 try:
Jon Hall43060f62020-06-23 13:13:33 -0700609 main.log.debug( self.name + ": Building ARP Frame" )
alisone14d7b02016-07-06 10:31:51 -0700610 # Set the ARP frame
611 cmd = 'arp = ARP( '
612 options = []
613 for key, value in kwargs.iteritems( ):
614 if isinstance( value, str ):
615 value = '"' + value + '"'
616 options.append( str( key ) + "=" + str( value ) )
617 cmd += ", ".join( options )
618 cmd += ' )'
619 self.handle.sendline( cmd )
620 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700621 response = self.cleanOutput( self.handle.before )
622 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700623 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700624 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700625 return main.FALSE
626 self.handle.sendline( "packet = ether/arp" )
627 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700628 response = self.cleanOutput( self.handle.before )
629 if "Traceback" in response:
alisone14d7b02016-07-06 10:31:51 -0700630 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700631 main.log.error( "Error in sending command: " + response )
alisone14d7b02016-07-06 10:31:51 -0700632 return main.FALSE
633 return main.TRUE
634 except pexpect.TIMEOUT:
635 main.log.exception( self.name + ": Command timed out" )
636 return main.FALSE
637 except pexpect.EOF:
638 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700639 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700640 except Exception:
641 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700642 main.cleanAndExit()
alisone14d7b02016-07-06 10:31:51 -0700643
644 def buildICMP( self, ipVersion=4, **kwargs ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800645 """
646 Build an ICMP frame
647
648 Will create a frame class with the given options. If a field is
649 left blank it will default to the below value unless it is
650 overwritten by the next frame.
651 Default frame:
652 ###[ ICMP ]###
653 type= echo-request
654 code= 0
655 chksum= None
656 id= 0x0
657 seq= 0x0
658
alisone14d7b02016-07-06 10:31:51 -0700659 Options:
660 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
661 frame to use to encapsulate into
662
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800663 Returns main.TRUE or main.FALSE on error
664 """
665 try:
Jon Hall43060f62020-06-23 13:13:33 -0700666 main.log.debug( self.name + ": Building ICMP Frame" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800667 # Set the ICMP frame
alisone14d7b02016-07-06 10:31:51 -0700668 if str( ipVersion ) is '4':
669 cmd = 'icmp = ICMP( '
670 elif str( ipVersion ) is '6':
671 cmd = 'icmp6 = ICMPv6EchoReply( '
672 else:
673 main.log.error( "Unrecognized option for ipVersion, given " +
674 repr( ipVersion ) )
675 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800676 options = []
alisone14d7b02016-07-06 10:31:51 -0700677 for key, value in kwargs.iteritems( ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800678 if isinstance( value, str ):
679 value = '"' + value + '"'
680 options.append( str( key ) + "=" + str( value ) )
681 cmd += ", ".join( options )
682 cmd += ' )'
683 self.handle.sendline( cmd )
684 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700685 response = self.cleanOutput( self.handle.before )
686 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800687 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700688 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800689 return main.FALSE
alisone14d7b02016-07-06 10:31:51 -0700690
691 if str( ipVersion ) is '4':
692 self.handle.sendline( "packet = ether/ip/icmp" )
693 elif str( ipVersion ) is '6':
694 self.handle.sendline( "packet = ether/ipv6/icmp6" )
695 else:
696 main.log.error( "Unrecognized option for ipVersion, given " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700697 repr( ipVersion ) )
alisone14d7b02016-07-06 10:31:51 -0700698 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800699 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700700 response = self.cleanOutput( self.handle.before )
701 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800702 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700703 main.log.error( "Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800704 return main.FALSE
705 return main.TRUE
706 except pexpect.TIMEOUT:
707 main.log.exception( self.name + ": Command timed out" )
708 return main.FALSE
709 except pexpect.EOF:
710 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700711 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800712 except Exception:
713 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700714 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800715
Jon Hall43060f62020-06-23 13:13:33 -0700716 def clearBuffer( self, debug=False ):
717 """
718 Keep reading from buffer until its empty
719 Everything seems to be printed twice in newer versions of
720 scapy, even when turning off fancy output
721 """
722 i = 0
723 response = ''
724 while True:
725 try:
726 i += 1
727 # clear buffer
728 if debug:
729 main.log.warn( "%s expect loop iteration" % i )
Jon Hall627b1572020-12-01 12:01:15 -0800730 self.handle.expect( self.scapyPrompt, timeout=5 )
Jon Hall43060f62020-06-23 13:13:33 -0700731 response += self.cleanOutput( self.handle.before, debug )
732 except pexpect.TIMEOUT:
733 return response
734
735 def sendPacket( self, iface=None, packet=None, timeout=1, debug=True ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800736 """
737 Send a packet with either the given scapy packet command, or use the
738 packet saved in the variable 'packet'.
739
740 Examples of a valid string for packet:
741
742 Simple IP packet
743 packet='Ether(dst="a6:d9:26:df:1d:4b")/IP(dst="10.0.0.2")'
744
745 A Ping with two vlan tags
746 packet='Ether(dst='ff:ff:ff:ff:ff:ff')/Dot1Q(vlan=1)/Dot1Q(vlan=10)/
747 IP(dst='255.255.255.255', src='192.168.0.1')/ICMP()'
748
749 Returns main.TRUE or main.FALSE on error
750 """
751 try:
Jon Hall43060f62020-06-23 13:13:33 -0700752 main.log.debug( self.name + ": Sending Packet" )
753 if debug:
754 self.handle.sendline( "packet.summary()" )
755 self.handle.expect( self.scapyPrompt )
756 self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800757 # TODO: add all params, or use kwargs
Jon Hall43060f62020-06-23 13:13:33 -0700758 sendCmd = 'sendp( '
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800759 if packet:
760 sendCmd += packet
761 else:
762 sendCmd += "packet"
763 if iface:
764 sendCmd += ", iface='{}'".format( iface )
765
Jon Hall43060f62020-06-23 13:13:33 -0700766 if debug:
767 sendCmd += ', return_packets=True).summary()' # show packet(s) sent
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800768 self.handle.sendline( sendCmd )
769 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700770 response = self.cleanOutput( self.handle.before )
771 main.log.debug( self.name + ": Send packet response: {}".format( response ) )
772 if "Traceback" in response:
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800773 # KeyError, SyntaxError, ...
Jon Hall43060f62020-06-23 13:13:33 -0700774 main.log.error( self.name + ": Error in sending command: " + response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800775 return main.FALSE
776 # TODO: Check # of packets sent?
777 return main.TRUE
778 except pexpect.TIMEOUT:
779 main.log.exception( self.name + ": Command timed out" )
780 return main.FALSE
781 except pexpect.EOF:
782 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700783 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800784 except Exception:
785 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700786 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800787
788 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
789 """
790 Listen for packets using the given filters
791
792 Options:
793 ifaceName - the name of the interface to listen on. If none is given,
You Wangdafb6e22018-01-22 17:01:00 -0800794 defaults to self.ifaceName which is <host name>-eth0
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800795 pktFilter - A string in Berkeley Packet Filter (BPF) format which
796 specifies which packets to sniff
797 sniffCount - The number of matching packets to capture before returning
798
799 Returns main.TRUE or main.FALSE on error
800 """
801 try:
Jon Hall43060f62020-06-23 13:13:33 -0700802 main.log.info( self.name + ": Starting filter on interface %s" % ifaceName )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800803 # TODO: add all params, or use kwargs
You Wangdafb6e22018-01-22 17:01:00 -0800804 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800805 # Set interface
You Wangbd848ed2018-03-23 13:57:42 -0700806 self.handle.sendline( 'conf.iface = "' + ifaceName + '"' )
Jon Hall43060f62020-06-23 13:13:33 -0700807 self.handle.expect( ifaceName )
808 self.cleanOutput( self.handle.before + self.handle.after )
809 self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800810 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700811 response = self.handle.before + self.handle.after
812 self.cleanOutput( response )
813 cmd = 'pkts = sniff(count = %s, filter = "%s", prn=lambda p: p.summary() )' % ( sniffCount, pktFilter )
814 main.log.info( self.name + ": Starting filter on " + self.name + ' > ' + cmd )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800815 self.handle.sendline( cmd )
Jon Hall43060f62020-06-23 13:13:33 -0700816 response = self.clearBuffer()
817
You Wang3a5f74c2018-08-03 14:58:15 -0700818 # Make sure the sniff function didn't exit due to failures
819 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=3 )
Jon Hall43060f62020-06-23 13:13:33 -0700820 response = self.cleanOutput( self.handle.before + str( self.handle.after ) )
You Wang3a5f74c2018-08-03 14:58:15 -0700821 if i == 0:
822 # sniff exited
823 main.log.error( self.name + ": sniff function exited" )
Jon Hall43060f62020-06-23 13:13:33 -0700824 main.log.error( self.name + ": " + response )
You Wang3a5f74c2018-08-03 14:58:15 -0700825 return main.FALSE
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800826 return main.TRUE
827 except pexpect.TIMEOUT:
828 main.log.exception( self.name + ": Command timed out" )
829 return main.FALSE
830 except pexpect.EOF:
831 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700832 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800833 except Exception:
834 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700835 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800836
837 def checkFilter( self, timeout=10 ):
838 """
Jon Hall43060f62020-06-23 13:13:33 -0700839 Check if a filter is still running.
840 Returns:
841 main.TRUE if the filter stopped
842 main.FALSE if the filter is still running
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800843 """
844 try:
Jon Hall43060f62020-06-23 13:13:33 -0700845 main.log.debug( self.name + ": Checking Filter" )
846 self.handle.sendline( "" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800847 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=timeout )
Jon Hall43060f62020-06-23 13:13:33 -0700848 response = self.cleanOutput( self.handle.before + str( self.handle.after ), debug=True )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800849 if i == 0:
850 return main.TRUE
851 else:
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 killFilter( self ):
861 """
862 Kill a scapy filter
863 """
864 try:
Jon Hall43060f62020-06-23 13:13:33 -0700865 main.log.debug( self.name + ": Killing scapy filter" )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800866 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
867 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700868 output = self.cleanOutput( self.handle.before, debug=True )
869 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800870 except pexpect.TIMEOUT:
871 main.log.exception( self.name + ": Command timed out" )
872 return None
873 except pexpect.EOF:
874 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700875 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800876 except Exception:
877 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700878 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800879
You Wang548db382020-08-12 09:17:13 -0700880 def readPackets( self, detailed=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800881 """
882 Read all the packets captured by the previous filter
883 """
884 try:
Jon Hall43060f62020-06-23 13:13:33 -0700885 main.log.debug( self.name + ": Reading Packets" )
886 main.log.debug( self.name + ": Begin clear buffer" )
887 self.clearBuffer()
888 main.log.debug( self.name + ": end clear buffer" )
889
You Wang548db382020-08-12 09:17:13 -0700890 if detailed:
891 self.handle.sendline( "[p for p in pkts]")
892 else:
893 self.handle.sendline( "pkts.summary()")
Jon Hall43060f62020-06-23 13:13:33 -0700894 output = self.clearBuffer()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800895 except pexpect.TIMEOUT:
896 main.log.exception( self.name + ": Command timed out" )
897 return None
898 except pexpect.EOF:
899 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -0700900 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800901 except Exception:
902 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700903 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700904 return output
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800905
alisone14d7b02016-07-06 10:31:51 -0700906 def updateSelf( self, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800907 """
908 Updates local MAC and IP fields
909 """
910 self.hostMac = self.getMac()
alisone14d7b02016-07-06 10:31:51 -0700911 if IPv6:
912 self.hostIp = self.getIp( IPv6=True )
913 else:
914 self.hostIp = self.getIp()
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800915
916 def getMac( self, ifaceName=None ):
917 """
918 Save host's MAC address
919 """
920 try:
You Wangdafb6e22018-01-22 17:01:00 -0800921 ifaceName = str( ifaceName ) if ifaceName else self.ifaceName
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800922 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
923 self.handle.sendline( cmd )
924 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700925 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800926 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
Jon Hall43060f62020-06-23 13:13:33 -0700927 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800928 if match:
929 return match.group()
930 else:
931 # the command will have an exception if iface doesn't exist
932 return None
933 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
alisone14d7b02016-07-06 10:31:51 -0700943 def getIp( self, ifaceName=None, IPv6=False ):
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800944 """
945 Save host's IP address
946
947 Returns the IP of the first interface that is not a loopback device.
948 If no IP could be found then it will return 0.0.0.0.
alisone14d7b02016-07-06 10:31:51 -0700949
950 If IPv6 is equal to True, returns IPv6 of the first interface that is not a loopback device.
951 If no IPv6 could be found then it will return :: .
952
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800953 """
954 def getIPofInterface( ifaceName ):
955 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
alisone14d7b02016-07-06 10:31:51 -0700956 if IPv6:
957 cmd = 'get_if_raw_addr6("' + str( ifaceName ) + '")'
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800958 self.handle.sendline( cmd )
959 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -0700960 response = self.cleanOutput( self.handle.before )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800961
962 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 -0700963 if IPv6:
964 pattern = r'(\\x([0-9]|[a-f]|[A-F])([0-9]|[a-f]|[A-F])){16}'
Jon Hall43060f62020-06-23 13:13:33 -0700965 match = re.search( pattern, response )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800966 if match:
967 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700968 if IPv6 is not True:
alisone14d7b02016-07-06 10:31:51 -0700969 if match.group() == '0.0.0.0':
970 main.log.warn( 'iface {0} has no IPv4 address'.format( ifaceName ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800971 return match.group()
972 else:
973 return None
974 try:
975 if not ifaceName:
976 # Get list of interfaces
977 ifList = self.getIfList()
alisone14d7b02016-07-06 10:31:51 -0700978 if IPv6:
979 for ifaceName in ifList:
980 if ifaceName == "lo":
981 continue
982 ip = getIPofInterface( ifaceName )
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700983 if ip is not None:
984 newip = ip
alisone14d7b02016-07-06 10:31:51 -0700985 tmp = newip.split( "\\x" )
986 ip = ""
987 counter = 0
988 for i in tmp:
989 if i != "":
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700990 counter = counter + 1
alisone14d7b02016-07-06 10:31:51 -0700991 if counter % 2 == 0 and counter < 16:
992 ip = ip + i + ":"
993 else:
994 ip = ip + i
995 return ip
996 return "::"
997 else:
998 for ifaceName in ifList:
999 if ifaceName == "lo":
1000 continue
1001 ip = getIPofInterface( ifaceName )
1002 if ip != "0.0.0.0":
1003 return ip
1004 return "0.0.0.0"
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001005 else:
1006 return getIPofInterface( ifaceName )
1007
1008 except pexpect.TIMEOUT:
1009 main.log.exception( self.name + ": Command timed out" )
1010 return None
1011 except pexpect.EOF:
1012 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001013 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001014 except Exception:
1015 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001016 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001017
Jon Hall43060f62020-06-23 13:13:33 -07001018 def addRoute( self, network, gateway, interface=None ):
1019 """
1020 Add a route to the current scapy session
1021 """
1022 main.log.info( self.name + ": Adding route to scapy session; %s via %s out of interface %s" % ( network, gateway, interface ) )
1023 if gateway is None:
1024 main.log.error( self.name + ": Gateway is None, cannot set route" )
1025 return main.FALSE
1026 try:
1027 cmdStr = 'conf.route.add( net="%s", gw="%s"' % ( network, gateway )
1028 if interface:
1029 cmdStr += ', dev="%s"' % interface
1030 cmdStr += ')'
1031 self.handle.sendline( cmdStr )
1032 self.handle.expect( self.scapyPrompt )
1033 response = self.cleanOutput( self.handle.before )
1034 if "Traceback" in response:
1035 main.log.error( self.name + ": Error in adding route to scappy session" )
1036 main.log.debug( response )
1037 return main.FALSE
1038 return main.TRUE
1039 except pexpect.TIMEOUT:
1040 main.log.exception( self.name + ": Command timed out" )
1041 return None
1042 except pexpect.EOF:
1043 main.log.exception( self.name + ": connection closed." )
1044 main.cleanAndExit()
1045 except Exception:
1046 main.log.exception( self.name + ": Uncaught exception!" )
1047 main.cleanAndExit()
1048
1049 def addRoutes( self ):
1050 """
1051 Add any routes configured for the host
1052 """
1053 returnValues = []
1054 for route in self.routes:
1055 gw = route.get( 'gw' )
1056 iface = route.get( 'interface' )
1057 returnValues .append( self.addRoute( "%s/%s" % ( route.get( 'network' ), route.get( 'netmask' ) ),
1058 gw if gw else main.Cluster.active(0).ipAddress,
1059 interface=iface if iface else self.interfaces[ 0 ].get( 'name' ) ) )
1060 return returnValues
1061
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001062 def getIfList( self ):
1063 """
1064 Return List of Interfaces
1065 """
1066 try:
1067 self.handle.sendline( 'get_if_list()' )
1068 self.handle.expect( self.scapyPrompt )
Jon Hall43060f62020-06-23 13:13:33 -07001069 response = self.cleanOutput( self.handle.before )
1070 ifList = response.split( '\r\n' )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001071 ifList = ifList[ 1 ].replace( "'", "" )[ 1:-1 ].split( ', ' )
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001072 return ifList
1073
1074 except pexpect.TIMEOUT:
1075 main.log.exception( self.name + ": Command timed out" )
1076 return None
1077 except pexpect.EOF:
1078 main.log.exception( self.name + ": connection closed." )
Devin Lim44075962017-08-11 10:56:37 -07001079 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001080 except Exception:
1081 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001082 main.cleanAndExit()
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001083
1084if __name__ != "__main__":
1085 sys.modules[ __name__ ] = ScapyCliDriver()