1 //--------------------------------------------------------------------------
2 // Copyright (C) 2019-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation.  You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // http2_stream.cc author Tom Peters <thopeter@cisco.com>
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "http2_enum.h"
25 #include "http2_stream.h"
26 
27 #include "service_inspectors/http_inspect/http_enum.h"
28 #include "service_inspectors/http_inspect/http_flow_data.h"
29 #include "service_inspectors/http_inspect/http_stream_splitter.h"
30 
31 #include "http2_data_cutter.h"
32 #include "http2_dummy_packet.h"
33 #include "http2_flow_data.h"
34 
35 using namespace HttpCommon;
36 using namespace Http2Enums;
37 using namespace HttpEnums;
38 
Http2Stream(uint32_t stream_id_,Http2FlowData * session_data_)39 Http2Stream::Http2Stream(uint32_t stream_id_, Http2FlowData* session_data_) :
40     stream_id(stream_id_),
41     session_data(session_data_)
42 {
43 }
44 
~Http2Stream()45 Http2Stream::~Http2Stream()
46 {
47     delete current_frame;
48     delete hi_flow_data;
49 }
50 
eval_frame(const uint8_t * header_buffer,uint32_t header_len,const uint8_t * data_buffer,uint32_t data_len,SourceId source_id)51 void Http2Stream::eval_frame(const uint8_t* header_buffer, uint32_t header_len,
52     const uint8_t* data_buffer, uint32_t data_len, SourceId source_id)
53 {
54     assert(current_frame == nullptr);
55     current_frame = Http2Frame::new_frame(header_buffer, header_len, data_buffer,
56         data_len, session_data, source_id, this);
57     if (!session_data->abort_flow[source_id] && (get_state(source_id) != STREAM_ERROR))
58     {
59         if (current_frame->valid_sequence(state[source_id]))
60         {
61             current_frame->analyze_http1();
62             current_frame->update_stream_state();
63         }
64         else
65         {
66             set_state(source_id, STREAM_ERROR);
67         }
68     }
69 }
70 
71 // check if stream is completed, do cleanup if it is
check_and_cleanup_completed()72 void Http2Stream::check_and_cleanup_completed()
73 {
74     if ((state[SRC_CLIENT] >= STREAM_COMPLETE) && (state[SRC_SERVER] >= STREAM_COMPLETE))
75     {
76         if (hi_flow_data != nullptr)
77         {
78             delete hi_flow_data;
79             hi_flow_data = nullptr;
80         }
81         session_data->delete_stream = true;
82     }
83 }
84 
clear_frame()85 void Http2Stream::clear_frame()
86 {
87     assert(current_frame != nullptr);
88     current_frame->clear();
89     delete current_frame;
90     current_frame = nullptr;
91 
92     check_and_cleanup_completed();
93 }
94 
set_state(HttpCommon::SourceId source_id,StreamState new_state)95 void Http2Stream::set_state(HttpCommon::SourceId source_id, StreamState new_state)
96 {
97     assert((STREAM_EXPECT_HEADERS <= new_state) && (new_state <= STREAM_ERROR));
98     assert(state[source_id] < new_state);
99     assert((new_state < STREAM_EXPECT_BODY) || (new_state > STREAM_BODY) ||
100         (get_hi_flow_data() != nullptr));
101     state[source_id] = new_state;
102 }
103 
set_hi_flow_data(HttpFlowData * flow_data)104 void Http2Stream::set_hi_flow_data(HttpFlowData* flow_data)
105 {
106     assert(hi_flow_data == nullptr);
107     hi_flow_data = flow_data;
108 }
109 
get_buf(unsigned id)110 const Field& Http2Stream::get_buf(unsigned id)
111 {
112     if (current_frame != nullptr)
113         return current_frame->get_buf(id);
114     return Field::FIELD_NULL;
115 }
116 
117 #ifdef REG_TEST
print_frame(FILE * output)118 void Http2Stream::print_frame(FILE* output)
119 {
120     if (current_frame != nullptr)
121         current_frame->print_frame(output);
122 }
123 #endif
124 
is_open(HttpCommon::SourceId source_id)125 bool Http2Stream::is_open(HttpCommon::SourceId source_id)
126 {
127     return (state[source_id] == STREAM_EXPECT_BODY) || (state[source_id] == STREAM_BODY);
128 }
129 
finish_msg_body(HttpCommon::SourceId source_id,bool expect_trailers,bool clear_partial_buffer)130 void Http2Stream::finish_msg_body(HttpCommon::SourceId source_id, bool expect_trailers,
131     bool clear_partial_buffer)
132 {
133     uint32_t http_flush_offset = 0;
134     Http2DummyPacket dummy_pkt;
135     dummy_pkt.flow = session_data->flow;
136     const H2BodyState body_state = expect_trailers ?
137         H2_BODY_COMPLETE_EXPECT_TRAILERS : H2_BODY_COMPLETE;
138     get_hi_flow_data()->finish_h2_body(source_id, body_state, clear_partial_buffer);
139     if (clear_partial_buffer)
140     {
141         uint32_t unused = 0;
142         const snort::StreamSplitter::Status scan_result = session_data->hi_ss[source_id]->scan(
143             &dummy_pkt, nullptr, 0, unused, &http_flush_offset);
144         assert(scan_result == snort::StreamSplitter::FLUSH);
145         UNUSED(scan_result);
146     }
147 }
148