cloretsblackのテクニカルノート

言葉の意味はよくわからんがとにかくすごい自信だ

ギンギラギンにさりげなくTCPコネクションを可視化してみた

私は普段、ネットワークを運用する人々のためにどうやったらネットワークをよりよく可視化出来るか、みたいな事を考えているわけなんですが、何をトチ狂ったのか、いっそのことアートっぽくしてみたら良いんじゃないかという思い付きを得てしまったので、形にしてみました。

一般的に、スイッチのアクセスインジケータはフレームの通過をLEDランプで可視化しています。同じノリでTCPの各種フラグを可視化してみたら、「なんか今日はRST多いなー?」とか「SYN多くね?サービス落ちてんの?」みたいなことがなんとなく分かるんじゃないかと思ったわけなのです。

フラグにそれぞれ色を割り当てて、パケットが通過するたびにLEDを光らせてみたいと思います。 「Crystal Signal Pi」 というRaspberryPiを使ってマルチカラーLEDを光らせるキットが販売されていたので使ってみました。

今回使用した「Crystal Signal Pi」 にはWEBサーバが用意されており、curlで色や光り方を指定して信号を送るとLEDがパカパカ光る仕組みになっています。 パケットキャプチャとして取得したデータをPythonでフラグだけ抽出し、フラグに応じてcurlを送る事にします。 継続的にパケットを取得する仕組みには、ソナーマンを使います。

手前味噌で大変恐縮ですが、ソナーマンは私、黒ブラが開発しておりますパケットレコーダー製品です。 継続的にパケットキャプチャを収集し、車のドライブレコーダーのように、障害が起きたその時にネットワークがどういう状態だったのかを後から検証できる大変便利な商品でございます。 コレを説明しだすと長くなりますので詳細は割愛します。 一応リンクだけ貼っておきます。 develup-japan.co.jp

スイッチはNETGEARのGS108Eを使用しました。実売5,000円前後でミラーリング機能が付いているので、非常に使い勝手が良いです。僕は大好きです。

さて以下のようにTCPフラグに応じて光らせる色を決めます。

SYN …青
SYN+ACK …白
ACK+PSH …緑
FIN+ACK …オレンジ
RST …赤

コネクションの開始と終了が青から赤に向かって見えると直感的に理解しやすいと思います。 なお、ACK+PSHフラグは大量に出現するので、初回の3回のみ光らせるという制限を入れています。

コードは以下の通りです。 /capture/cap/以下のパケットキャプチャファイルを連続して読み込み、LEDを光らせていきます。

import dpkt
import os.path
import glob

file_list = sorted(glob.glob('/capture/cap/*.pcap'))
for filename in file_list:
    with open(filename, 'rb') as f:
        p = dpkt.pcap.Reader(f)
        counter = 0

        for ts,buf in p:
            eth = dpkt.ethernet.Ethernet(buf)
        #ipv4
            if type(eth.data) == dpkt.ip.IP:
                ip = eth.data
                if type(ip.data) == dpkt.tcp.TCP:
                    tcp = ip.data
                    fin_flag = int(( tcp.flags & dpkt.tcp.TH_FIN ) != 0)
                    syn_flag = int(( tcp.flags & dpkt.tcp.TH_SYN ) != 0)
                    rst_flag = int(( tcp.flags & dpkt.tcp.TH_RST ) != 0)
                    psh_flag = int(( tcp.flags & dpkt.tcp.TH_PUSH) != 0)
                    ack_flag = int(( tcp.flags & dpkt.tcp.TH_ACK ) != 0)
                    urg_flag = int(( tcp.flags & dpkt.tcp.TH_URG ) != 0)

                    curlcmd = ""

                    if syn_flag == 1 and ack_flag == 1:
                        curlcmd ="curl 'http://localhost:8080/ctrl/?color=50,200,255&mode=1&repeat=1&period=300'"

                    elif syn_flag == 1:
                        curlcmd ="curl 'http://localhost:8080/ctrl/?color=00,00,255&mode=1&repeat=1&period=300'"
                        counter = 0

                    elif ack_flag == 1 and psh_flag == 1 and counter < 3 :
                        curlcmd ="curl 'http://localhost:8080/ctrl/?color=00,255,20&mode=1&repeat=1&period=300'"
                        counter += 1

                    elif fin_flag == 1 and ack_flag == 1:
                        curlcmd ="curl 'http://localhost:8080/ctrl/?color=255,127,0&mode=1&repeat=1&period=300'"

                    elif rst_flag == 1:
                        curlcmd ="curl 'http://localhost:8080/ctrl/?color=255,00,00&mode=1&repeat=1&period=300'"

                    if curlcmd != "":
                       req = os.system(curlcmd)

パケットキャプチャからフラグを読み取る処理時間と、光らせる秒数を一律300msに設定している関係上、完全なリアルタイムにはなりませんでした。しかし、完全にリアルタイムである必要はなく、雰囲気が伝わればOKということであまり深く考えない事にします。楽しければ良い。

ビカビカ光るんだけども、いつものネットワークをさりげなく可視化してくれるシステムと言う事で、近藤真彦御大の「ギンギラギンにさりげなく」をバックミュージックにデモムービーを作りましたので、ご覧ください。

youtu.be

こんな動画を作ってる暇があったら技術書典の原稿を進めろというツッコミはご遠慮ください。本人は気にしておりますので。