TCPのハーフコネクション・ハーフオープン
TCPでデータを転送する場合、データの転送を行う前にコネクションが確立されている必要があります。
一方で、TCPは、状態を持つ(ステートフルな)プロトコルであり、サーバ、クライアントそれぞれが状態を持つことになります。
TCPのハーフコネクション・ハーフオープンは、サーバまたはクライアントのノードが、他方に知らせることなく終了した場合などに発生し、そのどちらかのノードのみがコネクション接続状態となっていることを示します。
この状態となってしまった場合、そのコネクションを使った通信には応答が返ってくることありません。コネクションプールで常時接続を行うアプリケーションでは、応答が返らないことで障害が長期化する恐れがあります。
本事象は、対抗ノードのOSのクラッシュ、プロセス停止なしでのNICの停止、ケーブルが抜けたケースなどで発生する可能性があります。
TCPキープアライブの機能を有効とすることで、ハーフコネクション・ハーフオープンの状態を検知し、解消することが可能です。TCPキープアライブについては以下のエントリを参照してください。
tcpdumpとiptablesで理解するTCPのキープアライブ(TCP keepalive)
TCPのコネクションについての詳細は以下のエントリを参照してください。
上記TCPのハーフコネクション・ハーフオープンの状態をiptablesコマンドとtcpdumpコマンドで実際に確認して行きます。
tcpdumpとiptablesで理解するTCPのハーフコネクション・ハーフオープン
0.前準備
本エントリでは、以下のLinuxコマンドを使用します。
- tcpdump
- ネットワーク上のパケットを出力するために使用します。
- nc,telnet
- tcpサーバー/クライアントとして使用します。
- netstat
- コネクションの状態を確認するために使用します。
- iptables
- コネクション確立要求をDROPするために使用します。
上記コマンドがインストールされていない場合、以下のコマンドでインストールします。
$ sudo yum -y install tcpdump nc telnet net-tools iptables
1. コネクションの確認、iptablesの前準備
以下のエントリの1.2.の手順を実施して、コネクションの確認、iptablesの前準備までを確認してください。
tcpdumpとiptablesで理解するTCPのコネクションタイムアウト (connection timeout)
-
- コネクションの確認
-
- iptablesの前準備
2. iptablesでハーフコネクション・ハーフオープンを発生させる
telnetまたはncコマンドでTCPクライアントを起動し、ローカルで起動している1.のTCPサーバに接続します。
$ telnet 127.0.0.1 12345
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
netstatコマンドでncとtelnetのコネクションが確立されている(ESTABLISHになっている)事を確認します。
$ netstat -anp | grep 12345
tcp 0 0 0.0.0.0:12345 0.0.0.0:* LISTEN <PID>/nc
tcp 0 0 127.0.0.1:<port> 127.0.0.1:12345 ESTABLISHED <PID>/telnet
tcp 0 0 127.0.0.1:12345 127.0.0.1:<port> ESTABLISHED <PID>/nc
tcpdumpコマンドでlocal interfaceのport12345を指定して実行します。
$ sudo tcpdump -i lo -nnn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
iptablesで、上記ののport番号のdestination portのパケット廃棄(DROP)のためのルールを設定します。
$ sudo iptables -A INPUT -p tcp -d 127.0.0.1 --dport <port> -j DROP
ここで、TCPサーバとして起動していたncのプロセスを停止します。
ncプロセスにkillコマンドまたはCtrl-cにてシグナルを送信します。
ここでtcpdumpの出力に以下のような、FINパケットの再送が確認できます。
20:28:59.148263 IP 127.0.0.1.12345 > 127.0.0.1.<port>: Flags [F.],
20:28:59.349161 IP 127.0.0.1.12345 > 127.0.0.1.<port>: Flags [F.],
20:28:59.752355 IP 127.0.0.1.12345 > 127.0.0.1.<port>: Flags [F.],
20:29:00.557410 IP 127.0.0.1.12345 > 127.0.0.1.<port>: Flags [F.],
この状態で、netstatを実行すると以下のような結果が得られます。
$ netstat -anp | grep 12345
tcp 0 0 127.0.0.1:<port> 127.0.0.1:12345 ESTABLISHED <PID>/telnet
$
nc(TCPサーバ)のプロセスがない状態で、telnet(TCPクライアント)がESTABLISHになっています。
この状態をTCPのハーフコネクション・ハーフオープンと呼びます。
この状態で、telnet(TCPクライアント)がいかなる要求を発行しても、nc(TCPサーバ)から応答が返ることはありません。