1.はじめに
本記事は前編http://qiita.com/jinnai73/items/5135f528578ae1612338 からの続きです。
前編ではTelnetポートテストの便利さについて書きました。
後編ではシステム構築中に実際に嵌った落とし穴について書きたいと思います。
2.構築環境
3.問題発生
図のような構成でPC-AからServerにアプリケーション接続を行うという要件でした。PC-AからServerに対してPingが通り(IP接続性の担保)、さらにTelnetポートテストが通った状態で(TCP接続性の担保)、PC-Aにデプロイされたアプリケーションが動きません。
切り分けのためにPC-Bにアプリケーションを入れるとこちらは動作をしたため、ネットワークのどこかに問題がありそうということが分かり、PC-AとServerそれぞれでパケットキャプチャを実施しました。以下がパケットキャプチャの結果です。
PC-A: SYN送信、SYN+ACK受信、ACK送信
Server: SYN受信、SYN+ACK送信、SYN+ACK再送、SYN+ACK再送、、、タイムアウト
PC-Aから見ると正常にTCPコネクションが張れているように見えており、netstatの結果もEstablishedになりました。しかし最後のACKがserverに届いていません。ACKだけ止めるようなネットワーク……明らかに図のFirewallが悪さをしています。非対称ルーティングが出来てしまっている典型的な現象です。
Firewall周辺の担当者にヒアリングを行った結果、最終的には上の絵には無い別の経路があったため非対称ルーティングになってしまっていて、Firewallのステートフルインスペクションで最後のACKだけが落とされていたことが分かりました。
非対称ルーティングは勿論あってはならないものなので修正しましたが、しかしそれでも「クライアント側から見るとTelnetテストを通ってしまう」というのには気付かず、問題発見まで時間がかかりました。
4.再現試験
ということで再現してみます。我が家には残念ながらFWが無いため、CatalystスイッチのACLでACKだけを止める設定で代用します。なおサーバも無くPCも一台しかないため、サーバ側もCatalystスイッチのWebサーバ機能で代用します。
肝心のACKの止め方ですが、ACLのestablishedオプションを使います。establishedオプションをつけるとACKもしくはRSTのセットされたパケットのみに合致するようになります。
http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/security/a1/sec-a1-cr-book/sec-cr-a2.html#wp4698537840
では設定していきましょう。
4-1.ACL無し
L3スイッチ機能の有効化:
Switch(config)#ip routing
HTTPサーバの有効化:
Switch(config)#ip http server
インターフェースの設定:
Switch(config)#interface FastEthernet 1/0/1
Switch(config-if)#no switchport
Switch(config-if)#ip address 192.168.1.254 255.255.255.0
この状態でHTTPサーバへの接続ができるようになったはずです。コマンドプロンプトからPing、Telnetテスト、およびブラウザからの接続を試してみます。Telnetは真っ黒画面に遷移してしまうため、コマンドプロンプトを2窓開いてnetstatでコネクション状態を確認します。
c:\>ping 192.168.1.254
192.168.1.254 に ping を送信しています 32 バイトのデータ:
192.168.1.254 からの応答: バイト数 =32 時間 <1ms TTL=255
192.168.1.254 からの応答: バイト数 =32 時間 <1ms TTL=255
192.168.1.254 からの応答: バイト数 =32 時間 <1ms TTL=255
192.168.1.254 からの応答: バイト数 =32 時間 <1ms TTL=255
192.168.1.254 の ping 統計:
パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
最小 = 0ms、最大 = 0ms、平均 = 0ms
c:\>telnet 192.168.1.254 80
(真っ黒な画面に遷移)
c:\>netstat -na |find "192.168.1.254"
TCP 192.168.1.1:64609 192.168.1.254:80 ESTABLISHED
4-2.ACL有り
ACKビットの立っているパケットを拒否するACL作成:
Switch(config)#ip access-list extended 100
Switch(config-ext-nacl)#deny tcp any any established
Switch(config-ext-nacl)#permit ip any any
インターフェースへの適用
Switch(config)#interface FastEthernet 1/0/1
Switch(config-if)#ip access-group 100 in
先ほどと同じテストをします。
c:\>ping 192.168.1.254
192.168.1.254 に ping を送信しています 32 バイトのデータ:
192.168.1.254 からの応答: バイト数 =32 時間 =1ms TTL=255
192.168.1.254 からの応答: バイト数 =32 時間 <1ms TTL=255
192.168.1.254 からの応答: バイト数 =32 時間 =1ms TTL=255
192.168.1.254 からの応答: バイト数 =32 時間 <1ms TTL=255
192.168.1.254 の ping 統計:
パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
最小 = 0ms、最大 = 1ms、平均 = 0ms
c:\>telnet 192.168.1.254 80
(真っ黒な画面に遷移)
c:\>netstat -na |find "192.168.1.254"
TCP 192.168.1.1:64720 192.168.1.254:80 ESTABLISHED
TCPまでは異常なしですが、実はACKがWebサーバに到達していないためTCP 3ウェイ・ハンドシェイクは完了していません。よってアプリケーションレベルでも通信はできません。
5.まとめ
クライアント側がESTABLISHEDと言っていても、サーバ側がESTABLISHEDになっているとは限らないというお話でした。対策としてはサーバ側でもパケットキャプチャをしてみるぐらいです。
あと、非対称ルーティングは駄目、絶対。見つけたら即直しましょう。