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