Skip to content

Commit

Permalink
Allow overriding http2 rate limits
Browse files Browse the repository at this point in the history
  • Loading branch information
FinleyMcIlwaine committed Jul 17, 2024
1 parent 442fa23 commit 350aaff
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 45 deletions.
10 changes: 10 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ package grapesy

constraints: network-control==0.1.2

-- TODO: Remove once we have an http2-tls release
source-repository-package
type: git
location: https://github.com/kazu-yamamoto/http2-tls
tag: 13f1532a294cb85ce14dc66e3ac919db29e1b165
source-repository-package
type: git
location: https://github.com/kazu-yamamoto/network-run
tag: 4ffaab7c212d0889f00988d04f4acc189496e2fd

--
-- ghc 9.10
--
Expand Down
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 = Nothing
, http2OverrideEmptyFrameRateLimit = Nothing
, http2OverrideSettingsRateLimit = Nothing
, http2OverrideRstRateLimit = Nothing
}
where
defMaxConcurrentStreams = 128
Expand Down
36 changes: 36 additions & 0 deletions src/Network/GRPC/Server/Run.hs
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,46 @@ runInsecure params cfg socketTMVar server = do
} = params

serverConfig :: HTTP2.ServerConfig
<<<<<<< HEAD
serverConfig =
mkServerConfig
serverHTTP2Settings
serverOverrideNumberOfWorkers
=======
serverConfig = HTTP2.defaultServerConfig {
HTTP2.numberOfWorkers =
fromMaybe
(HTTP2.numberOfWorkers HTTP2.defaultServerConfig)
(fromIntegral <$> serverOverrideNumberOfWorkers)
, HTTP2.connectionWindowSize =
fromIntegral $ http2ConnectionWindowSize serverHTTP2Settings
, HTTP2.settings =
HTTP2.defaultSettings {
HTTP2.initialWindowSize =
fromIntegral $
http2StreamWindowSize serverHTTP2Settings
, HTTP2.maxConcurrentStreams =
Just . fromIntegral $
http2MaxConcurrentStreams serverHTTP2Settings
, HTTP2.pingRateLimit =
case http2OverridePingRateLimit serverHTTP2Settings of
Nothing -> HTTP2.pingRateLimit HTTP2.defaultSettings
Just limit -> limit
, HTTP2.emptyFrameRateLimit =
case http2OverrideEmptyFrameRateLimit serverHTTP2Settings of
Nothing -> HTTP2.emptyFrameRateLimit HTTP2.defaultSettings
Just limit -> limit
, HTTP2.settingsRateLimit =
case http2OverrideSettingsRateLimit serverHTTP2Settings of
Nothing -> HTTP2.settingsRateLimit HTTP2.defaultSettings
Just limit -> limit
, HTTP2.rstRateLimit =
case http2OverrideRstRateLimit serverHTTP2Settings of
Nothing -> HTTP2.rstRateLimit HTTP2.defaultSettings
Just limit -> limit
}
}
>>>>>>> 32b6b17 (Allow overriding `http2` rate limits)

{-------------------------------------------------------------------------------
Secure (over TLS)
Expand Down
65 changes: 48 additions & 17 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 serverHTTP2Settings
, Server.maxConcurrentStreams =
Just . fromIntegral $
http2MaxConcurrentStreams serverHTTP2Settings
, Server.pingRateLimit =
case http2OverridePingRateLimit serverHTTP2Settings of
Nothing -> Server.pingRateLimit Server.defaultSettings
Just limit -> limit
, Server.emptyFrameRateLimit =
case http2OverrideEmptyFrameRateLimit serverHTTP2Settings of
Nothing -> Server.emptyFrameRateLimit Server.defaultSettings
Just limit -> limit
, Server.settingsRateLimit =
case http2OverrideSettingsRateLimit serverHTTP2Settings of
Nothing -> Server.settingsRateLimit Server.defaultSettings
Just limit -> limit
, Server.rstRateLimit =
case http2OverrideRstRateLimit serverHTTP2Settings of
Nothing -> Server.rstRateLimit Server.defaultSettings
Just limit -> limit
}
}

-- | Settings for secure server (with TLS)
Expand All @@ -179,13 +194,29 @@ mkTlsSettings http2Settings numberOfWorkers keyLogger =
, Server.TLS.settingsNumberOfWorkers =
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
(fromIntegral <$> serverOverrideNumberOfWorkers)
, Server.TLS.settingsConnectionWindowSize =
fromIntegral $ http2ConnectionWindowSize serverHTTP2Settings
, Server.TLS.settingsStreamWindowSize =
fromIntegral $ http2StreamWindowSize serverHTTP2Settings
, Server.TLS.settingsConcurrentStreams =
fromIntegral $ http2MaxConcurrentStreams serverHTTP2Settings
, Server.TLS.settingsPingRateLimit =
case http2OverridePingRateLimit serverHTTP2Settings of
Nothing -> Server.pingRateLimit Server.defaultSettings
Just limit -> limit
, Server.TLS.settingsEmptyFrameRateLimit =
case http2OverrideEmptyFrameRateLimit serverHTTP2Settings of
Nothing -> Server.emptyFrameRateLimit Server.defaultSettings
Just limit -> limit
, Server.TLS.settingsSettingsRateLimit =
case http2OverrideSettingsRateLimit serverHTTP2Settings of
Nothing -> Server.settingsRateLimit Server.defaultSettings
Just limit -> limit
, Server.TLS.settingsRstRateLimit =
case http2OverrideRstRateLimit serverHTTP2Settings of
Nothing -> Server.rstRateLimit Server.defaultSettings
Just limit -> limit
}

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

0 comments on commit 350aaff

Please sign in to comment.