Bind JMX to localhost unless explicitly configured otherwise
diff --git a/CHANGES.txt b/CHANGES.txt
index 954fa3f..50c7967 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,6 @@
+2.1.4
+ * If no JMX flags are set start a localhost only JMX service
+
2.1.3
* Fix HSHA/offheap_objects corruption (CASSANDRA-8719)
* Upgrade libthrift to 0.9.2 (CASSANDRA-8685)
diff --git a/NEWS.txt b/NEWS.txt
index 602770c..076885c 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -13,6 +13,12 @@
'sstableloader' tool. You can upgrade the file format of your snapshots
using the provided 'sstableupgrade' tool.
+2.1.4
+=====
+
+The default JMX config now listens to localhost only. You must enable
+the other JMX flags in cassandra-env.sh manually.
+
2.1.3
=====
diff --git a/bin/cassandra.bat b/bin/cassandra.bat
index 99b291a..fefd3fc 100644
--- a/bin/cassandra.bat
+++ b/bin/cassandra.bat
@@ -65,10 +65,13 @@
-XX:MaxTenuringThreshold=1^
-XX:CMSInitiatingOccupancyFraction=75^
-XX:+UseCMSInitiatingOccupancyOnly^
- -Dcom.sun.management.jmxremote.port=7199^
- -Dcom.sun.management.jmxremote.ssl=false^
- -Dcom.sun.management.jmxremote.authenticate=false^
- -Dlogback.configurationFile=logback.xml
+ -Dlogback.configurationFile=logback.xml^
+ -Dcassandra.jmx.local.port=7199
+REM **** JMX REMOTE ACCESS SETTINGS SEE: https://wiki.apache.org/cassandra/JmxSecurity ***
+REM -Dcom.sun.management.jmxremote.port=7199^
+REM -Dcom.sun.management.jmxremote.ssl=false^
+REM -Dcom.sun.management.jmxremote.authenticate=true^
+REM -Dcom.sun.management.jmxremote.password.file=C:\jmxremote.password
REM ***** CLASSPATH library setting *****
REM Ensure that any user defined CLASSPATH variables are not used on startup
diff --git a/build.xml b/build.xml
index eaef534..cf401e4 100644
--- a/build.xml
+++ b/build.xml
@@ -25,7 +25,7 @@
<property name="debuglevel" value="source,lines,vars"/>
<!-- default version and SCM information -->
- <property name="base.version" value="2.1.3"/>
+ <property name="base.version" value="2.1.4"/>
<property name="scm.connection" value="scm:git://git.apache.org/cassandra.git"/>
<property name="scm.developerConnection" value="scm:git://git.apache.org/cassandra.git"/>
<property name="scm.url" value="http://git-wip-us.apache.org/repos/asf?p=cassandra.git;a=tree"/>
@@ -1113,6 +1113,7 @@
<jvmarg value="-Xss256k"/>
<jvmarg value="-Dcassandra.memtable_row_overhead_computation_step=100"/>
<jvmarg value="-Dcassandra.test.use_prepared=${cassandra.test.use_prepared}"/>
+ <jvmarg value="-Dcassandra.jmx.local.port=7199" />
<jvmarg value="-Dcassandra.test.offsetseed=@{poffset}"/>
<optjvmargs/>
<classpath>
diff --git a/conf/cassandra-env.ps1 b/conf/cassandra-env.ps1
index 9c6b6f4..7a71a13 100644
--- a/conf/cassandra-env.ps1
+++ b/conf/cassandra-env.ps1
@@ -400,10 +400,17 @@
# https://blogs.oracle.com/jmxetc/entry/troubleshooting_connection_problems_in_jconsole
# for more on configuring JMX through firewalls, etc. (Short version:
# get it working with no firewall first.)
- $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT"
- $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false"
- $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
+ #
+ # Due to potential security exploits, Cassandra ships with JMX accessible
+ # *only* from localhost. To enable remote JMX connections, uncomment lines below
+ # with authentication and ssl enabled. See https://wiki.apache.org/cassandra/JmxSecurity
+ #
+ #$env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT"
+ #$env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false"
+ #$env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=true"
#$env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.password.file=C:/jmxremote.password"
+ $env:JVM_OPTS="$env:JVM_OPTS -Dcassandra.jmx.local.port=$JMX_PORT -XX:+DisableExplicitGC"
+
$env:JVM_OPTS="$env:JVM_OPTS $JVM_EXTRA_OPTS"
$env:JVM_OPTS = "$env:JVM_OPTS -Dlog4j.configuration=log4j-server.properties"
diff --git a/conf/cassandra-env.sh b/conf/cassandra-env.sh
index 3f4c21b..58022e6 100644
--- a/conf/cassandra-env.sh
+++ b/conf/cassandra-env.sh
@@ -270,6 +270,22 @@
# https://blogs.oracle.com/jmxetc/entry/troubleshooting_connection_problems_in_jconsole
# for more on configuring JMX through firewalls, etc. (Short version:
# get it working with no firewall first.)
+#
+# Cassandra ships with JMX accessible *only* from localhost.
+# To enable remote JMX connections, uncomment lines below
+# with authentication and/or ssl enabled. See https://wiki.apache.org/cassandra/JmxSecurity
+#
+LOCAL_JMX=yes
+
+if [ "$LOCAL_JMX" = "yes" ]; then
+ JVM_OPTS="$JVM_OPTS -Dcassandra.jmx.local.port=$JMX_PORT -XX:+DisableExplicitGC"
+else
+ JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT"
+ JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT"
+ JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false"
+ JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=true"
+ JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password"
+fi
# To use mx4j, an HTML interface for JMX, add mx4j-tools.jar to the lib/
# directory.
@@ -279,11 +295,6 @@
#MX4J_ADDRESS="-Dmx4jaddress=127.0.0.1"
#MX4J_PORT="-Dmx4jport=8081"
-JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT"
-JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT"
-JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false"
-JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
-#JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password"
JVM_OPTS="$JVM_OPTS $MX4J_ADDRESS"
JVM_OPTS="$JVM_OPTS $MX4J_PORT"
JVM_OPTS="$JVM_OPTS $JVM_EXTRA_OPTS"
diff --git a/debian/changelog b/debian/changelog
index 339da0c..8075460 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+cassandra (2.1.4) unstable; urgency=medium
+
+ * New release
+
+ -- Jake Luciani <jake@apache.org> Fri, 27 Mar 2015 13:48:25 -0400
+
cassandra (2.1.3) unstable; urgency=medium
* New release
diff --git a/src/java/org/apache/cassandra/service/CassandraDaemon.java b/src/java/org/apache/cassandra/service/CassandraDaemon.java
index 50c8295..3e398bf 100644
--- a/src/java/org/apache/cassandra/service/CassandraDaemon.java
+++ b/src/java/org/apache/cassandra/service/CassandraDaemon.java
@@ -23,14 +23,16 @@
import java.lang.management.MemoryPoolMXBean;
import java.net.InetAddress;
import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.server.RMIServerSocketFactory;
+import java.util.*;
+ import java.util.concurrent.TimeUnit;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.StandardMBean;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Uninterruptibles;
@@ -66,9 +68,61 @@
public class CassandraDaemon
{
public static final String MBEAN_NAME = "org.apache.cassandra.db:type=NativeAccess";
+ public static JMXConnectorServer jmxServer = null;
private static final Logger logger = LoggerFactory.getLogger(CassandraDaemon.class);
+ private static void maybeInitJmx()
+ {
+ String jmxPort = System.getProperty("com.sun.management.jmxremote.port");
+
+ if (jmxPort == null)
+ {
+ logger.warn("JMX is not enabled to receive remote connections. Please see cassandra-env.sh for more info.");
+
+ jmxPort = System.getProperty("cassandra.jmx.local.port");
+
+ if (jmxPort == null)
+ {
+ logger.error("cassandra.jmx.local.port missing from cassandra-env.sh, unable to start local JMX service." + jmxPort);
+ }
+ else
+ {
+ System.setProperty("java.rmi.server.hostname","127.0.0.1");
+
+ try
+ {
+ RMIServerSocketFactory serverFactory = new RMIServerSocketFactoryImpl();
+ LocateRegistry.createRegistry(Integer.valueOf(jmxPort), null, serverFactory);
+
+ StringBuffer url = new StringBuffer();
+ url.append("service:jmx:");
+ url.append("rmi://localhost/jndi/");
+ url.append("rmi://localhost:").append(jmxPort).append("/jmxrmi");
+
+ Map env = new HashMap();
+ env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverFactory);
+
+ jmxServer = new RMIConnectorServer(
+ new JMXServiceURL(url.toString()),
+ env,
+ ManagementFactory.getPlatformMBeanServer()
+ );
+
+ jmxServer.start();
+ }
+ catch (IOException e)
+ {
+ logger.error("Error starting local jmx server: ", e);
+ }
+ }
+ }
+ else
+ {
+ logger.info("JMX is enabled to receive remote connections on port: " + jmxPort);
+ }
+ }
+
private static final CassandraDaemon instance = new CassandraDaemon();
/**
@@ -159,6 +213,8 @@
CLibrary.tryMlockall();
+ maybeInitJmx();
+
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
{
public void uncaughtException(Thread t, Throwable e)
@@ -432,6 +488,18 @@
// We rely on the shutdown hook to drain the node
if (FBUtilities.isWindows())
System.exit(0);
+
+ if (jmxServer != null)
+ {
+ try
+ {
+ jmxServer.stop();
+ }
+ catch (IOException e)
+ {
+ logger.error("Error shutting down local JMX server: ", e);
+ }
+ }
}
diff --git a/src/java/org/apache/cassandra/utils/RMIServerSocketFactoryImpl.java b/src/java/org/apache/cassandra/utils/RMIServerSocketFactoryImpl.java
new file mode 100644
index 0000000..75331ab
--- /dev/null
+++ b/src/java/org/apache/cassandra/utils/RMIServerSocketFactoryImpl.java
@@ -0,0 +1,34 @@
+package org.apache.cassandra.utils;
+
+import java.io.IOException;
+import java.net.*;
+import java.rmi.server.RMIServerSocketFactory;
+import javax.net.ServerSocketFactory;
+
+
+public class RMIServerSocketFactoryImpl implements RMIServerSocketFactory
+{
+
+ public ServerSocket createServerSocket(final int pPort) throws IOException {
+ return ServerSocketFactory.getDefault().createServerSocket(pPort, 0, InetAddress.getLoopbackAddress());
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+ if (obj == this)
+ {
+ return true;
+ }
+
+ return obj.getClass().equals(getClass());
+ }
+
+ public int hashCode()
+ {
+ return RMIServerSocketFactoryImpl.class.hashCode();
+ }
+}