class ResetAction : public snort::ActiveAction
{
public:
- ResetAction() : ActiveAction(ActionType::ACT_RESET) {}
+ ResetAction() : ActiveAction(ActionType::ACT_RESET) { }
void exec(snort::Packet* p) override
{
if ( use_direct_inject )
{
DIOCTL_DirectInjectReset msg =
- { p->daq_msg, (uint8_t)((tmp_flags & ENC_FLAG_FWD) ? DAQ_DIR_FORWARD : DAQ_DIR_REVERSE) };
+ { p->daq_msg, (uint8_t)((tmp_flags & ENC_FLAG_FWD) ? DAQ_DIR_FORWARD :
+ DAQ_DIR_REVERSE) };
ret = p->daq_instance->ioctl(DIOCTL_DIRECT_INJECT_RESET,
&msg, sizeof(msg));
if ( ret != DAQ_SUCCESS )
uint32_t sent = 0;
- // Inject the payload.
- if ( use_direct_inject )
+ if (buf != nullptr)
{
- flags = (flags & ~ENC_FLAG_VAL);
- const DAQ_DIPayloadSegment segments[] = { {buf, blen} };
- const DAQ_DIPayloadSegment* payload[] = { &segments[0] };
- DIOCTL_DirectInjectPayload msg = { p->daq_msg, payload, 1,
- (uint8_t)((flags & ENC_FLAG_FWD) ? DAQ_DIR_FORWARD : DAQ_DIR_REVERSE) };
- ret = p->daq_instance->ioctl(DIOCTL_DIRECT_INJECT_PAYLOAD,
- &msg, sizeof(msg));
- if ( ret != DAQ_SUCCESS )
+ // Inject the payload.
+ if ( use_direct_inject )
{
- active_counts.failed_direct_injects++;
- return 0;
- }
-
- sent = blen;
- active_counts.direct_injects++;
- }
- else
- {
- const uint16_t maxPayload = PacketManager::encode_get_max_payload(p);
+ flags = (flags & ~ENC_FLAG_VAL);
+ const DAQ_DIPayloadSegment segments[] = {
+ { buf, blen }
+ };
+ const DAQ_DIPayloadSegment* payload[] = { &segments[0] };
+ DIOCTL_DirectInjectPayload msg = { p->daq_msg, payload, 1,
+ (uint8_t)((flags & ENC_FLAG_FWD) ? DAQ_DIR_FORWARD :
+ DAQ_DIR_REVERSE) };
+ ret = p->daq_instance->ioctl(DIOCTL_DIRECT_INJECT_PAYLOAD,
+ &msg, sizeof(msg));
+ if ( ret != DAQ_SUCCESS )
+ {
+ active_counts.failed_direct_injects++;
+ return 0;
+ }
- if (maxPayload)
+ sent = blen;
+ active_counts.direct_injects++;
+ }
+ else
{
- uint32_t toSend;
- do
- {
- plen = 0;
- flags = (flags & ~ENC_FLAG_VAL) | sent;
- toSend = blen > maxPayload ? maxPayload : blen;
- seg = PacketManager::encode_response(TcpResponse::PUSH, flags, p, plen, buf, toSend);
+ const uint16_t maxPayload = PacketManager::encode_get_max_payload(p);
- if ( !seg )
+ if (maxPayload)
+ {
+ uint32_t toSend;
+ do
{
- active_counts.failed_injects++;
- return sent;
+ plen = 0;
+ flags = (flags & ~ENC_FLAG_VAL) | sent;
+ toSend = blen > maxPayload ? maxPayload : blen;
+ seg = PacketManager::encode_response(TcpResponse::PUSH, flags, p, plen, buf,
+ toSend);
+
+ if ( !seg )
+ {
+ active_counts.failed_injects++;
+ return sent;
+ }
+
+ ret = s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
+ if ( ret )
+ active_counts.failed_injects++;
+ else
+ active_counts.injects++;
+
+ sent += toSend;
+ buf += toSend;
}
-
- ret = s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
- if ( ret )
- active_counts.failed_injects++;
- else
- active_counts.injects++;
-
- sent += toSend;
- buf += toSend;
+ while (blen -= toSend);
}
- while (blen -= toSend);
}
}
// FIXIT-L: Currently there is no support for injecting a FIN via
// direct injection.
- if ( ! use_direct_inject )
+ if ( !use_direct_inject )
{
plen = 0;
flags = (flags & ~ENC_FLAG_VAL) | sent;
return false;
// FIXIT-L same semi-arbitrary heuristic as the retry queue logic - reevaluate later
- if (!p->daq_instance || p->daq_instance->get_pool_available() < p->daq_instance->get_batch_size())
+ if (!p->daq_instance || p->daq_instance->get_pool_available() <
+ p->daq_instance->get_batch_size())
{
active_counts.holds_denied++;
return false;
reset_session(p, delayed_reject, force);
break;
case ACT_RETRY:
- if(!retry_packet(p))
+ if (!retry_packet(p))
drop_packet(p, force);
break;
default:
delayed_active_action = ACT_ALLOW;
}
-
//--------------------------------------------------------------------
bool Active::open(const char* dev)
if ( reason != -1 )
p.daq_instance->set_packet_verdict_reason(p.daq_msg, reason);
}
+
#include "packet_io/active.h"
#include "protocols/packet.h"
-#ifdef UNIT_TEST
-#include "catch/snort_catch.h"
-#endif
-
#define s_name "payload_injector"
#define s_help \
"payload injection utility"
const PegInfo payload_injector_pegs[] =
{
{ CountType::SUM, "http_injects", "total number of http injections" },
+ { CountType::SUM, "http2_injects", "total number of http2 injections" },
{ CountType::END, nullptr, nullptr }
};
return true;
}
-InjectionReturnStatus PayloadInjectorModule::inject_http_payload(Packet* p, InjectionControl& control)
+InjectionReturnStatus PayloadInjectorModule::inject_http_payload(Packet* p,
+ InjectionControl& control)
{
InjectionReturnStatus status = INJECTION_SUCCESS;
if (p->packet_flags & PKT_STREAM_EST)
{
- payload_injector_stats.http_injects++;
- p->active->send_data(p, df, control.http_page, control.http_page_len);
+ if (!p->flow || !p->flow->gadget)
+ status = ERR_UNIDENTIFIED_PROTOCOL;
+ else if (strcmp(p->flow->gadget->get_name(),"http_inspect") == 0)
+ {
+ payload_injector_stats.http_injects++;
+ p->active->send_data(p, df, control.http_page, control.http_page_len);
+ }
+ else if (strcmp(p->flow->gadget->get_name(),"http2_inspect") == 0)
+ {
+ if (control.stream_id != 0)
+ {
+ payload_injector_stats.http2_injects++;
+ // FIXIT-E translate page, inject payload
+ p->active->send_data(p, df, nullptr, 0);
+ }
+ else
+ status = ERR_HTTP2_STREAM_ID_0;
+ }
+ else
+ status = ERR_UNIDENTIFIED_PROTOCOL;
}
else
status = ERR_STREAM_NOT_ESTABLISHED;
struct PayloadInjectorCounts
{
PegCount http_injects;
+ PegCount http2_injects;
};
extern THREAD_LOCAL PayloadInjectorCounts payload_injection_stats;
INJECTION_SUCCESS = 1,
ERR_INJECTOR_NOT_CONFIGURED = -1,
ERR_STREAM_NOT_ESTABLISHED = -2,
+ ERR_HTTP2_STREAM_ID_0 = -3,
+ ERR_UNIDENTIFIED_PROTOCOL = -4,
};
struct InjectionControl
{
const uint8_t* http_page = nullptr;
uint32_t http_page_len = 0;
+ uint32_t stream_id = 0;
};
class SO_PUBLIC PayloadInjectorModule : public snort::Module
}
void Active::block_session(snort::Packet*, bool) { }
void DetectionEngine::disable_all(snort::Packet*) { }
-Flow::Flow() { }
+Flow::Flow() { memset(this, 0, sizeof(*this)); }
Flow::~Flow() { }
Packet::Packet(bool) { packet_flags = 0; flow = nullptr; }
Packet::~Packet() { }
+
+InspectApi mock_api;
+Inspector::Inspector()
+{
+ set_api(&mock_api);
+}
+Inspector::~Inspector() = default;
+bool Inspector::likes(Packet*) { return true; }
+bool Inspector::get_buf(const char*, Packet*, InspectionBuffer&) { return true; }
+class StreamSplitter* Inspector::get_splitter(bool) { return nullptr; }
+
}
void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { }
void show_stats(PegCount*, const PegInfo*, const IndexVec&, const char*, FILE*) { }
+class MockInspector : public snort::Inspector
+{
+public:
+
+ MockInspector() {}
+ ~MockInspector() override {}
+ void eval(snort::Packet*) override {}
+ bool configure(snort::SnortConfig*) override { return true;}
+};
+
+
TEST_GROUP(payload_injector_test)
{
PayloadInjectorModule mod;
InjectionControl control;
- PegCount* counts = mod.get_counts();
+ PayloadInjectorCounts* counts = (PayloadInjectorCounts*)mod.get_counts();
Flow flow;
void setup() override
{
- counts[0] = 0;
+ counts->http_injects = 0;
+ counts->http2_injects = 0;
control.http_page = (const uint8_t*)"test";
control.http_page_len = 4;
flow.set_state(Flow::FlowState::INSPECT);
Packet p(false);
p.flow = &flow;
InjectionReturnStatus status = mod.inject_http_payload(&p, control);
- CHECK(counts[0] == 0);
+ CHECK(counts->http_injects == 0);
CHECK(status == ERR_INJECTOR_NOT_CONFIGURED);
CHECK(flow.flow_state == Flow::FlowState::BLOCK);
}
p.packet_flags = PKT_STREAM_EST;
p.flow = &flow;
InjectionReturnStatus status = mod.inject_http_payload(&p, control);
- CHECK(counts[0] == 0);
+ CHECK(counts->http_injects == 0);
CHECK(status == ERR_INJECTOR_NOT_CONFIGURED);
CHECK(flow.flow_state == Flow::FlowState::BLOCK);
}
Packet p(false);
p.flow = &flow;
InjectionReturnStatus status = mod.inject_http_payload(&p, control);
- CHECK(counts[0] == 0);
+ CHECK(counts->http_injects == 0);
CHECK(status == ERR_STREAM_NOT_ESTABLISHED);
CHECK(flow.flow_state == Flow::FlowState::BLOCK);
}
mod.set_configured(true);
Packet p(false);
p.packet_flags = PKT_STREAM_EST;
+ mock_api.base.name = "http_inspect";
+ flow.gadget = new MockInspector();
+ p.flow = &flow;
+ InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+ CHECK(counts->http_injects == 1);
+ CHECK(status == INJECTION_SUCCESS);
+ CHECK(flow.flow_state == Flow::FlowState::BLOCK);
+ delete flow.gadget;
+}
+
+TEST(payload_injector_test, http2_stream0)
+{
+ mod.set_configured(true);
+ Packet p(false);
+ p.packet_flags = PKT_STREAM_EST;
+ mock_api.base.name = "http2_inspect";
+ flow.gadget = new MockInspector();
+ p.flow = &flow;
+ InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+ CHECK(counts->http2_injects == 0);
+ CHECK(status == ERR_HTTP2_STREAM_ID_0);
+ CHECK(flow.flow_state == Flow::FlowState::BLOCK);
+ delete flow.gadget;
+}
+
+TEST(payload_injector_test, http2_success)
+{
+ mod.set_configured(true);
+ Packet p(false);
+ p.packet_flags = PKT_STREAM_EST;
+ mock_api.base.name = "http2_inspect";
+ flow.gadget = new MockInspector();
p.flow = &flow;
+ control.stream_id = 1;
InjectionReturnStatus status = mod.inject_http_payload(&p, control);
- CHECK(counts[0] == 1);
+ CHECK(counts->http2_injects == 1);
CHECK(status == INJECTION_SUCCESS);
CHECK(flow.flow_state == Flow::FlowState::BLOCK);
+ delete flow.gadget;
+}
+
+TEST(payload_injector_test, unidentified_gadget_is_null)
+{
+ mod.set_configured(true);
+ Packet p(false);
+ p.packet_flags = PKT_STREAM_EST;
+ p.flow = &flow;
+ InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+ CHECK(status == ERR_UNIDENTIFIED_PROTOCOL);
+ CHECK(flow.flow_state == Flow::FlowState::BLOCK);
+}
+
+TEST(payload_injector_test, unidentified_gadget_name)
+{
+ mod.set_configured(true);
+ Packet p(false);
+ p.packet_flags = PKT_STREAM_EST;
+ mock_api.base.name = "inspector";
+ flow.gadget = new MockInspector();
+ p.flow = &flow;
+ InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+ CHECK(status == ERR_UNIDENTIFIED_PROTOCOL);
+ CHECK(flow.flow_state == Flow::FlowState::BLOCK);
+ delete flow.gadget;
}
int main(int argc, char** argv)