#include <cstring>
#include "flow/flow_stash.h"
+#include "flow/stream_flow.h"
#include "main/snort_config.h"
#include "managers/inspector_manager.h"
#include "profiler/profiler.h"
AppIdDnsSession* AppIdSession::create_dns_session()
{
- if (api.dsession)
- delete api.dsession;
- api.dsession = new AppIdDnsSession();
- return api.dsession;
+ if (flow->stream_intf)
+ {
+ int64_t stream_id;
+ flow->stream_intf->get_stream_id(flow, stream_id);
+ api.dsessions.emplace(stream_id, new AppIdDnsSession());
+ return api.dsessions[stream_id];
+ }
+ else
+ {
+ if (api.dsession)
+ delete api.dsession;
+ api.dsession = new AppIdDnsSession();
+ return api.dsession;
+ }
}
AppIdDnsSession* AppIdSession::get_dns_session() const
{
- return api.dsession;
+ if (flow->stream_intf)
+ {
+ int64_t stream_id;
+ flow->stream_intf->get_stream_id(flow, stream_id);
+ if (stream_id == 0xFFFFFFFF) // no stream id is processing now, pick the last processed
+ {
+ if (!api.dsessions.empty())
+ return std::prev(api.dsessions.end())->second;
+ else
+ return nullptr;
+ }
+ auto it = api.dsessions.find(stream_id);
+ if (it != api.dsessions.end())
+ return it->second;
+
+ return nullptr;
+ }
+ else if (!api.dsessions.empty()) // flow data of inspector who handles stream_intf got deleted, take the last one
+ return std::prev(api.dsessions.end())->second;
+ else
+ return api.dsession;
}
bool AppIdSession::is_tp_appid_done() const
#include "detector_dns.h"
+#include "flow/stream_flow.h"
+
#include "appid_config.h"
#include "appid_dns_session.h"
#include "app_info_table.h"
free_dns_cache();
}
+class ServiceDNSDoQData : public AppIdFlowData
+{
+public:
+ ServiceDNSDoQData() = default;
+ ~ServiceDNSDoQData() override;
+
+ std::unordered_map<int64_t, ServiceDNSData*> service_dns_data;
+ ServiceDNSData* get_stream_dns_data(int64_t stream_id)
+ {
+ auto it = service_dns_data.find(stream_id);
+ if (it != service_dns_data.end())
+ return it->second;
+ else
+ return nullptr;
+ }
+ ServiceDNSData* create_stream_dns_data(int64_t stream_id)
+ {
+ ServiceDNSData* dns_data = new ServiceDNSData();
+ service_dns_data[stream_id] = dns_data;
+ return dns_data;
+ }
+};
+
+ServiceDNSDoQData::~ServiceDNSDoQData()
+{
+ for (auto& it: service_dns_data)
+ delete it.second;
+ service_dns_data.clear();
+}
+
DnsTcpServiceDetector::DnsTcpServiceDetector(ServiceDiscovery* sd)
{
handler = sd;
uint8_t* reallocated_data = nullptr;
const uint8_t* data = args.data;
uint16_t size = args.size;
- ServiceDNSData* dd = static_cast<ServiceDNSData*>(data_get(args.asd));
+ ServiceDNSDoQData* dd_doq;
+ ServiceDNSData* dd;
{
if (!args.size)
goto inprocess;
else
goto fail;
}
-
- if (!dd)
+ if (args.asd.flow->stream_intf)
{
- dd = new ServiceDNSData;
- data_add(args.asd, dd);
+ dd_doq = static_cast<ServiceDNSDoQData*>(data_get(args.asd));
+ if (!dd_doq)
+ {
+ dd_doq = new ServiceDNSDoQData;
+ data_add(args.asd, dd_doq);
+ }
+ int64_t stream_id;
+ args.asd.flow->stream_intf->get_stream_id(args.asd.flow, stream_id);
+ dd = dd_doq->get_stream_dns_data(stream_id);
+ if (!dd)
+ dd = dd_doq->create_stream_dns_data(stream_id);
+ }
+ else
+ {
+ dd = static_cast<ServiceDNSData*>(data_get(args.asd));
+ if (!dd)
+ {
+ dd = new ServiceDNSData;
+ data_add(args.asd, dd);
+ }
}
-
if (dd->cached_data and dd->cached_len and args.dir == APP_ID_FROM_INITIATOR)
{
reallocated_data = static_cast<uint8_t*>(snort_calloc(dd->cached_len + args.size, sizeof(uint8_t)));
using namespace snort;
+Flow::~Flow() = default;
+class QuicStreamIntf: public snort::StreamFlowIntf
+{
+public:
+ void get_stream_id(const snort::Flow* flow, int64_t& stream_id) override
+ {
+ stream_id = 0;
+ }
+};
+static QuicStreamIntf quic_stream_intf;
+
static ServiceDiscovery test_discovery;
static AppIdDnsSession static_dns_session;
}
// Stubs for AppIdInspector
static ServiceDNSData dd;
+static bool return_null_data = false;
+ServiceDNSDoQData* dns_doq_data = nullptr;
AppIdConfig test_app_config;
AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { }
void AppIdDetector::add_user(AppIdSession&, const char*, AppId, bool, AppidChangeBits&){}
-int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*) { return 1; }
+int AppIdDetector::data_add(AppIdSession&, AppIdFlowData* dns_data)
+{
+ if (return_null_data)
+ {
+ dns_doq_data = static_cast<ServiceDNSDoQData*>(dns_data);
+ return 1;
+ }
+ return 1;
+}
AppIdFlowData* AppIdDetector::data_get(const AppIdSession&)
{
- return ⅆ
+ return return_null_data ? nullptr : ⅆ
}
int ServiceDetector::fail_service(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir) { return 1; }
AppIdInspector test_inspector(test_module);
dd.state = DNS_STATE_QUERY;
AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0);
- uint8_t dns_tcp_packet[] = {
+ Flow* flow = new Flow;
+ test_asd.flow = flow;
+ uint8_t dns_tcp_packet[] = {
0x00, 0x1c, // TCP length (28 bytes)
0x12, 0x34, // id
0x01, 0x00, // flags
AppIdDiscoveryArgs response_args(dns_tcp_response, sizeof(dns_tcp_response), APP_ID_FROM_RESPONDER, test_asd, nullptr, change_bits);
result = test_detector->validate_doq(response_args);
-
+ delete flow;
CHECK_EQUAL(APPID_SUCCESS, result);
}
AppIdInspector test_inspector(test_module);
dd.state = DNS_STATE_QUERY;
AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0);
+ Flow* flow = new Flow;
+ test_asd.flow = flow;
// partial data
uint8_t dns_tcp_packet_1[] = {
0x00, 0x1c, // TCP length (28 bytes)
};
AppIdDiscoveryArgs args2(dns_tcp_packet_2, sizeof(dns_tcp_packet_2), APP_ID_FROM_INITIATOR, test_asd, nullptr, change_bits);
result = test_detector->validate_doq(args2);
+ delete flow;
CHECK_EQUAL(APPID_INPROCESS, result);
}
AppIdInspector test_inspector(test_module);
dd.state = DNS_STATE_QUERY;
AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0);
- uint8_t dns_tcp_packet[] = {
+ Flow* flow = new Flow;
+ test_asd.flow = flow;
+
+ uint8_t dns_tcp_packet[] = {
0x00, 0x01, // TCP length (1 bytes)
0x12, 0x34, // id
0x01, 0x00, // flags
AppidChangeBits change_bits;
AppIdDiscoveryArgs args(dns_tcp_packet, sizeof(dns_tcp_packet), APP_ID_FROM_INITIATOR, test_asd, nullptr, change_bits);
auto result = test_detector->validate_doq(args);
+ delete flow;
CHECK_EQUAL(APPID_NOT_COMPATIBLE, result);
}
AppIdInspector test_inspector(test_module);
dd.state = DNS_STATE_QUERY;
AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0);
- uint8_t dns_tcp_packet[] = {
+ Flow* flow = new Flow;
+ test_asd.flow = flow;
+ uint8_t dns_tcp_packet[] = {
0x00, 0x10, // TCP length (28 bytes)
0x12, 0x34, // id
0x01, 0x00, // flags
AppidChangeBits change_bits;
AppIdDiscoveryArgs args(dns_tcp_packet, sizeof(dns_tcp_packet), APP_ID_FROM_RESPONDER, test_asd, nullptr, change_bits);
auto result = test_detector->validate_doq(args);
+ delete flow;
CHECK_EQUAL(APPID_NOMATCH, result);
}
+TEST(detector_dns_doq_tests, doq_validator_stream_intf)
+{
+ OdpContext test_odp_ctxt(test_app_config, nullptr);
+ AppIdModule test_module;
+ AppIdInspector test_inspector(test_module);
+ dd.state = DNS_STATE_QUERY;
+ AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0);
+ Flow* flow = new Flow;
+ test_asd.flow = flow;
+ flow->stream_intf = &quic_stream_intf;
+ return_null_data = true; // Set flag to return nullptr from data_get
+ uint8_t dns_tcp_packet[] = {
+ 0x00, 0x1c, // TCP length (28 bytes)
+ 0x12, 0x34, // id
+ 0x01, 0x00, // flags
+ 0x00, 0x01, // QDCount
+ 0x00, 0x00, // ANCount
+ 0x00, 0x00, // NSCount
+ 0x00, 0x00, // ARCount
+ 0x03, 'w', 'w', 'w', 0x00, // "www"
+ 0x00, 0x01, // QType A
+ 0x00, 0x01 // QClass IN
+ };
+
+ AppidChangeBits change_bits;
+ AppIdDiscoveryArgs args(dns_tcp_packet, sizeof(dns_tcp_packet), APP_ID_FROM_INITIATOR, test_asd, nullptr, change_bits);
+ auto result = test_detector->validate_doq(args);
+ delete flow;
+ return_null_data = false;
+ delete dns_doq_data;
+ dns_doq_data = nullptr;
+ CHECK_EQUAL(APPID_INPROCESS, result);
+}
+
int main(int argc, char** argv)