Skip to content

Commit

Permalink
app-layer: make number of alprotos dynamic
Browse files Browse the repository at this point in the history
Ticket: 5053

The names are now dynamically registered at runtime.
The AppProto alproto enum identifiers are still static for now.

This is the final step before app-layer plugins.
  • Loading branch information
catenacyber committed Jan 9, 2025
1 parent 2d480be commit 4e001c2
Showing 17 changed files with 158 additions and 121 deletions.
2 changes: 1 addition & 1 deletion scripts/setup-app-layer.py
Original file line number Diff line number Diff line change
@@ -129,7 +129,7 @@ def patch_app_layer_protos_h(protoname):
open(filename, "w").write(output.getvalue())

def patch_app_layer_protos_c(protoname):
filename = "src/app-layer-protos.c"
filename = "src/app-layer.c"
print("Patching %s." % (filename))
output = io.StringIO()

40 changes: 20 additions & 20 deletions src/app-layer-detect-proto.c
Original file line number Diff line number Diff line change
@@ -292,7 +292,7 @@ static inline int PMGetProtoInspect(AppLayerProtoDetectThreadCtx *tctx,
}

/* alproto bit field */
uint8_t pm_results_bf[(ALPROTO_MAX / 8) + 1];
uint8_t pm_results_bf[(AlprotoMax / 8) + 1];
memset(pm_results_bf, 0, sizeof(pm_results_bf));

