mirror of https://github.com/OISF/suricata
Initial code of Application Layer parsing framework. Rename of L7* to AppLayer*.
parent
95f4706549
commit
8e10844f95
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef __APP_LAYER_DETECT_PROTO_H__
|
||||||
|
#define __APP_LAYER_DETECT_PROTO_H__
|
||||||
|
|
||||||
|
void *AppLayerDetectProtoThread(void *td);
|
||||||
|
|
||||||
|
void AppLayerDetectProtoThreadSpawn(void);
|
||||||
|
|
||||||
|
#endif /* __APP_LAYER_DETECT_PROTO_H__ */
|
||||||
|
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
/* Copyright (c) 2009 Victor Julien */
|
||||||
|
|
||||||
|
#include "eidps.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "decode.h"
|
||||||
|
#include "threads.h"
|
||||||
|
|
||||||
|
#include "util-print.h"
|
||||||
|
#include "util-pool.h"
|
||||||
|
|
||||||
|
#include "stream-tcp-private.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#include "app-layer-protos.h"
|
||||||
|
#include "app-layer-parser.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HTTP_FIELD_NONE = 0,
|
||||||
|
|
||||||
|
HTTP_FIELD_REQUEST_LINE,
|
||||||
|
HTTP_FIELD_REQUEST_HEADERS,
|
||||||
|
HTTP_FIELD_REQUEST_BODY,
|
||||||
|
|
||||||
|
HTTP_FIELD_REQUEST_METHOD,
|
||||||
|
HTTP_FIELD_REQUEST_URI,
|
||||||
|
HTTP_FIELD_REQUEST_VERSION,
|
||||||
|
|
||||||
|
/* must be last */
|
||||||
|
HTTP_FIELD_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Mapping between HTTP_FIELD_* and AppLayerParsers
|
||||||
|
*
|
||||||
|
* Map the http fields identifiers to the parsers.
|
||||||
|
*/
|
||||||
|
typedef struct HTTPParser_ {
|
||||||
|
u_int16_t parser_idx;
|
||||||
|
} HTTPParser;
|
||||||
|
|
||||||
|
static HTTPParser http_field_table[HTTP_FIELD_MAX];
|
||||||
|
|
||||||
|
|
||||||
|
int HTTPParseRequestLine(void *http_state, void *parser_state, u_int8_t *input, u_int32_t input_len, AppLayerParserResultElement **output, u_int16_t *output_num) {
|
||||||
|
printf("HTTPParseRequestLine: http_state %p, parser_state %p, input %p, input_len %u\n",
|
||||||
|
http_state, parser_state, input, input_len);
|
||||||
|
PrintRawDataFp(stdout, input,input_len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HTTPParseRequest(void *http_state, void *parser_state, u_int8_t *input, u_int32_t input_len, AppLayerParserResultElement **output, u_int16_t *output_num) {
|
||||||
|
printf("HTTPParseRequest: http_state %p, parser_state %p, input %p, input_len %u\n",
|
||||||
|
http_state, parser_state, input, input_len);
|
||||||
|
|
||||||
|
char done = FALSE;
|
||||||
|
AppLayerParserState *pstate = (AppLayerParserState *)parser_state;
|
||||||
|
|
||||||
|
printf("HTTPParseRequest: pstate->buflen %u\n", pstate->buflen);
|
||||||
|
|
||||||
|
u_int32_t u32 = 0;
|
||||||
|
for ( ; u32 < input_len; u32++) {
|
||||||
|
pstate->buf[pstate->buflen] = input[u32];
|
||||||
|
pstate->buflen++;
|
||||||
|
|
||||||
|
if (pstate->buflen > 1 && pstate->buf[pstate->buflen - 2] == '\r' && pstate->buf[pstate->buflen - 1] == '\n') {
|
||||||
|
printf("HTTPParseRequest: request line done.\n");
|
||||||
|
done = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done == TRUE) {
|
||||||
|
printf("HTTPParseRequest: request line:\n");
|
||||||
|
PrintRawDataFp(stdout, pstate->buf,pstate->buflen);
|
||||||
|
pstate->flags |= APP_LAYER_PARSER_DONE;
|
||||||
|
|
||||||
|
pstate->buflen = 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HTTPParseResponse(void *http_state, void *parser_state, u_int8_t *input, u_int32_t input_len, AppLayerParserResultElement **output, u_int16_t *output_num) {
|
||||||
|
printf("HTTPParseResponse: http_state %p, parser_state %p, input %p, input_len %u\n",
|
||||||
|
http_state, parser_state, input, input_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterHTTPParsers(void) {
|
||||||
|
AppLayerRegisterProto("http", ALPROTO_HTTP, STREAM_TOSERVER, HTTPParseRequest);
|
||||||
|
AppLayerRegisterProto("http", ALPROTO_HTTP, STREAM_TOCLIENT, HTTPParseResponse);
|
||||||
|
|
||||||
|
AppLayerRegisterParser("http.request_line", HTTPParseRequestLine, "http");
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef __APP_LAYER_HTTP_H__
|
||||||
|
#define __APP_LAYER_HTTP_H__
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __APP_LAYER_HTTP_H__ */
|
||||||
|
|
||||||
@ -0,0 +1,152 @@
|
|||||||
|
/* Copyright (c) 2009 Victor Julien */
|
||||||
|
|
||||||
|
#include "eidps.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "decode.h"
|
||||||
|
#include "threads.h"
|
||||||
|
|
||||||
|
#include "util-print.h"
|
||||||
|
#include "util-pool.h"
|
||||||
|
|
||||||
|
#include "stream-tcp-private.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#include "app-layer-protos.h"
|
||||||
|
#include "app-layer-parser.h"
|
||||||
|
|
||||||
|
static u_int16_t app_layer_sid = 0;
|
||||||
|
static AppLayerProto al_proto_table[ALPROTO_MAX];
|
||||||
|
|
||||||
|
#define MAX_PARSERS 16
|
||||||
|
static AppLayerParserTableElement al_parser_table[MAX_PARSERS];
|
||||||
|
static u_int16_t al_max_parsers = 0; /* incremented for every registered parser */
|
||||||
|
|
||||||
|
/** \brief Get the Parsers id for storing the parser state.
|
||||||
|
*
|
||||||
|
* \retval Parser subsys id
|
||||||
|
*/
|
||||||
|
u_int16_t AppLayerParserGetStorageId(void) {
|
||||||
|
return app_layer_sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Description: register a parser.
|
||||||
|
*
|
||||||
|
* \param name full parser name, e.g. "http.request_line"
|
||||||
|
* \todo do we need recursive, so a "http" and a "request_line" where the engine knows it's actually "http.request_line"... same difference maybe.
|
||||||
|
* \param AppLayerParser pointer to the parser function
|
||||||
|
* \param max_outputs max number of unique outputs the parser can generate
|
||||||
|
*
|
||||||
|
* \retval 0 on success
|
||||||
|
* \retval -1 on error
|
||||||
|
*/
|
||||||
|
int AppLayerRegisterParser(char *name, int (*AppLayerParser)(void *protocol_state, void *parser_state, u_int8_t *input, u_int32_t input_len, AppLayerParserResultElement **output, u_int16_t *output_num), char *dependency) {
|
||||||
|
|
||||||
|
al_max_parsers++;
|
||||||
|
|
||||||
|
al_parser_table[al_max_parsers].name = name;
|
||||||
|
al_parser_table[al_max_parsers].AppLayerParser = AppLayerParser;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Description: register a protocol parser.
|
||||||
|
*
|
||||||
|
* \param name full parser name, e.g. "http.request_line"
|
||||||
|
* \todo do we need recursive, so a "http" and a "request_line" where the engine knows it's actually "http.request_line"... same difference maybe.
|
||||||
|
* \param AppLayerParser pointer to the parser function
|
||||||
|
* \param max_outputs max number of unique outputs the parser can generate
|
||||||
|
*
|
||||||
|
* \retval 0 on success
|
||||||
|
* \retval -1 on error
|
||||||
|
*/
|
||||||
|
int AppLayerRegisterProto(char *name, u_int8_t proto, u_int8_t flags, int (*AppLayerParser)(void *protocol_state, void *parser_state, u_int8_t *input, u_int32_t input_len, AppLayerParserResultElement **output, u_int16_t *output_num)) {
|
||||||
|
|
||||||
|
al_max_parsers++;
|
||||||
|
|
||||||
|
al_parser_table[al_max_parsers].name = name;
|
||||||
|
al_parser_table[al_max_parsers].AppLayerParser = AppLayerParser;
|
||||||
|
|
||||||
|
/* create proto, direction -- parser mapping */
|
||||||
|
if (flags & STREAM_TOSERVER) {
|
||||||
|
al_proto_table[proto].to_server = al_max_parsers;
|
||||||
|
} else if (flags & STREAM_TOCLIENT) {
|
||||||
|
al_proto_table[proto].to_client = al_max_parsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (al_proto_table[proto].storage_id == 0) {
|
||||||
|
al_proto_table[proto].storage_id = StreamL7RegisterModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("AppLayerRegisterProto: registered %p at proto %u flags %02X, al_proto_table idx %u, storage_id %u\n",
|
||||||
|
AppLayerParser, proto, flags, al_max_parsers, al_proto_table[proto].storage_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppLayerParserState* AppLayerParserStateAlloc(void) {
|
||||||
|
AppLayerParserState *s = (AppLayerParserState *)malloc(sizeof(AppLayerParserState));
|
||||||
|
if (s == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(s, 0, sizeof(AppLayerParserState));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Layer 7 Parsing main entry point.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int AppLayerParse(Flow *f, u_int8_t proto, u_int8_t flags, u_int8_t *input, u_int32_t input_len) {
|
||||||
|
printf("AppLayerParse: proto %u, flags %02X\n", proto, flags);
|
||||||
|
|
||||||
|
u_int16_t parser_idx = 0;
|
||||||
|
AppLayerProto *p = &al_proto_table[proto];
|
||||||
|
|
||||||
|
TcpSession *ssn = f->stream;
|
||||||
|
if (ssn == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the parser state (if any) */
|
||||||
|
AppLayerParserState *parser_state = (AppLayerParserState *)ssn->l7data[app_layer_sid];
|
||||||
|
/* See if we already have a 'app' state */
|
||||||
|
void *app_layer_state = ssn->l7data[p->storage_id];
|
||||||
|
|
||||||
|
if (parser_state == NULL) {
|
||||||
|
if (flags & STREAM_TOSERVER) {
|
||||||
|
parser_idx = p->to_server;
|
||||||
|
} else if (flags & STREAM_TOCLIENT) {
|
||||||
|
parser_idx = p->to_client;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("L7Parse: using parser %u we stored before\n", parser_state->cur_parser);
|
||||||
|
parser_idx = parser_state->cur_parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_idx == 0) {
|
||||||
|
printf("L7Parse: no parser for protocol %u\n", proto);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_state == NULL) {
|
||||||
|
parser_state = AppLayerParserStateAlloc();
|
||||||
|
if (parser_state != NULL) {
|
||||||
|
parser_state->cur_parser = parser_idx;
|
||||||
|
|
||||||
|
ssn->l7data[app_layer_sid] = (void *)parser_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int r = al_parser_table[parser_idx].AppLayerParser(app_layer_state, parser_state, input, input_len, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterAppLayerParsers(void) {
|
||||||
|
/** \todo move to general init function */
|
||||||
|
memset(&al_proto_table, 0, sizeof(al_proto_table));
|
||||||
|
memset(&al_parser_table, 0, sizeof(al_parser_table));
|
||||||
|
|
||||||
|
app_layer_sid = StreamL7RegisterModule();
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef __APP_LAYER_PARSER_H__
|
||||||
|
#define __APP_LAYER_PARSER_H__
|
||||||
|
|
||||||
|
/** \brief Mapping between ALPROTO_* and L7Parsers
|
||||||
|
*
|
||||||
|
* Map the proto to the parsers for the to_client and to_server directions.
|
||||||
|
*/
|
||||||
|
typedef struct AppLayerProto_ {
|
||||||
|
u_int16_t to_server;
|
||||||
|
u_int16_t to_client;
|
||||||
|
u_int8_t storage_id;
|
||||||
|
} AppLayerProto;
|
||||||
|
|
||||||
|
typedef struct AppLayerParserResultElement_ {
|
||||||
|
u_int16_t flags; /* flags. E.g. local alloc */
|
||||||
|
u_int16_t name_idx; /* idx for names like "http.request_line.uri" */
|
||||||
|
|
||||||
|
u_int8_t *data_ptr; /* point to the position in the "input" data
|
||||||
|
* or ptr to new mem if local alloc flag set */
|
||||||
|
u_int32_t data_len; /* length of the data from the ptr */
|
||||||
|
} AppLayerParserResultElement;
|
||||||
|
|
||||||
|
typedef struct AppLayerParserTableElement_ {
|
||||||
|
char *name;
|
||||||
|
u_int8_t flags;
|
||||||
|
int (*AppLayerParser)(void *protocol_state, void *parser_state, u_int8_t *input, u_int32_t input_len, AppLayerParserResultElement **output, u_int16_t *output_num);
|
||||||
|
u_int16_t max_outputs; /* rationele is that if we know the max outputs of all parsers, we
|
||||||
|
can statically define our output array to be a certain size */
|
||||||
|
} AppLayerParserTableElement;
|
||||||
|
|
||||||
|
#define APP_LAYER_PARSER_DONE 0x01 /** the last parser was done */
|
||||||
|
#define APP_LAYER_PARSER_MAYBE 0x02 /** we're not sure if the last parser is done */
|
||||||
|
#define APP_LAYER_PARSER_CONT 0x04 /** the last parser is still working */
|
||||||
|
|
||||||
|
typedef struct AppLayerParserState_ {
|
||||||
|
u_int8_t flags;
|
||||||
|
u_int16_t cur_parser; /* idx of currently active parser */
|
||||||
|
|
||||||
|
/** \todo this needs to become dynamic */
|
||||||
|
u_int8_t buf[1024];
|
||||||
|
u_int8_t buflen;
|
||||||
|
} AppLayerParserState;
|
||||||
|
|
||||||
|
#endif /* __APP_LAYER_PARSER_H__ */
|
||||||
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __APP_LAYER_PROTOS_H__
|
||||||
|
#define __APP_LAYER_PROTOS_H__
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ALPROTO_UNKNOWN = 0,
|
||||||
|
ALPROTO_HTTP,
|
||||||
|
ALPROTO_FTP,
|
||||||
|
ALPROTO_SMTP,
|
||||||
|
|
||||||
|
/* keep last */
|
||||||
|
ALPROTO_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __APP_LAYER_PROTOS_H__ */
|
||||||
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
#ifndef __L7_APP_DETECT_H__
|
|
||||||
#define __L7_APP_DETECT_H__
|
|
||||||
|
|
||||||
void *L7AppDetectThread(void *td);
|
|
||||||
|
|
||||||
void L7AppDetectThreadSpawn(void);
|
|
||||||
|
|
||||||
#endif /* __L7_APP_DETECT_H__ */
|
|
||||||
Loading…
Reference in New Issue