blob: 456e565eebd6a6453a6cf1df3f839795fc4907cb [file] [log] [blame]
Jeremy Songster1f39bf02016-01-20 17:17:25 -08001#!/usr/bin/env python
2"""
32015-2016
Jeremy Songsterae01bba2016-07-11 15:39:17 -07004Modified 2016 by ON.Lab
5
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
30import types
31import os
32from drivers.common.cli.emulatordriver import Emulator
33
34
35class ScapyCliDriver( Emulator ):
36
37 """
38 ScapyCliDriver is the basic driver which will handle
39 the Scapy functions"""
40 def __init__( self ):
41 super( Emulator, self ).__init__()
42 self.handle = self
43 self.name = None
44 self.home = None
45 self.wrapped = sys.modules[ __name__ ]
46 self.flag = 0
47 # TODO: Refactor driver to use these everywhere
48 self.hostPrompt = "~#"
49 self.bashPrompt = "\$"
50 self.scapyPrompt = ">>>"
51
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 ]
59 self.home = "~/mininet"
60 self.name = self.options[ 'name' ]
61 for key in self.options:
62 if key == "home":
63 self.home = self.options[ 'home' ]
64 break
65 if self.home is None or self.home == "":
66 self.home = "~/mininet"
67
68 try:
69 if os.getenv( str( self.ip_address ) ) is not None:
70 self.ip_address = os.getenv( str( self.ip_address ) )
71 else:
72 main.log.info( self.name +
73 ": Trying to connect to " +
74 self.ip_address )
75
76 except KeyError:
77 main.log.info( "Invalid host name," +
78 " connecting to local host instead" )
79 self.ip_address = 'localhost'
80 except Exception as inst:
81 main.log.error( "Uncaught exception: " + str( inst ) )
82
83 self.handle = super(
84 ScapyCliDriver,
85 self ).connect(
86 user_name=self.user_name,
87 ip_address=self.ip_address,
88 port=None,
89 pwd=self.pwd )
90
91 if self.handle:
92 main.log.info( "Connection successful to the host " +
93 self.user_name +
94 "@" +
95 self.ip_address )
96 return main.TRUE
97 else:
98 main.log.error( "Connection failed to the host " +
99 self.user_name +
100 "@" +
101 self.ip_address )
102 main.log.error( "Failed to connect to the Mininet Host" )
103 return main.FALSE
104 except pexpect.EOF:
105 main.log.error( self.name + ": EOF exception found" )
106 main.log.error( self.name + ": " + self.handle.before )
107 main.cleanup()
108 main.exit()
109 except Exception:
110 main.log.exception( self.name + ": Uncaught exception!" )
111 main.cleanup()
112 main.exit()
113
114 def disconnect( self ):
115 """
116 Called at the end of the test to stop the scapy component and
117 disconnect the handle.
118 """
119 self.handle.sendline( '' )
120 i = self.handle.expect( [ 'mininet>', pexpect.EOF, pexpect.TIMEOUT ],
121 timeout=2 )
122 response = main.TRUE
123 if i == 0:
124 response = self.stopNet()
125 elif i == 1:
126 return main.TRUE
127 # print "Disconnecting Mininet"
128 if self.handle:
129 self.handle.sendline( "exit" )
130 self.handle.expect( "exit" )
131 self.handle.expect( "(.*)" )
132 else:
133 main.log.error( "Connection failed to the host" )
134 return response
135
136 def stopNet( self, fileName="", timeout=5 ):
137 """
138 Stops mininet.
139 Returns main.TRUE if the mininet successfully stops and
140 main.FALSE if the pexpect handle does not exist.
141
142 Will cleanup and exit the test if scapy fails to stop
143 """
144 main.log.info( self.name + ": Stopping scapy..." )
145 response = ''
146 if self.handle:
147 try:
148 self.handle.sendline( "" )
149 i = self.handle.expect( [ '>>>',
150 '\$',
151 pexpect.EOF,
152 pexpect.TIMEOUT ],
153 timeout )
154 if i == 0:
155 main.log.info( "Exiting scapy..." )
156 response = self.execute(
157 cmd="exit",
158 prompt="(.*)",
159 timeout=120 )
160 main.log.info( self.name + ": Stopped" )
161 response = main.TRUE
162
163 if i == 1:
164 main.log.info( " Mininet trying to exit while not " +
165 "in the mininet prompt" )
166 elif i == 2:
167 main.log.error( "Something went wrong exiting mininet" )
168 elif i == 3: # timeout
169 main.log.error( "Something went wrong exiting mininet " +
170 "TIMEOUT" )
171
172 if fileName:
173 self.handle.sendline( "" )
174 self.handle.expect( '\$' )
175 self.handle.sendline(
176 "sudo kill -9 \`ps -ef | grep \"" +
177 fileName +
178 "\" | grep -v grep | awk '{print $2}'\`" )
179 except pexpect.EOF:
180 main.log.error( self.name + ": EOF exception found" )
181 main.log.error( self.name + ": " + self.handle.before )
182 main.cleanup()
183 main.exit()
184 else:
185 main.log.error( self.name + ": Connection failed to the host" )
186 response = main.FALSE
187 return response
188
189 def createHostComponent( self, name ):
190 """
191 Creates a new mininet cli component with the same parameters as self.
192 This new component is intended to be used to login to the hosts created
193 by mininet.
194
195 Arguments:
196 name - The string of the name of this component. The new component
197 will be assigned to main.<name> .
198 In addition, main.<name>.name = str( name )
199 """
200 try:
201 # look to see if this component already exists
202 getattr( main, name )
203 except AttributeError:
204 # namespace is clear, creating component
205 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
206 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
207 main.componentInit( name )
208 except Exception:
209 main.log.exception( self.name + ": Uncaught exception!" )
210 main.cleanup()
211 main.exit()
212 else:
213 # namespace is not clear!
214 main.log.error( name + " component already exists!" )
215 main.cleanup()
216 main.exit()
217
218 def removeHostComponent( self, name ):
219 """
220 Remove host component
221 Arguments:
222 name - The string of the name of the component to delete.
223 """
224 try:
225 # Get host component
226 component = getattr( main, name )
227 except AttributeError:
228 main.log.error( "Component " + name + " does not exist." )
229 return main.FALSE
230 try:
231 # Disconnect from component
232 component.disconnect()
233 # Delete component
234 delattr( main, name )
235 # Delete component from ComponentDictionary
236 del( main.componentDictionary[name] )
237 return main.TRUE
238 except Exception:
239 main.log.exception( self.name + ": Uncaught exception!" )
240 main.cleanup()
241 main.exit()
242
243 def startHostCli( self, host=None ):
244 """
245 Use the mininet m utility to connect to the host's cli
246 """
247 # These are fields that can be used by scapy packets. Initialized to None
248 self.hostIp = None
249 self.hostMac = None
250 try:
251 if not host:
252 host = self.name
253 self.handle.sendline( self.home + "/util/m " + host )
254 self.handle.expect( self.hostPrompt )
255 return main.TRUE
256 except pexpect.TIMEOUT:
257 main.log.exception( self.name + ": Command timed out" )
258 return main.FALSE
259 except pexpect.EOF:
260 main.log.exception( self.name + ": connection closed." )
261 main.cleanup()
262 main.exit()
263 except Exception:
264 main.log.exception( self.name + ": Uncaught exception!" )
265 main.cleanup()
266 main.exit()
267
268 def startScapy( self, mplsPath="" ):
269 """
270 Start the Scapy cli
271 optional:
272 mplsPath - The path where the MPLS class is located
273 NOTE: This can be a relative path from the user's home dir
274 """
275 mplsLines = ['import imp',
276 'imp.load_source( "mplsClass", "{}mplsClass.py" )'.format(mplsPath),
277 'from mplsClass import MPLS',
278 'bind_layers(Ether, MPLS, type = 0x8847)',
279 'bind_layers(MPLS, MPLS, bottom_of_label_stack = 0)',
280 'bind_layers(MPLS, IP)']
281
282 try:
283 self.handle.sendline( "scapy" )
284 self.handle.expect( self.scapyPrompt )
285 self.handle.sendline( "conf.color_theme = NoTheme()" )
286 self.handle.expect( self.scapyPrompt )
287 if mplsPath:
288 main.log.info( "Adding MPLS class" )
289 main.log.info( "MPLS class path: " + mplsPath )
290 for line in mplsLines:
291 main.log.info( "sending line: " + line )
292 self.handle.sendline( line )
293 self.handle.expect( self.scapyPrompt )
294 return main.TRUE
295 except pexpect.TIMEOUT:
296 main.log.exception( self.name + ": Command timed out" )
297 return main.FALSE
298 except pexpect.EOF:
299 main.log.exception( self.name + ": connection closed." )
300 main.cleanup()
301 main.exit()
302 except Exception:
303 main.log.exception( self.name + ": Uncaught exception!" )
304 main.cleanup()
305 main.exit()
306
307 def stopScapy( self ):
308 """
309 Exit the Scapy cli
310 """
311 try:
312 self.handle.sendline( "exit()" )
313 self.handle.expect( self.hostPrompt )
314 return main.TRUE
315 except pexpect.TIMEOUT:
316 main.log.exception( self.name + ": Command timed out" )
317 return main.FALSE
318 except pexpect.EOF:
319 main.log.exception( self.name + ": connection closed." )
320 main.cleanup()
321 main.exit()
322 except Exception:
323 main.log.exception( self.name + ": Uncaught exception!" )
324 main.cleanup()
325 main.exit()
326
327 def buildEther( self, **kwargs ):
328 """
329 Build an Ethernet frame
330
331 Will create a frame class with the given options. If a field is
332 left blank it will default to the below value unless it is
333 overwritten by the next frame.
334 Default frame:
335 ###[ Ethernet ]###
336 dst= ff:ff:ff:ff:ff:ff
337 src= 00:00:00:00:00:00
338 type= 0x800
339
340 Returns main.TRUE or main.FALSE on error
341 """
342 try:
343 # Set the Ethernet frame
344 cmd = 'ether = Ether( '
345 options = []
346 for key, value in kwargs.iteritems():
347 if isinstance( value, str ):
348 value = '"' + value + '"'
349 options.append( str( key ) + "=" + str( value ) )
350 cmd += ", ".join( options )
351 cmd += ' )'
352 self.handle.sendline( cmd )
353 self.handle.expect( self.scapyPrompt )
354 if "Traceback" in self.handle.before:
355 # KeyError, SyntaxError, ...
356 main.log.error( "Error in sending command: " + self.handle.before )
357 return main.FALSE
358 self.handle.sendline( "packet = ether" )
359 self.handle.expect( self.scapyPrompt )
360 if "Traceback" in self.handle.before:
361 # KeyError, SyntaxError, ...
362 main.log.error( "Error in sending command: " + self.handle.before )
363 return main.FALSE
364 return main.TRUE
365 except pexpect.TIMEOUT:
366 main.log.exception( self.name + ": Command timed out" )
367 return main.FALSE
368 except pexpect.EOF:
369 main.log.exception( self.name + ": connection closed." )
370 main.cleanup()
371 main.exit()
372 except Exception:
373 main.log.exception( self.name + ": Uncaught exception!" )
374 main.cleanup()
375 main.exit()
376
377 def buildIP( self, **kwargs ):
378 """
379 Build an IP frame
380
381 Will create a frame class with the given options. If a field is
382 left blank it will default to the below value unless it is
383 overwritten by the next frame.
384 Default frame:
385 ###[ IP ]###
386 version= 4
387 ihl= None
388 tos= 0x0
389 len= None
390 id= 1
391 flags=
392 frag= 0
393 ttl= 64
394 proto= hopopt
395 chksum= None
396 src= 127.0.0.1
397 dst= 127.0.0.1
398 \options\
399
400 Returns main.TRUE or main.FALSE on error
401 """
402 try:
403 # Set the IP frame
404 cmd = 'ip = IP( '
405 options = []
406 for key, value in kwargs.iteritems():
407 if isinstance( value, str ):
408 value = '"' + value + '"'
409 options.append( str( key ) + "=" + str( value ) )
410 cmd += ", ".join( options )
411 cmd += ' )'
412 self.handle.sendline( cmd )
413 self.handle.expect( self.scapyPrompt )
414 if "Traceback" in self.handle.before:
415 # KeyError, SyntaxError, ...
416 main.log.error( "Error in sending command: " + self.handle.before )
417 return main.FALSE
418 self.handle.sendline( "packet = ether/ip" )
419 self.handle.expect( self.scapyPrompt )
420 if "Traceback" in self.handle.before:
421 # KeyError, SyntaxError, ...
422 main.log.error( "Error in sending command: " + self.handle.before )
423 return main.FALSE
424 return main.TRUE
425 except pexpect.TIMEOUT:
426 main.log.exception( self.name + ": Command timed out" )
427 return main.FALSE
428 except pexpect.EOF:
429 main.log.exception( self.name + ": connection closed." )
430 main.cleanup()
431 main.exit()
432 except Exception:
433 main.log.exception( self.name + ": Uncaught exception!" )
434 main.cleanup()
435 main.exit()
436
437 def buildIPv6( self, **kwargs ):
438 """
439 Build an IPv6 frame
440
441 Will create a frame class with the given options. If a field is
442 left blank it will default to the below value unless it is
443 overwritten by the next frame.
444 Default frame:
445 ###[ IPv6 ]###
446 version= 6
447 tc= 0
448 fl= 0
449 plen= None
450 nh= No Next Header
451 hlim= 64
452 src= ::1
453 dst= ::1
454
455 Returns main.TRUE or main.FALSE on error
456 """
457 try:
458 # Set the IPv6 frame
459 cmd = 'ipv6 = IPv6( '
460 options = []
461 for key, value in kwargs.iteritems():
462 if isinstance( value, str ):
463 value = '"' + value + '"'
464 options.append( str( key ) + "=" + str( value ) )
465 cmd += ", ".join( options )
466 cmd += ' )'
467 self.handle.sendline( cmd )
468 self.handle.expect( self.scapyPrompt )
469 if "Traceback" in self.handle.before:
470 # KeyError, SyntaxError, ...
471 main.log.error( "Error in sending command: " + self.handle.before )
472 return main.FALSE
473 self.handle.sendline( "packet = ether/ipv6" )
474 self.handle.expect( self.scapyPrompt )
475 if "Traceback" in self.handle.before:
476 # KeyError, SyntaxError, ...
477 main.log.error( "Error in sending command: " + self.handle.before )
478 return main.FALSE
479 return main.TRUE
480 except pexpect.TIMEOUT:
481 main.log.exception( self.name + ": Command timed out" )
482 return main.FALSE
483 except pexpect.EOF:
484 main.log.exception( self.name + ": connection closed." )
485 main.cleanup()
486 main.exit()
487 except Exception:
488 main.log.exception( self.name + ": Uncaught exception!" )
489 main.cleanup()
490 main.exit()
491
492 def buildTCP( self, ipVersion=4, **kwargs ):
493 """
494 Build an TCP frame
495
496 Will create a frame class with the given options. If a field is
497 left blank it will default to the below value unless it is
498 overwritten by the next frame.
499
500 NOTE: Some arguments require quotes around them. It's up to you to
501 know which ones and to add them yourself. Arguments with an asterisk
502 do not need quotes.
503
504 Options:
505 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
506 frame to use to encapsulate into
507 Default frame:
508 ###[ TCP ]###
509 sport= ftp_data *
510 dport= http *
511 seq= 0
512 ack= 0
513 dataofs= None
514 reserved= 0
515 flags= S
516 window= 8192
517 chksum= None
518 urgptr= 0
519 options= {}
520
521 Returns main.TRUE or main.FALSE on error
522 """
523 try:
524 # Set the TCP frame
525 cmd = 'tcp = TCP( '
526 options = []
527 for key, value in kwargs.iteritems():
528 options.append( str( key ) + "=" + str( value ) )
529 cmd += ", ".join( options )
530 cmd += ' )'
531 self.handle.sendline( cmd )
532 self.handle.expect( self.scapyPrompt )
533 if "Traceback" in self.handle.before:
534 # KeyError, SyntaxError, ...
535 main.log.error( "Error in sending command: " + self.handle.before )
536 return main.FALSE
537 if str( ipVersion ) is '4':
538 self.handle.sendline( "packet = ether/ip/tcp" )
539 elif str( ipVersion ) is '6':
540 self.handle.sendline( "packet = ether/ipv6/tcp" )
541 else:
542 main.log.error( "Unrecognized option for ipVersion, given " +
543 repr( ipVersion ) )
544 return main.FALSE
545 self.handle.expect( self.scapyPrompt )
546 if "Traceback" in self.handle.before:
547 # KeyError, SyntaxError, ...
548 main.log.error( "Error in sending command: " + self.handle.before )
549 return main.FALSE
550 return main.TRUE
551 except pexpect.TIMEOUT:
552 main.log.exception( self.name + ": Command timed out" )
553 return main.FALSE
554 except pexpect.EOF:
555 main.log.exception( self.name + ": connection closed." )
556 main.cleanup()
557 main.exit()
558 except Exception:
559 main.log.exception( self.name + ": Uncaught exception!" )
560 main.cleanup()
561 main.exit()
562
563 def buildUDP( self, ipVersion=4, **kwargs ):
564 """
565 Build an UDP frame
566
567 Will create a frame class with the given options. If a field is
568 left blank it will default to the below value unless it is
569 overwritten by the next frame.
570
571 NOTE: Some arguments require quotes around them. It's up to you to
572 know which ones and to add them yourself. Arguments with an asterisk
573 do not need quotes.
574
575 Options:
576 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
577 frame to use to encapsulate into
578 Default frame:
579 ###[ UDP ]###
580 sport= domain *
581 dport= domain *
582 len= None
583 chksum= None
584
585 Returns main.TRUE or main.FALSE on error
586 """
587 try:
588 # Set the UDP frame
589 cmd = 'udp = UDP( '
590 options = []
591 for key, value in kwargs.iteritems():
592 options.append( str( key ) + "=" + str( value ) )
593 cmd += ", ".join( options )
594 cmd += ' )'
595 self.handle.sendline( cmd )
596 self.handle.expect( self.scapyPrompt )
597 if "Traceback" in self.handle.before:
598 # KeyError, SyntaxError, ...
599 main.log.error( "Error in sending command: " + self.handle.before )
600 return main.FALSE
601 if str( ipVersion ) is '4':
602 self.handle.sendline( "packet = ether/ip/udp" )
603 elif str( ipVersion ) is '6':
604 self.handle.sendline( "packet = ether/ipv6/udp" )
605 else:
606 main.log.error( "Unrecognized option for ipVersion, given " +
607 repr( ipVersion ) )
608 return main.FALSE
609 self.handle.expect( self.scapyPrompt )
610 if "Traceback" in self.handle.before:
611 # KeyError, SyntaxError, ...
612 main.log.error( "Error in sending command: " + self.handle.before )
613 return main.FALSE
614 return main.TRUE
615 except pexpect.TIMEOUT:
616 main.log.exception( self.name + ": Command timed out" )
617 return main.FALSE
618 except pexpect.EOF:
619 main.log.exception( self.name + ": connection closed." )
620 main.cleanup()
621 main.exit()
622 except Exception:
623 main.log.exception( self.name + ": Uncaught exception!" )
624 main.cleanup()
625 main.exit()
626
627 def buildICMP( self, **kwargs ):
628 """
629 Build an ICMP frame
630
631 Will create a frame class with the given options. If a field is
632 left blank it will default to the below value unless it is
633 overwritten by the next frame.
634 Default frame:
635 ###[ ICMP ]###
636 type= echo-request
637 code= 0
638 chksum= None
639 id= 0x0
640 seq= 0x0
641
642 Returns main.TRUE or main.FALSE on error
643 """
644 try:
645 # Set the ICMP frame
646 cmd = 'icmp = ICMP( '
647 options = []
648 for key, value in kwargs.iteritems():
649 if isinstance( value, str ):
650 value = '"' + value + '"'
651 options.append( str( key ) + "=" + str( value ) )
652 cmd += ", ".join( options )
653 cmd += ' )'
654 self.handle.sendline( cmd )
655 self.handle.expect( self.scapyPrompt )
656 if "Traceback" in self.handle.before:
657 # KeyError, SyntaxError, ...
658 main.log.error( "Error in sending command: " + self.handle.before )
659 return main.FALSE
660 self.handle.sendline( "packet = ether/ip/icmp" )
661 self.handle.expect( self.scapyPrompt )
662 if "Traceback" in self.handle.before:
663 # KeyError, SyntaxError, ...
664 main.log.error( "Error in sending command: " + self.handle.before )
665 return main.FALSE
666 return main.TRUE
667 except pexpect.TIMEOUT:
668 main.log.exception( self.name + ": Command timed out" )
669 return main.FALSE
670 except pexpect.EOF:
671 main.log.exception( self.name + ": connection closed." )
672 main.cleanup()
673 main.exit()
674 except Exception:
675 main.log.exception( self.name + ": Uncaught exception!" )
676 main.cleanup()
677 main.exit()
678
679 def sendPacket( self, iface=None, packet=None, timeout=1 ):
680 """
681 Send a packet with either the given scapy packet command, or use the
682 packet saved in the variable 'packet'.
683
684 Examples of a valid string for packet:
685
686 Simple IP packet
687 packet='Ether(dst="a6:d9:26:df:1d:4b")/IP(dst="10.0.0.2")'
688
689 A Ping with two vlan tags
690 packet='Ether(dst='ff:ff:ff:ff:ff:ff')/Dot1Q(vlan=1)/Dot1Q(vlan=10)/
691 IP(dst='255.255.255.255', src='192.168.0.1')/ICMP()'
692
693 Returns main.TRUE or main.FALSE on error
694 """
695 try:
696 # TODO: add all params, or use kwargs
697 sendCmd = 'srp( '
698 if packet:
699 sendCmd += packet
700 else:
701 sendCmd += "packet"
702 if iface:
703 sendCmd += ", iface='{}'".format( iface )
704
705 sendCmd += ', timeout=' + str( timeout ) + ')'
706 self.handle.sendline( sendCmd )
707 self.handle.expect( self.scapyPrompt )
Jon Halla510a8a2016-05-04 15:09:28 -0700708 # main.log.warn( "Send packet response: {}".format( self.handle.before ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800709 if "Traceback" in self.handle.before:
710 # KeyError, SyntaxError, ...
711 main.log.error( "Error in sending command: " + self.handle.before )
712 return main.FALSE
713 # TODO: Check # of packets sent?
714 return main.TRUE
715 except pexpect.TIMEOUT:
716 main.log.exception( self.name + ": Command timed out" )
717 return main.FALSE
718 except pexpect.EOF:
719 main.log.exception( self.name + ": connection closed." )
720 main.cleanup()
721 main.exit()
722 except Exception:
723 main.log.exception( self.name + ": Uncaught exception!" )
724 main.cleanup()
725 main.exit()
726
727 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
728 """
729 Listen for packets using the given filters
730
731 Options:
732 ifaceName - the name of the interface to listen on. If none is given,
733 defaults to <host name>-eth0
734 pktFilter - A string in Berkeley Packet Filter (BPF) format which
735 specifies which packets to sniff
736 sniffCount - The number of matching packets to capture before returning
737
738 Returns main.TRUE or main.FALSE on error
739 """
740 try:
741 # TODO: add all params, or use kwargs
742 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
743 # Set interface
744 self.handle.sendline( ' conf.iface = "' + ifaceName + '"' )
745 self.handle.expect( self.scapyPrompt )
746 cmd = 'pkt = sniff(count = ' + str( sniffCount ) +\
747 ', filter = "' + str( pktFilter ) + '")'
Jon Halla510a8a2016-05-04 15:09:28 -0700748 main.log.info( "Filter on " + self.name + ' > ' + cmd )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800749 self.handle.sendline( cmd )
750 self.handle.expect( '"\)\r\n' )
751 # TODO: parse this?
752 return main.TRUE
753 except pexpect.TIMEOUT:
754 main.log.exception( self.name + ": Command timed out" )
755 return main.FALSE
756 except pexpect.EOF:
757 main.log.exception( self.name + ": connection closed." )
758 main.cleanup()
759 main.exit()
760 except Exception:
761 main.log.exception( self.name + ": Uncaught exception!" )
762 main.cleanup()
763 main.exit()
764
765 def checkFilter( self, timeout=10 ):
766 """
767 Check that a filter returned and returns the reponse
768 """
769 try:
770 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=timeout )
771 if i == 0:
772 return main.TRUE
773 else:
774 return main.FALSE
775 except pexpect.EOF:
776 main.log.exception( self.name + ": connection closed." )
777 main.cleanup()
778 main.exit()
779 except Exception:
780 main.log.exception( self.name + ": Uncaught exception!" )
781 main.cleanup()
782 main.exit()
783
784 def killFilter( self ):
785 """
786 Kill a scapy filter
787 """
788 try:
789 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
790 self.handle.expect( self.scapyPrompt )
791 return self.handle.before
792 except pexpect.TIMEOUT:
793 main.log.exception( self.name + ": Command timed out" )
794 return None
795 except pexpect.EOF:
796 main.log.exception( self.name + ": connection closed." )
797 main.cleanup()
798 main.exit()
799 except Exception:
800 main.log.exception( self.name + ": Uncaught exception!" )
801 main.cleanup()
802 main.exit()
803
804 def readPackets( self ):
805 """
806 Read all the packets captured by the previous filter
807 """
808 try:
809 self.handle.sendline( "for p in pkt: p \n")
810 self.handle.expect( "for p in pkt: p \r\n... \r\n" )
811 self.handle.expect( self.scapyPrompt )
812 except pexpect.TIMEOUT:
813 main.log.exception( self.name + ": Command timed out" )
814 return None
815 except pexpect.EOF:
816 main.log.exception( self.name + ": connection closed." )
817 main.cleanup()
818 main.exit()
819 except Exception:
820 main.log.exception( self.name + ": Uncaught exception!" )
821 main.cleanup()
822 main.exit()
823 return self.handle.before
824
825 def updateSelf( self ):
826 """
827 Updates local MAC and IP fields
828 """
829 self.hostMac = self.getMac()
830 self.hostIp = self.getIp()
831
832 def getMac( self, ifaceName=None ):
833 """
834 Save host's MAC address
835 """
836 try:
837 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
838 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
839 self.handle.sendline( cmd )
840 self.handle.expect( self.scapyPrompt )
841 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
842 match = re.search( pattern, self.handle.before )
843 if match:
844 return match.group()
845 else:
846 # the command will have an exception if iface doesn't exist
847 return None
848 except pexpect.TIMEOUT:
849 main.log.exception( self.name + ": Command timed out" )
850 return None
851 except pexpect.EOF:
852 main.log.exception( self.name + ": connection closed." )
853 main.cleanup()
854 main.exit()
855 except Exception:
856 main.log.exception( self.name + ": Uncaught exception!" )
857 main.cleanup()
858 main.exit()
859
860 def getIp( self, ifaceName=None ):
861 """
862 Save host's IP address
863
864 Returns the IP of the first interface that is not a loopback device.
865 If no IP could be found then it will return 0.0.0.0.
866 """
867 def getIPofInterface( ifaceName ):
868 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
869 self.handle.sendline( cmd )
870 self.handle.expect( self.scapyPrompt )
871
872 pattern = r'(((2[0-5]|1[0-9]|[0-9])?[0-9]\.){3}((2[0-5]|1[0-9]|[0-9])?[0-9]))'
873 match = re.search( pattern, self.handle.before )
874 if match:
875 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
876 if match.group() == '0.0.0.0':
877 main.log.warn( 'iface {0} has no IPv4 address'.format( ifaceName ) )
878 return match.group()
879 else:
880 return None
881 try:
882 if not ifaceName:
883 # Get list of interfaces
884 ifList = self.getIfList()
885 for ifaceName in ifList:
886 if ifaceName == "lo":
887 continue
888 ip = getIPofInterface( ifaceName )
889 if ip != "0.0.0.0":
890 return ip
891 return "0.0.0.0"
892 else:
893 return getIPofInterface( ifaceName )
894
895 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." )
900 main.cleanup()
901 main.exit()
902 except Exception:
903 main.log.exception( self.name + ": Uncaught exception!" )
904 main.cleanup()
905 main.exit()
906
907 def getIfList( self ):
908 """
909 Return List of Interfaces
910 """
911 try:
912 self.handle.sendline( 'get_if_list()' )
913 self.handle.expect( self.scapyPrompt )
914 ifList = self.handle.before.split( '\r\n' )
915 ifList = ifList[ 1 ].replace( "'","" )[ 1:-1 ].split( ', ' )
916 return ifList
917
918 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." )
923 main.cleanup()
924 main.exit()
925 except Exception:
926 main.log.exception( self.name + ": Uncaught exception!" )
927 main.cleanup()
928 main.exit()
929
930if __name__ != "__main__":
931 sys.modules[ __name__ ] = ScapyCliDriver()