/* loop through unique pattern id's. Can't use search_cnt here,
@@ -324,7 +324,7 @@ static inline int PMGetProtoInspect(AppLayerProtoDetectThreadCtx *tctx,
/** \internal
* \brief Run Pattern Sigs against buffer
* \param direction direction for the patterns
* \param pm_results[out] AppProto array of size ALPROTO_MAX */
* \param pm_results[out] AppProto array of size AlprotoMax */
static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f,
const uint8_t *buf, uint32_t buflen, uint8_t flags, AppProto *pm_results, bool *rflow)
{
@@ -804,7 +804,7 @@ static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParser
"register the probing parser. min_depth >= max_depth");
goto error;
}
if (alproto <= ALPROTO_UNKNOWN || alproto >= ALPROTO_MAX) {
if (alproto <= ALPROTO_UNKNOWN || alproto >= AlprotoMax) {
SCLogError("Invalid arguments sent to register "
"the probing parser. Invalid alproto - %d",
alproto);
@@ -1411,7 +1411,7 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f
AppProto pm_alproto = ALPROTO_UNKNOWN;

if (!FLOW_IS_PM_DONE(f, flags)) {
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
uint16_t pm_matches = AppLayerProtoDetectPMGetProto(
tctx, f, buf, buflen, flags, pm_results, reverse_flow);
if (pm_matches > 0) {
@@ -1725,12 +1725,12 @@ int AppLayerProtoDetectSetup(void)
}
}

alpd_ctx.alproto_names = SCCalloc(ALPROTO_MAX, sizeof(char *));
alpd_ctx.alproto_names = SCCalloc(AlprotoMax, sizeof(char *));
if (unlikely(alpd_ctx.alproto_names == NULL)) {
FatalError("Unable to alloc alproto_names.");
}
// to realloc when dynamic protos are added
alpd_ctx.expectation_proto = SCCalloc(ALPROTO_MAX, sizeof(uint8_t));
alpd_ctx.expectation_proto = SCCalloc(AlprotoMax, sizeof(uint8_t));
if (unlikely(alpd_ctx.expectation_proto == NULL)) {
FatalError("Unable to alloc expectation_proto.");
}
@@ -2090,7 +2090,7 @@ AppProto AppLayerProtoDetectGetProtoByName(const char *alproto_name)

AppProto a;
AppProto b = StringToAppProto(alproto_name);
for (a = 0; a < ALPROTO_MAX; a++) {
for (a = 0; a < AlprotoMax; a++) {
if (alpd_ctx.alproto_names[a] != NULL && AppProtoEquals(b, a)) {
// That means return HTTP_ANY if HTTP1 or HTTP2 is enabled
SCReturnCT(b, "AppProto");
@@ -2121,11 +2121,11 @@ void AppLayerProtoDetectSupportedAppProtocols(AppProto *alprotos)
{
SCEnter();

memset(alprotos, 0, ALPROTO_MAX * sizeof(AppProto));
memset(alprotos, 0, AlprotoMax * sizeof(AppProto));

int alproto;

for (alproto = 0; alproto != ALPROTO_MAX; alproto++) {
for (alproto = 0; alproto != AlprotoMax; alproto++) {
if (alpd_ctx.alproto_names[alproto] != NULL)
alprotos[alproto] = 1;
}
@@ -2229,7 +2229,7 @@ static int AppLayerProtoDetectTest03(void)
AppLayerProtoDetectSetup();

uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n";
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
memset(pm_results, 0, sizeof(pm_results));
Flow f;
memset(&f, 0x00, sizeof(f));
@@ -2276,7 +2276,7 @@ static int AppLayerProtoDetectTest04(void)
uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n";
Flow f;
memset(&f, 0x00, sizeof(f));
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
memset(pm_results, 0, sizeof(pm_results));
f.protomap = FlowGetProtoMapping(IPPROTO_TCP);

@@ -2314,7 +2314,7 @@ static int AppLayerProtoDetectTest05(void)
AppLayerProtoDetectSetup();

uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n<HTML><BODY>Blahblah</BODY></HTML>";
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
memset(pm_results, 0, sizeof(pm_results));
Flow f;
memset(&f, 0x00, sizeof(f));
@@ -2358,7 +2358,7 @@ static int AppLayerProtoDetectTest06(void)
AppLayerProtoDetectSetup();

uint8_t l7data[] = "220 Welcome to the OISF FTP server\r\n";
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
memset(pm_results, 0, sizeof(pm_results));
Flow f;
memset(&f, 0x00, sizeof(f));
@@ -2404,7 +2404,7 @@ static int AppLayerProtoDetectTest07(void)
Flow f;
memset(&f, 0x00, sizeof(f));
f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
memset(pm_results, 0, sizeof(pm_results));

const char *buf = "HTTP";
@@ -2458,7 +2458,7 @@ static int AppLayerProtoDetectTest08(void)
0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32,
0x00
};
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
memset(pm_results, 0, sizeof(pm_results));
Flow f;
memset(&f, 0x00, sizeof(f));
@@ -2513,7 +2513,7 @@ static int AppLayerProtoDetectTest09(void)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x02
};
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
memset(pm_results, 0, sizeof(pm_results));
Flow f;
memset(&f, 0x00, sizeof(f));
@@ -2563,7 +2563,7 @@ static int AppLayerProtoDetectTest10(void)
0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00,
0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00
};
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
memset(pm_results, 0, sizeof(pm_results));
Flow f;
memset(&f, 0x00, sizeof(f));
@@ -2608,7 +2608,7 @@ static int AppLayerProtoDetectTest11(void)

uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
memset(pm_results, 0, sizeof(pm_results));
Flow f;
memset(&f, 0x00, sizeof(f));
@@ -2733,7 +2733,7 @@ static int AppLayerProtoDetectTest13(void)

uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];

Flow f;
memset(&f, 0x00, sizeof(f));
@@ -2804,7 +2804,7 @@ static int AppLayerProtoDetectTest14(void)

uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
AppProto pm_results[ALPROTO_MAX];
AppProto pm_results[AlprotoMax];
uint32_t cnt;
Flow f;
memset(&f, 0x00, sizeof(f));
8 changes: 4 additions & 4 deletions src/app-layer-frames.c
Original file line number Diff line number Diff line change
@@ -33,16 +33,16 @@
struct FrameConfig {
SC_ATOMIC_DECLARE(uint64_t, types);
};
/* This array should be allocated to contain ALPROTO_MAX protocols. */
/* This array should be allocated to contain AlprotoMax protocols. */
static struct FrameConfig *frame_config;

void FrameConfigInit(void)
{
frame_config = SCCalloc(ALPROTO_MAX, sizeof(struct FrameConfig));
frame_config = SCCalloc(AlprotoMax, sizeof(struct FrameConfig));
if (unlikely(frame_config == NULL)) {
FatalError("Unable to alloc frame_config.");
}
for (AppProto p = 0; p < ALPROTO_MAX; p++) {
for (AppProto p = 0; p < AlprotoMax; p++) {
SC_ATOMIC_INIT(frame_config[p].types);
}
}
@@ -55,7 +55,7 @@ void FrameConfigDeInit(void)
void FrameConfigEnableAll(void)
{
const uint64_t bits = UINT64_MAX;
for (AppProto p = 0; p < ALPROTO_MAX; p++) {
for (AppProto p = 0; p < AlprotoMax; p++) {
struct FrameConfig *fc = &frame_config[p];
SC_ATOMIC_OR(fc->types, bits);
}
16 changes: 8 additions & 8 deletions src/app-layer-parser.c
Original file line number Diff line number Diff line change
@@ -249,8 +249,8 @@ int AppLayerParserSetup(void)
{
SCEnter();
// initial allocation that will later be grown using realloc,
// when new protocols register themselves and make ALPROTO_MAX grow
alp_ctx.ctxs = SCCalloc(ALPROTO_MAX, sizeof(AppLayerParserProtoCtx[FLOW_PROTO_MAX]));
// when new protocols register themselves and make AlprotoMax grow
alp_ctx.ctxs = SCCalloc(AlprotoMax, sizeof(AppLayerParserProtoCtx[FLOW_PROTO_MAX]));
if (unlikely(alp_ctx.ctxs == NULL)) {
FatalError("Unable to alloc alp_ctx.ctxs.");
}
@@ -261,7 +261,7 @@ void AppLayerParserPostStreamSetup(void)
{
/* lets set a default value for stream_depth */
for (int flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) {
for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) {
for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) {
if (!(alp_ctx.ctxs[alproto][flow_proto].internal_flags &
APP_LAYER_PARSER_INT_STREAM_DEPTH_SET)) {
alp_ctx.ctxs[alproto][flow_proto].stream_depth = stream_config.reassembly_depth;
@@ -290,14 +290,14 @@ AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void)
if (tctx == NULL)
goto end;

tctx->alproto_local_storage = SCCalloc(ALPROTO_MAX, sizeof(void *[FLOW_PROTO_MAX]));
tctx->alproto_local_storage = SCCalloc(AlprotoMax, sizeof(void *[FLOW_PROTO_MAX]));
if (unlikely(tctx->alproto_local_storage == NULL)) {
SCFree(tctx);
tctx = NULL;
goto end;
}
for (uint8_t flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) {
for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) {
for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) {
uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto);

tctx->alproto_local_storage[alproto][flow_proto] =
@@ -314,7 +314,7 @@ void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
SCEnter();

for (uint8_t flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) {
for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) {
for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) {
uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto);

AppLayerParserDestroyProtocolParserLocalStorage(
@@ -1695,7 +1695,7 @@ static void ValidateParser(AppProto alproto)
static void ValidateParsers(void)
{
AppProto p = 0;
for ( ; p < ALPROTO_MAX; p++) {
for (; p < AlprotoMax; p++) {
ValidateParser(p);
}
}
@@ -1795,7 +1795,7 @@ void AppLayerParserRegisterUnittests(void)
AppLayerParserProtoCtx *ctx;

for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) {
for (alproto = 0; alproto < ALPROTO_MAX; alproto++) {
for (alproto = 0; alproto < AlprotoMax; alproto++) {
ctx = &alp_ctx.ctxs[alproto][ip];
if (ctx->RegisterUnittests == NULL)
continue;
76 changes: 33 additions & 43 deletions src/app-layer-protos.c
Original file line number Diff line number Diff line change
@@ -24,53 +24,18 @@

#include "suricata-common.h"
#include "app-layer-protos.h"
#include "rust.h"

AppProto AlprotoMax = ALPROTO_MAX_STATIC + 1;
#define ARRAY_CAP_STEP 16
AppProto AppProtoStringsCap = ALPROTO_MAX_STATIC + 1;

typedef struct AppProtoStringTuple {
AppProto alproto;
const char *str;
} AppProtoStringTuple;

const AppProtoStringTuple AppProtoStrings[ALPROTO_MAX] = {
{ ALPROTO_UNKNOWN, "unknown" },
{ ALPROTO_FAILED, "failed" },
{ ALPROTO_HTTP1, "http1" },
{ ALPROTO_FTP, "ftp" },
{ ALPROTO_SMTP, "smtp" },
{ ALPROTO_TLS, "tls" },
{ ALPROTO_SSH, "ssh" },
{ ALPROTO_IMAP, "imap" },
{ ALPROTO_JABBER, "jabber" },
{ ALPROTO_SMB, "smb" },
{ ALPROTO_DCERPC, "dcerpc" },
{ ALPROTO_IRC, "irc" },
{ ALPROTO_DNS, "dns" },
{ ALPROTO_MODBUS, "modbus" },
{ ALPROTO_ENIP, "enip" },
{ ALPROTO_DNP3, "dnp3" },
{ ALPROTO_NFS, "nfs" },
{ ALPROTO_NTP, "ntp" },
{ ALPROTO_FTPDATA, "ftp-data" },
{ ALPROTO_TFTP, "tftp" },
{ ALPROTO_IKE, "ike" },
{ ALPROTO_KRB5, "krb5" },
{ ALPROTO_QUIC, "quic" },
{ ALPROTO_DHCP, "dhcp" },
{ ALPROTO_SNMP, "snmp" },
{ ALPROTO_SIP, "sip" },
{ ALPROTO_RFB, "rfb" },
{ ALPROTO_MQTT, "mqtt" },
{ ALPROTO_PGSQL, "pgsql" },
{ ALPROTO_TELNET, "telnet" },
{ ALPROTO_WEBSOCKET, "websocket" },
{ ALPROTO_LDAP, "ldap" },
{ ALPROTO_DOH2, "doh2" },
{ ALPROTO_TEMPLATE, "template" },
{ ALPROTO_RDP, "rdp" },
{ ALPROTO_HTTP2, "http2" },
{ ALPROTO_BITTORRENT_DHT, "bittorrent-dht" },
{ ALPROTO_POP3, "pop3" },
{ ALPROTO_HTTP, "http" },
};
AppProtoStringTuple *AppProtoStrings = NULL;

const char *AppProtoToString(AppProto alproto)
{
@@ -84,7 +49,7 @@ const char *AppProtoToString(AppProto alproto)
proto_name = "http_any";
break;
default:
if (alproto < ARRAY_SIZE(AppProtoStrings)) {
if (alproto < AlprotoMax) {
BUG_ON(AppProtoStrings[alproto].alproto != alproto);
proto_name = AppProtoStrings[alproto].str;
}
@@ -98,10 +63,35 @@ AppProto StringToAppProto(const char *proto_name)
return ALPROTO_UNKNOWN;

// We could use a Multi Pattern Matcher
for (size_t i = 0; i < ARRAY_SIZE(AppProtoStrings); i++) {
for (size_t i = 0; i < AlprotoMax; i++) {
if (strcmp(proto_name, AppProtoStrings[i].str) == 0)
return AppProtoStrings[i].alproto;
}

return ALPROTO_UNKNOWN;
}

void AppProtoRegisterProtoString(AppProto alproto, const char *proto_name)
{
if (alproto < ALPROTO_MAX_STATIC) {
if (AppProtoStrings == NULL) {
AppProtoStrings = SCCalloc(AppProtoStringsCap, sizeof(AppProtoStringTuple));
if (AppProtoStrings == NULL) {
FatalError("Unable to allocate AppProtoStrings");
}
}
} else if (alproto + 1 == AlprotoMax) {
if (AlprotoMax == AppProtoStringsCap) {
void *tmp = SCRealloc(AppProtoStrings,
sizeof(AppProtoStringTuple) * (AppProtoStringsCap + ARRAY_CAP_STEP));
if (tmp == NULL) {
FatalError("Unable to reallocate AppProtoStrings");
}
AppProtoStringsCap += ARRAY_CAP_STEP;
AppProtoStrings = tmp;
}
AlprotoMax++;
}
AppProtoStrings[alproto].str = proto_name;
AppProtoStrings[alproto].alproto = alproto;
}
Loading

0 comments on commit 4e001c2

Please sign in to comment.