2014-01-13 16 views
6

私はscapyを使用してミラーポートを盗聴し、ネットワーク上で最大の帯域幅を使用する上位10の「話し手」リストを生成しています。私はiftopntopのような既に利用可能なツールについて知っていますが、出力をより詳細に制御する必要があります。scapy、iftop-styleでIPごとの帯域幅使用量を計算します

次のスクリプトは、トラフィックを30秒間サンプリングし、上位10人のトーカーのリストを "source host - > destination host:bytes"の形式で出力します。それは素晴らしいですが、平均を計算するにはバイト/秒

私は、sample_intervalを1秒に変更すると、トラフィックのサンプリングが適切でないため、平均化する必要があるようです。だから私はスクリプトの最後にこれを試しました:

bytes per second = (total bytes/sample_interval)

しかし、結果のBytes/sはかなり低いようです。たとえば、2つのホスト間でrsyncを1.5 MB/sの速度で生成しましたが、上記の平均計算を使用して、スクリプトはこれらのホスト間の速度を約200 KB/s ... 1.5 MBよりずっと低く計算し続けました/ sのように私は期待しています。私はiftopを使って1.5MB/sが実際にこれらの2つのホスト間の速度であることを確認できます。

scapyでパケットの長さが正しく集計されません(traffic_monitor_callbak機能を参照)。またはこれは完全に貧しい解決策ですか:)?

from scapy.all import * 
from collections import defaultdict 
import socket 
from pprint import pprint 
from operator import itemgetter 

sample_interval = 30 # how long to capture traffic, in seconds 

# initialize traffic dict 
traffic = defaultdict(list) 

# return human readable units given bytes 
def human(num): 
    for x in ['bytes','KB','MB','GB','TB']: 
     if num < 1024.0: 
      return "%3.1f %s" % (num, x) 
     num /= 1024.0 

# callback function to process each packet 
# get total packets for each source->destination combo 
def traffic_monitor_callbak(pkt): 
    if IP in pkt: 
     src = pkt.sprintf("%IP.src%") 
     dst = pkt.sprintf("%IP.dst%") 

     size = pkt.sprintf("%IP.len%") 

     # initialize 
     if (src, dst) not in traffic: 
      traffic[(src, dst)] = 0 

     else: 
      traffic[(src, dst)] += int(size) 

sniff(iface="eth1", prn=traffic_monitor_callbak, store=0, timeout=sample_interval) 

# sort by total bytes, descending 
traffic_sorted = sorted(traffic.iteritems(), key=itemgetter(1), reverse=True)  

# print top 10 talkers 
for x in range(0, 10): 
    src = traffic_sorted[x][0][0] 
    dst = traffic_sorted[x][0][1] 
    host_total = traffic_sorted[x][3] 

    # get hostname from IP 
    try: 
     src_hostname = socket.gethostbyaddr(src) 
    except: 
     src_hostname = src 

    try:  
     dst_hostname = socket.gethostbyaddr(dst) 
    except: 
     dst_hostname = dst 


    print "%s: %s (%s) -> %s (%s)" % (human(host_total), src_hostname[0], src, dst_hostname[0], dst) 

私は、これは一般的なネットワーキングの質問のプログラミング(scapy/pythonの)質問以上であるので、私はネットワークプログラミングの質問、それを呼んでいるかはわかりません。

答えて

3

こんにちは、すべての

まずある場合は、コードのバグを持っていますあなたは投稿しました:host_total = traffic_sorted[x][3]の代わりに、おそらくhost_total = traffic_sorted[x][1]を意味します。

次に、host_totalsample_interval値で割ることを忘れてしまいました。

また、受信者から送信者へのトラフィックと送信者から受信者を追加する場合は、「順序付けられた」タプルを使用するのが最善の方法だと思います(順序自体はここでは重要ではありません。 IPアドレスは4オクテットの整数なので、算術順序を使用することもできます)をCounterオブジェクトのキーとして使用できます。これはうまくいくようです。

#! /usr/bin/env python 

sample_interval = 10 
interface="eth1" 

from scapy.all import * 
from collections import Counter 


# Counter is a *much* better option for what you're doing here. See 
# http://docs.python.org/2/library/collections.html#collections.Counter 
traffic = Counter() 
# You should probably use a cache for your IP resolutions 
hosts = {} 

def human(num): 
    for x in ['', 'k', 'M', 'G', 'T']: 
     if num < 1024.: return "%3.1f %sB" % (num, x) 
     num /= 1024. 
    # just in case! 
    return "%3.1f PB" % (num) 

def traffic_monitor_callback(pkt): 
    if IP in pkt: 
     pkt = pkt[IP] 
     # You don't want to use sprintf here, particularly as you're 
     # converting .len after that! 
     # Here is the first place where you're happy to use a Counter! 
     # We use a tuple(sorted()) because a tuple is hashable (so it 
     # can be used as a key in a Counter) and we want to sort the 
     # addresses to count mix sender-to-receiver traffic together 
     # with receiver-to-sender 
     traffic.update({tuple(sorted(map(atol, (pkt.src, pkt.dst)))): pkt.len}) 

