AWS EC2でtcpdumpを使って解析

DNS FirewallがGoogleドメインをブロックする動作をAWS EC2でtcpdumpを使って解析

お世話になっております。yasuokaです。

本記事では、AWS EC2インスタンス上で tcpdump を使用し、AWS Route 53 DNS Firewall (DnsFW) がGoogleドメインをブロックしている様子をキャプチャする方法について解説します。

1. 事前準備:AWS EC2にログイン

a. AWS Systems Manager (SSM) を使ってEC2にログイン

AWS Systems Manager(SSM)を使用することで、SSH接続を使用せずにEC2インスタンスにログインできます。事前にEC2インスタンスに AmazonEC2RoleforSSM のIAMロールが付与されていることを確認してください。

手順:

  1. AWS マネジメントコンソールにログインし、Systems Managerを開きます。
  2. 左メニューから「セッションマネージャー」を選択します。
  3. セッションの開始」をクリックし、対象のEC2インスタンスを選択します。
  4. セッションの開始」ボタンをクリックすると、EC2インスタンスのシェルにアクセスできます。

DNSFWについては下記をご参照ください。

2. DNS Firewallの動作をtcpdumpでキャプチャ

a. 基本的なtcpdumpコマンド

tcpdump は、ネットワーク上のパケットをキャプチャし、リアルタイムで解析できるツールです。
ここでは、Googleドメインに関連するDNSトラフィックをキャプチャするため、DNSのポート(ポート53)をフィルタリングします。

コマンド例:

sudo tcpdump -i any -ttttv port 53
  • -i any: すべてのネットワークインターフェースでパケットをキャプチャ
  • -tttt: タイムスタンプを人間に読みやすい形式で表示
  • -v: 詳細モードでパケット情報を表示
  • port 53: DNSのポート(53)をフィルタリング

b. Googleドメインへのリクエスト確認

DNSFWがGoogleドメインをブロックしているかを確認するために、dig コマンドを使用してGoogleドメインに対してDNSリクエストを送信します。

コマンド例:

dig google.com

この際、tcpdump の出力にGoogleドメインへのDNSクエリが表示されるはずです。

出力例:

2024-10-09 15:30:00.123456 IP 192.168.1.100.12345 > 8.8.8.8.53: 12345+ A? google.com. (32)

3. DNS Firewallによるブロックの確認

DnsFWがGoogleドメインをブロックしている場合、NXDomain というエラーメッセージが返されることがあります。これは、リクエストされたドメインが存在しない、またはブロックされていることを意味します。

出力例:

2024-10-09 15:30:01.123456 IP 8.8.8.8.53 > 192.168.1.100.12345: 12345 NXDomain* 0/1/0 (92)

このようなエラーメッセージが表示された場合、GoogleドメインがDnsFWによってブロックされていることが確認できます。


4. tcpdumpの詳細と活用法

a. tcpdumpのオプション解説

  • -i any: すべてのインターフェースでパケットをキャプチャ。複数のインターフェースがある場合でも、DNSリクエストを逃さずにキャプチャできます。
  • -tttt: パケットのタイムスタンプを詳細に表示。トラブルシューティングや問題発生時の解析に便利です。
  • -v: 詳細なパケット情報を表示し、通常の出力には含まれないヘッダー情報も確認できます。

b. ログファイルとして保存

リアルタイムでの監視だけでなく、キャプチャ結果をログファイルとして保存することも可能です。

コマンド例:

sudo tcpdump -i any -ttttv port 53 > dns_capture.log

これにより、後で結果を解析したり、チームで共有することができます。

5. まとめ

この記事では、AWS EC2インスタンス上で tcpdump を使用して、DNS FirewallがGoogleドメインをブロックしている様子をキャプチャする手順を紹介しました。

tcpdump は、ネットワークトラブルを迅速に特定し、原因を解析するための強力なツールです。

DNSFWのように特定ドメインをブロックする際、その動作を確認するには非常に有効です。

