From 188fc5fe96791e4215abe3632938359d8e0a67ea Mon Sep 17 00:00:00 2001 From: yungyu16 Date: Tue, 11 Nov 2025 13:30:45 +0800 Subject: [PATCH] fix: enhance token server request handling and add max frame length validation --- .../cluster/server/NettyTransportServer.java | 58 ++++++++++--------- .../cluster/server/ServerConstants.java | 5 +- .../data/ParamFlowRequestDataDecoder.java | 17 +++--- .../codec/data/PingRequestDataDecoder.java | 17 +++--- 4 files changed, 54 insertions(+), 43 deletions(-) diff --git a/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/NettyTransportServer.java b/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/NettyTransportServer.java index 25468551f0..cf50d12cce 100644 --- a/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/NettyTransportServer.java +++ b/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/NettyTransportServer.java @@ -15,17 +15,12 @@ */ package com.alibaba.csp.sentinel.cluster.server; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - import com.alibaba.csp.sentinel.cluster.server.codec.netty.NettyRequestDecoder; import com.alibaba.csp.sentinel.cluster.server.codec.netty.NettyResponseEncoder; import com.alibaba.csp.sentinel.cluster.server.connection.Connection; import com.alibaba.csp.sentinel.cluster.server.connection.ConnectionPool; import com.alibaba.csp.sentinel.cluster.server.handler.TokenServerHandler; import com.alibaba.csp.sentinel.log.RecordLog; - import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.ChannelFuture; @@ -42,7 +37,14 @@ import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.internal.SystemPropertyUtil; -import static com.alibaba.csp.sentinel.cluster.server.ServerConstants.*; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import static com.alibaba.csp.sentinel.cluster.server.ServerConstants.NETTY_MAX_FRAME_LENGTH; +import static com.alibaba.csp.sentinel.cluster.server.ServerConstants.SERVER_STATUS_OFF; +import static com.alibaba.csp.sentinel.cluster.server.ServerConstants.SERVER_STATUS_STARTED; +import static com.alibaba.csp.sentinel.cluster.server.ServerConstants.SERVER_STATUS_STARTING; /** * @author Eric Zhao @@ -51,7 +53,7 @@ public class NettyTransportServer implements ClusterTokenServer { private static final int DEFAULT_EVENT_LOOP_THREADS = Math.max(1, - SystemPropertyUtil.getInt("io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2)); + SystemPropertyUtil.getInt("io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2)); private static final int MAX_RETRY_TIMES = 3; private static final int RETRY_SLEEP_MS = 2000; @@ -79,32 +81,32 @@ public void start() { this.bossGroup = new NioEventLoopGroup(1); this.workerGroup = new NioEventLoopGroup(DEFAULT_EVENT_LOOP_THREADS); b.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .option(ChannelOption.SO_BACKLOG, 128) - .handler(new LoggingHandler(LogLevel.INFO)) - .childHandler(new ChannelInitializer() { - @Override - public void initChannel(SocketChannel ch) throws Exception { - ChannelPipeline p = ch.pipeline(); - p.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, 0, 2)); - p.addLast(new NettyRequestDecoder()); - p.addLast(new LengthFieldPrepender(2)); - p.addLast(new NettyResponseEncoder()); - p.addLast(new TokenServerHandler(connectionPool)); - } - }) - .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) - .childOption(ChannelOption.SO_SNDBUF, 32 * 1024) - .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) - .childOption(ChannelOption.SO_TIMEOUT, 10) - .childOption(ChannelOption.TCP_NODELAY, true) - .childOption(ChannelOption.SO_RCVBUF, 32 * 1024); + .channel(NioServerSocketChannel.class) + .option(ChannelOption.SO_BACKLOG, 128) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline p = ch.pipeline(); + p.addLast(new LengthFieldBasedFrameDecoder(NETTY_MAX_FRAME_LENGTH, 0, 2, 0, 2)); + p.addLast(new NettyRequestDecoder()); + p.addLast(new LengthFieldPrepender(2)); + p.addLast(new NettyResponseEncoder()); + p.addLast(new TokenServerHandler(connectionPool)); + } + }) + .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .childOption(ChannelOption.SO_SNDBUF, 32 * 1024) + .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) + .childOption(ChannelOption.SO_TIMEOUT, 10) + .childOption(ChannelOption.TCP_NODELAY, true) + .childOption(ChannelOption.SO_RCVBUF, 32 * 1024); b.bind(port).addListener(new GenericFutureListener() { @Override public void operationComplete(ChannelFuture future) { if (future.cause() != null) { RecordLog.info("[NettyTransportServer] Token server start failed (port=" + port + "), failedTimes: " + failedTimes.get(), - future.cause()); + future.cause()); currentState.compareAndSet(SERVER_STATUS_STARTING, SERVER_STATUS_OFF); int failCount = failedTimes.incrementAndGet(); if (failCount > MAX_RETRY_TIMES) { diff --git a/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/ServerConstants.java b/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/ServerConstants.java index 6569cef8cd..1f934f9f1c 100644 --- a/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/ServerConstants.java +++ b/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/ServerConstants.java @@ -27,5 +27,8 @@ public final class ServerConstants { public static final String DEFAULT_NAMESPACE = "default"; - private ServerConstants() {} + public static final int NETTY_MAX_FRAME_LENGTH = 1024; + + private ServerConstants() { + } } diff --git a/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/codec/data/ParamFlowRequestDataDecoder.java b/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/codec/data/ParamFlowRequestDataDecoder.java index fd4eab6f6f..9cb3c3bd74 100644 --- a/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/codec/data/ParamFlowRequestDataDecoder.java +++ b/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/codec/data/ParamFlowRequestDataDecoder.java @@ -15,15 +15,15 @@ */ package com.alibaba.csp.sentinel.cluster.server.codec.data; -import java.util.ArrayList; -import java.util.List; - import com.alibaba.csp.sentinel.cluster.ClusterConstants; import com.alibaba.csp.sentinel.cluster.codec.EntityDecoder; import com.alibaba.csp.sentinel.cluster.request.data.ParamFlowRequestData; - +import com.alibaba.csp.sentinel.cluster.server.ServerConstants; import io.netty.buffer.ByteBuf; +import java.util.ArrayList; +import java.util.List; + /** * @author jialiang.linjl * @author Eric Zhao @@ -35,12 +35,12 @@ public class ParamFlowRequestDataDecoder implements EntityDecoder= 16) { ParamFlowRequestData requestData = new ParamFlowRequestData() - .setFlowId(source.readLong()) - .setCount(source.readInt()); + .setFlowId(source.readLong()) + .setCount(source.readInt()); int amount = source.readInt(); if (amount > 0) { - List params = new ArrayList<>(amount); + List params = new ArrayList<>(16); for (int i = 0; i < amount; i++) { decodeParam(source, params); } @@ -61,6 +61,9 @@ private boolean decodeParam(ByteBuf source, List params) { return true; case ClusterConstants.PARAM_TYPE_STRING: int length = source.readInt(); + if (length > ServerConstants.NETTY_MAX_FRAME_LENGTH) { + throw new IllegalStateException("[ParamFlowRequestDataDecoder] String param length (" + length + ") exceeds max frame length (" + ServerConstants.NETTY_MAX_FRAME_LENGTH + ")"); + } byte[] bytes = new byte[length]; source.readBytes(bytes); // TODO: take care of charset? diff --git a/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/codec/data/PingRequestDataDecoder.java b/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/codec/data/PingRequestDataDecoder.java index cef33119bb..e8058e25de 100644 --- a/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/codec/data/PingRequestDataDecoder.java +++ b/sentinel-cluster/sentinel-cluster-server-default/src/main/java/com/alibaba/csp/sentinel/cluster/server/codec/data/PingRequestDataDecoder.java @@ -16,7 +16,7 @@ package com.alibaba.csp.sentinel.cluster.server.codec.data; import com.alibaba.csp.sentinel.cluster.codec.EntityDecoder; - +import com.alibaba.csp.sentinel.log.RecordLog; import io.netty.buffer.ByteBuf; /** @@ -27,13 +27,16 @@ public class PingRequestDataDecoder implements EntityDecoder { @Override public String decode(ByteBuf source) { - if (source.readableBytes() >= 4) { - int length = source.readInt(); - if (length > 0 && source.readableBytes() > 0) { - byte[] bytes = new byte[length]; - source.readBytes(bytes); - return new String(bytes); + int readableBytes = source.readableBytes(); + if (readableBytes >= 4) { + int packetLen = source.readInt(); + if (readableBytes != packetLen) { // 畸形报文,可能是端口扫描 + RecordLog.warn("[NettyTransportServer] Abnormal packet detected: expected length = {}, actual readableBytes = {}", packetLen, readableBytes); + return null; } + byte[] bytes = new byte[packetLen]; + source.readBytes(bytes); + return new String(bytes); } return null; }