sniff(iface=interface, prn=traffic_monitor_callback, store=False, 
     timeout=sample_interval) 

# ... and now comes the second place where you're happy to use a 
# Counter! 
# Plus you can use value unpacking in your for statement. 
for (h1, h2), total in traffic.most_common(10): 
    # Let's factor out some code here 
    h1, h2 = map(ltoa, (h1, h2)) 
    for host in (h1, h2): 
     if host not in hosts: 
      try: 
       rhost = socket.gethostbyaddr(host) 
       hosts[host] = rhost[0] 
      except: 
       hosts[host] = None 
    # Get a nice output 
    h1 = "%s (%s)" % (hosts[h1], h1) if hosts[h1] is not None else h1 
    h2 = "%s (%s)" % (hosts[h2], h2) if hosts[h2] is not None else h2 
    print "%s/s: %s - %s" % (human(float(total)/sample_interval), h1, h2) 

Scapyがジョブを実行するのに十分速くない可能性があります。確実にするには、たとえば次のようにします。 tcpdump -w、あなたのトラフィックをsample_interval秒間ファイルにキャプチャしてから実行してください(ところで、パケットに機能を適用する方法を見て、Scapyを頻繁に使用するかどうかはわかります)

#! /usr/bin/env python 

sample_interval = 10 
filename="capture.cap" 

from scapy.all import * 
from collections import Counter 

traffic = Counter() 
hosts = {} 

def human(num): 
    for x in ['', 'k', 'M', 'G', 'T']: 
     if num < 1024.: return "%3.1f %sB" % (num, x) 
     num /= 1024. 
    return "%3.1f PB" % (num) 

def traffic_monitor_callback(pkt): 
    if IP in pkt: 
     pkt = pkt[IP] 
     traffic.update({tuple(sorted(map(atol, (pkt.src, pkt.dst)))): pkt.len}) 

# A trick I like: don't use rdpcap() that would waste your memory; 
# iterate over a PcapReader object instead. 
for p in PcapReader("capture.cap"): 
    traffic_monitor_callback(p) 

for (h1, h2), total in traffic.most_common(10): 
    h1, h2 = map(ltoa, (h1, h2)) 
    for host in (h1, h2): 
     if host not in hosts: 
      try: 
       rhost = socket.gethostbyaddr(host) 
       hosts[host] = rhost[0] 
      except: 
       hosts[host] = None 
    h1 = "%s (%s)" % (hosts[h1], h1) if hosts[h1] is not None else h1 
    h2 = "%s (%s)" % (hosts[h2], h2) if hosts[h2] is not None else h2 
    print "%s/s: %s - %s" % (human(float(total)/sample_interval), h1, h2) 
+0

はい送信者と受信者のトラフィックについてあなたが正しいと思います。 'iftop'の出力を見ると、2つのホスト間にトラフィックが混在していることがわかります。結果を最後に組み合わせる、つまりタプルを結合するのはどうですか?たとえば、(host1、host2)+(host2、host1)の 'traffic'命令の結果があるとします。 – Banjer

+0

私の答えをちょうど更新しました。これはあなたの質問に完全に答えますか? – Pierre

+0

うわー、素敵なコード。私よりもはるかに効率的で賢い:)。私は、各ホストペアの最終的な合計が、トラフィック方向が組み合わされていても、iftopと並んで比較した場合でも、なぜそれほど低いのか不思議です。 'iftop'は自分の抑制されたrsyncテストに基づいて正しいようです。おそらく、sample_intervalを60秒に設定する必要がありますか?私は 'iftop'がシーンの裏で何をしているのだろうと思っています...それは、私がかなり同じことをしようとしているが、' scapy'をもっているので、最良の例かもしれません。 – Banjer

0

これはそれではないかもしれないが、あなたは多分メガ* ビット毎秒 *(メガビット/秒)とメガ*秒(MB /秒)あたりバイト *を混合していますか?バイトで送信されたデータの量を測定してからMB/sに変換するようですが、rsyncで1.5Mb /秒のビット数でビットを設定するのは不思議です。ので、あなたのスクリプトはあなたに200 KB /秒を与えているという事実が...少なくとも1.5 Mb /秒で右球場で

+0

私はrsyncで '--bwlimit = 1500'オプションを使用しています。'man rsync'はこれが' I/O帯域幅を制限することです。それはおよそ1.5メガバイト/秒です。私はiftopと(Cacti)[http://www.cacti.net/]グラフを使って、実際にそのトラフィック量を押していることを確認できます。しかし、明らかにしてくれてありがとう。 – Banjer

関連する問題