it.jnrpe.JNRPE Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jnrpe-lib Show documentation
Show all versions of jnrpe-lib Show documentation
A library that implements the NRPE protocol for JAVA applications
The newest version!
/*******************************************************************************
* Copyright (c) 2007, 2014 Massimiliano Ziccardi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package it.jnrpe;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.IdleStateHandler;
import it.jnrpe.commands.CommandInvoker;
import it.jnrpe.commands.CommandRepository;
import it.jnrpe.events.JNRPEStatusEvent;
import it.jnrpe.events.JNRPEStatusEvent.STATUS;
import it.jnrpe.net.JNRPEIdleStateHandler;
import it.jnrpe.net.JNRPERequestDecoder;
import it.jnrpe.net.JNRPEResponseEncoder;
import it.jnrpe.net.JNRPEServerHandler;
import it.jnrpe.plugins.IPluginRepository;
import it.jnrpe.utils.StreamManager;
import java.io.IOException;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Collection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
/**
* This class is the real JNRPE worker. It must be used to start listening for
* NRPE requests
*
* @author Massimiliano Ziccardi
* @version $Revision: 1.0 $
*/
public final class JNRPE {
/**
* The JNRPE logger.
*/
private final JNRPELogger LOG = new JNRPELogger(this);
/**
* The current execution context.
*/
private final IJNRPEExecutionContext context;
/**
* Default number of accepted connections.
*/
static final int DEFAULT_MAX_ACCEPTED_CONNECTIONS = 128;
/**
* The boss group (see netty documentation).
*/
private final EventLoopGroup bossGroup = new NioEventLoopGroup();
/**
* The worker group (see netty documentation).
*/
private final EventLoopGroup workerGroup = new NioEventLoopGroup();
/**
* The default keystore name (used to perform SSL).
*/
private static final String KEYSTORE_NAME = "keys.jks";
/**
* The default keystore password.
*/
private static final String KEYSTORE_PWD = "p@55w0rd";
/**
* The plugin repository to be used to find the requested plugin.
*/
private final IPluginRepository pluginRepository;
/**
* The command repository to be used to find the requested command.
*/
private final CommandRepository commandRepository;
/**
* The list of accepted clients.
*/
private Collection acceptedHostsList = new ArrayList();
/**
* Charset that will be used by JNRPE.
*/
private final Charset charset;
/**
* The maximum number of concurrent connection allowed by JNRPE.
*/
private final int maxAcceptedConnections;
/**
* The maximum number of seconds that JNRPE will wait for a client to send a
* command.
*/
private final int readTimeout;
/**
* The maximum number of seconds that JNRPE will wait for a plugin to
* produce a result.
*/
private final int writeTimeout;
/**
* true
if $ARGxx$ macros must be expanded.
*/
private final boolean acceptParams;
/**
* Instantiates the JNRPE engine.
*
* @param pluginRepo
* The plugin repository object
* @param commandRepo
* The command repository object
*
* @deprecated This constructor will be removed as of version 2.0.5. Use
* {@link JNRPEBuilder} instead
*/
@Deprecated
public JNRPE(final IPluginRepository pluginRepo, final CommandRepository commandRepo) {
if (pluginRepo == null) {
throw new IllegalArgumentException("Plugin repository cannot be null");
}
if (commandRepo == null) {
throw new IllegalArgumentException("Command repository cannot be null");
}
pluginRepository = pluginRepo;
commandRepository = commandRepo;
charset = Charset.forName("UTF-8");
acceptParams = true;
maxAcceptedConnections = DEFAULT_MAX_ACCEPTED_CONNECTIONS;
readTimeout = 10;
writeTimeout = 60;
context = new JNRPEExecutionContext(new JNRPEEventBus(), charset);
}
/**
* Initializes the JNRPE worker.
*
* @param pluginRepo
* The repository containing all the installed plugins
* @param commandRepo
* The repository containing all the configured commands.
* @param newCharset
* The charset that will be used by JNRPE
* @param acceptParameters
* Sets if $ARGxx$ macros should be expanded
* @deprecated This constructor will be removed as of version 2.0.5. Use
* {@link JNRPEBuilder} instead
*/
@Deprecated
public JNRPE(final IPluginRepository pluginRepo, final CommandRepository commandRepo, final Charset newCharset, final boolean acceptParameters) {
if (pluginRepo == null) {
throw new IllegalArgumentException("Plugin repository cannot be null");
}
if (commandRepo == null) {
throw new IllegalArgumentException("Command repository cannot be null");
}
pluginRepository = pluginRepo;
commandRepository = commandRepo;
charset = newCharset;
acceptParams = acceptParameters;
maxAcceptedConnections = DEFAULT_MAX_ACCEPTED_CONNECTIONS;
readTimeout = 10;
writeTimeout = 60;
context = new JNRPEExecutionContext(new JNRPEEventBus(), newCharset);
}
/**
* Constructor used by the {@link JNRPEBuilder} to build an immutable
* instance of {@link JNRPE}.
*
* @param pluginRepo
* The plugin repository object
* @param commandRepo
* The command repository object
* @param newCharset
* The charset that JNRPE will use
* @param acceptParameters
* Sets if $ARGxx$ macros should be expanded
* @param acceptedHostsCollection
* The list of accepted client hosts
* @param maxConnections
* The maximum number of concurrent connections
* @param readTimeoutSeconds
* The maximum number of seconds to wait for the client to send
* the command
* @param writeTimeoutSeconds
* The maximum number of seconds to wait for a plugin to return a
* result
*/
JNRPE(final IPluginRepository pluginRepo,
final CommandRepository commandRepo,
final Charset newCharset,
final boolean acceptParameters,
final Collection acceptedHostsCollection,
final int maxConnections,
final int readTimeoutSeconds,
final int writeTimeoutSeconds) {
if (pluginRepo == null) {
throw new IllegalArgumentException("Plugin repository cannot be null");
}
if (commandRepo == null) {
throw new IllegalArgumentException("Command repository cannot be null");
}
pluginRepository = pluginRepo;
commandRepository = commandRepo;
charset = newCharset;
acceptParams = acceptParameters;
acceptedHostsList = acceptedHostsCollection;
maxAcceptedConnections = maxConnections;
readTimeout = readTimeoutSeconds;
writeTimeout = writeTimeoutSeconds;
context = new JNRPEExecutionContext(new JNRPEEventBus(), newCharset);
}
/**
* Instructs the server to listen to the given IP/port.
*
* @param address
* The address to bind to
* @param port
* The port to bind to
* @throws UnknownHostException
* - */
public void listen(final String address, final int port) throws UnknownHostException {
listen(address, port, true);
}
/**
* Creates, configures and returns the SSL engine.
*
* @return the SSL Engine * @throws KeyStoreException
* on keystore errorss * @throws CertificateException
* on certificate errors * @throws IOException
* on I/O errors * @throws UnrecoverableKeyException
* if key is unrecoverable * @throws KeyManagementException
* key management error */
private SSLEngine getSSLEngine() throws KeyStoreException,
CertificateException,
IOException,
UnrecoverableKeyException,
KeyManagementException {
// Open the KeyStore Stream
final StreamManager streamManager = new StreamManager();
SSLContext ctx;
KeyManagerFactory kmf;
try {
final InputStream ksStream = getClass().getClassLoader().getResourceAsStream(KEYSTORE_NAME);
streamManager.handle(ksStream);
ctx = SSLContext.getInstance("SSLv3");
kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
final KeyStore ks = KeyStore.getInstance("JKS");
char[] passphrase = KEYSTORE_PWD.toCharArray();
ks.load(ksStream, passphrase);
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), null, new java.security.SecureRandom());
} catch (NoSuchAlgorithmException e) {
throw new SSLException("Unable to initialize SSLSocketFactory" + e.getMessage(), e);
} finally {
streamManager.closeAll();
}
return ctx.createSSLEngine();
}
/**
* Creates and returns a configured NETTY ServerBootstrap object.
*
* @param useSSL
* true
if SSL must be used.
* @return the server bootstrap object */
private ServerBootstrap getServerBootstrap(final boolean useSSL) {
final CommandInvoker invoker = new CommandInvoker(pluginRepository, commandRepository, acceptParams, getExecutionContext());
final ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() {
@Override
public void initChannel(final SocketChannel ch) throws Exception {
if (useSSL) {
final SSLEngine engine = getSSLEngine();
engine.setEnabledCipherSuites(engine.getSupportedCipherSuites());
engine.setUseClientMode(false);
engine.setNeedClientAuth(false);
ch.pipeline().addLast("ssl", new SslHandler(engine));
}
ch.pipeline()
.addLast(new JNRPERequestDecoder(), new JNRPEResponseEncoder(), new JNRPEServerHandler(invoker, context))
.addLast("idleStateHandler", new IdleStateHandler(readTimeout, writeTimeout, 0))
.addLast(
"jnrpeIdleStateHandler",
new JNRPEIdleStateHandler(context));
}
}).option(ChannelOption.SO_BACKLOG, maxAcceptedConnections).childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE);
return serverBootstrap;
}
/**
* Starts a new thread that listen for requests. The method is not
* blocking
*
* @param address
* The address to bind to
* @param port
* The listening port
* @param useSSL
* true
if an SSL socket must be created.
* @throws UnknownHostException
* - */
public void listen(final String address, final int port, final boolean useSSL) throws UnknownHostException {
// Bind and start to accept incoming connections.
ChannelFuture cf = getServerBootstrap(useSSL).bind(address, port);
cf.addListener(new ChannelFutureListener() {
public void operationComplete(final ChannelFuture future) throws Exception {
if (future.isSuccess()) {
context.getEventBus().post(new JNRPEStatusEvent(STATUS.STARTED, this, "JNRPE Server started"));
LOG.info(context, "Listening on " + (useSSL ? "SSL/" : "") + address + ":" + port);
} else {
getExecutionContext().getEventBus().post(new JNRPEStatusEvent(STATUS.FAILED, this, "JNRPE Server start failed"));
LOG.error(context, "Unable to listen on " + (useSSL ? "SSL/" : "") + address + ":" + port, future.cause());
}
}
});
}
/**
* Adds an address to the list of accepted hosts.
*
* @param address
* The address to accept
* @deprecated The JNRPE object will become immutable as of version 2.0.5.
* Use {@link JNRPEBuilder} instead
*/
@Deprecated
public void addAcceptedHost(final String address) {
acceptedHostsList.add(address);
}
/**
* Returns the current JNRPE Execution context. An execution context
* contains useful informations such the encoding to be used ad the list of
* listeners configured to receive the events.
*
* @return the current JNRPE Execution context. */
public IJNRPEExecutionContext getExecutionContext() {
//return new JNRPEExecutionContext(eventBus, charset, pluginRepository, commandRepository);
return context;
}
/**
* Shuts down the server.
*/
public void shutdown() {
workerGroup.shutdownGracefully().syncUninterruptibly();
bossGroup.shutdownGracefully().syncUninterruptibly();
getExecutionContext().getEventBus().post(new JNRPEStatusEvent(STATUS.STOPPED, this, "JNRPE Server stopped"));
}
/**
* Method toString.
* @return String
*/
@Override
public String toString() {
return "JNRPE [LOG=" + LOG + ", context=" + context + ", bossGroup=" + bossGroup + ", workerGroup=" + workerGroup + ", pluginRepository="
+ pluginRepository + ", commandRepository=" + commandRepository + ", acceptedHostsList=" + acceptedHostsList + ", charset=" + charset
+ ", maxAcceptedConnections=" + maxAcceptedConnections + ", readTimeout=" + readTimeout + ", writeTimeout=" + writeTimeout
+ ", acceptParams=" + acceptParams + "]";
}
}