tcpdumpを活用して、ネットワークの監視やトラブルシューティングを効率的に行いたいと思います。

6. 追記

Tcpdumpのログから、以下の要件を満たす情報を抽出して表示するために、awkとgrepを使用してみます。

要件:

  1. タイムスタンプ
  2. 送信元IPアドレスとポート
  3. 受信先IPアドレスとポート
  4. プロトコル番号
  5. 特定のプロトコルやコマンドの抽出:
    • Traceroute
    • Ping
    • Telnet

awk –version
grep –version

方法:

  1. tcpdumpのログ形式を前提に、grepawkで必要な部分を抽出。
  2. 各プロトコルやツールに関連するパターンに合わせてフィルタリング。
  3. sedを使用して、抽出した情報を整形。

出力例を送信元と受信先で分けて、TimestampSource(送信元IPアドレス)、Destination(受信先IPアドレス)、Type(プロトコルの種類)、Protocol(プロトコル番号)を表示する形式に修正します。

以下は、awkgrepを使用して、TcpdumpのログからICMP、TCP、UDPの通信を抽出し、フォーマットするコマンドです。

1. Ping (ICMP)

grep "ICMP" /path/to/tcpdump.log | grep -E "echo request|echo reply" | \
awk '{
    split($3, src, "\\."); 
    src_ip=src[1]"."src[2]"."src[3]"."src[4];

    if ($NF == "echo" && $(NF-1) == "request") {
        print "Timestamp: " $1, $2 ", Source: " src_ip ", Type: ICMP Echo Request, Protocol: 1";
    } else if ($NF == "echo" && $(NF-1) == "reply") {
        print "Timestamp: " $1, $2 ", Source: " src_ip ", Type: ICMP Echo Reply, Protocol: 1";
    }
}'

このコマンドは、tcpdumpでキャプチャされたICMP通信(特に「echo request」と「echo reply」)をフィルタし、フォーマットされた形で表示するものです。それぞれの部分の意味と動作を以下で詳しく説明します。

1. grep "ICMP" /path/to/tcpdump.log

  • 目的: tcpdump.logファイルからICMPパケット(例えばPing通信など)を含む行を検索します。
  • 動作: ログファイル内で「ICMP」という文字列を含む行を全て出力します。

2. grep -E "echo request|echo reply"

  • 目的: 先ほどのgrep結果の中から、さらに「echo request」または「echo reply」というフレーズを持つ行をフィルタします。
  • 動作: -Eオプションを使用して、正規表現をサポートし、echo requestまたはecho replyを含む行だけを残します。
    • echo request: ICMP Echo Request(Pingのリクエスト)。
    • echo reply: ICMP Echo Reply(Pingの応答)。

3. awk '{...}'

  • 目的: 残ったログ行から必要な情報(タイムスタンプ、送信元IPアドレス、通信のタイプなど)を抽出し、フォーマットして出力します。
  • 動作: awkを使ってフィールドを分割し、ICMPの情報を整形します。

split($3, src, "\\.");

  • 目的: tcpdumpのログの第3フィールドにある送信元IPアドレス(例:192.168.1.10)を分割します。
  • 動作: .で送信元IPアドレスを分割し、srcという配列に格納します。$3はログの3番目のフィールドで、送信元IPアドレスがここにあります。

src_ip=src[1]"."src[2]"."src[3]"."src[4];

  • 目的: splitで分割したIPアドレスを再度結合して、送信元IPアドレスとして使用します。
  • 動作: src配列の各要素(IPアドレスのそれぞれの部分)を.でつなげて元の形式に戻します。

if ($NF == "echo" && $(NF-1) == "request") {...}

  • 目的: ICMP Echo Requestであるかどうかを判定します。
  • 動作:
    • NFawkで「行のフィールド数」を表します。$NFは「最後のフィールド」を示し、この場合は「echo」という単語を指します。
    • $(NF-1)は最後から2番目のフィールドを示し、この場合は「request」や「reply」を指します。
    • このif文では、ICMP Echo Request(echo request)であれば、整形された出力を生成します。

