]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2011 in SNORT/snort3 from ~STECHEW/snort3:inject_ioctls to master
authorSteve Chew (stechew) <stechew@cisco.com>
Thu, 27 Feb 2020 21:03:27 +0000 (21:03 +0000)
committerSteve Chew (stechew) <stechew@cisco.com>
Thu, 27 Feb 2020 21:03:27 +0000 (21:03 +0000)
Squashed commit of the following:

commit b45dc3b4723aa06a7c058bd94b6da8226ba50c0f
Author: Steve Chew <stechew@cisco.com>
Date:   Fri Feb 14 17:35:50 2020 -0500

    active: Add ability to inject resets and payload via IOCTLs.

src/actions/act_react.cc
src/flow/flow.cc
src/flow/flow.h
src/flow/flow_control.cc
src/main/analyzer.cc
src/main/modules.cc
src/packet_io/active.cc
src/packet_io/active.h
src/protocols/packet.h
src/stream/stream.cc

index 9605227ef7f72a6875b0c1a24c546d59be94f453..63985f12de8b1cb799cf510a27a69a95c9608a10 100644 (file)
@@ -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);
 }
 
 //-------------------------------------------------------------------------
index be3815b6e4bcfd69ef4c2874cc0606025e104556..f6b4ca4cda14015540d63852a398f36a6617b6b8 100644 (file)
@@ -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);
index f5299c2c1380af4997894e79d53c37dbee07eb0b..662275868e32fc81bb33756e3da746a2e41e58da 100644 (file)
@@ -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;
 
index c6be9bd52eac20af28696166d06404eabe779909..ea0fe94508fd228590ba657a7b70cab885074311 100644 (file)
@@ -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
index 26eb50b8592bbca89e2814ab29d45a8fac284cb2..922f5440933f442923d465931771253bb58060cd 100644 (file)
@@ -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);
index fccc523afc24fddd1f10baec280fb720d6c550e3..ade160e8ed909bd8beb8e59876befc5785dec1bd 100644 (file)
@@ -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 }
 };
 
index d91cfe4ea4918db381f4d88db19beaac82bc9263..85ae185f63f243cc60aba6808a3e01db43c415dc 100644 (file)
@@ -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++;
 }
 
 //--------------------------------------------------------------------
index 387b595f81ac4da38652b60dbd41a66b345aa549..f67360390ce32893479bc046d00fa4333a7d4d43 100644 (file)
@@ -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*);
index e6c0265cfbedf85d5e91df50809ab08c32959346..892a86c4227dad5d5b49c7ba97ead528d09949fb 100644 (file)
@@ -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
 
index 1b686a9475a024f4002c9b82ffdd013dbdd32b8b..c2f8733945de5c96dffa2397b4838686889b0ff1 100644 (file)
@@ -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() )