From 9af5bd326500773d89ce30311af5e3cac2a9b3f5 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Tue, 29 Sep 2026 06:39:04 +0000
Subject: [PATCH] [#1112] Listen on the configured listen-address in the HTTP connection handler and the JMX RMI connector (#1113)
---
opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java | 82 ++++++++++++++++++++++++++++++++++++++++-
1 files changed, 80 insertions(+), 2 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java
index 3b7f82e..626f94d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java
@@ -22,9 +22,11 @@
import java.io.IOException;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
+import java.rmi.server.RMIServerSocketFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
@@ -168,6 +170,18 @@
*/
private String rmiVersion;
+ /**
+ * The system property that names the host the stubs of the objects exported
+ * through RMI advertise.
+ */
+ private static final String RMI_SERVER_HOSTNAME = "java.rmi.server.hostname";
+
+ /**
+ * The value this server gave to {@code java.rmi.server.hostname}, or
+ * {@code null} if the server did not set it.
+ */
+ private static String rmiServerHostnameSetByServer;
+
// ===================================================================
// CONSTRUCTOR
// ===================================================================
@@ -319,8 +333,10 @@
// ---------------------
// init an ssl context
// ---------------------
+ // Both server socket factories listen on the configured listen address:
+ // the default RMI factory would listen on every interface.
SslRMIClientSocketFactory rmiClientSockeyFactory = null;
- DirectoryRMIServerSocketFactory rmiServerSockeyFactory = null;
+ RMIServerSocketFactory rmiServerSockeyFactory;
if (jmxConnectionHandler.isUseSSL())
{
if (logger.isTraceEnabled())
@@ -355,7 +371,8 @@
SSLSocketFactory ssf = ctx.getSocketFactory();
// set the Server socket factory in the JMX map
- rmiServerSockeyFactory = new DirectoryRMIServerSocketFactory(ssf, false);
+ rmiServerSockeyFactory = new DirectoryRMIServerSocketFactory(
+ ssf, false, jmxConnectionHandler.getListenAddress());
env.put(
"jmx.remote.rmi.server.socket.factory",
rmiServerSockeyFactory);
@@ -376,6 +393,8 @@
{
logger.trace("UNSECURE CONNECTION");
}
+ rmiServerSockeyFactory = new OpendsRmiServerSocketFactory(
+ jmxConnectionHandler.getListenAddress());
}
// specify the rmi JMX authenticator to be used
@@ -399,6 +418,7 @@
{
logger.trace("Create and start the JMX RMI connector");
}
+ advertiseListenAddress(jmxConnectionHandler.getListenAddress());
OpendsRMIJRMPServerImpl opendsRmiConnectorServer =
new OpendsRMIJRMPServerImpl(jmxConnectionHandler.getRmiPort(),
rmiClientSockeyFactory, rmiServerSockeyFactory, env);
@@ -426,6 +446,64 @@
}
+ /**
+ * Makes the stub of the RMI connector advertise the listen address.
+ * <p>
+ * The stub that a client gets from the RMI registry advertises the host that
+ * {@code java.rmi.server.hostname} names, or else the address of the local host,
+ * whatever address the connector listens on: a connector bound to another
+ * address refuses the client. The JDK reads the property again at each export.
+ * A value that this server did not set is the operator's, and is kept.
+ *
+ * @param listenAddress
+ * the address the connector listens on
+ */
+ private static synchronized void advertiseListenAddress(InetAddress listenAddress)
+ {
+ final String hostname = System.getProperty(RMI_SERVER_HOSTNAME);
+ if (hostname != null && !hostname.equals(rmiServerHostnameSetByServer))
+ {
+ return;
+ }
+ if (listenAddress.isAnyLocalAddress())
+ {
+ // Cleared, the property would leave the JDK advertising the host it last
+ // read: the address a connector of this server listened on before, which
+ // a remote client cannot reach if it was a loopback one. Advertise the
+ // local host instead, as the JDK does by default.
+ final InetAddress localHost = getLocalHostOrNull();
+ if (rmiServerHostnameSetByServer != null
+ && localHost != null && !localHost.isLoopbackAddress())
+ {
+ rmiServerHostnameSetByServer = localHost.getHostAddress();
+ System.setProperty(RMI_SERVER_HOSTNAME, rmiServerHostnameSetByServer);
+ }
+ else
+ {
+ System.clearProperty(RMI_SERVER_HOSTNAME);
+ rmiServerHostnameSetByServer = null;
+ }
+ }
+ else
+ {
+ rmiServerHostnameSetByServer = listenAddress.getHostAddress();
+ System.setProperty(RMI_SERVER_HOSTNAME, rmiServerHostnameSetByServer);
+ }
+ }
+
+ private static InetAddress getLocalHostOrNull()
+ {
+ try
+ {
+ return InetAddress.getLocalHost();
+ }
+ catch (UnknownHostException e)
+ {
+ logger.traceException(e);
+ return null;
+ }
+ }
+
static void configureJmxDeserializationProtection(Map<String, Object> env)
{
// Tightly constrain the credentials object exchanged during authentication
--
Gitblit v1.10.0