"description": "Errors encountered parsing DNS/UDP protocol",
"$ref": "#/$defs/stats_applayer_error"
},
+ "doh2": {
+ "$ref": "#/$defs/stats_applayer_error"
+ },
"enip_tcp": {
"description": "Errors encounterd parsing ENIP/TCP",
"$ref": "#/$defs/stats_applayer_error"
"description": "Number of flows for DNS/UDP protocol",
"type": "integer"
},
+ "doh2": {
+ "type": "integer"
+ },
"enip_tcp": {
"description": "Number of flows for ENIP/TCP",
"type": "integer"
"description": "Number of transactions for DNS/UDP protocol",
"type": "integer"
},
+ "doh2": {
+ "type": "integer"
+ },
"enip_tcp": {
"description": "Number of transactions for ENIP/TCP",
"type": "integer"
// Defined in app-layer-detect-proto.h
extern {
+ pub fn AppLayerForceProtocolChange(f: *const Flow, new_proto: AppProto);
pub fn AppLayerProtoDetectPPRegister(ipproto: u8, portstr: *const c_char, alproto: AppProto,
min_depth: u16, max_depth: u16, dir: u8,
pparser1: ProbeFn, pparser2: ProbeFn);
use std::io;
static mut ALPROTO_HTTP2: AppProto = ALPROTO_UNKNOWN;
+static mut ALPROTO_DOH2: AppProto = ALPROTO_UNKNOWN;
const HTTP2_DEFAULT_MAX_FRAME_SIZE: u32 = 16384;
const HTTP2_MAX_HANDLED_FRAME_SIZE: usize = 65536;
}
}
}
- if doh {
+ if doh && unsafe {ALPROTO_DOH2} != ALPROTO_UNKNOWN {
if let Some(p) = path {
if let Ok((_, dns_req)) = parser::doh_extract_request(p) {
return Some(dns_req);
&xid,
);
};
- // we store DNS response, and process it when complete
- if self.is_doh_response && self.doh_response_buf.len() < 0xFFFF {
- // a DNS message is U16_MAX
- self.doh_response_buf.extend_from_slice(decompressed);
+ if unsafe {ALPROTO_DOH2} != ALPROTO_UNKNOWN {
+ // we store DNS response, and process it when complete
+ if self.is_doh_response && self.doh_response_buf.len() < 0xFFFF {
+ // a DNS message is U16_MAX
+ self.doh_response_buf.extend_from_slice(decompressed);
+ }
}
return Ok(());
}
return AppLayerResult::err();
}
let tx = tx.unwrap();
+ if let Some(doh_req_buf) = tx.handle_frame(&head, &txdata, dir) {
+ if let Ok(mut dtx) = dns_parse_request(&doh_req_buf) {
+ dtx.id = 1;
+ tx.dns_request_tx = Some(dtx);
+ unsafe {
+ AppLayerForceProtocolChange(flow, ALPROTO_DOH2);
+ }
+ }
+ }
if reass_limit_reached {
tx.tx_data
.set_event(HTTP2Event::ReassemblyLimitReached as u8);
flow,
) {
Ok(_) => {
- if !tx_same.doh_response_buf.is_empty() {
- if over {
- if let Ok(dtx) = dns_parse_response(
- &tx_same.doh_response_buf,
- ) {
- tx_same.dns_response_tx = Some(dtx);
+ if !tx_same.doh_response_buf.is_empty() && over {
+ if let Ok(mut dtx) =
+ dns_parse_response(&tx_same.doh_response_buf)
+ {
+ dtx.id = 1;
+ tx_same.dns_response_tx = Some(dtx);
+ unsafe {
+ AppLayerForceProtocolChange(
+ flow,
+ ALPROTO_DOH2,
+ );
}
}
}
#[no_mangle]
pub unsafe extern "C" fn rs_http2_register_parser() {
let default_port = CString::new("[80]").unwrap();
- let parser = RustParser {
+ let mut parser = RustParser {
name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
default_port: default_port.as_ptr(),
ipproto: IPPROTO_TCP,
} else {
SCLogNotice!("Protocol detector and parser disabled for HTTP2.");
}
+
+ // doh2 is just http2 wrapped in another name
+ parser.name = b"doh2\0".as_ptr() as *const std::os::raw::c_char;
+ parser.probe_tc = None;
+ parser.default_port = std::ptr::null();
+ if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
+ let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
+ ALPROTO_DOH2 = alproto;
+ if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
+ let _ = AppLayerRegisterParser(&parser, alproto);
+ } else {
+ SCLogWarning!("DOH2 is not meant to be detection-only.");
+ }
+ AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DOH2);
+ SCLogDebug!("Rust doh2 parser registered.");
+ } else {
+ SCLogNotice!("Protocol detector and parser disabled for DOH2.");
+ }
}
return AppLayerRequestProtocolChange(f, 443, ALPROTO_TLS);
}
+void AppLayerForceProtocolChange(Flow *f, AppProto new_proto)
+{
+ if (new_proto != f->alproto) {
+ f->alproto_orig = f->alproto;
+ f->alproto = new_proto;
+ f->alproto_ts = f->alproto;
+ f->alproto_tc = f->alproto;
+ }
+}
+
void AppLayerProtoDetectReset(Flow *f)
{
FLOW_RESET_PM_DONE(f, STREAM_TOSERVER);
bool AppLayerRequestProtocolChange(Flow *f, uint16_t dp, AppProto expect_proto);
bool AppLayerRequestProtocolTLSUpgrade(Flow *f);
+void AppLayerForceProtocolChange(Flow *f, AppProto new_proto);
+
/**
* \brief Cleans up the app layer protocol detection phase.
*/
{ ALPROTO_TELNET, "telnet" },
{ ALPROTO_WEBSOCKET, "websocket" },
{ ALPROTO_LDAP, "ldap" },
+ { ALPROTO_DOH2, "doh2" },
{ ALPROTO_TEMPLATE, "template" },
{ ALPROTO_RDP, "rdp" },
{ ALPROTO_HTTP2, "http2" },
ALPROTO_TELNET,
ALPROTO_WEBSOCKET,
ALPROTO_LDAP,
+ ALPROTO_DOH2,
ALPROTO_TEMPLATE,
ALPROTO_RDP,
ALPROTO_HTTP2,
OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonLdapLog", "eve-log.ldap",
OutputJsonLogInitSub, ALPROTO_LDAP, JsonGenericDirPacketLogger, JsonLogThreadInit,
JsonLogThreadDeinit, NULL);
+ /* DoH2 JSON logger. */
+ OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonDoH2Log", "eve-log.doh2",
+ OutputJsonLogInitSub, ALPROTO_DOH2, JsonGenericDirFlowLogger, JsonLogThreadInit,
+ JsonLogThreadDeinit, NULL);
/* Template JSON logger. */
OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonTemplateLog", "eve-log.template",
OutputJsonLogInitSub, ALPROTO_TEMPLATE, JsonGenericDirPacketLogger, JsonLogThreadInit,
{ ALPROTO_TELNET, NULL }, // no logging
{ ALPROTO_WEBSOCKET, rs_websocket_logger_log },
{ ALPROTO_LDAP, rs_ldap_logger_log },
+ { ALPROTO_DOH2, rs_http2_log_json }, // http2 logger knows how to log dns
{ ALPROTO_TEMPLATE, rs_template_logger_log },
{ ALPROTO_RDP, (EveJsonSimpleTxLogFunc)rs_rdp_to_json },
{ ALPROTO_HTTP2, rs_http2_log_json },
# the maximum parsed message size (see
# app-layer configuration)
- http2
+ # dns over http2
+ - doh2
- pgsql:
enabled: no
# passwords: yes # enable output of passwords. Disabled by default
ssh:
enabled: yes
#hassh: yes
+ doh2:
+ enabled: yes
http2:
enabled: yes
# Maximum number of live HTTP2 streams in a flow