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ロールが付与されていることを確認してください。
手順:
- AWS マネジメントコンソールにログインし、Systems Managerを開きます。
- 左メニューから「セッションマネージャー」を選択します。
- 「セッションの開始」をクリックし、対象のEC2インスタンスを選択します。
- 「セッションの開始」ボタンをクリックすると、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を使用してみます。
要件:
- タイムスタンプ
- 送信元IPアドレスとポート
- 受信先IPアドレスとポート
- プロトコル番号
- 特定のプロトコルやコマンドの抽出:
- Traceroute
- Ping
- Telnet
awk –version
grep –version
方法:
tcpdump
のログ形式を前提に、grep
やawk
で必要な部分を抽出。- 各プロトコルやツールに関連するパターンに合わせてフィルタリング。
sed
を使用して、抽出した情報を整形。
出力例を送信元と受信先で分けて、Timestamp
、Source
(送信元IPアドレス)、Destination
(受信先IPアドレス)、Type
(プロトコルの種類)、Protocol
(プロトコル番号)を表示する形式に修正します。
以下は、awk
とgrep
を使用して、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であるかどうかを判定します。
- 動作:
NF
はawk
で「行のフィールド数」を表します。$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の応答)に対応する出力を生成します。
全体の流れ
grep
でICMPのパケットをフィルタリング。- さらに
grep
で「echo request」や「echo reply」を持つ行を選び出す。 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
を使わないで、grep
やsed
だけで同様のICMPのログを整形する方法を以下に示します。この場合、grep
やsed
を組み合わせて情報を抽出し、必要な情報を整形します。
追記の追記 ICMPのgrep
やsed
を使った例
コマンド例
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/'
コマンドの詳細な説明
-
grep "ICMP" /path/to/tcpdump.log
- 目的:
tcpdump
のログファイルから「ICMP」に関連するパケットを含む行を抽出します。 - 動作:
tcpdump.log
の中で「ICMP」が含まれている行のみをフィルタリングします。
- 目的:
-
grep -E "echo request|echo reply"
- 目的: ICMPパケットの中でも、特に
echo request
またはecho reply
の行をフィルタします。 - 動作:
-E
は正規表現をサポートし、「echo request」または「echo reply」を含む行だけを選びます。
- 目的: ICMPパケットの中でも、特に
-
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より難しいです。