htp: allow HTTP pickup of response data

Now that libhtp can pick up sessions that start with a response
we can enable support for it as well.
pull/3201/head
Victor Julien 8 years ago
parent 49927024c6
commit e64941144e

@ -78,6 +78,7 @@
#include "util-memcmp.h"
#include "util-random.h"
#include "util-validate.h"
//#define PRINT
@ -647,38 +648,11 @@ static inline void HTPErrorCheckTxRequestFlags(HtpState *s, htp_tx_t *tx)
}
}
/**
* \brief Function to handle the reassembled data from client and feed it to
* the HTP library to process it.
*
* \param flow Pointer to the flow the data belong to
* \param htp_state Pointer the state in which the parsed value to be stored
* \param pstate Application layer parser state for this session
* \param input Pointer the received HTTP client data
* \param input_len Length in bytes of the received data
* \param output Pointer to the output (not used in this function)
*
* \retval On success returns 1 or on failure returns -1.
*/
static int HTPHandleRequestData(Flow *f, void *htp_state,
AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len,
void *local_data)
static int Setup(Flow *f, HtpState *hstate)
{
SCEnter();
int r = -1;
int ret = 1;
//PrintRawDataFp(stdout, input, input_len);
HtpState *hstate = (HtpState *)htp_state;
/* store flow ref in state so callbacks can access it */
hstate->f = f;
/* On the first invocation, create the connection parser structure to
* be used by HTP library. This is looked up via IP in the radix
* tree. Failing that, the default HTP config is used.
*/
if (NULL == hstate->conn) {
HTPCfgRec *htp_cfg_rec = &cfglist;
htp_cfg_t *htp = cfglist.cfg; /* Default to the global HTP config */
void *user_data = NULL;
@ -723,26 +697,52 @@ static int HTPHandleRequestData(Flow *f, void *htp_state,
hstate->cfg = htp_cfg_rec;
SCLogDebug("New hstate->connp %p", hstate->connp);
}
/* the code block above should make sure connp is never NULL here */
#ifdef DEBUG_VALIDATION
BUG_ON(hstate->connp == NULL);
#endif
htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, &f->startts);
/* Unset the body inspection (the callback should
* reactivate it if necessary) */
hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
return 0;
error:
return -1;
}
/* Open the HTTP connection on receiving the first request */
if (!(hstate->flags & HTP_FLAG_STATE_OPEN)) {
SCLogDebug("opening htp handle at %p", hstate->connp);
/**
* \brief Function to handle the reassembled data from client and feed it to
* the HTP library to process it.
*
* \param flow Pointer to the flow the data belong to
* \param htp_state Pointer the state in which the parsed value to be stored
* \param pstate Application layer parser state for this session
* \param input Pointer the received HTTP client data
* \param input_len Length in bytes of the received data
* \param output Pointer to the output (not used in this function)
*
* \retval On success returns 1 or on failure returns -1.
*/
static int HTPHandleRequestData(Flow *f, void *htp_state,
AppLayerParserState *pstate,
uint8_t *input, uint32_t input_len,
void *local_data)
{
SCEnter();
int r = -1;
int ret = 1;
htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, &f->startts);
hstate->flags |= HTP_FLAG_STATE_OPEN;
} else {
SCLogDebug("using existing htp handle at %p", hstate->connp);
HtpState *hstate = (HtpState *)htp_state;
/* On the first invocation, create the connection parser structure to
* be used by HTP library. This is looked up via IP in the radix
* tree. Failing that, the default HTP config is used.
*/
if (NULL == hstate->conn) {
if (Setup(f, hstate) != 0) {
goto error;
}
}
DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL);
/* Unset the body inspection (the callback should
* reactivate it if necessary) */
hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec };
/* pass the new data to the htp parser */
@ -810,14 +810,16 @@ static int HTPHandleResponseData(Flow *f, void *htp_state,
int ret = 1;
HtpState *hstate = (HtpState *)htp_state;
hstate->f = f;
if (hstate->connp == NULL) {
SCLogDebug("HTP state has no connp");
/* till we have the new libhtp changes that allow response first,
* let's take response in first. */
//BUG_ON(1);
SCReturnInt(-1);
/* On the first invocation, create the connection parser structure to
* be used by HTP library. This is looked up via IP in the radix
* tree. Failing that, the default HTP config is used.
*/
if (NULL == hstate->conn) {
if (Setup(f, hstate) != 0) {
goto error;
}
}
DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL);
/* Unset the body inspection (the callback should
* reactivate it if necessary) */
@ -856,6 +858,8 @@ static int HTPHandleResponseData(Flow *f, void *htp_state,
SCLogDebug("hstate->connp %p", hstate->connp);
SCReturnInt(ret);
error:
SCReturnInt(-1);
}
/**
@ -2882,7 +2886,8 @@ void RegisterHTPParsers(void)
AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOCLIENT,
HTPHandleResponseData);
SC_ATOMIC_INIT(htp_config_flags);
AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOSERVER);
AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP,
ALPROTO_HTTP, STREAM_TOSERVER|STREAM_TOCLIENT);
HTPConfigure();
} else {
SCLogInfo("Parsed disabled for %s protocol. Protocol detection"

@ -57,8 +57,7 @@
/** a boundary should be smaller in size */
#define HTP_BOUNDARY_MAX 200U
#define HTP_FLAG_STATE_OPEN 0x0001 /**< Flag to indicate that HTTP
connection is open */
// 0x0001 not used
#define HTP_FLAG_STATE_CLOSED_TS 0x0002 /**< Flag to indicate that HTTP
connection is closed */
#define HTP_FLAG_STATE_CLOSED_TC 0x0004 /**< Flag to indicate that HTTP

@ -1831,17 +1831,36 @@ static int AppLayerTest06(void)
p->payload = request;
FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_FAILED);
FAIL_IF(f.alproto_ts != ALPROTO_FAILED);
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED));
FAIL_IF((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED));
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
p->tcph->th_ack = htonl(1 + sizeof(request));
p->tcph->th_seq = htonl(328);
p->tcph->th_flags = TH_PUSH | TH_ACK;
p->flowflags = FLOW_PKT_TOCLIENT;
p->payload_len = 0;
p->payload = NULL;
FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
TEST_END;
PASS;
}

Loading…
Cancel
Save