diff --git a/Network/HTTP2/Client.hs b/Network/HTTP2/Client.hs index 0db82173..fe95835d 100644 --- a/Network/HTTP2/Client.hs +++ b/Network/HTTP2/Client.hs @@ -66,6 +66,7 @@ module Network.HTTP2.Client ( initialWindowSize, maxFrameSize, maxHeaderListSize, + pingRateLimit, -- * Common configuration Config (..), diff --git a/Network/HTTP2/Client/Run.hs b/Network/HTTP2/Client/Run.hs index 5bcfb7bc..2fefe37e 100644 --- a/Network/HTTP2/Client/Run.hs +++ b/Network/HTTP2/Client/Run.hs @@ -52,7 +52,7 @@ data ClientConfig = ClientConfig -- @userinfo\@@ as part of the authority. -- -- >>> defaultClientConfig --- ClientConfig {scheme = "http", authority = "localhost", cacheLimit = 64, connectionWindowSize = 1048576, settings = Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Just 64, initialWindowSize = 262144, maxFrameSize = 16384, maxHeaderListSize = Nothing}} +-- ClientConfig {scheme = "http", authority = "localhost", cacheLimit = 64, connectionWindowSize = 1048576, settings = Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Just 64, initialWindowSize = 262144, maxFrameSize = 16384, maxHeaderListSize = Nothing, pingRateLimit = 10}} defaultClientConfig :: ClientConfig defaultClientConfig = ClientConfig diff --git a/Network/HTTP2/H2/Receiver.hs b/Network/HTTP2/H2/Receiver.hs index 4ced970a..0dc7fd8b 100644 --- a/Network/HTTP2/H2/Receiver.hs +++ b/Network/HTTP2/H2/Receiver.hs @@ -39,9 +39,6 @@ continuationLimit = 10 headerFragmentLimit :: Int headerFragmentLimit = 51200 -- 50K -pingRateLimit :: Int -pingRateLimit = 4 - settingsRateLimit :: Int settingsRateLimit = 4 @@ -328,11 +325,10 @@ control FrameSettings header@FrameHeader{flags, streamId} bs Context{myFirstSett setframe = CFrames (Just peerAlist) (frames ++ [ack]) writeIORef myFirstSettings True enqueueControl controlQ setframe -control FramePing FrameHeader{flags, streamId} bs Context{controlQ, pingRate} = +control FramePing FrameHeader{flags, streamId} bs Context{mySettings, controlQ, pingRate} = unless (testAck flags) $ do - -- Ping Flood - CVE-2019-9512 rate <- getRate pingRate - if rate > pingRateLimit + if rate > pingRateLimit mySettings then E.throwIO $ ConnectionErrorIsSent EnhanceYourCalm streamId "too many ping" else do let frame = pingFrame bs diff --git a/Network/HTTP2/H2/Settings.hs b/Network/HTTP2/H2/Settings.hs index 65f14132..2324deaa 100644 --- a/Network/HTTP2/H2/Settings.hs +++ b/Network/HTTP2/H2/Settings.hs @@ -25,13 +25,15 @@ data Settings = Settings -- ^ SETTINGS_MAX_FRAME_SIZE , maxHeaderListSize :: Maybe Int -- ^ SETTINGS_MAX_HEADER_LIST_SIZE + , pingRateLimit :: Int + -- ^ Maximum number of pings allowed per second (CVE-2019-9512) } deriving (Eq, Show) -- | The default settings. -- -- >>> baseSettings --- Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Nothing, initialWindowSize = 65535, maxFrameSize = 16384, maxHeaderListSize = Nothing} +-- Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Nothing, initialWindowSize = 65535, maxFrameSize = 16384, maxHeaderListSize = Nothing, pingRateLimit = 10} baseSettings :: Settings baseSettings = Settings @@ -41,12 +43,13 @@ baseSettings = , initialWindowSize = defaultWindowSize -- 64K (65,535) , maxFrameSize = defaultPayloadLength -- 2^14 (16,384) , maxHeaderListSize = Nothing + , pingRateLimit = 10 } -- | The default settings. -- -- >>> defaultSettings --- Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Just 64, initialWindowSize = 262144, maxFrameSize = 16384, maxHeaderListSize = Nothing} +-- Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Just 64, initialWindowSize = 262144, maxFrameSize = 16384, maxHeaderListSize = Nothing, pingRateLimit = 10} defaultSettings :: Settings defaultSettings = baseSettings @@ -59,7 +62,7 @@ defaultSettings = -- | Updating settings. -- -- >>> fromSettingsList defaultSettings [(SettingsEnablePush,0),(SettingsMaxHeaderListSize,200)] --- Settings {headerTableSize = 4096, enablePush = False, maxConcurrentStreams = Just 64, initialWindowSize = 262144, maxFrameSize = 16384, maxHeaderListSize = Just 200} +-- Settings {headerTableSize = 4096, enablePush = False, maxConcurrentStreams = Just 64, initialWindowSize = 262144, maxFrameSize = 16384, maxHeaderListSize = Just 200, pingRateLimit = 10} {- FOURMOLU_DISABLE -} fromSettingsList :: Settings -> SettingsList -> Settings fromSettingsList settings kvs = foldl' update settings kvs diff --git a/Network/HTTP2/Server/Run.hs b/Network/HTTP2/Server/Run.hs index 4d53c946..452c8d62 100644 --- a/Network/HTTP2/Server/Run.hs +++ b/Network/HTTP2/Server/Run.hs @@ -30,7 +30,7 @@ data ServerConfig = ServerConfig -- | The default server config. -- -- >>> defaultServerConfig --- ServerConfig {numberOfWorkers = 8, connectionWindowSize = 1048576, settings = Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Just 64, initialWindowSize = 262144, maxFrameSize = 16384, maxHeaderListSize = Nothing}} +-- ServerConfig {numberOfWorkers = 8, connectionWindowSize = 1048576, settings = Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Just 64, initialWindowSize = 262144, maxFrameSize = 16384, maxHeaderListSize = Nothing, pingRateLimit = 10}} defaultServerConfig :: ServerConfig defaultServerConfig = ServerConfig diff --git a/test/HTTP2/ServerSpec.hs b/test/HTTP2/ServerSpec.hs index 71b7a0ab..3db31d69 100644 --- a/test/HTTP2/ServerSpec.hs +++ b/test/HTTP2/ServerSpec.hs @@ -345,15 +345,7 @@ rapidPing C.ClientIO{..} = do let einfo = EncodeInfo defaultFlags 0 Nothing opaque64 = "01234567" bs = encodeFrame einfo $ PingFrame opaque64 - cioWriteBytes bs - cioWriteBytes bs - cioWriteBytes bs - cioWriteBytes bs - cioWriteBytes bs - cioWriteBytes bs - cioWriteBytes bs - cioWriteBytes bs - cioWriteBytes bs + replicateM_ 20 $ cioWriteBytes bs rapidEmptyHeader :: C.ClientIO -> IO () rapidEmptyHeader C.ClientIO{..} = do