1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package it.jnrpe;
17
18 import io.netty.bootstrap.ServerBootstrap;
19 import io.netty.channel.ChannelFuture;
20 import io.netty.channel.ChannelFutureListener;
21 import io.netty.channel.ChannelInitializer;
22 import io.netty.channel.ChannelOption;
23 import io.netty.channel.EventLoopGroup;
24 import io.netty.channel.nio.NioEventLoopGroup;
25 import io.netty.channel.socket.SocketChannel;
26 import io.netty.channel.socket.nio.NioServerSocketChannel;
27 import io.netty.handler.ssl.SslHandler;
28 import io.netty.handler.timeout.IdleStateHandler;
29 import it.jnrpe.commands.CommandInvoker;
30 import it.jnrpe.commands.CommandRepository;
31 import it.jnrpe.events.EventsUtil;
32 import it.jnrpe.events.IJNRPEEventListener;
33 import it.jnrpe.events.LogEvent;
34 import it.jnrpe.net.JNRPEIdleStateHandler;
35 import it.jnrpe.net.JNRPERequestDecoder;
36 import it.jnrpe.net.JNRPEResponseEncoder;
37 import it.jnrpe.net.JNRPEServerHandler;
38 import it.jnrpe.plugins.IPluginRepository;
39 import it.jnrpe.utils.StreamManager;
40
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.net.UnknownHostException;
44 import java.nio.charset.Charset;
45 import java.security.KeyManagementException;
46 import java.security.KeyStore;
47 import java.security.KeyStoreException;
48 import java.security.NoSuchAlgorithmException;
49 import java.security.UnrecoverableKeyException;
50 import java.security.cert.CertificateException;
51 import java.util.ArrayList;
52 import java.util.Collection;
53 import java.util.HashSet;
54
55 import javax.net.ssl.KeyManagerFactory;
56 import javax.net.ssl.SSLContext;
57 import javax.net.ssl.SSLEngine;
58 import javax.net.ssl.SSLException;
59
60
61
62
63
64
65
66 public final class JNRPE {
67
68
69
70
71 static final int DEFAULT_MAX_ACCEPTED_CONNECTIONS = 128;
72
73
74
75
76 private final EventLoopGroup bossGroup = new NioEventLoopGroup();
77
78
79
80
81 private final EventLoopGroup workerGroup = new NioEventLoopGroup();
82
83
84
85
86 private static final String KEYSTORE_NAME = "keys.jks";
87
88
89
90
91 private static final String KEYSTORE_PWD = "p@55w0rd";
92
93
94
95
96 private final IPluginRepository pluginRepository;
97
98
99
100 private final CommandRepository commandRepository;
101
102
103
104
105 private Collection<String> acceptedHostsList = new ArrayList<String>();
106
107
108
109
110 private Collection<IJNRPEEventListener> eventListenersSet = new HashSet<IJNRPEEventListener>();
111
112
113
114
115 private final Charset charset;
116
117
118
119
120 private final int maxAcceptedConnections;
121
122
123
124
125
126 private final int readTimeout;
127
128
129
130
131
132 private final int writeTimeout;
133
134
135
136
137 private final boolean acceptParams;
138
139
140
141
142
143
144
145
146
147
148
149
150 @Deprecated
151 public JNRPE(final IPluginRepository pluginRepo,
152 final CommandRepository commandRepo) {
153 if (pluginRepo == null) {
154 throw new IllegalArgumentException(
155 "Plugin repository cannot be null");
156 }
157
158 if (commandRepo == null) {
159 throw new IllegalArgumentException(
160 "Command repository cannot be null");
161 }
162 pluginRepository = pluginRepo;
163 commandRepository = commandRepo;
164 charset = Charset.forName("UTF-8");
165 this.acceptParams = true;
166 this.maxAcceptedConnections = DEFAULT_MAX_ACCEPTED_CONNECTIONS;
167 readTimeout = 10;
168 writeTimeout = 60;
169 }
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 @Deprecated
186 public JNRPE(final IPluginRepository pluginRepo,
187 final CommandRepository commandRepo, final Charset newCharset,
188 final boolean acceptParameters) {
189 if (pluginRepo == null) {
190 throw new IllegalArgumentException(
191 "Plugin repository cannot be null");
192 }
193
194 if (commandRepo == null) {
195 throw new IllegalArgumentException(
196 "Command repository cannot be null");
197 }
198 pluginRepository = pluginRepo;
199 commandRepository = commandRepo;
200 this.charset = newCharset;
201 this.acceptParams = acceptParameters;
202 this.maxAcceptedConnections = DEFAULT_MAX_ACCEPTED_CONNECTIONS;
203 readTimeout = 10;
204 writeTimeout = 60;
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 JNRPE(final IPluginRepository pluginRepo,
233 final CommandRepository commandRepo, final Charset newCharset,
234 final boolean acceptParameters,
235 final Collection<String> acceptedHostsCollection,
236 final int maxConnections, final int readTimeoutSeconds,
237 final int writeTimeoutSeconds,
238 final Collection<IJNRPEEventListener> eventListeners) {
239 if (pluginRepo == null) {
240 throw new IllegalArgumentException(
241 "Plugin repository cannot be null");
242 }
243
244 if (commandRepo == null) {
245 throw new IllegalArgumentException(
246 "Command repository cannot be null");
247 }
248 pluginRepository = pluginRepo;
249 commandRepository = commandRepo;
250 this.charset = newCharset;
251 this.acceptParams = acceptParameters;
252 this.acceptedHostsList = acceptedHostsCollection;
253 this.eventListenersSet = eventListeners;
254 this.maxAcceptedConnections = maxConnections;
255 this.readTimeout = readTimeoutSeconds;
256 this.writeTimeout = writeTimeoutSeconds;
257
258 }
259
260
261
262
263
264
265
266
267
268
269
270 public void listen(final String address, final int port)
271 throws UnknownHostException {
272 listen(address, port, true);
273 }
274
275
276
277
278
279
280
281
282
283
284 @Deprecated
285 public void addEventListener(final IJNRPEEventListener listener) {
286 eventListenersSet.add(listener);
287 }
288
289
290
291
292
293
294
295
296
297
298
299 private SSLEngine getSSLEngine() throws KeyStoreException,
300 CertificateException, IOException, UnrecoverableKeyException,
301 KeyManagementException {
302
303
304 StreamManager h = new StreamManager();
305
306 SSLContext ctx;
307 KeyManagerFactory kmf;
308
309 try {
310 InputStream ksStream = getClass().getClassLoader()
311 .getResourceAsStream(KEYSTORE_NAME);
312 h.handle(ksStream);
313 ctx = SSLContext.getInstance("SSLv3");
314
315 kmf = KeyManagerFactory.getInstance(KeyManagerFactory
316 .getDefaultAlgorithm());
317
318 KeyStore ks = KeyStore.getInstance("JKS");
319 char[] passphrase = KEYSTORE_PWD.toCharArray();
320 ks.load(ksStream, passphrase);
321
322 kmf.init(ks, passphrase);
323 ctx.init(kmf.getKeyManagers(), null,
324 new java.security.SecureRandom());
325 } catch (NoSuchAlgorithmException e) {
326 throw new SSLException("Unable to initialize SSLSocketFactory.\n"
327 + e.getMessage());
328 } finally {
329 h.closeAll();
330 }
331
332 return ctx.createSSLEngine();
333 }
334
335
336
337
338
339
340
341
342 private ServerBootstrap getServerBootstrap(final boolean useSSL) {
343
344 final CommandInvoker invoker = new CommandInvoker(pluginRepository,
345 commandRepository, acceptParams, eventListenersSet);
346
347 ServerBootstrap b = new ServerBootstrap();
348 b.group(bossGroup, workerGroup)
349 .channel(NioServerSocketChannel.class)
350 .childHandler(new ChannelInitializer<SocketChannel>() {
351 @Override
352 public void initChannel(final SocketChannel ch)
353 throws Exception {
354
355 if (useSSL) {
356 SSLEngine engine = getSSLEngine();
357 engine.setEnabledCipherSuites(engine
358 .getSupportedCipherSuites());
359 engine.setUseClientMode(false);
360 engine.setNeedClientAuth(false);
361 ch.pipeline()
362 .addLast("ssl", new SslHandler(engine));
363 }
364
365 ch.pipeline()
366 .addLast(
367 new JNRPERequestDecoder(),
368 new JNRPEResponseEncoder(),
369 new JNRPEServerHandler(invoker,
370 eventListenersSet))
371 .addLast(
372 "idleStateHandler",
373 new IdleStateHandler(readTimeout,
374 writeTimeout, 0))
375 .addLast(
376 "jnrpeIdleStateHandler",
377 new JNRPEIdleStateHandler(
378 new JNRPEExecutionContext(
379 JNRPE.this.eventListenersSet,
380 Charset.defaultCharset())));
381 }
382 })
383 .option(ChannelOption.SO_BACKLOG, this.maxAcceptedConnections)
384 .childOption(ChannelOption.SO_KEEPALIVE, true);
385
386 return b;
387 }
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402 public void listen(final String address, final int port,
403 final boolean useSSL) throws UnknownHostException {
404
405
406 ChannelFuture cf = getServerBootstrap(useSSL).bind(address, port);
407 cf.addListener(new ChannelFutureListener() {
408
409 public void operationComplete(final ChannelFuture future)
410 throws Exception {
411 if (future.isSuccess()) {
412 EventsUtil.sendEvent(eventListenersSet, this,
413 LogEvent.INFO, "Listening on "
414 + (useSSL ? "SSL/" : "") + address + ":"
415 + port);
416 } else {
417 EventsUtil.sendEvent(eventListenersSet, this,
418 LogEvent.ERROR, "Unable to listen on "
419 + (useSSL ? "SSL/" : "") + address + ":"
420 + port, future.cause());
421 }
422 }
423 });
424
425 }
426
427
428
429
430
431
432
433
434
435 @Deprecated
436 public void addAcceptedHost(final String address) {
437 acceptedHostsList.add(address);
438 }
439
440
441
442
443 public void shutdown() {
444 workerGroup.shutdownGracefully().syncUninterruptibly();
445 bossGroup.shutdownGracefully().syncUninterruptibly();
446 }
447 }