Skip to content

Commit

Permalink
detect: clean support for multi-protocol keywords
Browse files Browse the repository at this point in the history
such as ja4

Ticket: 7304
  • Loading branch information
catenacyber committed Nov 27, 2024
1 parent bd7d38e commit bbc62a6
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 0 deletions.
89 changes: 89 additions & 0 deletions src/detect-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1734,6 +1734,80 @@ int DetectSignatureAddTransform(Signature *s, int transform, void *options)
SCReturnInt(0);
}

int DetectSignatureSetMultiAppProto(Signature *s, const AppProto *alprotos)
{
if (s->alproto != ALPROTO_UNKNOWN) {
// One alproto was set, check if it matches the new ones proposed
while (*alprotos != ALPROTO_UNKNOWN) {
if (s->alproto == *alprotos) {
// alproto already set to only one
return 0;
}
alprotos++;
}
// alproto already set and not matching the new set of alprotos
return -1;
}
if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
// check intersection of already used alprotos and new ones
for (size_t i = 0; i < SIG_ALPROTO_MAX; i++) {
// first disable the ones that do not match
bool found = false;
while (*alprotos != ALPROTO_UNKNOWN) {
if (s->init_data->alprotos[i] == *alprotos) {
found = true;
break;
}
alprotos++;
}
if (!found) {
s->init_data->alprotos[i] = ALPROTO_UNKNOWN;
}
}
// Then put at the beginning every defined protocol
for (size_t i = 0; i < SIG_ALPROTO_MAX; i++) {
if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
for (size_t j = SIG_ALPROTO_MAX - 1; j > i; j--) {
if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
s->init_data->alprotos[i] = s->init_data->alprotos[j];
s->init_data->alprotos[j] = ALPROTO_UNKNOWN;
break;
}
}
if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
if (i == 0) {
// there was no intersection
return -1;
} else if (i == 1) {
// intersection is singleton, set it as usual
AppProto alproto = s->init_data->alprotos[0];
s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
return DetectSignatureSetAppProto(s, alproto);
}
break;
}
}
}
} else {
if (alprotos[0] == ALPROTO_UNKNOWN) {
// do not allow empty set
return -1;
}
if (alprotos[1] == ALPROTO_UNKNOWN) {
// allow singleton, but call traditional setter
return DetectSignatureSetAppProto(s, alprotos[0]);
}
// first time we enforce alprotos
for (size_t i = 0; i < SIG_ALPROTO_MAX; i++) {
if (alprotos[i] == ALPROTO_UNKNOWN) {
break;
}
s->init_data->alprotos[i] = alprotos[i];
}
}
return 0;
}

int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
{
if (alproto == ALPROTO_UNKNOWN ||
Expand All @@ -1742,6 +1816,21 @@ int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
return -1;
}

if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
// Multiple protocols were set, check if we restrict to one
bool found = false;
for (size_t i = 0; i < SIG_ALPROTO_MAX; i++) {
if (s->init_data->alprotos[i] == alproto) {
found = true;
break;
}
}
if (!found) {
return -1;
}
s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
}

if (s->alproto != ALPROTO_UNKNOWN) {
alproto = AppProtoCommon(s->alproto, alproto);
if (alproto == ALPROTO_FAILED) {
Expand Down
1 change: 1 addition & 0 deletions src/detect-parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...);

int DetectSignatureAddTransform(Signature *s, int transform, void *options);
int WARN_UNUSED DetectSignatureSetAppProto(Signature *s, AppProto alproto);
int WARN_UNUSED DetectSignatureSetMultiAppProto(Signature *s, const AppProto *alprotos);

/* parse regex setup and free util funcs */

Expand Down
5 changes: 5 additions & 0 deletions src/detect.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@ typedef struct SignatureInitDataBuffer_ {
SigMatch *tail;
} SignatureInitDataBuffer;

#define SIG_ALPROTO_MAX 4

typedef struct SignatureInitData_ {
/** Number of sigmatches. Used for assigning SigMatch::idx */
uint16_t sm_cnt;
Expand All @@ -553,6 +555,9 @@ typedef struct SignatureInitData_ {
uint32_t init_flags;
/* coccinelle: SignatureInitData:init_flags:SIG_FLAG_INIT_ */

/* alproto mask if multiple protocols are possible */
AppProto alprotos[SIG_ALPROTO_MAX];

/* used at init to determine max dsize */
SigMatch *dsize_sm;

Expand Down

0 comments on commit bbc62a6

Please sign in to comment.