print "Timestamp: " $1, $2 ", Source: " src_ip ", Type: ICMP Echo Request, Protocol: 1";

  • 目的: タイムスタンプ、送信元IP、通信のタイプを整形して出力します。
  • 動作:
    • $1$2は、最初と2番目のフィールド(タイムスタンプ部分)を取得。
    • src_ipは先ほど結合した送信元IPアドレス。
    • Type: ICMP Echo RequestはICMPリクエストであることを示します。
    • Protocol: 1はICMPプロトコルの番号(常に1)を表します。

else if ($NF == "echo" && $(NF-1) == "reply") {...}

  • 目的: ICMP Echo Replyであるかどうかを判定します。
  • 動作: ICMP Echo Reply(echo reply)であれば、別のフォーマットで出力します。

print "Timestamp: " $1, $2 ", Source: " src_ip ", Type: ICMP Echo Reply, Protocol: 1";

  • 目的: ICMP Echo Reply(Pingの応答)に対応する出力を生成します。

全体の流れ

  1. grepでICMPのパケットをフィルタリング。
  2. さらにgrepで「echo request」や「echo reply」を持つ行を選び出す。
  3. awkで、タイムスタンプ、送信元IPアドレス、通信のタイプを抽出してフォーマットし、出力。

意図

  • grepで必要なログを絞り込み、awkでそれを整形して人間が読みやすい形式に変換するプロセスです。
  • tcpdumpログの構造に依存しますが、この方法でICMP通信の基本的な情報(タイムスタンプ、送信元IP、通信タイプ、プロトコル番号)を効率的に抽出できます。

2. Traceroute (UDP)

grep "UDP" /path/to/tcpdump.log | \
awk '{
    split($3, src, "\\."); 
    split($5, dest, "\\.");
    src_ip=src[1]"."src[2]"."src[3]"."src[4];
    dest_ip=dest[1]"."dest[2]"."dest[3]"."dest[4];

    print "Timestamp: " $1, $2 ", Source: " src_ip ", Destination: " dest_ip ", Type: UDP, Protocol: 17";
}'

3. Telnet (TCP)

grep "TCP" /path/to/tcpdump.log | grep ":23 " | \
awk '{
    split($3, src, "\\."); 
    split($5, dest, "\\.");
    src_ip=src[1]"."src[2]"."src[3]"."src[4];
    dest_ip=dest[1]"."dest[2]"."dest[3]"."dest[4];

    print "Timestamp: " $1, $2 ", Source: " src_ip ", Destination: " dest_ip ", Type: TCP, Protocol: 6";
}'

出力例

実行結果は以下のように表示されます。

Timestamp: 2024-10-11 10:00:00, Source: 192.168.1.10, Type: ICMP Echo Request, Protocol: 1
Timestamp: 2024-10-11 10:00:01, Source: 192.168.1.20, Type: ICMP Echo Reply, Protocol: 1
Timestamp: 2024-10-11 10:00:02, Source: 192.168.1.10, Destination: 192.168.1.20, Type: TCP, Protocol: 6
Timestamp: 2024-10-11 10:00:03, Source: 192.168.1.10, Destination: 192.168.1.20, Type: UDP, Protocol: 17

ICMPの出力例は、以下のようになります。

ICMP Echo Request(Pingのリクエスト)

Timestamp: 2024-10-11 10:00:00, Source: 192.168.1.10, Type: ICMP Echo Request, Protocol: 1

ICMP Echo Reply(Pingのリプライ)

Timestamp: 2024-10-11 10:00:01, Source: 192.168.1.20, Type: ICMP Echo Reply, Protocol: 1

このように、ICMPプロトコルでは「Echo Request(リクエスト)」と「Echo Reply(応答)」が主要な通信タイプで、プロトコル番号は常に 1 です。

