Pysharkをマスターする:Pythonでリアルタイムのネットワークトラフィックを「監視」する

Python tutorial - IT technology blog
Python tutorial - IT technology blog

ネットワークトラフィックを「監視」するためにどのツールを選ぶべきか?

DevOpsエンジニアやシステム管理者なら、サーバーが突然「重く」なったり, APIが500エラーを返し続けたり、不審なトラフィックによる攻撃が疑われたりする場面に遭遇したことがあるでしょう。従来の方法では、tcpdump.pcapファイルを保存し、それをローカルにダウンロードしてWiresharkで解析するのが一般的でした。このプロセスは有効ですが、あくまで事後解析(post-analysis)に過ぎません。

自動監視システムを構築したり、マルウェアを検知した際に即座にアラートを出したり、IPアドレスに基づいてリクエストを迅速にフィルタリングしたりしたい場合は、コードによる介入が必要です。Pythonの世界では、主に3つのアプローチがあります。

1. Scapy

Scapyは万能ナイフのようなもので、データの各ビットまで深く介入できます。しかし、最大の障壁は学習曲線が非常に急(steep learning curve)であることです。大量のトラフィックを処理する際のパフォーマンスも、それほど高くはありません。Scapyは、大量のパケットキャプチャよりも、パケットの生成(Packet Crafting)に適しています。

2. Tcpdump / TShark (コマンドライン)

これらは速度の面で非常に優れており、軽量で、ほとんどのLinuxディストリビューションで利用可能です。しかし、HTTPペイロードからJSON文字列をパースするためにBashスクリプトを書くのは、まさに苦行です。特殊文字や改行の処理だけで、丸一日費やしてしまうこともあるでしょう。

3. Pyshark

Pyshark自体がパケットをキャプチャするのではなく、TSharkの「ラッパー」として機能します。最大の利点は、Wiresharkが持つ3,000以上のプロトコル解析能力をそのまま継承している点です。生データを非常に扱いやすいPythonオブジェクトに変換してくれます。

なぜPysharkが実務プロジェクトで最適な選択肢なのか?

多くのプロジェクトを経て、Pysharkはパワーと使いやすさのバランスが最も優れていると感じています。ヘッダー内の各バイトの位置を覚える代わりに、packet.ip.srcを呼び出すだけで済みます。

実のところ、Wiresharkがそのプロトコルを読み取れるのであれば、Pysharkでも処理可能です。複雑なパケット構造を再定義する必要はありません. 純粋なC言語のライブラリよりはパフォーマンスがわずかに劣りますが、一般的な監視タスクであれば、Pysharkで十分対応できます。

Pysharkの実装:インストールから実行まで

まず、マシンにTSharkがインストールされている必要があります。Ubuntuの場合は、以下のコマンドを実行してください。

sudo apt update && sudo apt install tshark -y

次に、pipを使用してライブラリをインストールします。

pip install pyshark

リアルタイムパケットキャプチャ (Live Capture)

最も一般的なシナリオは、ネットワークカードを介したトラフィックの監視です。以下のコードは、インターフェースeth0でパケットをキャプチャし、基本情報を表示します。

import pyshark

def live_capture_basic(interface_name):
    # LiveCaptureの初期化
    capture = pyshark.LiveCapture(interface=interface_name)
    print(f"[*] {interface_name} でスキャン中... 停止するには Ctrl+C を押してください。")

    try:
        for packet in capture.sniff_continuously(packet_count=10):
            if 'IP' in packet:
                src = packet.ip.src
                dst = packet.ip.dst
                proto = packet.transport_layer
                print(f"[+] {proto}: {src} -> {dst}")
    except KeyboardInterrupt:
        print("\n[*] 停止しました。")

if __name__ == "__main__":
    live_capture_basic('eth0')

BPF Filterによるスマートなデータフィルタリング

特定のサービスだけを監視したい場合に、すべてのトラフィックをキャプチャしないでください。これはCPUとRAMの深刻な浪費につながります。カーネル層でフィルタリングを行うBPF (Berkeley Packet Filter)を活用しましょう。

# 特定のIPからのHTTPトラフィック (port 80) のみをキャプチャ
capture = pyshark.LiveCapture(
    interface='eth0', 
    bpf_filter='tcp port 80 and host 192.168.1.5'
)

レイヤーとペイロードの詳細分析

Pysharkの強力な点は、レイヤーを分解できることです。例えば、HTTPリクエストからURLを取得するには、次のように記述できます。

import pyshark

def analyze_http(interface_name):
    capture = pyshark.LiveCapture(interface=interface_name, display_filter='http')

    for packet in capture.sniff_continuously():
        try:
            if hasattr(packet, 'http'):
                host = packet.http.host
                uri = packet.http.request_uri
                print(f"[HTTP] {packet.http.request_method} {host}{uri}")
                
                if hasattr(packet.http, 'file_data'):
                    print(f" ペイロード: {packet.http.file_data}")
        except AttributeError:
            continue

analyze_http('eth0')

ペイロードを処理する際、データは通常16進数形式であったり、エンコードされていたりします。正規表現を使用してトークンやAPIキーを抽出する場合は、ミスを防ぐためにパターンを慎重に確認する必要があります。私は、本番コードに組み込む前に toolcraft.app/ja/tools/developer/regex-tester などの正規表現テスターを使用して、パターンを素早くテストするようにしています。これにより、スクリプトを実行中のデバッグ時間を大幅に短縮できます。

パケットドロップを防ぐためのAsync利用

ループ内で重いロジックを処理すると、スクリプトがボトルネックになり、後続のパケットがドロップ (drop) してしまう可能性があります。解決策は、AsyncLiveCaptureを使用して非同期で処理することです。

import asyncio
import pyshark

async def capture_packets():
    capture = pyshark.LiveCapture(interface='eth0', display_filter='icmp')
    async for packet in capture.sniff_continuously():
        print(f"ICMPを検出: {packet.ip.src}")

loop = asyncio.get_event_loop()
loop.run_until_complete(capture_packets())

パフォーマンスに関する重要な注意点

  1. 実行権限: パケットキャプチャにはroot権限が必要です。sudo dpkg-reconfigure wireshark-commonを実行して、一般ユーザーが常にsudoを使わずにTSharkを実行できるように設定してください。
  2. メモリ管理: Pysharkはデフォルトで古いパケットを保持します。スクリプトを24時間365日稼働させる場合は、メモリ不足に注意してください。定期的にデータを格納しているリストをクリアするようにしましょう。
  3. BPF vs Display Filter: BPF Filterはカーネル層でフィルタリングを行うため、非常に高速です。Display FilterはTSharkがパケットを受け取った後にフィルタリングを行うため、より多くのリソースを消費します。可能な限りBPFを優先してください。

Pysharkをpandasと組み合わせて統計を取ったり、Telegram経由でアラートを送信したりすることで、非常に強力な監視システムを構築できます。このツールが皆さんの日常のシステム運用業務に役立つことを願っています。

Share: