Skip to content

Commit

Permalink
doh: make dns and http keywords for doh2
Browse files Browse the repository at this point in the history
Ticket: 5773
  • Loading branch information
catenacyber committed Jan 16, 2024
1 parent 211be62 commit 8df8746
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 16 deletions.
16 changes: 16 additions & 0 deletions rust/src/http2/http2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,22 @@ impl HTTP2State {

// C exports.

#[no_mangle]
pub unsafe extern "C" fn SCDoH2GetDnsTx(
tx: &HTTP2Transaction, flags: u8,
) -> *mut std::os::raw::c_void {
if flags & Direction::ToServer as u8 != 0 {
if let Some(ref dtx) = &tx.dns_request_tx {
return dtx as *const _ as *mut _;
}
} else if flags & Direction::ToClient as u8 != 0 {
if let Some(ref dtx) = &tx.dns_response_tx {
return dtx as *const _ as *mut _;
}
}
std::ptr::null_mut()
}

export_tx_data_get!(rs_http2_get_tx_data, HTTP2Transaction);
export_state_data_get!(rs_http2_get_state_data, HTTP2State);

Expand Down
3 changes: 3 additions & 0 deletions src/app-layer-detect-proto.c
Original file line number Diff line number Diff line change
Expand Up @@ -2057,6 +2057,9 @@ void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos)
if (alproto == ALPROTO_HTTP) {
AppLayerProtoDetectSupportedIpprotos(ALPROTO_HTTP1, ipprotos);
AppLayerProtoDetectSupportedIpprotos(ALPROTO_HTTP2, ipprotos);
} else if (alproto == ALPROTO_DOH2) {
// DOH2 is not detected, just HTTP2
AppLayerProtoDetectSupportedIpprotos(ALPROTO_HTTP2, ipprotos);
} else {
AppLayerProtoDetectPMGetIpprotos(alproto, ipprotos);
AppLayerProtoDetectPPGetIpprotos(alproto, ipprotos);
Expand Down
59 changes: 59 additions & 0 deletions src/app-layer-protos.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,30 @@ static inline bool AppProtoIsValid(AppProto a)
return ((a > ALPROTO_UNKNOWN && a < ALPROTO_FAILED));
}

// whether an engine proto works on a flow proto
static inline bool AppProtoCompatible(AppProto eng_proto, AppProto alproto)
{
switch (alproto) {
case ALPROTO_DOH2:
return (eng_proto == ALPROTO_HTTP2) || (eng_proto == ALPROTO_DNS);
}
return (eng_proto == alproto);
}

