1 //-------------------------------------------------------------------------- 2 // Copyright (C) 2014-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 // http_flow_data.h author Tom Peters <thopeter@cisco.com> 19 20 #ifndef HTTP_FLOW_DATA_H 21 #define HTTP_FLOW_DATA_H 22 23 #include <zlib.h> 24 25 #include <cstdio> 26 27 #include "flow/flow.h" 28 #include "mime/file_mime_process.h" 29 #include "utils/util_utf.h" 30 #include "decompress/file_decomp.h" 31 32 #include "http_common.h" 33 #include "http_enum.h" 34 #include "http_event.h" 35 36 class HttpTransaction; 37 class HttpJsNorm; 38 class HttpMsgSection; 39 class HttpCutter; 40 class HttpQueryParser; 41 class JSIdentifierCtxBase; 42 43 namespace snort 44 { 45 class JSNormalizer; 46 } 47 48 class HttpFlowData : public snort::FlowData 49 { 50 public: 51 HttpFlowData(snort::Flow* flow); 52 ~HttpFlowData() override; 53 static unsigned inspector_id; init()54 static void init() { inspector_id = snort::FlowData::create_flow_data_id(); } 55 56 friend class HttpBodyCutter; 57 friend class HttpInspect; 58 friend class HttpJsNorm; 59 friend class HttpMsgSection; 60 friend class HttpMsgStart; 61 friend class HttpMsgRequest; 62 friend class HttpMsgStatus; 63 friend class HttpMsgHeader; 64 friend class HttpMsgHeadShared; 65 friend class HttpMsgTrailer; 66 friend class HttpMsgBody; 67 friend class HttpMsgBodyChunk; 68 friend class HttpMsgBodyCl; 69 friend class HttpMsgBodyH2; 70 friend class HttpMsgBodyOld; 71 friend class HttpQueryParser; 72 friend class HttpStreamSplitter; 73 friend class HttpTransaction; 74 #if defined(REG_TEST) || defined(UNIT_TEST) 75 friend class HttpUnitTestSetup; 76 #endif 77 get_type_expected(HttpCommon::SourceId source_id)78 HttpEnums::SectionType get_type_expected(HttpCommon::SourceId source_id) const 79 { return type_expected[source_id]; } 80 81 void finish_h2_body(HttpCommon::SourceId source_id, HttpEnums::H2BodyState state, 82 bool clear_partial_buffer); 83 set_h2_body_state(HttpCommon::SourceId source_id,HttpEnums::H2BodyState state)84 void set_h2_body_state(HttpCommon::SourceId source_id, HttpEnums::H2BodyState state) 85 { h2_body_state[source_id] = state; } 86 87 uint32_t get_h2_stream_id() const; 88 89 private: 90 // HTTP/2 handling 91 bool for_http2 = false; 92 HttpEnums::H2BodyState h2_body_state[2] = { HttpEnums::H2_BODY_NOT_COMPLETE, 93 HttpEnums::H2_BODY_NOT_COMPLETE }; 94 uint32_t h2_stream_id = 0; 95 96 // Convenience routines 97 void half_reset(HttpCommon::SourceId source_id); 98 void trailer_prep(HttpCommon::SourceId source_id); 99 void garbage_collect(); 100 101 // 0 element refers to client request, 1 element refers to server response 102 103 // *** StreamSplitter internal data - scan() 104 HttpCutter* cutter[2] = { nullptr, nullptr }; 105 106 // *** StreamSplitter internal data - reassemble() 107 uint8_t* section_buffer[2] = { nullptr, nullptr }; 108 uint32_t section_offset[2] = { 0, 0 }; 109 uint32_t chunk_expected_length[2] = { 0, 0 }; 110 uint32_t running_total[2] = { 0, 0 }; 111 HttpEnums::ChunkState chunk_state[2] = { HttpEnums::CHUNK_NEWLINES, 112 HttpEnums::CHUNK_NEWLINES }; 113 uint32_t partial_raw_bytes[2] = { 0, 0 }; 114 uint8_t* partial_buffer[2] = { nullptr, nullptr }; 115 uint32_t partial_buffer_length[2] = { 0, 0 }; 116 117 // *** StreamSplitter internal data - scan() => reassemble() 118 uint32_t num_excess[2] = { 0, 0 }; 119 uint32_t num_good_chunks[2] = { 0, 0 }; 120 uint32_t octets_expected[2] = { 0, 0 }; 121 bool is_broken_chunk[2] = { false, false }; 122 123 // *** StreamSplitter => Inspector (facts about the most recent message section) 124 HttpEnums::SectionType section_type[2] = { HttpEnums::SEC__NOT_COMPUTE, 125 HttpEnums::SEC__NOT_COMPUTE }; 126 int32_t octets_reassembled[2] = { HttpCommon::STAT_NOT_PRESENT, HttpCommon::STAT_NOT_PRESENT }; 127 int32_t num_head_lines[2] = { HttpCommon::STAT_NOT_PRESENT, HttpCommon::STAT_NOT_PRESENT }; 128 bool tcp_close[2] = { false, false }; 129 bool partial_flush[2] = { false, false }; 130 uint64_t last_connect_trans_w_early_traffic = 0; 131 132 HttpInfractions* infractions[2] = { new HttpInfractions, new HttpInfractions }; 133 HttpEventGen* events[2] = { new HttpEventGen, new HttpEventGen }; 134 135 // Infractions are associated with a specific message and are stored in the transaction for 136 // that message. But StreamSplitter splits the start line before there is a transaction and 137 // needs a place to put the problems it finds. Hence infractions are created before there is a 138 // transaction to associate them with and stored here until attach_my_transaction() takes them 139 // away and resets these to nullptr. The accessor method hides this from StreamSplitter. 140 HttpInfractions* get_infractions(HttpCommon::SourceId source_id); 141 142 // *** Inspector => StreamSplitter (facts about the message section that is coming next) 143 HttpEnums::SectionType type_expected[2] = { HttpEnums::SEC_REQUEST, HttpEnums::SEC_STATUS }; 144 uint64_t last_request_was_connect = false; 145 z_stream* compress_stream[2] = { nullptr, nullptr }; 146 uint64_t zero_nine_expected = 0; 147 // length of the data from Content-Length field 148 int64_t data_length[2] = { HttpCommon::STAT_NOT_PRESENT, HttpCommon::STAT_NOT_PRESENT }; 149 uint32_t section_size_target[2] = { 0, 0 }; 150 HttpEnums::CompressId compression[2] = { HttpEnums::CMP_NONE, HttpEnums::CMP_NONE }; 151 HttpEnums::DetectionStatus detection_status[2] = { HttpEnums::DET_ON, HttpEnums::DET_ON }; 152 bool stretch_section_to_packet[2] = { false, false }; 153 bool accelerated_blocking[2] = { false, false }; 154 155 // *** Inspector's internal data about the current message 156 struct FdCallbackContext 157 { 158 HttpInfractions* infractions = nullptr; 159 HttpEventGen* events = nullptr; 160 }; 161 FdCallbackContext fd_alert_context; // SRC_SERVER only 162 snort::MimeSession* mime_state[2] = { nullptr, nullptr }; 163 snort::UtfDecodeSession* utf_state = nullptr; // SRC_SERVER only 164 fd_session_t* fd_state = nullptr; // SRC_SERVER only 165 int64_t file_depth_remaining[2] = { HttpCommon::STAT_NOT_PRESENT, 166 HttpCommon::STAT_NOT_PRESENT }; 167 int64_t detect_depth_remaining[2] = { HttpCommon::STAT_NOT_PRESENT, 168 HttpCommon::STAT_NOT_PRESENT }; 169 int32_t publish_depth_remaining[2] = { HttpCommon::STAT_NOT_PRESENT, 170 HttpCommon::STAT_NOT_PRESENT }; 171 int32_t file_decomp_buffer_size_remaining[2] = { HttpCommon::STAT_NOT_PRESENT, 172 HttpCommon::STAT_NOT_PRESENT }; 173 uint64_t expected_trans_num[2] = { 1, 1 }; 174 175 // number of user data octets seen so far (regular body or chunks) 176 int64_t body_octets[2] = { HttpCommon::STAT_NOT_PRESENT, HttpCommon::STAT_NOT_PRESENT }; 177 // normalized octets forwarded to file or MIME processing 178 int64_t file_octets[2] = { HttpCommon::STAT_NOT_PRESENT, HttpCommon::STAT_NOT_PRESENT }; 179 int32_t publish_octets[2] = { HttpCommon::STAT_NOT_PRESENT, HttpCommon::STAT_NOT_PRESENT }; 180 uint32_t partial_inspected_octets[2] = { 0, 0 }; 181 uint8_t* partial_detect_buffer[2] = { nullptr, nullptr }; 182 uint32_t partial_detect_length[2] = { 0, 0 }; 183 uint32_t partial_js_detect_length[2] = { 0, 0 }; 184 int32_t status_code_num = HttpCommon::STAT_NOT_PRESENT; 185 HttpEnums::VersionId version_id[2] = { HttpEnums::VERS__NOT_PRESENT, 186 HttpEnums::VERS__NOT_PRESENT }; 187 HttpEnums::MethodId method_id = HttpEnums::METH__NOT_PRESENT; 188 189 // *** Transaction management including pipelining 190 static const int MAX_PIPELINE = 100; // requests seen - responses seen <= MAX_PIPELINE 191 HttpTransaction* transaction[2] = { nullptr, nullptr }; 192 HttpTransaction** pipeline = nullptr; 193 int16_t pipeline_front = 0; 194 int16_t pipeline_back = 0; 195 uint32_t pdu_idx = 0; 196 uint32_t js_pdu_idx = 0; 197 bool js_data_lost_once = false; 198 bool pipeline_overflow = false; 199 bool pipeline_underflow = false; 200 201 bool add_to_pipeline(HttpTransaction* latest); 202 HttpTransaction* take_from_pipeline(); 203 void delete_pipeline(); 204 205 // Transactions with uncleared sections awaiting deletion 206 HttpTransaction* discard_list = nullptr; 207 208 209 // Memory footprint required by zlib inflation. Formula from https://zlib.net/zlib_tech.html 210 // Accounts for a 32k sliding window and 11520 bytes of inflate_huft allocations 211 static const size_t zlib_inflate_memory = (1 << 15) + 1440*2*sizeof(int); 212 213 // *** HttpJsNorm 214 JSIdentifierCtxBase* js_ident_ctx = nullptr; 215 snort::JSNormalizer* js_normalizer = nullptr; 216 bool js_continue = false; 217 bool js_built_in_event = false; 218 219 void reset_js_pdu_idx(); 220 void reset_js_ident_ctx(); 221 snort::JSNormalizer& acquire_js_ctx(int32_t ident_depth, size_t norm_depth, 222 uint8_t max_template_nesting, uint32_t max_bracket_depth, uint32_t max_scope_depth, 223 const std::unordered_set<std::string>& ignored_ids); 224 void release_js_ctx(); 225 bool is_pdu_missed(); 226 227 bool cutover_on_clear = false; 228 bool ssl_search_abandoned = false; 229 230 #ifdef REG_TEST 231 static uint64_t instance_count; 232 uint64_t seq_num; 233 234 void show(FILE* out_file) const; 235 #endif 236 }; 237 238 #endif 239 240