From: Steve Chew (stechew) Date: Thu, 27 Feb 2020 21:03:27 +0000 (+0000) Subject: Merge pull request #2011 in SNORT/snort3 from ~STECHEW/snort3:inject_ioctls to master X-Git-Tag: 3.0.0-269~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=23e1b4324bf904cb2c8f06711843e114a229f86f;p=thirdparty%2Fsnort3.git Merge pull request #2011 in SNORT/snort3 from ~STECHEW/snort3:inject_ioctls to master Squashed commit of the following: commit b45dc3b4723aa06a7c058bd94b6da8226ba50c0f Author: Steve Chew Date: Fri Feb 14 17:35:50 2020 -0500 active: Add ability to inject resets and payload via IOCTLs. --- diff --git a/src/actions/act_react.cc b/src/actions/act_react.cc index 9605227ef..63985f12d 100644 --- a/src/actions/act_react.cc +++ b/src/actions/act_react.cc @@ -180,19 +180,21 @@ void ReactAction::exec(Packet* p) void ReactAction::send(Packet* p) { EncodeFlags df = (p->is_from_server()) ? ENC_FLAG_FWD : 0; - EncodeFlags sent = config->get_buf_len(); + EncodeFlags sent = 0; Active* act = p->active; if ( p->packet_flags & PKT_STREAM_EST ) { - act->send_data(p, df, (const uint8_t*)config->get_resp_buf(), sent); - // act->send_data() sends a FIN, so need to bump seq by 1. - sent++; + sent = act->send_data(p, df, (const uint8_t*)config->get_resp_buf(), config->get_buf_len()); } EncodeFlags rf = ENC_FLAG_SEQ | (ENC_FLAG_VAL & sent); act->send_reset(p, rf); + + // Blacklist the flow so that no additional data goes through in case + // the RST is lost. + act->block_session(p); } //------------------------------------------------------------------------- diff --git a/src/flow/flow.cc b/src/flow/flow.cc index be3815b6e..f6b4ca4cd 100644 --- a/src/flow/flow.cc +++ b/src/flow/flow.cc @@ -537,7 +537,7 @@ void Flow::set_service(Packet* pkt, const char* new_service) void Flow::swap_roles() { - client_initiated = !client_initiated; + flags.client_initiated = !flags.client_initiated; std::swap(client_ip, server_ip); std::swap(client_port, server_port); std::swap(flowstats.client_pkts, flowstats.server_pkts); diff --git a/src/flow/flow.h b/src/flow/flow.h index f5299c2c1..662275868 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -237,17 +237,17 @@ public: stash->store(key, val); } - uint32_t update_session_flags(uint32_t flags) - { return ssn_state.session_flags = flags; } + uint32_t update_session_flags(uint32_t ssn_flags) + { return ssn_state.session_flags = ssn_flags; } - uint32_t set_session_flags(uint32_t flags) - { return ssn_state.session_flags |= flags; } + uint32_t set_session_flags(uint32_t ssn_flags) + { return ssn_state.session_flags |= ssn_flags; } uint32_t get_session_flags() { return ssn_state.session_flags; } - uint32_t clear_session_flags(uint32_t flags) - { return ssn_state.session_flags &= ~flags; } + uint32_t clear_session_flags(uint32_t ssn_flags) + { return ssn_state.session_flags &= ~ssn_flags; } void set_to_client_detection(bool enable); void set_to_server_detection(bool enable); @@ -350,10 +350,10 @@ public: } void disable_inspection() - { disable_inspect = true; } + { flags.disable_inspect = true; } bool is_inspection_disabled() const - { return disable_inspect; } + { return flags.disable_inspect; } bool is_suspended() const { return context_chain.front(); } @@ -441,9 +441,13 @@ public: // FIXIT-M privatize if possible uint8_t response_count; - bool disable_inspect; - bool trigger_finalize_event; - bool client_initiated; + struct + { + bool client_initiated : 1; + bool disable_inspect : 1; + bool trigger_finalize_event : 1; + bool use_direct_inject : 1; + } flags; FlowState flow_state; diff --git a/src/flow/flow_control.cc b/src/flow/flow_control.cc index c6be9bd52..ea0fe9450 100644 --- a/src/flow/flow_control.cc +++ b/src/flow/flow_control.cc @@ -420,7 +420,7 @@ unsigned FlowControl::process(Flow* flow, Packet* p) ++news; flow->flowstats.start_time = p->pkth->ts; - flow->client_initiated = p->is_from_client(); + flow->flags.client_initiated = p->is_from_client(); } // This requires the packet direction to be set diff --git a/src/main/analyzer.cc b/src/main/analyzer.cc index 26eb50b85..922f54409 100644 --- a/src/main/analyzer.cc +++ b/src/main/analyzer.cc @@ -229,7 +229,7 @@ static void handle_deferred_whitelist(Packet* pkt, DAQ_Verdict& verdict) verdict = DAQ_VERDICT_PASS; pkt->flow->deferred_whitelist = WHITELIST_DEFER_STARTED; pkt->flow->set_state(Flow::FlowState::INSPECT); - pkt->flow->disable_inspect = false; + pkt->flow->flags.disable_inspect = false; } return; } @@ -238,7 +238,7 @@ static void handle_deferred_whitelist(Packet* pkt, DAQ_Verdict& verdict) { verdict = DAQ_VERDICT_PASS; pkt->flow->set_state(Flow::FlowState::INSPECT); - pkt->flow->disable_inspect = false; + pkt->flow->flags.disable_inspect = false; return; } @@ -250,7 +250,7 @@ static void handle_deferred_whitelist(Packet* pkt, DAQ_Verdict& verdict) // Turn inspection back off and allow the flow. pkt->flow->set_state(Flow::FlowState::ALLOW); - pkt->flow->disable_inspect = true; + pkt->flow->flags.disable_inspect = true; } } @@ -362,7 +362,7 @@ void Analyzer::post_process_daq_pkt_msg(Packet* p) { // Publish an event if something has indicated that it wants the // finalize event on this flow. - if (p->flow and p->flow->trigger_finalize_event) + if (p->flow and p->flow->flags.trigger_finalize_event) { FinalizePacketEvent event(p, verdict); DataBus::publish(FINALIZE_PACKET_EVENT, event); diff --git a/src/main/modules.cc b/src/main/modules.cc index fccc523af..ade160e8e 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -986,7 +986,10 @@ static const Parameter active_params[] = static PegInfo active_pegs[] { - { CountType::SUM, "injects", "total crafted packets injected" }, + { CountType::SUM, "injects", "total crafted packets encoded and injected" }, + { CountType::SUM, "failed_injects", "total crafted packet encode + injects that failed" }, + { CountType::SUM, "direct_injects", "total crafted packets directly injected" }, + { CountType::SUM, "failed_direct_injects", "total crafted packet direct injects that failed" }, { CountType::END, nullptr, nullptr } }; diff --git a/src/packet_io/active.cc b/src/packet_io/active.cc index d91cfe4ea..85ae185f6 100644 --- a/src/packet_io/active.cc +++ b/src/packet_io/active.cc @@ -86,7 +86,6 @@ int Active::send_eth( DAQ_Msg_h, int, const uint8_t* buf, uint32_t len) { ssize_t sent = eth_send(s_link, buf, len); - active_counts.injects++; return ( (uint32_t)sent != len ); } @@ -94,7 +93,6 @@ int Active::send_ip( DAQ_Msg_h, int, const uint8_t* buf, uint32_t len) { ssize_t sent = ip_send(s_ipnet, buf, len); - active_counts.injects++; return ( (uint32_t)sent != len ); } @@ -220,16 +218,40 @@ void Active::send_reset(Packet* p, EncodeFlags ef) for ( i = 0; i < s_attempts; i++ ) { - uint32_t len; - const uint8_t* rej; - - value = Strafe(i, value, p); - - rej = PacketManager::encode_response(TcpResponse::RST, flags|value, p, len); - if ( !rej ) - return; - - s_send(p->daq_msg, !(ef & ENC_FLAG_FWD), rej, len); + if ( (p->packet_flags & PKT_USE_DIRECT_INJECT) or + (p->flow and p->flow->flags.use_direct_inject) ) + { + DIOCTL_DirectInjectReset msg = { p->daq_msg, !(ef & ENC_FLAG_FWD) }; + int ret = p->daq_instance->ioctl(DIOCTL_DIRECT_INJECT_RESET, + &msg, sizeof(msg)); + if ( ret != DAQ_SUCCESS ) + { + active_counts.failed_direct_injects++; + return; + } + + active_counts.direct_injects++; + } + else + { + uint32_t len; + const uint8_t* rej; + + value = Strafe(i, value, p); + + rej = PacketManager::encode_response(TcpResponse::RST, flags|value, p, len); + if ( !rej ) + { + active_counts.failed_injects++; + return; + } + + int ret = s_send(p->daq_msg, !(ef & ENC_FLAG_FWD), rej, len); + if ( ret ) + active_counts.failed_injects++; + else + active_counts.injects++; + } } } @@ -244,30 +266,62 @@ void Active::send_unreach(Packet* p, UnreachResponse type) rej = PacketManager::encode_reject(type, flags, p, len); if ( !rej ) + { + active_counts.failed_injects++; return; + } - s_send(p->daq_msg, 1, rej, len); + int ret = s_send(p->daq_msg, 1, rej, len); + if ( ret ) + active_counts.failed_injects++; + else + active_counts.injects++; } -bool Active::send_data( +uint32_t Active::send_data( Packet* p, EncodeFlags flags, const uint8_t* buf, uint32_t blen) { + int ret; const uint8_t* seg; uint32_t plen; + bool use_direct_inject = (p->packet_flags & PKT_USE_DIRECT_INJECT) or + (p->flow and p->flow->flags.use_direct_inject); flags |= GetFlags(); flags &= ~ENC_FLAG_VAL; + // Send RST to the originator of the data. if ( flags & ENC_FLAG_RST_SRVR ) { - plen = 0; - EncodeFlags tmp_flags = flags ^ ENC_FLAG_FWD; - seg = PacketManager::encode_response(TcpResponse::RST, tmp_flags, p, plen); - - if ( seg ) + if ( use_direct_inject ) { - s_send(p->daq_msg, !(tmp_flags & ENC_FLAG_FWD), seg, plen); - active_counts.injects++; + DIOCTL_DirectInjectReset msg = { p->daq_msg, !(flags & ENC_FLAG_FWD) }; + ret = p->daq_instance->ioctl(DIOCTL_DIRECT_INJECT_RESET, + &msg, sizeof(msg)); + if ( ret != DAQ_SUCCESS ) + { + active_counts.failed_direct_injects++; + return 0; + } + + active_counts.direct_injects++; + } + else + { + plen = 0; + EncodeFlags tmp_flags = flags ^ ENC_FLAG_FWD; + seg = PacketManager::encode_response(TcpResponse::RST, tmp_flags, p, plen); + + if ( seg ) + { + ret = s_send(p->daq_msg, !(tmp_flags & ENC_FLAG_FWD), seg, plen); + if ( ret ) + active_counts.failed_injects++; + else + active_counts.injects++; + } + else + active_counts.failed_injects++; } } flags |= ENC_FLAG_SEQ; @@ -275,6 +329,7 @@ bool Active::send_data( uint32_t sent = 0; const uint16_t maxPayload = PacketManager::encode_get_max_payload(p); + // Inject the payload. if (maxPayload) { uint16_t toSend; @@ -283,45 +338,104 @@ bool Active::send_data( plen = 0; toSend = blen > maxPayload ? maxPayload : blen; flags = (flags & ~ENC_FLAG_VAL) | sent; - seg = PacketManager::encode_response(TcpResponse::PUSH, flags, p, plen, buf, toSend); + if ( use_direct_inject ) + { + const DAQ_DIPayloadSegment segments[] = { {buf, toSend} }; + const DAQ_DIPayloadSegment* payload[] = { &segments[0] }; + DIOCTL_DirectInjectPayload msg = { p->daq_msg, payload, 1, !(flags & ENC_FLAG_FWD)}; + ret = p->daq_instance->ioctl(DIOCTL_DIRECT_INJECT_PAYLOAD, + &msg, sizeof(msg)); + if ( ret != DAQ_SUCCESS ) + { + active_counts.failed_direct_injects++; + return sent; + } + + active_counts.direct_injects++; + } + else + { + 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++; + } - if ( !seg ) - return false; - - s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen); - active_counts.injects++; - - buf += toSend; sent += toSend; + buf += toSend; } while (blen -= toSend); } - plen = 0; - flags = (flags & ~ENC_FLAG_VAL) | sent; - seg = PacketManager::encode_response(TcpResponse::FIN, flags, p, plen, nullptr, 0); + // FIXIT-L: Currently there is no support for injecting a FIN via + // direct injection. + if ( ! use_direct_inject ) + { + plen = 0; + flags = (flags & ~ENC_FLAG_VAL) | sent; + seg = PacketManager::encode_response(TcpResponse::FIN, flags, p, plen, nullptr, 0); - if ( !seg ) - return false; + if ( !seg ) + { + active_counts.failed_injects++; + return sent; + } - s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen); - active_counts.injects++; + ret = s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen); + if ( ret ) + active_counts.failed_injects++; + else + active_counts.injects++; + + // Sending a FIN requires that we bump the seq by 1. + sent++; + } + // Send RST to the receiver of the data. if (flags & ENC_FLAG_RST_CLNT) { - sent++; - plen = 0; flags = (flags & ~ENC_FLAG_VAL) | sent; - seg = PacketManager::encode_response(TcpResponse::RST, flags, p, plen); - - if ( seg ) + if ( use_direct_inject ) { - s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen); - active_counts.injects++; + DIOCTL_DirectInjectReset msg = { p->daq_msg, !(flags & ENC_FLAG_FWD) }; + ret = p->daq_instance->ioctl(DIOCTL_DIRECT_INJECT_RESET, + &msg, sizeof(msg)); + if ( ret != DAQ_SUCCESS ) + { + active_counts.failed_direct_injects++; + return sent; + } + + active_counts.direct_injects++; + } + else + { + plen = 0; + seg = PacketManager::encode_response(TcpResponse::RST, flags, p, plen); + + if ( seg ) + { + ret = s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen); + if ( ret ) + active_counts.failed_injects++; + else + active_counts.injects++; + } + else + active_counts.failed_injects++; } } - return true; + return sent; } void Active::inject_data( @@ -338,9 +452,16 @@ void Active::inject_data( seg = PacketManager::encode_response(TcpResponse::PUSH, flags, p, plen, buf, blen); if ( !seg ) + { + active_counts.failed_injects++; return; + } - s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen); + int ret = s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen); + if ( ret ) + active_counts.failed_injects++; + else + active_counts.injects++; } //-------------------------------------------------------------------- diff --git a/src/packet_io/active.h b/src/packet_io/active.h index 387b595f8..f67360390 100644 --- a/src/packet_io/active.h +++ b/src/packet_io/active.h @@ -39,6 +39,9 @@ public: struct Counts { PegCount injects; + PegCount failed_injects; + PegCount direct_injects; + PegCount failed_direct_injects; }; enum ActiveStatus : uint8_t @@ -67,7 +70,7 @@ public: void send_reset(Packet*, EncodeFlags); void send_unreach(Packet*, snort::UnreachResponse); - bool send_data(Packet*, EncodeFlags, const uint8_t* buf, uint32_t len); + uint32_t send_data(Packet*, EncodeFlags, const uint8_t* buf, uint32_t len); void inject_data(Packet*, EncodeFlags, const uint8_t* buf, uint32_t len); bool is_reset_candidate(const Packet*); diff --git a/src/protocols/packet.h b/src/protocols/packet.h index e6c0265cf..892a86c42 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -80,7 +80,8 @@ class SFDAQInstance; #define PKT_RETRANSMIT 0x01000000 // packet is a re-transmitted pkt. #define PKT_RETRY 0x02000000 /* this packet is being re-evaluated from the internal retry queue */ #define PKT_REP_MONITORED 0x04000000 /* this packet is monitored by reputation */ -#define PKT_UNUSED_FLAGS 0xf8000000 +#define PKT_USE_DIRECT_INJECT 0x08000000 /* Use ioctl when injecting. */ +#define PKT_UNUSED_FLAGS 0xf0000000 #define PKT_TS_OFFLOADED 0x01 diff --git a/src/stream/stream.cc b/src/stream/stream.cc index 1b686a947..c2f873394 100644 --- a/src/stream/stream.cc +++ b/src/stream/stream.cc @@ -159,6 +159,10 @@ void Stream::check_flow_closed(Packet* p) { assert(flow_con); + // Will no longer have flow so save use_direct_inject state on packet. + if ( flow->flags.use_direct_inject ) + p->packet_flags |= PKT_USE_DIRECT_INJECT; + // this will get called on each onload // eventually all onloads will occur and delete will be called if ( not flow->is_suspended() )