|
|
|
|
@ -2215,7 +2215,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p,
|
|
|
|
|
&ssn->server, p, pq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (p->tcph->th_flags & TH_FIN) {
|
|
|
|
|
} else if ((p->tcph->th_flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) {
|
|
|
|
|
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
|
|
|
|
|
if (!StreamTcpValidateTimestamp(ssn, p))
|
|
|
|
|
return -1;
|
|
|
|
|
@ -2323,6 +2323,113 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p,
|
|
|
|
|
ssn->client.last_ack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (p->tcph->th_flags & TH_FIN) {
|
|
|
|
|
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
|
|
|
|
|
if (!StreamTcpValidateTimestamp(ssn, p))
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PKT_IS_TOSERVER(p)) {
|
|
|
|
|
SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
|
|
|
|
|
"%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
|
|
|
|
|
TCP_GET_SEQ(p), TCP_GET_ACK(p));
|
|
|
|
|
|
|
|
|
|
if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
|
|
|
|
|
SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
|
|
|
|
|
{
|
|
|
|
|
SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
|
|
|
|
|
" != %" PRIu32 " from stream", ssn,
|
|
|
|
|
TCP_GET_SEQ(p), ssn->client.next_seq);
|
|
|
|
|
StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
|
|
|
|
|
SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
|
|
|
|
|
StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
|
|
|
|
|
ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED;
|
|
|
|
|
SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
|
|
|
|
|
|
|
|
|
|
ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
|
|
|
|
|
|
|
|
|
|
StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
|
|
|
|
|
|
|
|
|
|
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
|
|
|
|
|
StreamTcpHandleTimestamp(ssn, p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update the next_seq, in case if we have missed the client
|
|
|
|
|
packet and server has already received and acked it */
|
|
|
|
|
if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
|
|
|
|
|
ssn->server.next_seq = TCP_GET_ACK(p);
|
|
|
|
|
|
|
|
|
|
if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
|
|
|
|
|
ssn->client.next_seq += p->payload_len;
|
|
|
|
|
SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "",
|
|
|
|
|
ssn, ssn->client.next_seq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
|
|
|
|
|
&ssn->client, p, pq);
|
|
|
|
|
|
|
|
|
|
SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
|
|
|
|
|
"%" PRIu32 "", ssn, ssn->client.next_seq,
|
|
|
|
|
ssn->server.last_ack);
|
|
|
|
|
} else { /* implied to client */
|
|
|
|
|
SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
|
|
|
|
|
"%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
|
|
|
|
|
TCP_GET_SEQ(p), TCP_GET_ACK(p));
|
|
|
|
|
|
|
|
|
|
if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
|
|
|
|
|
SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
|
|
|
|
|
{
|
|
|
|
|
SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
|
|
|
|
|
" != %" PRIu32 " from stream", ssn,
|
|
|
|
|
TCP_GET_SEQ(p), ssn->server.next_seq);
|
|
|
|
|
StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
|
|
|
|
|
SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
|
|
|
|
|
StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
|
|
|
|
|
ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED;
|
|
|
|
|
SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
|
|
|
|
|
|
|
|
|
|
ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
|
|
|
|
|
|
|
|
|
|
StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
|
|
|
|
|
|
|
|
|
|
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
|
|
|
|
|
StreamTcpHandleTimestamp(ssn, p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update the next_seq, in case if we have missed the client
|
|
|
|
|
packet and server has already received and acked it */
|
|
|
|
|
if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
|
|
|
|
|
ssn->client.next_seq = TCP_GET_ACK(p);
|
|
|
|
|
|
|
|
|
|
if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
|
|
|
|
|
ssn->server.next_seq += p->payload_len;
|
|
|
|
|
SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "",
|
|
|
|
|
ssn, ssn->server.next_seq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
|
|
|
|
|
&ssn->server, p, pq);
|
|
|
|
|
|
|
|
|
|
SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
|
|
|
|
|
"%" PRIu32 "", ssn, ssn->server.next_seq,
|
|
|
|
|
ssn->client.last_ack);
|
|
|
|
|
}
|
|
|
|
|
} else if (p->tcph->th_flags & TH_SYN) {
|
|
|
|
|
SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
|
|
|
|
|
StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
|
|
|
|
|
|