Line data Source code
1 : #pragma once 2 : 3 : #include <cstdint> 4 : #include <functional> 5 : 6 : #include "envoy/config/core/v3/protocol.pb.h" 7 : #include "envoy/network/connection.h" 8 : 9 : #include "source/common/http/http2/codec_stats.h" 10 : #include "source/common/http/status.h" 11 : 12 : #include "nghttp2/nghttp2.h" 13 : 14 : namespace Envoy { 15 : namespace Http { 16 : namespace Http2 { 17 : 18 : // Class for detecting abusive peers and validating additional constraints imposed by Envoy. 19 : // This class does not check protocol compliance with the H/2 standard, as this is checked by 20 : // protocol framer/codec. Currently implemented constraints: 21 : // 1. detection of control frame (i.e. PING) initiated floods. 22 : // 2. detection of outbound DATA or HEADER frame floods. 23 : // 4. zero length, PRIORITY and WINDOW_UPDATE floods. 24 : 25 : class ProtocolConstraints : public ScopeTrackedObject { 26 : public: 27 : using ReleasorProc = std::function<void()>; 28 : 29 : explicit ProtocolConstraints(CodecStats& stats, 30 : const envoy::config::core::v3::Http2ProtocolOptions& http2_options); 31 : 32 : // Return ok status if no protocol constraints were violated. 33 : // Return error status of the first detected violation. Subsequent violations of constraints 34 : // do not reset the error status or increment stat counters. 35 0 : const Status& status() const { return status_; } 36 : 37 : // Increment counters of pending (buffered for sending to the peer) outbound frames. 38 : // If the `is_outbound_flood_monitored_control_frame` is false only the counter for all frame 39 : // types is incremented. If the `is_outbound_flood_monitored_control_frame` is true, both the 40 : // control frame and all frame types counters are incremented. 41 : // Returns callable for decrementing frame counters when frames was successfully written to 42 : // the underlying transport socket object. 43 : // To check if outbound frame constraints were violated call the `status()` method. 44 : // TODO(yanavlasov): return StatusOr<ReleasorProc> when flood checks are implemented for both 45 : // directions. 46 : ReleasorProc incrementOutboundFrameCount(bool is_outbound_flood_monitored_control_frame); 47 : 48 : // Track received frames of various types. 49 : // Return an error status if inbound frame constraints were violated. 50 : Status trackInboundFrames(size_t length, uint8_t type, uint8_t flags, uint32_t padding_length); 51 : // Increment the number of DATA frames sent to the peer. 52 22334 : void incrementOutboundDataFrameCount() { ++outbound_data_frames_; } 53 1974 : void incrementOpenedStreamCount() { ++opened_streams_; } 54 : 55 : Status checkOutboundFrameLimits(); 56 : 57 : // ScopeTrackedObject 58 : void dumpState(std::ostream& os, int indent_level) const override; 59 : 60 : private: 61 : void releaseOutboundFrame(); 62 : void releaseOutboundControlFrame(); 63 : Status checkInboundFrameLimits(); 64 : 65 : Status status_; 66 : CodecStats& stats_; 67 : // This counter keeps track of the number of outbound frames of all types (these that were 68 : // buffered in the underlying connection but not yet written into the socket). If this counter 69 : // exceeds the `max_outbound_frames_' value the connection is terminated. 70 : uint32_t outbound_frames_ = 0; 71 : // Maximum number of outbound frames. Initialized from corresponding http2_protocol_options. 72 : // Default value is 10000. 73 : const uint32_t max_outbound_frames_; 74 : ReleasorProc frame_buffer_releasor_; 75 : 76 : // This counter keeps track of the number of outbound frames of types PING, SETTINGS and 77 : // RST_STREAM (these that were buffered in the underlying connection but not yet written into the 78 : // socket). If this counter exceeds the `max_outbound_control_frames_' value the connection is 79 : // terminated. 80 : uint32_t outbound_control_frames_ = 0; 81 : // Maximum number of outbound frames of types PING, SETTINGS and RST_STREAM. Initialized from 82 : // corresponding http2_protocol_options. Default value is 1000. 83 : const uint32_t max_outbound_control_frames_; 84 : ReleasorProc control_frame_buffer_releasor_; 85 : 86 : // This counter keeps track of the number of consecutive inbound frames of types HEADERS, 87 : // CONTINUATION and DATA with an empty payload and no end stream flag. If this counter exceeds 88 : // the `max_consecutive_inbound_frames_with_empty_payload_` value the connection is terminated. 89 : uint32_t consecutive_inbound_frames_with_empty_payload_ = 0; 90 : // Maximum number of consecutive inbound frames of types HEADERS, CONTINUATION and DATA without 91 : // a payload. Initialized from corresponding http2_protocol_options. Default value is 1. 92 : const uint32_t max_consecutive_inbound_frames_with_empty_payload_; 93 : 94 : // This counter keeps track of the number of opened streams. 95 : // For downstream connection this is incremented when the first HEADERS frame with the new 96 : // stream ID is received from the client. 97 : // For upstream connections this is incremented when the first HEADERS frame with the new 98 : // stream ID is sent to the upstream server. 99 : uint32_t opened_streams_ = 0; 100 : // This counter keeps track of the number of inbound PRIORITY frames. If this counter exceeds 101 : // the value calculated using this formula: 102 : // 103 : // max_inbound_priority_frames_per_stream_ * (1 + inbound_streams_) 104 : // 105 : // the connection is terminated. 106 : uint64_t inbound_priority_frames_ = 0; 107 : // Maximum number of inbound PRIORITY frames per stream. Initialized from corresponding 108 : // http2_protocol_options. Default value is 100. 109 : const uint32_t max_inbound_priority_frames_per_stream_; 110 : 111 : // This counter keeps track of the number of inbound WINDOW_UPDATE frames. If this counter exceeds 112 : // the value calculated using this formula: 113 : // 114 : // 1 + 2 * (inbound_streams_ + 115 : // max_inbound_window_update_frames_per_data_frame_sent_ * outbound_data_frames_) 116 : // 117 : // the connection is terminated. 118 : uint64_t inbound_window_update_frames_ = 0; 119 : // This counter keeps track of the number of outbound DATA frames. 120 : uint64_t outbound_data_frames_ = 0; 121 : // Maximum number of inbound WINDOW_UPDATE frames per outbound DATA frame sent. Initialized 122 : // from corresponding http2_protocol_options. Default value is 10. 123 : const uint32_t max_inbound_window_update_frames_per_data_frame_sent_; 124 : }; 125 : 126 : } // namespace Http2 127 : } // namespace Http 128 : } // namespace Envoy