Initial code of Application Layer parsing framework. Rename of L7* to AppLayer*.

remotes/origin/master-1.0.x
Victor Julien 17 years ago
parent 95f4706549
commit 8e10844f95

@ -93,8 +93,11 @@ stream-tcp.c stream-tcp.h stream-tcp-private.h \
stream-tcp-reassemble.c stream-tcp-reassemble.h \
respond-reject.c respond-reject.h \
respond-reject-libnet11.h respond-reject-libnet11.c \
l7-app-detect.c l7-app-detect.h \
counters.c counter.h
counters.c counter.h \
app-layer-detect-proto.c app-layer-detect-proto.h \
app-layer-parser.c app-layer-parser.h \
app-layer-http.c app-layer-http.h \
app-layer-protos.h
# set the include path found by configure
INCLUDES= $(all_includes)

@ -14,51 +14,48 @@
#include "stream-tcp-private.h"
#include "stream.h"
#define INSPECT_BYTES 64
#include "app-layer-protos.h"
#define PROTO_UNKNOWN 0
#define PROTO_HTTP 1
#define PROTO_FTP 2
#define PROTO_SMTP 3
#define INSPECT_BYTES 32
static u_int8_t l7_proto_id = 0;
static u_int8_t al_proto_id = 0;
typedef struct L7AppDetectDataProto_ {
typedef struct AppLayerDetectProtoData_ {
u_int8_t proto;
} L7AppDetectDataProto;
} AppLayerDetectProtoData;
static Pool *l7appdetect_proto_pool = NULL;
static Pool *al_detect_proto_pool = NULL;
void *L7AppDetectProtoAlloc(void *null) {
L7AppDetectDataProto *d = malloc(sizeof(L7AppDetectDataProto));
void *AppLayerDetectProtoAlloc(void *null) {
AppLayerDetectProtoData *d = malloc(sizeof(AppLayerDetectProtoData));
if (d == NULL) {
return NULL;
}
d->proto = PROTO_UNKNOWN;
d->proto = ALPROTO_UNKNOWN;
return d;
}
#define L7AppDetectProtoFree free
#define AppLayerDetectProtoFree free
void L7AppDetectThreadInit(void) {
l7_proto_id = StreamL7RegisterModule();
void AppLayerDetectProtoThreadInit(void) {
al_proto_id = StreamL7RegisterModule();
l7appdetect_proto_pool = PoolInit(262144, 32768, L7AppDetectProtoAlloc, NULL, L7AppDetectProtoFree);
if (l7appdetect_proto_pool == NULL) {
al_detect_proto_pool = PoolInit(262144, 32768, AppLayerDetectProtoAlloc, NULL, AppLayerDetectProtoFree);
if (al_detect_proto_pool == NULL) {
exit(1);
}
}
u_int8_t L7AppDetectGetProto(u_int8_t *buf, u_int16_t buflen) {
u_int8_t AppLayerDetectGetProto(u_int8_t *buf, u_int16_t buflen) {
if (buflen < INSPECT_BYTES)
return PROTO_UNKNOWN;
return ALPROTO_UNKNOWN;
/* XXX do actual detect */
printf("L7AppDetectGetProto: protocol detection goes here.\n");
return PROTO_HTTP;
printf("AppLayerDetectGetProto: protocol detection goes here.\n");
return ALPROTO_HTTP;
}
void *L7AppDetectThread(void *td)
void *AppLayerDetectProtoThread(void *td)
{
ThreadVars *tv = (ThreadVars *)td;
char run = TRUE;
@ -88,7 +85,7 @@ void *L7AppDetectThread(void *td)
or make it part of the stream setup */
StreamL7DataPtrInit(ssn,StreamL7GetStorageSize());
}
void *l7_data_ptr = ssn->l7data[l7_proto_id];
void *al_data_ptr = ssn->l7data[al_proto_id];
if (smsg->flags & STREAM_START) {
//printf("L7AppDetectThread: stream initializer (len %u (%u))\n", smsg->data.data_len, MSG_DATA_SIZE);
@ -97,17 +94,19 @@ void *L7AppDetectThread(void *td)
//PrintRawDataFp(stdout, smsg->init.data, smsg->init.data_len);
//printf("=> Init Stream Data -- end\n");
if (l7_data_ptr == NULL) {
L7AppDetectDataProto *l7proto = (L7AppDetectDataProto *)PoolGet(l7appdetect_proto_pool);
if (l7proto != NULL) {
l7proto->proto = L7AppDetectGetProto(smsg->data.data, smsg->data.data_len);
if (al_data_ptr == NULL) {
AppLayerDetectProtoData *al_proto = (AppLayerDetectProtoData *)PoolGet(al_detect_proto_pool);
if (al_proto != NULL) {
al_proto->proto = AppLayerDetectGetProto(smsg->data.data, smsg->data.data_len);
/* store */
ssn->l7data[l7_proto_id] = (void *)l7proto;
ssn->l7data[al_proto_id] = (void *)al_proto;
AppLayerParse(smsg->flow, al_proto->proto, smsg->flags, smsg->data.data, smsg->data.data_len);
}
}
} else {
//printf("L7AppDetectThread: stream data (len %u (%u))\n", smsg->data.data_len, MSG_DATA_SIZE);
//printf("AppLayerDetectThread: stream data (len %u (%u))\n", smsg->data.data_len, MSG_DATA_SIZE);
//printf("=> Stream Data -- start\n");
//PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len);
@ -115,11 +114,13 @@ void *L7AppDetectThread(void *td)
/* if we don't have a data object here we are not getting it
* a start msg should have gotten us one */
if (l7_data_ptr != NULL) {
L7AppDetectDataProto *l7proto = (L7AppDetectDataProto *)l7_data_ptr;
printf("L7AppDetectThread: already established that the proto is %u\n", l7proto->proto);
if (al_data_ptr != NULL) {
AppLayerDetectProtoData *al_proto = (AppLayerDetectProtoData *)al_data_ptr;
printf("AppLayerDetectThread: already established that the proto is %u\n", al_proto->proto);
AppLayerParse(smsg->flow, al_proto->proto, smsg->flags, smsg->data.data, smsg->data.data_len);
} else {
printf("L7AppDetectThread: smsg not start, but no l7 data? Weird\n");
printf("AppLayerDetectThread: smsg not start, but no l7 data? Weird\n");
}
}
}
@ -138,22 +139,22 @@ void *L7AppDetectThread(void *td)
pthread_exit((void *) 0);
}
void L7AppDetectThreadSpawn()
void AppLayerDetectProtoThreadSpawn()
{
ThreadVars *tv_l7appdetect = NULL;
ThreadVars *tv_applayerdetect = NULL;
tv_l7appdetect = TmThreadCreate("L7AppDetectThread", NULL, NULL, NULL, NULL,
"custom", L7AppDetectThread, 0);
if (tv_l7appdetect == NULL) {
tv_applayerdetect = TmThreadCreate("AppLayerDetectProtoThread", NULL, NULL, NULL, NULL,
"custom", AppLayerDetectProtoThread, 0);
if (tv_applayerdetect == NULL) {
printf("ERROR: TmThreadsCreate failed\n");
exit(1);
}
if (TmThreadSpawn(tv_l7appdetect, TVT_PPT, THV_USE) != 0) {
if (TmThreadSpawn(tv_applayerdetect, TVT_PPT, THV_USE) != 0) {
printf("ERROR: TmThreadSpawn failed\n");
exit(1);
}
printf("L7_App_Detect thread created\n");
printf("AppLayerDetectProtoThread thread created\n");
return;
}

@ -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__ */

@ -58,7 +58,7 @@
#include "flow-bit.h"
#include "pkt-var.h"
#include "l7-app-detect.h"
#include "app-layer-detect-proto.h"
#include "util-cidr.h"
#include "util-unittest.h"
@ -898,7 +898,10 @@ int main(int argc, char **argv)
PerfInitCounterApi();
/* XXX we need an api for this */
L7AppDetectThreadInit();
AppLayerDetectProtoThreadInit();
RegisterAppLayerParsers();
RegisterHTTPParsers();
TmModuleReceiveNFQRegister();
TmModuleVerdictNFQRegister();
@ -994,7 +997,7 @@ int main(int argc, char **argv)
FlowManagerThreadSpawn();
/* Spawn the L7 App Detect thread */
L7AppDetectThreadSpawn();
AppLayerDetectProtoThreadSpawn();
/* Spawn the perf counter threads */
PerfSpawnThreads();

@ -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__ */

@ -796,7 +796,25 @@ static void StreamTcpSetupInitMsg(Packet *p, StreamMsg *smsg) {
}
}
int StreamTcpReassembleHandleSegmentUpdateACK(TcpSession *ssn, TcpStream *stream, Packet *p) {
static void StreamTcpSetupMsg(Packet *p, StreamMsg *smsg) {
if (p->flowflags & FLOW_PKT_TOSERVER) {
COPY_ADDRESS(&p->flow->src,&smsg->data.src_ip);
COPY_ADDRESS(&p->flow->dst,&smsg->data.dst_ip);
COPY_PORT(p->flow->sp,smsg->data.src_port);
COPY_PORT(p->flow->dp,smsg->data.dst_port);
smsg->flags |= STREAM_TOSERVER;
} else {
COPY_ADDRESS(&p->flow->dst,&smsg->data.src_ip);
COPY_ADDRESS(&p->flow->src,&smsg->data.dst_ip);
COPY_PORT(p->flow->dp,smsg->data.src_port);
COPY_PORT(p->flow->sp,smsg->data.dst_port);
smsg->flags |= STREAM_TOCLIENT;
}
}
int StreamTcpReassembleHandleSegmentUpdateACK (TcpSession *ssn, TcpStream *stream, Packet *p) {
if (stream->seg_list == NULL)
return 0;
@ -869,6 +887,8 @@ int StreamTcpReassembleHandleSegmentUpdateACK(TcpSession *ssn, TcpStream *stream
if (stream->ra_base_seq == stream->isn) {
StreamTcpSetupInitMsg(p, smsg);
} else {
StreamTcpSetupMsg(p, smsg);
}
smsg->data.data_len = 0;
smsg->flow = p->flow;
@ -970,7 +990,9 @@ int StreamTcpReassembleHandleSegmentUpdateACK(TcpSession *ssn, TcpStream *stream
if (smsg->flow)
smsg->flow->use_cnt++;
copy_size = sizeof (smsg->data.data) - smsg_offset;
StreamTcpSetupMsg(p,smsg);
copy_size = sizeof(smsg->data.data) - smsg_offset;
if (copy_size > (seg->payload_len - payload_offset)) {
copy_size = (seg->payload_len - payload_offset);
}

Loading…
Cancel
Save