開発環境でHTTPとかの通信をキャプチャしていい感じでデバッグする方法



この記事は[『LITALICO Engineers Advent Calendar 2017』](https://qiita.com/advent-calendar/2017/litalico)の21日目の記事です。

昨年は、[ナウでイケてる格安の分析基盤&BIツールをGoogleスプレッドシートとBigQueryを中心に構築する方法](https://qiita.com/wapa5pow/items/1e55774d49aa7b461c82)として、無料に近い価格で、分析環境を整える方法を紹介しました。今年に入っても2社ほど、この方法でダッシュボードを作ったりしていたのでまだまだ結構使える感じだと思います。無料の分析UIとして、Spreadsheetに加えて、Google Data StudioやRedashなどを使えたりしますが、まだまだSQLをかかなければいけないことが多かったり制約があったりするので、早くTableau的なやつが安く使えるといいなと思ってます。

今回のAdvent CalendarではWiresharkを使った、開発環境でのパケットキャプチャについて紹介します。LITALICO以外でも開発しているのですが、その開発環境としてGO言語で、`docker-compose up`して、dockerでDatastoreのEmulator, Elasticsearch, Pub/SubのEmulatorなどが動いていています。その他に、FirebaseにHTTPSでPush通知のリクエストを飛ばしたりしています。時々、アプリからElasticsearchやその他のサービスにどんなリクエストがみたくなるときがあって、GOにprint文とかをうめこんでみたりしているのですが、さすがにだるくなってきたので、Wiresharkでパケットをキャプチャしてどのようなリクエストとレスポンスが飛んでいるのか見れることをゴールにします。

# Wiresharkとは

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30079/9e527c48-f090-3cf4-a9c7-bd120712decf.png)

パケットをキャプチャするソフトウエアです。似たようなソフトソフトウエアとしては、Chalersなどがありますが、CharlesはHTTPに特化しているようなイメージで、WiresharkはIPとかTCPレイヤーとかまるっと見えます。今回Charlesではなく、Wiresharkを選んだのは、Charlesを使うと、Dockerで動かしているコンテナがとまってしまうのと([Issue](https://github.com/docker/for-mac/issues/2039))、gRPCとSSLをつかっていてその時のデバッグでWiresharkが役立ったので、簡単に使えるようになれるように選びました。

Wiresharkのインストールなどは公式HPや、他のQiita記事を参考にしてみてください

# Elasticsearchのパケットをいい感じでデバッグする

早速使い方を説明します。まずWiresharkを開くとネットワークインタフェースを選ぶ画面がでてきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30079/3b53d982-c8fe-af04-b704-b2c500eba3b9.png)

Wifi: en0とかついているのがネットワークインタフェースの名前で、どのインタフェースのパケットをキャプチャするか選びます。右側のうねうねとなっているグラフが現在までのパケット量を表しています。いま使っているMacはWifiとLANにつながっていますので、Wi-Fi: en0とAX88179...がそれぞれWifiとLANのネットワーク・インタフェースで、Loopback: lo0となっているのが、localhostなどにアクセスしたときに使われるネットワークインタフェースです。今回は開発環境でのパケットを取得したいので、Loopback: lo0を選択して次に進みます。

今回はcURLで以下のリクエストを飛ばしてそれがどのようにWiresharkで見つけられるかみてみます。

```bash
curl -XGET "http://localhost:9200/test/_analyze" -H 'Content-Type: application/json' -d'
{
  "analyzer" : "readingform_index_analyzer",
  "text" : "おいしい牛乳"
}'
```

Loopbackでキャプチャできるパケットが取得できるのですが、パケットが多すぎてフィルタしたくなります。
フィルタは以下からできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30079/7258b2fb-18e4-a361-6763-c4e97f987250.png)

Elasticsearchは9200のポートで、HTTPのみ表示させたいので`tcp.port == 9200 && http`のように指定するといい感じでフィルタできます。

ただ、Kibanaなどを動かしていると以下のようにやたらゴミなクエリがとんできていて、目的のものが見つけにくいです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30079/9e028211-883c-a621-7474-4355cc6850cc.png)

その場合はさらに、`tcp.port == 9200 && http && !(tcp.port == 52083 || tcp.port == 52082)`みたいにKibanaが使っているsrcポートを指定してフィルタします。
それでもフィルタできない場合は、リクエストまたはレスポンスに入っているであろうJSON文字列もフィルタできるので今回は`json contains analyzer`でフィルタします。analyzerが探したい文字列です

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30079/19e382a8-4bb0-d993-0d98-1ae399feb34f.png)

見つかった目的のパケットを選択した状態で、Wiresharkのメニューの以下からパケットを表示します。（パケット選択して、右クリックから、追跡=>HTTPストリーム、でもいけます。）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30079/16912fbb-b69b-ff49-5f55-072c531ef7f4.png)

すると以下のようにHTTPのリクエストとレスポンスが表示されていいかんじで見れました。これでデバッグが容易になります。
ちなみに、UTF-8形式にしないと日本語は表示されないので気をつけてください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30079/fefdc166-846d-899d-2257-c11a525eda6e.png)

それ以外の方法でも、`JavaScript Object Notation`を右クリックしてから、パケットバイト列を表示にしてから、HTML形式を選択してもJSON自体の中身は見ることができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30079/90aa4a75-314c-5216-12b5-c654f7a80263.png)

# まとめ

アプリにprint文などをうめこんでいなくてもWiresharkを使えば、サーバと他のサービス間での通信がキャプチャできます。その他にも、以前、GKEで、gRPCを使ってHTTP/2のSSL通信を使おうとしたときにうまくできなくてWiresharkでパケットをみながら解決したことがありましたので、プロトコルレベルでうまくかないときに使うのもおすすめです。