blob: 39c5c4d03335ba4d2a61e55629bf51eee8cc0c96 [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 )
Jon Halla510a8a2016-05-04 15:09:28 -0700703 # main.log.warn( "Send packet response: {}".format( self.handle.before ) )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800704 if "Traceback" in self.handle.before:
705 # KeyError, SyntaxError, ...
706 main.log.error( "Error in sending command: " + self.handle.before )
707 return main.FALSE
708 # TODO: Check # of packets sent?
709 return main.TRUE
710 except pexpect.TIMEOUT:
711 main.log.exception( self.name + ": Command timed out" )
712 return main.FALSE
713 except pexpect.EOF:
714 main.log.exception( self.name + ": connection closed." )
715 main.cleanup()
716 main.exit()
717 except Exception:
718 main.log.exception( self.name + ": Uncaught exception!" )
719 main.cleanup()
720 main.exit()
721
722 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
723 """
724 Listen for packets using the given filters
725
726 Options:
727 ifaceName - the name of the interface to listen on. If none is given,
728 defaults to <host name>-eth0
729 pktFilter - A string in Berkeley Packet Filter (BPF) format which
730 specifies which packets to sniff
731 sniffCount - The number of matching packets to capture before returning
732
733 Returns main.TRUE or main.FALSE on error
734 """
735 try:
736 # TODO: add all params, or use kwargs
737 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
738 # Set interface
739 self.handle.sendline( ' conf.iface = "' + ifaceName + '"' )
740 self.handle.expect( self.scapyPrompt )
741 cmd = 'pkt = sniff(count = ' + str( sniffCount ) +\
742 ', filter = "' + str( pktFilter ) + '")'
Jon Halla510a8a2016-05-04 15:09:28 -0700743 main.log.info( "Filter on " + self.name + ' > ' + cmd )
Jeremy Songster1f39bf02016-01-20 17:17:25 -0800744 self.handle.sendline( cmd )
745 self.handle.expect( '"\)\r\n' )
746 # TODO: parse this?
747 return main.TRUE
748 except pexpect.TIMEOUT:
749 main.log.exception( self.name + ": Command timed out" )
750 return main.FALSE
751 except pexpect.EOF:
752 main.log.exception( self.name + ": connection closed." )
753 main.cleanup()
754 main.exit()
755 except Exception:
756 main.log.exception( self.name + ": Uncaught exception!" )
757 main.cleanup()
758 main.exit()
759
760 def checkFilter( self, timeout=10 ):
761 """
762 Check that a filter returned and returns the reponse
763 """
764 try:
765 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ], timeout=timeout )
766 if i == 0:
767 return main.TRUE
768 else:
769 return main.FALSE
770 except pexpect.EOF:
771 main.log.exception( self.name + ": connection closed." )
772 main.cleanup()
773 main.exit()
774 except Exception:
775 main.log.exception( self.name + ": Uncaught exception!" )
776 main.cleanup()
777 main.exit()
778
779 def killFilter( self ):
780 """
781 Kill a scapy filter
782 """
783 try:
784 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
785 self.handle.expect( self.scapyPrompt )
786 return self.handle.before
787 except pexpect.TIMEOUT:
788 main.log.exception( self.name + ": Command timed out" )
789 return None
790 except pexpect.EOF:
791 main.log.exception( self.name + ": connection closed." )
792 main.cleanup()
793 main.exit()
794 except Exception:
795 main.log.exception( self.name + ": Uncaught exception!" )
796 main.cleanup()
797 main.exit()
798
799 def readPackets( self ):
800 """
801 Read all the packets captured by the previous filter
802 """
803 try:
804 self.handle.sendline( "for p in pkt: p \n")
805 self.handle.expect( "for p in pkt: p \r\n... \r\n" )
806 self.handle.expect( self.scapyPrompt )
807 except pexpect.TIMEOUT:
808 main.log.exception( self.name + ": Command timed out" )
809 return None
810 except pexpect.EOF:
811 main.log.exception( self.name + ": connection closed." )
812 main.cleanup()
813 main.exit()
814 except Exception:
815 main.log.exception( self.name + ": Uncaught exception!" )
816 main.cleanup()
817 main.exit()
818 return self.handle.before
819
820 def updateSelf( self ):
821 """
822 Updates local MAC and IP fields
823 """
824 self.hostMac = self.getMac()
825 self.hostIp = self.getIp()
826
827 def getMac( self, ifaceName=None ):
828 """
829 Save host's MAC address
830 """
831 try:
832 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
833 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
834 self.handle.sendline( cmd )
835 self.handle.expect( self.scapyPrompt )
836 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
837 match = re.search( pattern, self.handle.before )
838 if match:
839 return match.group()
840 else:
841 # the command will have an exception if iface doesn't exist
842 return None
843 except pexpect.TIMEOUT:
844 main.log.exception( self.name + ": Command timed out" )
845 return None
846 except pexpect.EOF:
847 main.log.exception( self.name + ": connection closed." )
848 main.cleanup()
849 main.exit()
850 except Exception:
851 main.log.exception( self.name + ": Uncaught exception!" )
852 main.cleanup()
853 main.exit()
854
855 def getIp( self, ifaceName=None ):
856 """
857 Save host's IP address
858
859 Returns the IP of the first interface that is not a loopback device.
860 If no IP could be found then it will return 0.0.0.0.
861 """
862 def getIPofInterface( ifaceName ):
863 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
864 self.handle.sendline( cmd )
865 self.handle.expect( self.scapyPrompt )
866
867 pattern = r'(((2[0-5]|1[0-9]|[0-9])?[0-9]\.){3}((2[0-5]|1[0-9]|[0-9])?[0-9]))'
868 match = re.search( pattern, self.handle.before )
869 if match:
870 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
871 if match.group() == '0.0.0.0':
872 main.log.warn( 'iface {0} has no IPv4 address'.format( ifaceName ) )
873 return match.group()
874 else:
875 return None
876 try:
877 if not ifaceName:
878 # Get list of interfaces
879 ifList = self.getIfList()
880 for ifaceName in ifList:
881 if ifaceName == "lo":
882 continue
883 ip = getIPofInterface( ifaceName )
884 if ip != "0.0.0.0":
885 return ip
886 return "0.0.0.0"
887 else:
888 return getIPofInterface( ifaceName )
889
890 except pexpect.TIMEOUT:
891 main.log.exception( self.name + ": Command timed out" )
892 return None
893 except pexpect.EOF:
894 main.log.exception( self.name + ": connection closed." )
895 main.cleanup()
896 main.exit()
897 except Exception:
898 main.log.exception( self.name + ": Uncaught exception!" )
899 main.cleanup()
900 main.exit()
901
902 def getIfList( self ):
903 """
904 Return List of Interfaces
905 """
906 try:
907 self.handle.sendline( 'get_if_list()' )
908 self.handle.expect( self.scapyPrompt )
909 ifList = self.handle.before.split( '\r\n' )
910 ifList = ifList[ 1 ].replace( "'","" )[ 1:-1 ].split( ', ' )
911 return ifList
912
913 except pexpect.TIMEOUT:
914 main.log.exception( self.name + ": Command timed out" )
915 return None
916 except pexpect.EOF:
917 main.log.exception( self.name + ": connection closed." )
918 main.cleanup()
919 main.exit()
920 except Exception:
921 main.log.exception( self.name + ": Uncaught exception!" )
922 main.cleanup()
923 main.exit()
924
925if __name__ != "__main__":
926 sys.modules[ __name__ ] = ScapyCliDriver()