Skip to content

Commit

Permalink
Allow overriding http2 rate limits
Browse files Browse the repository at this point in the history
  • Loading branch information
edsko authored and FinleyMcIlwaine committed Jul 17, 2024
1 parent bcb47e5 commit 48b5c15
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 44 deletions.
22 changes: 17 additions & 5 deletions src/Network/GRPC/Client/Connection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ connectInsecure connParams attempt addr = do
}

clientConfig :: HTTP2.Client.ClientConfig
clientConfig = overridePingRateLimit connParams $
clientConfig = overrideRateLimits connParams $
HTTP2.Client.defaultClientConfig {
HTTP2.Client.authority = authority addr
, HTTP2.Client.settings = settings
Expand Down Expand Up @@ -588,7 +588,7 @@ connectSecure connParams attempt validation sslKeyLog addr = do
}

clientConfig :: HTTP2.Client.ClientConfig
clientConfig = overridePingRateLimit connParams $
clientConfig = overrideRateLimits connParams $
HTTP2.TLS.Client.defaultClientConfig
settings
(authority addr)
Expand Down Expand Up @@ -618,16 +618,28 @@ authority addr =
Nothing -> addressHost addr
Just auth -> auth

-- | Override ping rate limit
overridePingRateLimit ::
-- | Override rate limits imposed by @http2@
overrideRateLimits ::
ConnParams
-> HTTP2.Client.ClientConfig -> HTTP2.Client.ClientConfig
overridePingRateLimit connParams clientConfig = clientConfig {
overrideRateLimits connParams clientConfig = clientConfig {
HTTP2.Client.settings = settings {
HTTP2.Client.pingRateLimit =
case http2OverridePingRateLimit (connHTTP2Settings connParams) of
Nothing -> HTTP2.Client.pingRateLimit settings
Just limit -> limit
, HTTP2.Client.emptyFrameRateLimit =
case http2OverrideEmptyFrameRateLimit (connHTTP2Settings connParams) of
Nothing -> HTTP2.Client.emptyFrameRateLimit settings
Just limit -> limit
, HTTP2.Client.settingsRateLimit =
case http2OverrideSettingsRateLimit (connHTTP2Settings connParams) of
Nothing -> HTTP2.Client.settingsRateLimit settings
Just limit -> limit
, HTTP2.Client.rstRateLimit =
case http2OverrideRstRateLimit (connHTTP2Settings connParams) of
Nothing -> HTTP2.Client.rstRateLimit settings
Just limit -> limit
}
}
where
Expand Down
106 changes: 83 additions & 23 deletions src/Network/GRPC/Common/HTTP2Settings.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,6 @@ data HTTP2Settings = HTTP2Settings {
-- information.
, http2ConnectionWindowSize :: Word32

-- | Ping rate limit
--
-- This setting is specific to the [@http2@
-- package's](https://hackage.haskell.org/package/http2) implementation of
-- the HTTP\/2 specification. In particular, the library imposes a ping
-- rate limit as a security measure against
-- [CVE-2019-9512](https://www.cve.org/CVERecord?id=CVE-2019-9512). By
-- default (as of version 5.1.2) it sets this limit at 10 pings/second. If
-- you find yourself being disconnected from a gRPC peer because that peer
-- is sending too many pings (you will see an
-- [EnhanceYourCalm](https://hackage.haskell.org/package/http2-5.1.2/docs/Network-HTTP2-Client.html#t:ErrorCode)
-- exception, corresponding to the
-- [ENHANCE_YOUR_CALM](https://www.rfc-editor.org/rfc/rfc9113#ErrorCodes)
-- HTTP\/2 error code), you may wish to increase this limit. If you are
-- connecting to a peer that you trust, you can set this limit to
-- 'maxBound' (effectively turning off protecting against ping flooding).
, http2OverridePingRateLimit :: Maybe Int

-- | Enable @TCP_NODELAY@
--
-- Send out TCP segments as soon as possible, even if there is only a
Expand Down Expand Up @@ -87,6 +69,81 @@ data HTTP2Settings = HTTP2Settings {
--
-- TL;DR: leave this at the default unless you know what you are doing.
, http2TcpNoDelay :: Bool

-- | Ping rate limit
--
-- This setting is specific to the [@http2@
-- package's](https://hackage.haskell.org/package/http2) implementation of
-- the HTTP\/2 specification. In particular, the library imposes a ping
-- rate limit as a security measure against
-- [CVE-2019-9512](https://www.cve.org/CVERecord?id=CVE-2019-9512). By
-- default (as of version 5.1.2) it sets this limit at 10 pings/second. If
-- you find yourself being disconnected from a gRPC peer because that peer
-- is sending too many pings (you will see an
-- [EnhanceYourCalm](https://hackage.haskell.org/package/http2-5.1.2/docs/Network-HTTP2-Client.html#t:ErrorCode)
-- exception, corresponding to the
-- [ENHANCE_YOUR_CALM](https://www.rfc-editor.org/rfc/rfc9113#ErrorCodes)
-- HTTP\/2 error code), you may wish to increase this limit. If you are
-- connecting to a peer that you trust, you can set this limit to
-- 'maxBound' (effectively turning off protection against ping flooding).
, http2OverridePingRateLimit :: Maybe Int

-- | Empty DATA frame rate limit
--
-- This setting is specific to the [@http2@
-- package's](https://hackage.haskell.org/package/http2) implementation of
-- the HTTP\/2 specification. In particular, the library imposes a rate
-- limit for empty DATA frames as a security measure against
-- [CVE-2019-9518](https://www.cve.org/CVERecord?id=CVE-2019-9518). By
-- default, it sets this limit at 4 frames/second. If you find yourself
-- being disconnected from a gRPC peer because that peer is sending too
-- many empty DATA frames (you will see an
-- [EnhanceYourCalm](https://hackage.haskell.org/package/http2-5.1.2/docs/Network-HTTP2-Client.html#t:ErrorCode)
-- exception, corresponding to the
-- [ENHANCE_YOUR_CALM](https://www.rfc-editor.org/rfc/rfc9113#ErrorCodes)
-- HTTP\/2 error code), you may wish to increase this limit. If you are
-- connecting to a peer that you trust, you can set this limit to
-- 'maxBound' (effectively turning off protection against empty DATA frame
-- flooding).
, http2OverrideEmptyFrameRateLimit :: Maybe Int

-- | SETTINGS frame rate limit
--
-- This setting is specific to the [@http2@
-- package's](https://hackage.haskell.org/package/http2) implementation of
-- the HTTP\/2 specification. In particular, the library imposes a rate
-- limit for SETTINGS frames as a security measure against
-- [CVE-2019-9515](https://www.cve.org/CVERecord?id=CVE-2019-9515). By
-- default, it sets this limit at 4 frames/second. If you find yourself
-- being disconnected from a gRPC peer because that peer is sending too
-- many SETTINGS frames (you will see an
-- [EnhanceYourCalm](https://hackage.haskell.org/package/http2-5.1.2/docs/Network-HTTP2-Client.html#t:ErrorCode)
-- exception, corresponding to the
-- [ENHANCE_YOUR_CALM](https://www.rfc-editor.org/rfc/rfc9113#ErrorCodes)
-- HTTP\/2 error code), you may wish to increase this limit. If you are
-- connecting to a peer that you trust, you can set this limit to
-- 'maxBound' (effectively turning off protection against SETTINGS frame
-- flooding).
, http2OverrideSettingsRateLimit :: Maybe Int

-- | Reset (RST) frame rate limit
--
-- This setting is specific to the [@http2@
-- package's](https://hackage.haskell.org/package/http2) implementation of
-- the HTTP\/2 specification. In particular, the library imposes a rate
-- limit for RST frames as a security measure against
-- [CVE-2023-44487](https://www.cve.org/CVERecord?id=CVE-2023-44487). By
-- default, it sets this limit at 4 frames/second. If you find yourself
-- being disconnected from a gRPC peer because that peer is sending too
-- many empty RST frames (you will see an
-- [EnhanceYourCalm](https://hackage.haskell.org/package/http2-5.1.2/docs/Network-HTTP2-Client.html#t:ErrorCode)
-- exception, corresponding to the
-- [ENHANCE_YOUR_CALM](https://www.rfc-editor.org/rfc/rfc9113#ErrorCodes)
-- HTTP\/2 error code), you may wish to increase this limit. If you are
-- connecting to a peer that you trust, you can set this limit to
-- 'maxBound' (effectively turning off protection against RST frame
-- flooding).
, http2OverrideRstRateLimit :: Maybe Int
}
deriving (Show)

Expand All @@ -109,11 +166,14 @@ data HTTP2Settings = HTTP2Settings {
-- PINGs/sec.
defaultHTTP2Settings :: HTTP2Settings
defaultHTTP2Settings = HTTP2Settings {
http2MaxConcurrentStreams = defMaxConcurrentStreams
, http2StreamWindowSize = defInitialStreamWindowSize
, http2ConnectionWindowSize = defMaxConcurrentStreams * defInitialStreamWindowSize
, http2OverridePingRateLimit = Just 100
, http2TcpNoDelay = True
http2MaxConcurrentStreams = defMaxConcurrentStreams
, http2StreamWindowSize = defInitialStreamWindowSize
, http2ConnectionWindowSize = defMaxConcurrentStreams * defInitialStreamWindowSize
, http2TcpNoDelay = True
, http2OverridePingRateLimit = Just 100
, http2OverrideEmptyFrameRateLimit = Nothing
, http2OverrideSettingsRateLimit = Nothing
, http2OverrideRstRateLimit = Nothing
}
where
defMaxConcurrentStreams = 128
Expand Down
63 changes: 47 additions & 16 deletions util/Network/GRPC/Util/HTTP2.hs
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,31 @@ mkServerConfig http2Settings numberOfWorkers =
(fromIntegral <$> numberOfWorkers)
, Server.connectionWindowSize = fromIntegral $
http2ConnectionWindowSize http2Settings
, Server.settings = Server.defaultSettings {
Server.initialWindowSize = fromIntegral $
http2StreamWindowSize http2Settings
, Server.maxConcurrentStreams = Just . fromIntegral $
http2MaxConcurrentStreams http2Settings
-- , Server.pingRateLimit =
-- fromMaybe
-- (Server.pingRateLimit Server.defaultSettings)
-- (http2OverridePingRateLimit http2Settings)
}
, Server.settings =
Server.defaultSettings {
Server.initialWindowSize =
fromIntegral $
http2StreamWindowSize http2Settings
, Server.maxConcurrentStreams =
Just . fromIntegral $
http2MaxConcurrentStreams http2Settings
, Server.pingRateLimit =
case http2OverridePingRateLimit http2Settings of
Nothing -> Server.pingRateLimit Server.defaultSettings
Just limit -> limit
, Server.emptyFrameRateLimit =
case http2OverrideEmptyFrameRateLimit http2Settings of
Nothing -> Server.emptyFrameRateLimit Server.defaultSettings
Just limit -> limit
, Server.settingsRateLimit =
case http2OverrideSettingsRateLimit http2Settings of
Nothing -> Server.settingsRateLimit Server.defaultSettings
Just limit -> limit
, Server.rstRateLimit =
case http2OverrideRstRateLimit http2Settings of
Nothing -> Server.rstRateLimit Server.defaultSettings
Just limit -> limit
}
}

-- | Settings for secure server (with TLS)
Expand All @@ -180,12 +195,28 @@ mkTlsSettings http2Settings numberOfWorkers keyLogger =
fromMaybe
(Server.TLS.settingsNumberOfWorkers Server.TLS.defaultSettings)
(fromIntegral <$> numberOfWorkers)
, Server.TLS.settingsConnectionWindowSize = fromIntegral $
http2ConnectionWindowSize http2Settings
, Server.TLS.settingsStreamWindowSize = fromIntegral $
http2StreamWindowSize http2Settings
, Server.TLS.settingsConcurrentStreams = fromIntegral $
http2MaxConcurrentStreams http2Settings
, Server.TLS.settingsConnectionWindowSize =
fromIntegral $ http2ConnectionWindowSize http2Settings
, Server.TLS.settingsStreamWindowSize =
fromIntegral $ http2StreamWindowSize http2Settings
, Server.TLS.settingsConcurrentStreams =
fromIntegral $ http2MaxConcurrentStreams http2Settings
, Server.TLS.settingsPingRateLimit =
case http2OverridePingRateLimit http2Settings of
Nothing -> Server.pingRateLimit Server.defaultSettings
Just limit -> limit
, Server.TLS.settingsEmptyFrameRateLimit =
case http2OverrideEmptyFrameRateLimit http2Settings of
Nothing -> Server.emptyFrameRateLimit Server.defaultSettings
Just limit -> limit
, Server.TLS.settingsSettingsRateLimit =
case http2OverrideSettingsRateLimit http2Settings of
Nothing -> Server.settingsRateLimit Server.defaultSettings
Just limit -> limit
, Server.TLS.settingsRstRateLimit =
case http2OverrideRstRateLimit http2Settings of
Nothing -> Server.rstRateLimit Server.defaultSettings
Just limit -> limit
}

{-------------------------------------------------------------------------------
Expand Down

0 comments on commit 48b5c15

Please sign in to comment.