diff --git a/src/decode-tcp.c b/src/decode-tcp.c index a67bfece8c..8fa8fd99ac 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -183,6 +183,26 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } break; + /* RFC 2385 MD5 option */ + case TCP_OPT_MD5: + SCLogDebug("MD5 option, len %u", olen); + if (olen != 18) { + ENGINE_SET_INVALID_EVENT(p,TCP_OPT_INVALID_LEN); + } else { + /* we can't validate the option as the key is out of band */ + p->tcpvars.md5_option_present = true; + } + break; + /* RFC 5925 AO option */ + case TCP_OPT_AO: + SCLogDebug("AU option, len %u", olen); + if (olen < 4) { + ENGINE_SET_INVALID_EVENT(p,TCP_OPT_INVALID_LEN); + } else { + /* we can't validate the option as the key is out of band */ + p->tcpvars.ao_option_present = true; + } + break; } pkt += olen; diff --git a/src/decode-tcp.h b/src/decode-tcp.h index b5804345e6..4bcb7b22e5 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -54,6 +54,8 @@ #define TCP_OPT_TFO 0x22 /* TCP Fast Open */ #define TCP_OPT_EXP1 0xfd /* Experimental, could be TFO */ #define TCP_OPT_EXP2 0xfe /* Experimental, could be TFO */ +#define TCP_OPT_MD5 0x13 /* 19: RFC 2385 TCP MD5 option */ +#define TCP_OPT_AO 0x1d /* 29: RFC 5925 TCP AO option */ #define TCP_OPT_SACKOK_LEN 2 #define TCP_OPT_WS_LEN 3 @@ -153,6 +155,8 @@ typedef struct TCPHdr_ typedef struct TCPVars_ { /* commonly used and needed opts */ + bool md5_option_present; + bool ao_option_present; bool ts_set; uint32_t ts_val; /* host-order */ uint32_t ts_ecr; /* host-order */ diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 1239cd0ba5..311ce1ed67 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4433,6 +4433,9 @@ static int StreamTcpPacketStateClosed(ThreadVars *tv, Packet *p, if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) { if (StreamTcpStateDispatch(tv, p, stt, ssn, &stt->pseudo_queue, ssn->pstate) < 0) return -1; + /* if state is still "closed", it wasn't updated by our dispatch. */ + if (ssn->state == TCP_CLOSED) + ssn->state = ssn->pstate; } } return 0; @@ -5410,7 +5413,6 @@ TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data) static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) { - uint8_t os_policy; if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { @@ -5448,6 +5450,21 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) } } + /* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't + * validate these (requires key that is set/transfered out of band), we can't know + * if the RST will be accepted or rejected by the end host. We accept it, but keep + * tracking if the sender of it ignores it, which would be a sign of injection. */ + if (p->tcpvars.md5_option_present || p->tcpvars.ao_option_present) { + TcpStream *receiver_stream; + if (PKT_IS_TOSERVER(p)) { + receiver_stream = &ssn->server; + } else { + receiver_stream = &ssn->client; + } + SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn); + receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV; + } + if (ssn->flags & STREAMTCP_FLAG_ASYNC) { if (PKT_IS_TOSERVER(p)) { if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {