root/scapy/sendrecv.py

Revision 896:b1db134eca25, 19.8 kB (checked in by Phil <phil@secdev.org>, 4 months ago)

Moved tethereal() to sendrecv.py and renamed it tshark()

Line 
1 ## This file is part of Scapy
2 ## See http://www.secdev.org/projects/scapy for more informations
3 ## Copyright (C) Philippe Biondi <phil@secdev.org>
4 ## This program is published under a GPLv2 license
5
6 import cPickle,os,sys,time,subprocess
7 from select import select
8 from data import *
9 from arch import *
10 from config import conf
11 from packet import Gen
12 from utils import warning
13 import plist
14 from error import log_runtime,log_interactive
15
16 #################
17 ## Debug class ##
18 #################
19
20 class debug:
21     recv=[]
22     sent=[]
23     match=[]
24
25
26 ####################
27 ## Send / Receive ##
28 ####################
29
30
31
32
33 def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, multi=0):
34     if not isinstance(pkt, Gen):
35         pkt = SetGen(pkt)
36        
37     if verbose is None:
38         verbose = conf.verb
39     debug.recv = plist.PacketList([],"Unanswered")
40     debug.sent = plist.PacketList([],"Sent")
41     debug.match = plist.SndRcvList([])
42     nbrecv=0
43     ans = []
44     # do it here to fix random fields, so that parent and child have the same
45     all_stimuli = tobesent = [p for p in pkt]
46     notans = len(tobesent)
47
48     hsent={}
49     for i in tobesent:
50         h = i.hashret()
51         if h in hsent:
52             hsent[h].append(i)
53         else:
54             hsent[h] = [i]
55     if retry < 0:
56         retry = -retry
57         autostop=retry
58     else:
59         autostop=0
60
61
62     while retry >= 0:
63         found=0
64    
65         if timeout < 0:
66             timeout = None
67            
68         rdpipe,wrpipe = os.pipe()
69         rdpipe=os.fdopen(rdpipe)
70         wrpipe=os.fdopen(wrpipe,"w")
71
72         pid=1
73         try:
74             pid = os.fork()
75             if pid == 0:
76                 try:
77                     sys.stdin.close()
78                     rdpipe.close()
79                     try:
80                         i = 0
81                         if verbose:
82                             print "Begin emission:"
83                         for p in tobesent:
84                             pks.send(p)
85                             i += 1
86                             time.sleep(inter)
87                         if verbose:
88                             print "Finished to send %i packets." % i
89                     except SystemExit:
90                         pass
91                     except KeyboardInterrupt:
92                         pass
93                     except:
94                         log_runtime.exception("--- Error in child %i" % os.getpid())
95                         log_runtime.info("--- Error in child %i" % os.getpid())
96                 finally:
97                     try:
98                         os.setpgrp() # Chance process group to avoid ctrl-C
99                         sent_times = [p.sent_time for p in all_stimuli if p.sent_time]
100                         cPickle.dump( (conf.netcache,sent_times), wrpipe )
101                         wrpipe.close()
102                     except:
103                         pass
104             elif pid < 0:
105                 log_runtime.error("fork error")
106             else:
107                 wrpipe.close()
108                 stoptime = 0
109                 remaintime = None
110                 inmask = [rdpipe,pks]
111                 try:
112                     try:
113                         while 1:
114                             if stoptime:
115                                 remaintime = stoptime-time.time()
116                                 if remaintime <= 0:
117                                     break
118                             r = None
119                             if FREEBSD or DARWIN:
120                                 inp, out, err = select(inmask,[],[], 0.05)
121                                 if len(inp) == 0 or pks in inp:
122                                     r = pks.nonblock_recv()
123                             else:
124                                 inp, out, err = select(inmask,[],[], remaintime)
125                                 if len(inp) == 0:
126                                     break
127                                 if pks in inp:
128                                     r = pks.recv(MTU)
129                             if rdpipe in inp:
130                                 if timeout:
131                                     stoptime = time.time()+timeout
132                                 del(inmask[inmask.index(rdpipe)])
133                             if r is None:
134                                 continue
135                             ok = 0
136                             h = r.hashret()
137                             if h in hsent:
138                                 hlst = hsent[h]
139                                 for i in range(len(hlst)):
140                                     if r.answers(hlst[i]):
141                                         ans.append((hlst[i],r))
142                                         if verbose > 1:
143                                             os.write(1, "*")
144                                         ok = 1                               
145                                         if not multi:
146                                             del(hlst[i])
147                                             notans -= 1;
148                                         else:
149                                             if not hasattr(hlst[i], '_answered'):
150                                                 notans -= 1;
151                                             hlst[i]._answered = 1;
152                                         break
153                             if notans == 0 and not multi:
154                                 break
155                             if not ok:
156                                 if verbose > 1:
157                                     os.write(1, ".")
158                                 nbrecv += 1
159                                 if conf.debug_match:
160                                     debug.recv.append(r)
161                     except KeyboardInterrupt:
162                         if chainCC:
163                             raise
164                 finally:
165                     try:
166                         nc,sent_times = cPickle.load(rdpipe)
167                     except EOFError:
168                         warning("Child died unexpectedly. Packets may have not been sent %i"%os.getpid())
169                     else:
170                         conf.netcache.update(nc)
171                         for p,t in zip(all_stimuli, sent_times):
172                             p.sent_time = t
173                     os.waitpid(pid,0)
174         finally:
175             if pid == 0:
176                 os._exit(0)
177
178         remain = reduce(list.__add__, hsent.values(), [])
179         if multi:
180             remain = filter(lambda p: not hasattr(p, '_answered'), remain);
181            
182         if autostop and len(remain) > 0 and len(remain) != len(tobesent):
183             retry = autostop
184            
185         tobesent = remain
186         if len(tobesent) == 0:
187             break
188         retry -= 1
189        
190     if conf.debug_match:
191         debug.sent=plist.PacketList(remain[:],"Sent")
192         debug.match=plist.SndRcvList(ans[:])
193
194     #clean the ans list to delete the field _answered
195     if (multi):
196         for s,r in ans:
197             if hasattr(s, '_answered'):
198                 del(s._answered)
199    
200     if verbose:
201         print "\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans)
202     return plist.SndRcvList(ans),plist.PacketList(remain,"Unanswered"),debug.recv
203
204
205 def __gen_send(s, x, inter=0, loop=0, count=None, verbose=None, *args, **kargs):
206     if not isinstance(x, Gen):
207         x = SetGen(x)
208     if verbose is None:
209         verbose = conf.verb
210     n = 0
211     if count is not None:
212         loop = -count
213     elif not loop:
214         loop=-1
215     try:
216         while loop:
217             for p in x:
218                 s.send(p)
219                 n += 1
220                 if verbose:
221                     os.write(1,".")
222                 time.sleep(inter)
223             if loop < 0:
224                 loop += 1
225     except KeyboardInterrupt:
226         pass
227     s.close()
228     if verbose:
229         print "\nSent %i packets." % n
230        
231 @conf.commands.register
232 def send(x, inter=0, loop=0, count=None, verbose=None, *args, **kargs):
233     """Send packets at layer 3
234 send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None"""
235     __gen_send(conf.L3socket(*args, **kargs), x, inter=inter, loop=loop, count=count,verbose=verbose)
236
237 @conf.commands.register
238 def sendp(x, inter=0, loop=0, iface=None, iface_hint=None, count=None, verbose=None, *args, **kargs):
239     """Send packets at layer 2
240 sendp(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None"""
241     if iface is None and iface_hint is not None:
242         iface = conf.route.route(iface_hint)[0]
243     __gen_send(conf.L2socket(iface=iface, *args, **kargs), x, inter=inter, loop=loop, count=count, verbose=verbose)
244
245 @conf.commands.register
246 def sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, iface=None):
247     """Send packets at layer 2 using tcpreplay for performance
248     pps:  packets per second
249     mpbs: MBits per second
250     realtime: use packet's timestamp, bending time with realtime value
251     loop: number of times to process the packet list
252     iface: output interface """
253     if iface is None:
254         iface = conf.iface
255     argv = [conf.prog.tcpreplay, "--intf1=%s" % iface ]
256     if pps is not None:
257         argv.append("--pps=%i" % pps)
258     elif mbps is not None:
259         argv.append("--mbps=%i" % mbps)
260     elif realtime is not None:
261         argv.append("--multiplier=%i" % realtime)
262     else:
263         argv.append("--topspeed")
264
265     if loop:
266         argv.append("--loop=%i" % loop)
267
268     f = os.tempnam("scapy")
269     argv.append(f)
270     wrpcap(f, x)
271     try:
272         subprocess.check_call(argv)
273     except KeyboardInterrupt:
274         log_interactive.info("Interrupted by user")
275     except Exception,e:
276         log_interactive.error(e)
277     finally:
278         os.unlink(f)
279
280        
281
282        
283    
284 @conf.commands.register
285 def sr(x,filter=None, iface=None, nofilter=0, *args,**kargs):
286     """Send and receive packets at layer 3
287 nofilter: put 1 to avoid use of bpf filters
288 retry:    if positive, how many times to resend unanswered packets
289           if negative, how many times to retry when no more packets are answered
290 timeout:  how much time to wait after the last packet has been sent
291 verbose:  set verbosity level
292 multi:    whether to accept multiple answers for the same stimulus
293 filter:   provide a BPF filter
294 iface:    listen answers only on the given interface"""
295     if not kargs.has_key("timeout"):
296         kargs["timeout"] = -1
297     s = conf.L3socket(filter=filter, iface=iface, nofilter=nofilter)
298     a,b,c=sndrcv(s,x,*args,**kargs)
299     s.close()
300     return a,b
301
302 @conf.commands.register
303 def sr1(x,filter=None,iface=None, nofilter=0, *args,**kargs):
304     """Send packets at layer 3 and return only the first answer
305 nofilter: put 1 to avoid use of bpf filters
306 retry:    if positive, how many times to resend unanswered packets
307           if negative, how many times to retry when no more packets are answered
308 timeout:  how much time to wait after the last packet has been sent
309 verbose:  set verbosity level
310 multi:    whether to accept multiple answers for the same stimulus
311 filter:   provide a BPF filter
312 iface:    listen answers only on the given interface"""
313     if not kargs.has_key("timeout"):
314         kargs["timeout"] = -1
315     s=conf.L3socket(filter=filter, nofilter=nofilter, iface=iface)
316     a,b,c=sndrcv(s,x,*args,**kargs)
317     s.close()
318     if len(a) > 0:
319         return a[0][1]
320     else:
321         return None
322
323 @conf.commands.register
324 def srp(x,iface=None, iface_hint=None, filter=None, nofilter=0, type=ETH_P_ALL, *args,**kargs):
325     """Send and receive packets at layer 2
326 nofilter: put 1 to avoid use of bpf filters
327 retry:    if positive, how many times to resend unanswered packets
328           if negative, how many times to retry when no more packets are answered
329 timeout:  how much time to wait after the last packet has been sent
330 verbose:  set verbosity level
331 multi:    whether to accept multiple answers for the same stimulus
332 filter:   provide a BPF filter
333 iface:    work only on the given interface"""
334     if not kargs.has_key("timeout"):
335         kargs["timeout"] = -1
336     if iface is None and iface_hint is not None:
337         iface = conf.route.route(iface_hint)[0]
338     s = conf.L2socket(iface=iface, filter=filter, nofilter=nofilter, type=type)
339     a,b,c=sndrcv(s ,x,*args,**kargs)
340     s.close()
341     return a,b
342
343 @conf.commands.register
344 def srp1(*args,**kargs):
345     """Send and receive packets at layer 2 and return only the first answer
346 nofilter: put 1 to avoid use of bpf filters
347 retry:    if positive, how many times to resend unanswered packets
348           if negative, how many times to retry when no more packets are answered
349 timeout:  how much time to wait after the last packet has been sent
350 verbose:  set verbosity level
351 multi:    whether to accept multiple answers for the same stimulus
352 filter:   provide a BPF filter
353 iface:    work only on the given interface"""
354     if not kargs.has_key("timeout"):
355         kargs["timeout"] = -1
356     a,b=srp(*args,**kargs)
357     if len(a) > 0:
358         return a[0][1]
359     else:
360         return None
361
362 def __sr_loop(srfunc, pkts, prn=lambda x:x[1].summary(), prnfail=lambda x:x.summary(), inter=1, timeout=None, count=None, verbose=None, store=1, *args, **kargs):
363     n = 0
364     r = 0
365     ct = conf.color_theme
366     if verbose is None:
367         verbose = conf.verb
368     parity = 0
369     ans=[]
370     unans=[]
371     if timeout is None:
372         timeout = min(2*inter, 5)
373     try:
374         while 1:
375             parity ^= 1
376             col = [ct.even,ct.odd][parity]
377             if count is not None:
378                 if count == 0:
379                     break
380                 count -= 1
381             start = time.time()
382             print "\rsend...\r",
383             res = srfunc(pkts, timeout=timeout, verbose=0, chainCC=1, *args, **kargs)
384             n += len(res[0])+len(res[1])
385             r += len(res[0])
386             if verbose > 1 and prn and len(res[0]) > 0:
387                 msg = "RECV %i:" % len(res[0])
388                 print  "\r"+ct.success(msg),
389                 for p in res[0]:
390                     print col(prn(p))
391                     print " "*len(msg),
392             if verbose > 1 and prnfail and len(res[1]) > 0:
393                 msg = "fail %i:" % len(res[1])
394                 print "\r"+ct.fail(msg),
395                 for p in res[1]:
396                     print col(prnfail(p))
397                     print " "*len(msg),
398             if verbose > 1 and not (prn or prnfail):
399                 print "recv:%i  fail:%i" % tuple(map(len, res[:2]))
400             if store:
401                 ans += res[0]
402                 unans += res[1]
403             end=time.time()
404             if end-start < inter:
405                 time.sleep(inter+start-end)
406     except KeyboardInterrupt:
407         pass
408  
409     if verbose and n>0:
410         print ct.normal("\nSent %i packets, received %i packets. %3.1f%% hits." % (n,r,100.0*r/n))
411     return plist.SndRcvList(ans),plist.PacketList(unans)
412
413 @conf.commands.register
414 def srloop(pkts, *args, **kargs):
415     """Send a packet at layer 3 in loop and print the answer each time
416 srloop(pkts, [prn], [inter], [count], ...) --> None"""
417     return __sr_loop(sr, pkts, *args, **kargs)
418
419 @conf.commands.register
420 def srploop(pkts, *args, **kargs):
421     """Send a packet at layer 2 in loop and print the answer each time
422 srloop(pkts, [prn], [inter], [count], ...) --> None"""
423     return __sr_loop(srp, pkts, *args, **kargs)
424
425
426 def sndrcvflood(pks, pkt, prn=lambda (s,r):r.summary(), chainCC=0, store=1, unique=0):
427     if not isinstance(pkt, Gen):
428         pkt = SetGen(pkt)
429     tobesent = [p for p in pkt]
430     received = plist.SndRcvList()
431     seen = {}
432
433     hsent={}
434     for i in tobesent:
435         h = i.hashret()
436         if h in hsent:
437             hsent[h].append(i)
438         else:
439             hsent[h] = [i]
440
441     def send_in_loop(tobesent):
442         while 1:
443             for p in tobesent:
444                 yield p
445
446     packets_to_send = send_in_loop(tobesent)
447
448     ssock = rsock = pks.fileno()
449
450     try:
451         while 1:
452             readyr,readys,_ = select([rsock],[ssock],[])
453             if ssock in readys:
454                 pks.send(packets_to_send.next())
455                
456             if rsock in readyr:
457                 p = pks.recv(MTU)
458                 if p is None:
459                     continue
460                 h = p.hashret()
461                 if h in hsent:
462                     hlst = hsent[h]
463                     for i in hlst:
464                         if p.answers(i):
465                             res = prn((i,p))
466                             if unique:
467                                 if res in seen:
468                                     continue
469                                 seen[res] = None
470                             if res is not None:
471                                 print res
472                             if store:
473                                 received.append((i,p))
474     except KeyboardInterrupt:
475         if chainCC:
476             raise
477     return received
478
479 @conf.commands.register
480 def srflood(x,filter=None, iface=None, nofilter=None, *args,**kargs):
481     """Flood and receive packets at layer 3
482 prn:      function applied to packets received. Ret val is printed if not None
483 store:    if 1 (default), store answers and return them
484 unique:   only consider packets whose print
485 nofilter: put 1 to avoid use of bpf filters
486 filter:   provide a BPF filter
487 iface:    listen answers only on the given interface"""
488     s = conf.L3socket(filter=filter, iface=iface, nofilter=nofilter)
489     r=sndrcvflood(s,x,*args,**kargs)
490     s.close()
491     return r
492
493 @conf.commands.register
494 def srpflood(x,filter=None, iface=None, iface_hint=None, nofilter=None, *args,**kargs):
495     """Flood and receive packets at layer 2
496 prn:      function applied to packets received. Ret val is printed if not None
497 store:    if 1 (default), store answers and return them
498 unique:   only consider packets whose print
499 nofilter: put 1 to avoid use of bpf filters
500 filter:   provide a BPF filter
501 iface:    listen answers only on the given interface"""
502     if iface is None and iface_hint is not None:
503         iface = conf.route.route(iface_hint)[0]   
504     s = conf.L2socket(filter=filter, iface=iface, nofilter=nofilter)
505     r=sndrcvflood(s,x,*args,**kargs)
506     s.close()
507     return r
508
509            
510
511
512 @conf.commands.register
513 def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, *arg, **karg):
514     """Sniff packets
515 sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets
516
517   count: number of packets to capture. 0 means infinity
518   store: wether to store sniffed packets or discard them
519     prn: function to apply to each packet. If something is returned,
520          it is displayed. Ex:
521          ex: prn = lambda x: x.summary()
522 lfilter: python function applied to each packet to determine
523          if further action may be done
524          ex: lfilter = lambda x: x.haslayer(Padding)
525 offline: pcap file to read packets from, instead of sniffing them
526 timeout: stop sniffing after a given time (default: None)
527 L2socket: use the provided L2socket
528     """
529     c = 0
530
531     if offline is None:
532         if L2socket is None:
533             L2socket = conf.L2listen
534         s = L2socket(type=ETH_P_ALL, *arg, **karg)
535     else:
536         s = PcapReader(offline)
537
538     lst = []
539     if timeout is not None:
540         stoptime = time.time()+timeout
541     remain = None
542     while 1:
543         try:
544             if timeout is not None:
545                 remain = stoptime-time.time()
546                 if remain <= 0:
547                     break
548             sel = select([s],[],[],remain)
549             if s in sel[0]:
550                 p = s.recv(MTU)
551                 if p is None:
552                     break
553                 if lfilter and not lfilter(p):
554                     continue
555                 if store:
556                     lst.append(p)
557                 c += 1
558                 if prn:
559                     r = prn(p)
560                     if r is not None:
561                         print r
562                 if count > 0 and c >= count:
563                     break
564         except KeyboardInterrupt:
565             break
566     s.close()
567     return plist.PacketList(lst,"Sniffed")
568
569 @conf.commands.register
570 def tshark(*args,**kargs):
571     """Sniff packets and print them calling pkt.show(), a bit like text wireshark"""
572     sniff(prn=lambda x: x.display(),*args,**kargs)
573
Note: See TracBrowser for help on using the browser.