全部博文(113)
分类: 嵌入式
2010-11-08 17:32:55
这比传统的向两端发送多个 RST 包试图切断 TCP 连接的方式要优雅得多。因为 TCP 连接在 ESTABLISHED 状态时收到 RST 包后,直接清理队列并删除 TCB,连接进入 CLOSED 状态。
以下为引用:
second check the RST bit,...
ESTABLISHED
FIN-WAIT-1
FIN-WAIT-2
CLOSE-WAITIf the RST bit is set then, any outstanding RECEIVEs and SEND
should receive "reset" responses. All segment queues should be
flushed. Users should also receive an unsolicited general
"connection reset" signal. Enter the CLOSED state, delete the
TCB, and return.
以下为引用:
C RST --> B (ESTABLISHED)
(ESTABLISHED) A DATA --> B (CLOSED)
(ESTABLISHED) A <-- RST C
(CLOSED) A <-- RST B (CLOSED)
以下为引用:
If the state is CLOSED (i.e., TCB does not exist) thenall data in the incoming segment is discarded. An incoming
segment containing a RST is discarded. An incoming segment not
containing a RST causes a RST to be sent in response. The
acknowledgment and sequence field values are selected to make the
reset sequence acceptable to the TCP that sent the offending
segment.
对上述漏洞所处的 ESTABLISHED 状态处理 SYN 包的流程, 中是如下描述的(rfc793.txt:4394):
以下为引用:
fourth, check the SYN bit,SYN-RECEIVED
ESTABLISHED STATE
FIN-WAIT STATE-1
FIN-WAIT STATE-2
CLOSE-WAIT STATE
CLOSING STATE
LAST-ACK STATE
TIME-WAIT STATEIf the SYN is in the window it is an error, send a reset, any
outstanding RECEIVEs and SEND should receive "reset" responses,
all segment queues should be flushed, the user should also
receive an unsolicited general "connection reset" signal, enter
the CLOSED state, delete the TCB, and return.If the SYN is not in the window this step would not be reached
and an ack would have been sent in the first step (sequence
number check).
翻阅了一下FreeBSD 5/Linux 2.4.26 和NT 4的TCP部分代码,在FreeBSD中很容易就找到了这种情况的处理代码(sys etinet cp_input.c:1697):
以下为引用:
/*
* If a SYN is in the window, then this is an
* error and we send an RST and drop the connection.
*/
if (thflags & TH_SYN) {
tp = tcp_drop(tp, ECONNRESET);
rstreason = BANDLIM_UNLIMITED;
goto drop;
}
以下为引用:
int tcp_rcv_established(...)
{
// ...
if(th->rst) {
tcp_reset(sk);
goto discard;
}tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
TCP_INC_STATS_BH(TcpInErrs);
NET_INC_STATS_BH(TCPAbortOnSyn);
tcp_reset(sk);
return 1;
}
// ...
}
以下为引用:
// At this point, the segment is in our window and does not overlap
// on either end. If it's the next sequence number we expect, we can
// handle the data now. Otherwise we'll queue it for later. In either
// case we'll handle RST and ACK information right now.// 按 RFC 793,首先检查 RST 位
// ...// 接着检查 SYN 位
if (RcvInfo.tri_flags & TCP_FLAG_SYN)
{
// ...SendRSTFromHeader(TCPH, Size, Src, Dest, OptInfo); // 发送 RST 包切断连接
// ...
return IP_SUCCESS;
}
而实际上通过阅读 RFC 和 FreeBSD/NT 相关源码,发现可能引起重置 TCP 连接的原因远远不止直接收到 RST 包或上述这种对 SYN 包的特殊处理。通过直接发送 RST 包只是主动重置的步骤,而还有很多情况可能引发被动重置。RFC 793 的 Reset Generation (rfc793.txt:2308) 中有非常详细的描述。但可惜的是这些重置发生的状态,都不是最容易被利用的 ESTABLISHED 状态,呵呵。
btw: 匆匆忙忙写完,估计问题挺多,呵呵,欢迎指正 :D