上記例の背景:

  • タイムスタンプ: ログが記録された時間(例:2024-10-11 10:00:00)。
  • Source: Pingを送信したIPアドレス(例:192.168.1.10がEcho Requestを送信)。
  • Type: 通信タイプ(ICMPのEcho RequestまたはEcho Reply)。
  • Protocol: ICMPのプロトコル番号は常に 1

これらのログは、ICMPの通信内容を表しており、Pingコマンドの結果をtcpdumpなどのネットワークパケットキャプチャツールで解析したときに見られる情報です。

  • Traceroute (UDP): UDPを使用した通信で、送信元と受信先、ポート番号とプロトコル番号(17)を表示。
  • Telnet (TCP): ポート23でのTCP通信を抽出し、Telnetの通信を表示。

AWKを使わないで、grepsedだけで同様のICMPのログを整形する方法を以下に示します。この場合、grepsedを組み合わせて情報を抽出し、必要な情報を整形します。

追記の追記 ICMPのgrepsedを使った例

コマンド例

grep "ICMP" /path/to/tcpdump.log | grep -E "echo request|echo reply" | \
sed -E 's/([0-9-]+ [0-9:]+)\..* IP ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+) > .*, (ICMP echo request|ICMP echo reply).*/Timestamp: \1, Source: \2, Type: \3, Protocol: 1/'

コマンドの詳細な説明

  1. grep "ICMP" /path/to/tcpdump.log

    • 目的: tcpdumpのログファイルから「ICMP」に関連するパケットを含む行を抽出します。
    • 動作: tcpdump.logの中で「ICMP」が含まれている行のみをフィルタリングします。
  2. grep -E "echo request|echo reply"

    • 目的: ICMPパケットの中でも、特にecho requestまたはecho replyの行をフィルタします。
    • 動作: -Eは正規表現をサポートし、「echo request」または「echo reply」を含む行だけを選びます。
  3. sed -E 's/([0-9-]+ [0-9:]+)\..* IP ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+) > .*, (ICMP echo request|ICMP echo reply).*/Timestamp: \1, Source: \2, Type: \3, Protocol: 1/'

    • 目的: フィルタされたログの各行を整形し、指定されたフォーマットで出力します。
    • 動作:
      • sed -Eは拡張正規表現を有効にします。
      • s/sedの置換コマンドです。s/パターン/置換/の形式でマッチした部分を置換します。
      • ([0-9-]+ [0-9:]+)はタイムスタンプ部分(2024-10-11 10:00:00の形式)を抽出。
      • ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)は送信元IPアドレスを抽出。
      • (ICMP echo request|ICMP echo reply)はICMPのタイプ(リクエストまたはリプライ)を抽出。
      • .*でその後の不要な情報を無視します。
      • \1, \2, \3は、それぞれ正規表現でキャプチャした部分(タイムスタンプ、IPアドレス、ICMPタイプ)を置換時に使用します。
      • Protocol: 1は固定値(ICMPのプロトコル番号)として追加します。

実行結果の例

もし、tcpdump.logに以下のようなICMPのパケットが含まれていた場合:

2024-10-11 10:00:00.123456 IP 192.168.1.10 > 192.168.1.20: ICMP echo request, id 1, seq 1, length 64
2024-10-11 10:00:01.123456 IP 192.168.1.20 > 192.168.1.10: ICMP echo reply, id 1, seq 1, length 64

上記のコマンドを実行すると、以下のような出力が得られます。

Timestamp: 2024-10-11 10:00:00, Source: 192.168.1.10, Type: ICMP Echo Request, Protocol: 1
Timestamp: 2024-10-11 10:00:01, Source: 192.168.1.20, Type: ICMP Echo Reply, Protocol: 1

この方法では、grepでログから必要な行を抽出し、sedでその行を整形して出力します。AWKを使わずに、sedの正規表現を使って行を処理することで、簡潔にデータを整形することが可能です。