// whether a signature AppProto matches a flow (or signature) AppProto
static inline bool AppProtoEquals(AppProto sigproto, AppProto alproto)
{
if (sigproto == alproto) {
return true;
}
switch (sigproto) {
case ALPROTO_DNS:
return (alproto == ALPROTO_DOH2) || (alproto == ALPROTO_DNS);
case ALPROTO_HTTP2:
return (alproto == ALPROTO_DOH2) || (alproto == ALPROTO_HTTP2);
case ALPROTO_DOH2:
return (alproto == ALPROTO_DOH2) || (alproto == ALPROTO_HTTP2) ||
(alproto == ALPROTO_DNS) || (alproto == ALPROTO_HTTP);
case ALPROTO_HTTP:
return (alproto == ALPROTO_HTTP1) || (alproto == ALPROTO_HTTP2);
case ALPROTO_DCERPC:
Expand All @@ -100,6 +117,48 @@ static inline bool AppProtoEquals(AppProto sigproto, AppProto alproto)
return false;
}

// whether a signature AppProto matches a flow (or signature) AppProto
static inline AppProto AppProtoCommon(AppProto sigproto, AppProto alproto)
{
switch (sigproto) {
case ALPROTO_SMB:
if (alproto == ALPROTO_DCERPC) {
// ok to have dcerpc keywords in smb sig
return ALPROTO_SMB;
}
break;
case ALPROTO_HTTP:
// we had a generic http sig, now version specific
if (alproto == ALPROTO_HTTP1) {
return ALPROTO_HTTP1;
} else if (alproto == ALPROTO_HTTP2) {
return ALPROTO_HTTP2;
}
break;
case ALPROTO_HTTP1:
// version-specific sig with a generic keyword
if (alproto == ALPROTO_HTTP) {
return ALPROTO_HTTP1;
}
break;
case ALPROTO_HTTP2:
if (alproto == ALPROTO_HTTP) {
return ALPROTO_HTTP2;
}
break;
case ALPROTO_DOH2:
// DOH2 accepts different protocol keywords
if (alproto == ALPROTO_HTTP || alproto == ALPROTO_HTTP2 || alproto == ALPROTO_DNS) {
return ALPROTO_DOH2;
}
break;
}
if (sigproto != alproto) {
return ALPROTO_FAILED;
}
return alproto;
}

/**
* \brief Maps the ALPROTO_*, to its string equivalent.
*
Expand Down
12 changes: 12 additions & 0 deletions src/detect-dns-answer-name.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ static uint8_t DetectEngineInspectCb(DetectEngineCtx *de_ctx, DetectEngineThread
transforms = engine->v2.transforms;
}

if (f->alproto == ALPROTO_DOH2) {
txv = SCDoH2GetDnsTx(txv, flags);
if (txv == NULL) {
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
}
}
for (uint32_t i = 0;; i++) {
InspectionBuffer *buffer = GetBuffer(det_ctx, flags, transforms, txv, i, engine->sm_list);
if (buffer == NULL || buffer->inspect == NULL) {
Expand All @@ -108,6 +114,12 @@ static void PrefilterTx(DetectEngineThreadCtx *det_ctx, const void *pectx, Packe
const MpmCtx *mpm_ctx = ctx->mpm_ctx;
const int list_id = ctx->list_id;

if (f->alproto == ALPROTO_DOH2) {
txv = SCDoH2GetDnsTx(txv, flags);
if (txv == NULL) {
return;
}
}
for (uint32_t i = 0;; i++) {
InspectionBuffer *buffer = GetBuffer(det_ctx, flags, ctx->transforms, txv, i, list_id);
if (buffer == NULL) {
Expand Down
6 changes: 6 additions & 0 deletions src/detect-dns-opcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ static int DetectDnsOpcodeMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
const SigMatchCtx *ctx)
{
if (f->alproto == ALPROTO_DOH2) {
txv = SCDoH2GetDnsTx(txv, flags);
if (txv == NULL) {
return 0;
}
}
return rs_dns_opcode_match(txv, (void *)ctx, flags);
}

Expand Down
12 changes: 12 additions & 0 deletions src/detect-dns-query-name.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ static uint8_t DetectEngineInspectCb(DetectEngineCtx *de_ctx, DetectEngineThread
transforms = engine->v2.transforms;
}

if (f->alproto == ALPROTO_DOH2) {
txv = SCDoH2GetDnsTx(txv, flags);
if (txv == NULL) {
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
}
}
for (uint32_t i = 0;; i++) {
InspectionBuffer *buffer = GetBuffer(det_ctx, flags, transforms, txv, i, engine->sm_list);
if (buffer == NULL || buffer->inspect == NULL) {
Expand All @@ -108,6 +114,12 @@ static void PrefilterTx(DetectEngineThreadCtx *det_ctx, const void *pectx, Packe
const MpmCtx *mpm_ctx = ctx->mpm_ctx;
const int list_id = ctx->list_id;

if (f->alproto == ALPROTO_DOH2) {
txv = SCDoH2GetDnsTx(txv, flags);
if (txv == NULL) {
return;
}
}
for (uint32_t i = 0;; i++) {
InspectionBuffer *buffer = GetBuffer(det_ctx, flags, ctx->transforms, txv, i, list_id);
if (buffer == NULL) {
Expand Down
12 changes: 12 additions & 0 deletions src/detect-dns-query.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ static uint8_t DetectEngineInspectDnsQuery(DetectEngineCtx *de_ctx, DetectEngine
transforms = engine->v2.transforms;
}

if (f->alproto == ALPROTO_DOH2) {
txv = SCDoH2GetDnsTx(txv, flags);
if (txv == NULL) {
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
}
}
while(1) {
struct DnsQueryGetDataArgs cbdata = { local_id, txv, };
InspectionBuffer *buffer =
Expand Down Expand Up @@ -149,6 +155,12 @@ static void PrefilterTxDnsQuery(DetectEngineThreadCtx *det_ctx, const void *pect
const int list_id = ctx->list_id;

uint32_t local_id = 0;
if (f->alproto == ALPROTO_DOH2) {
txv = SCDoH2GetDnsTx(txv, flags);
if (txv == NULL) {
return;
}
}
while(1) {
// loop until we get a NULL

Expand Down
5 changes: 5 additions & 0 deletions src/detect-engine-mpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ void DetectAppLayerMpmRegister(const char *name, int direction, int priority,
FatalError("MPM engine registration for %s failed", name);
}

// every HTTP2 can be accessed from DOH2
if (alproto == ALPROTO_HTTP2 || alproto == ALPROTO_DNS) {
DetectAppLayerMpmRegister(name, direction, priority, PrefilterRegister, GetData,
ALPROTO_DOH2, tx_min_progress);
}
DetectBufferMpmRegistry *am = SCCalloc(1, sizeof(*am));
BUG_ON(am == NULL);
am->name = name;
Expand Down
2 changes: 1 addition & 1 deletion src/detect-engine-prefilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx,

PrefilterEngine *engine = sgh->tx_engines;
do {
if (engine->alproto != alproto)
if (!AppProtoCompatible(engine->alproto, alproto))
goto next;
if (engine->ctx.tx_min_progress > tx->tx_progress)
break;
Expand Down
4 changes: 4 additions & 0 deletions src/detect-engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uin
} else {
direction = 1;
}
// every DNS or HTTP2 can be accessed from DOH2
if (alproto == ALPROTO_HTTP2 || alproto == ALPROTO_DNS) {
DetectAppLayerInspectEngineRegister(name, ALPROTO_DOH2, dir, progress, Callback, GetData);
}

DetectEngineAppInspectionEngine *new_engine =
SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
Expand Down
17 changes: 3 additions & 14 deletions src/detect-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1757,20 +1757,9 @@ int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
return -1;
}

/* since AppProtoEquals is quite permissive wrt dcerpc and smb, make sure
* we refuse `alert dcerpc ... smb.share; content...` explicitly. */
if (alproto == ALPROTO_SMB && s->alproto == ALPROTO_DCERPC) {
SCLogError("can't set rule app proto to %s: already set to %s", AppProtoToString(alproto),
AppProtoToString(s->alproto));
return -1;
}

if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) {
if (AppProtoEquals(alproto, s->alproto)) {
// happens if alproto = HTTP_ANY and s->alproto = HTTP1
// in this case, we must keep the most restrictive HTTP1
alproto = s->alproto;
} else {
if (s->alproto != ALPROTO_UNKNOWN) {
alproto = AppProtoCommon(s->alproto, alproto);
if (alproto == ALPROTO_FAILED) {
SCLogError("can't set rule app proto to %s: already set to %s",
AppProtoToString(alproto), AppProtoToString(s->alproto));
return -1;
Expand Down
4 changes: 3 additions & 1 deletion src/detect.c
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,9 @@ static bool DetectRunTxInspectRule(ThreadVars *tv,
if (!(inspect_flags & BIT_U32(engine->id)) &&
direction == engine->dir)
{
const bool skip_engine = (engine->alproto != 0 && engine->alproto != f->alproto);
const bool skip_engine =
(engine->alproto != 0 && !AppProtoCompatible(engine->alproto, f->alproto));

/* special case: file_data on 'alert tcp' will have engines
* in the list that are not for us. */
if (unlikely(skip_engine)) {
Expand Down

0 comments on commit 8df8746

Please sign in to comment.