From eb98c01b4bf3e872d6382789b4e6041537b96ead Mon Sep 17 00:00:00 2001 From: Vasiliy Mikhailov Date: Fri, 26 Jun 2026 00:35:49 +0400 Subject: [PATCH] Guard against unresolved remote address in TokenClientHandler.getRemoteAddress getRemoteAddress does inetAddress.getAddress().getHostAddress(), which throws NullPointerException when the channel's remote address is an unresolved InetSocketAddress (getAddress() returns null). It is reached from channelUnregistered, which logs getRemoteAddress(ctx) during channel cleanup, so a channel with an unresolved remote address NPEs on unregister. Fall back to getHostName() when getAddress() is null. Adds a regression test. --- .../client/handler/TokenClientHandler.java | 4 +- .../handler/TokenClientHandlerTest.java | 47 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 sentinel-cluster/sentinel-cluster-client-default/src/test/java/com/alibaba/csp/sentinel/cluster/client/handler/TokenClientHandlerTest.java diff --git a/sentinel-cluster/sentinel-cluster-client-default/src/main/java/com/alibaba/csp/sentinel/cluster/client/handler/TokenClientHandler.java b/sentinel-cluster/sentinel-cluster-client-default/src/main/java/com/alibaba/csp/sentinel/cluster/client/handler/TokenClientHandler.java index 41ee220dbf..0dad9cb8e8 100644 --- a/sentinel-cluster/sentinel-cluster-client-default/src/main/java/com/alibaba/csp/sentinel/cluster/client/handler/TokenClientHandler.java +++ b/sentinel-cluster/sentinel-cluster-client-default/src/main/java/com/alibaba/csp/sentinel/cluster/client/handler/TokenClientHandler.java @@ -15,6 +15,7 @@ */ package com.alibaba.csp.sentinel.cluster.client.handler; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.atomic.AtomicInteger; @@ -106,7 +107,8 @@ private String getRemoteAddress(ChannelHandlerContext ctx) { return null; } InetSocketAddress inetAddress = (InetSocketAddress) ctx.channel().remoteAddress(); - return inetAddress.getAddress().getHostAddress() + ":" + inetAddress.getPort(); + InetAddress addr = inetAddress.getAddress(); + return (addr != null ? addr.getHostAddress() : inetAddress.getHostName()) + ":" + inetAddress.getPort(); } public int getCurrentState() { diff --git a/sentinel-cluster/sentinel-cluster-client-default/src/test/java/com/alibaba/csp/sentinel/cluster/client/handler/TokenClientHandlerTest.java b/sentinel-cluster/sentinel-cluster-client-default/src/test/java/com/alibaba/csp/sentinel/cluster/client/handler/TokenClientHandlerTest.java new file mode 100644 index 0000000000..35d507938e --- /dev/null +++ b/sentinel-cluster/sentinel-cluster-client-default/src/test/java/com/alibaba/csp/sentinel/cluster/client/handler/TokenClientHandlerTest.java @@ -0,0 +1,47 @@ +package com.alibaba.csp.sentinel.cluster.client.handler; + +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.util.concurrent.atomic.AtomicInteger; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class TokenClientHandlerTest { + + private Channel mockChannel; + private ChannelHandlerContext mockCtx; + private TokenClientHandler handler; + + @Before + public void setUp() { + mockChannel = mock(Channel.class); + mockCtx = mock(ChannelHandlerContext.class); + handler = new TokenClientHandler(new AtomicInteger(0), () -> { }); + when(mockCtx.channel()).thenReturn(mockChannel); + } + + @Test + public void testGetRemoteAddressWithUnresolvedSocketAddress() throws Exception { + InetSocketAddress unresolved = InetSocketAddress.createUnresolved("unresolved.host", 8710); + Assert.assertNull("Unresolved address should have null InetAddress", unresolved.getAddress()); + when(mockChannel.remoteAddress()).thenReturn(unresolved); + Method method = TokenClientHandler.class.getDeclaredMethod("getRemoteAddress", ChannelHandlerContext.class); + method.setAccessible(true); + try { + String result = (String) method.invoke(handler, mockCtx); + Assert.assertNotNull("Should return a non-null result for unresolved address", result); + } catch (java.lang.reflect.InvocationTargetException e) { + if (e.getCause() instanceof NullPointerException) { + Assert.fail("getRemoteAddress should handle unresolved InetSocketAddress without NPE, but got: " + e.getCause()); + } + throw e; + } + } +}