@@ -125,10 +125,13 @@ class NettyServerHandler extends AbstractNettyHandler {
125
125
private final long keepAliveTimeoutInNanos ;
126
126
private final long maxConnectionAgeInNanos ;
127
127
private final long maxConnectionAgeGraceInNanos ;
128
+ private final int maxRstCount ;
129
+ private final long maxRstPeriodNanos ;
128
130
private final List <? extends ServerStreamTracer .Factory > streamTracerFactories ;
129
131
private final TransportTracer transportTracer ;
130
132
private final KeepAliveEnforcer keepAliveEnforcer ;
131
133
private final Attributes eagAttributes ;
134
+ private final Ticker ticker ;
132
135
/** Incomplete attributes produced by negotiator. */
133
136
private Attributes negotiationAttributes ;
134
137
private InternalChannelz .Security securityInfo ;
@@ -146,6 +149,9 @@ class NettyServerHandler extends AbstractNettyHandler {
146
149
private ScheduledFuture <?> maxConnectionAgeMonitor ;
147
150
@ CheckForNull
148
151
private GracefulShutdown gracefulShutdown ;
152
+ private int rstCount ;
153
+ private long lastRstNanoTime ;
154
+
149
155
150
156
static NettyServerHandler newHandler (
151
157
ServerTransportListener transportListener ,
@@ -164,6 +170,8 @@ static NettyServerHandler newHandler(
164
170
long maxConnectionAgeGraceInNanos ,
165
171
boolean permitKeepAliveWithoutCalls ,
166
172
long permitKeepAliveTimeInNanos ,
173
+ int maxRstCount ,
174
+ long maxRstPeriodNanos ,
167
175
Attributes eagAttributes ) {
168
176
Preconditions .checkArgument (maxHeaderListSize > 0 , "maxHeaderListSize must be positive: %s" ,
169
177
maxHeaderListSize );
@@ -192,6 +200,8 @@ static NettyServerHandler newHandler(
192
200
maxConnectionAgeGraceInNanos ,
193
201
permitKeepAliveWithoutCalls ,
194
202
permitKeepAliveTimeInNanos ,
203
+ maxRstCount ,
204
+ maxRstPeriodNanos ,
195
205
eagAttributes ,
196
206
Ticker .systemTicker ());
197
207
}
@@ -215,6 +225,8 @@ static NettyServerHandler newHandler(
215
225
long maxConnectionAgeGraceInNanos ,
216
226
boolean permitKeepAliveWithoutCalls ,
217
227
long permitKeepAliveTimeInNanos ,
228
+ int maxRstCount ,
229
+ long maxRstPeriodNanos ,
218
230
Attributes eagAttributes ,
219
231
Ticker ticker ) {
220
232
Preconditions .checkArgument (maxStreams > 0 , "maxStreams must be positive: %s" , maxStreams );
@@ -266,6 +278,8 @@ static NettyServerHandler newHandler(
266
278
maxConnectionAgeInNanos , maxConnectionAgeGraceInNanos ,
267
279
keepAliveEnforcer ,
268
280
autoFlowControl ,
281
+ maxRstCount ,
282
+ maxRstPeriodNanos ,
269
283
eagAttributes , ticker );
270
284
}
271
285
@@ -286,6 +300,8 @@ private NettyServerHandler(
286
300
long maxConnectionAgeGraceInNanos ,
287
301
final KeepAliveEnforcer keepAliveEnforcer ,
288
302
boolean autoFlowControl ,
303
+ int maxRstCount ,
304
+ long maxRstPeriodNanos ,
289
305
Attributes eagAttributes ,
290
306
Ticker ticker ) {
291
307
super (channelUnused , decoder , encoder , settings , new ServerChannelLogger (),
@@ -328,8 +344,12 @@ public void onStreamClosed(Http2Stream stream) {
328
344
this .maxConnectionAgeInNanos = maxConnectionAgeInNanos ;
329
345
this .maxConnectionAgeGraceInNanos = maxConnectionAgeGraceInNanos ;
330
346
this .keepAliveEnforcer = checkNotNull (keepAliveEnforcer , "keepAliveEnforcer" );
347
+ this .maxRstCount = maxRstCount ;
348
+ this .maxRstPeriodNanos = maxRstPeriodNanos ;
331
349
this .eagAttributes = checkNotNull (eagAttributes , "eagAttributes" );
350
+ this .ticker = checkNotNull (ticker , "ticker" );
332
351
352
+ this .lastRstNanoTime = ticker .read ();
333
353
streamKey = encoder .connection ().newKey ();
334
354
this .transportListener = checkNotNull (transportListener , "transportListener" );
335
355
this .streamTracerFactories = checkNotNull (streamTracerFactories , "streamTracerFactories" );
@@ -527,6 +547,26 @@ private void onDataRead(int streamId, ByteBuf data, int padding, boolean endOfSt
527
547
}
528
548
529
549
private void onRstStreamRead (int streamId , long errorCode ) throws Http2Exception {
550
+ if (maxRstCount > 0 ) {
551
+ long now = ticker .read ();
552
+ if (now - lastRstNanoTime > maxRstPeriodNanos ) {
553
+ lastRstNanoTime = now ;
554
+ rstCount = 1 ;
555
+ } else {
556
+ rstCount ++;
557
+ if (rstCount > maxRstCount ) {
558
+ throw new Http2Exception (Http2Error .ENHANCE_YOUR_CALM , "too_many_rststreams" ) {
559
+ @ SuppressWarnings ("UnsynchronizedOverridesSynchronized" ) // No memory accesses
560
+ @ Override
561
+ public Throwable fillInStackTrace () {
562
+ // Avoid the CPU cycles, since the resets may be a CPU consumption attack
563
+ return this ;
564
+ }
565
+ };
566
+ }
567
+ }
568
+ }
569
+
530
570
try {
531
571
NettyServerStream .TransportState stream = serverStream (connection ().stream (streamId ));
532
572
if (stream != null ) {
0 commit comments