1. ツールの目的と機能

  • AWK: データ処理に特化したツールで、フィールド単位での操作が簡単にでき、計算や条件分岐、変数操作など、より柔軟なデータ処理が可能です。データをフィールドに分けて操作する場合や複雑な条件を含む場合に有利です。
  • sed: 主に文字列の検索・置換を行うストリームエディタで、行全体の文字列操作が得意です。フィールド単位の操作は苦手で、条件分岐や計算処理が限られます。

2. データの操作

  • AWK: 各フィールドを簡単に分割し、柔軟に操作することができます。例えば、ログの送信元IP、宛先IP、プロトコルなどをフィールドごとに分けてアクセスし、複数の条件を組み合わせることが可能です。split()関数や条件分岐 (if-else) などを使って複雑な操作を行えます。
  • sed: 正規表現を使って行全体を処理し、文字列のパターンにマッチさせてから部分的に抽出・置換します。sedは行全体を処理するため、フィールド単位の細かな操作は難しいです。

例: AWK vs sedの処理の違い

AWKでの操作:

awk '{
    split($3, src, "\\.");
    src_ip=src[1]"."src[2]"."src[3]"."src[4];

    if ($NF == "echo" && $(NF-1) == "request") {
        print "Timestamp: " $1, $2 ", Source: " src_ip ", Type: ICMP Echo Request, Protocol: 1";
    } else if ($NF == "echo" && $(NF-1) == "reply") {
        print "Timestamp: " $1, $2 ", Source: " src_ip ", Type: ICMP Echo Reply, Protocol: 1";
    }
}'
  • split()関数でフィールドを分割し、IPアドレスを操作しやすい形にします。
  • $NFは最後のフィールド、$(NF-1)は最後から2番目のフィールドを指し、条件分岐 (if-else) で複雑な処理が簡単にできます。

sedでの操作:

sed -E 's/([0-9-]+ [0-9:]+)\..* IP ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+) > .*, (ICMP echo request|ICMP echo reply).*/Timestamp: \1, Source: \2, Type: \3, Protocol: 1/'
  • 正規表現で、行全体からタイムスタンプやIPアドレス、ICMPのタイプをキャプチャし、それを所定の形式で出力します。
  • sedではフィールド単位の操作がないため、正規表現でパターンマッチングと置換を行います。

3. 複雑な処理

  • AWK: 複数条件に基づいた分岐処理や、算術計算などが簡単にできます。また、フィールドごとに分割して処理する場合、非常に直感的です。
  • sed: 正規表現を使って文字列のパターンマッチングと置換を行うため、シンプルなテキスト処理には向いていますが、複雑な条件分岐やデータの操作には適していません。

AWKの複雑な処理例:

例えば、AWKでは次のように複数の条件を組み合わせてデータ処理が可能です。

awk '{
    split($3, src, "\\.");
    split($5, dst, "\\.");
    src_ip=src[1]"."src[2]"."src[3]"."src[4];
    dst_ip=dst[1]"."dst[2]"."dst[3]"."dst[4];

    if ($NF == "echo" && $(NF-1) == "request") {
        print "Timestamp: " $1, $2 ", Source: " src_ip ", Destination: " dst_ip ", Type: ICMP Echo Request, Protocol: 1";
    }
}'

これは、送信元と受信先のIPアドレスを取り出し、if文で複雑な条件分岐を行っています。

4. 学習曲線

  • AWK: 構文がやや独特で、基本的な操作を覚えるまでに少し時間がかかるかもしれません。しかし、データ処理やテキスト処理の強力なツールとして非常に有用です。
  • sed: 基本的には検索・置換に特化しており、正規表現に慣れていれば簡単に使えますが、柔軟性はAWKに比べて低いです。

まとめ

  • AWKの強み: フィールド単位の柔軟なデータ操作、条件分岐や計算が必要な場合に非常に適しています。複雑なログ解析や高度なデータ処理に向いています。
  • sed/grepの強み: シンプルなパターンマッチングや文字列の置換に向いています。行全体のテキスト操作には強いですが、フィールド単位の操作はAWKより難しいです。
Last modified: 2024-10-15

Author