fa8793de79e2f0ddb2c8fc20a74bdacc937087e6
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / core / TlsDetector.java
1 /* Copyright (C)2013 Pantheon Technologies, s.r.o. All rights reserved. */
2 package org.opendaylight.openflowjava.protocol.impl.core;
3
4 import io.netty.buffer.ByteBuf;
5 import io.netty.channel.ChannelHandlerContext;
6 import io.netty.channel.ChannelPipeline;
7 import io.netty.handler.codec.ByteToMessageDecoder;
8 import io.netty.handler.ssl.SslHandler;
9
10 import java.util.List;
11
12 import javax.net.ssl.SSLEngine;
13
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16 import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade;
17 import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler.COMPONENT_NAMES;
18 import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils;
19
20 /**
21  * Class for detecting TLS encrypted connection. If TLS encrypted connection is detected,
22  * TLSDetector engages SSLHandler and OFFrameDecoder into pipeline else it engages only
23  * OFFrameDecoder.
24  *
25  * @author michal.polkorab
26  */
27 public class TlsDetector extends ByteToMessageDecoder {
28
29     private boolean detectSsl;
30     private static final Logger LOGGER = LoggerFactory
31             .getLogger(TlsDetector.class);
32     
33     private ConnectionFacade connectionFacade;
34
35     /**
36      * Constructor of class
37      */
38     public TlsDetector() {
39         LOGGER.info("Creating TLS Detector");
40         detectSsl = true;
41     }
42
43     @Override
44     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
45         LOGGER.warn("Unexpected exception from downstream.",
46                 cause);
47         ctx.close();
48     }
49
50     private boolean isSsl(ByteBuf bb) {
51         if (detectSsl) {
52             LOGGER.info("Testing connection for TLS");
53             return SslHandler.isEncrypted(bb);
54         }
55         return false;
56     }
57
58     private static void enableSsl(ChannelHandlerContext ctx) {
59         if (ctx.pipeline().get(COMPONENT_NAMES.SSL_HANDLER.name()) == null) {
60             LOGGER.info("Engaging TLS handler");
61             ChannelPipeline p = ctx.channel().pipeline();
62             SSLEngine engine = SslContextFactory.getServerContext()
63                     .createSSLEngine();
64             engine.setUseClientMode(false);
65             p.addAfter(COMPONENT_NAMES.TLS_DETECTOR.name(), COMPONENT_NAMES.SSL_HANDLER.name(),
66                     new SslHandler(engine));
67         }
68     }
69
70     @Override
71     protected void decode(ChannelHandlerContext ctx, ByteBuf bb,
72             List<Object> list) throws Exception {
73         if (bb.readableBytes() < 5) {
74             return;
75         }
76         if (LOGGER.isDebugEnabled()) {
77             LOGGER.debug(ByteBufUtils.byteBufToHexString(bb));
78         }
79         if (isSsl(bb)) {
80             LOGGER.info("Connection is encrypted");
81             enableSsl(ctx);
82         } else {
83             LOGGER.info("Connection is not encrypted");
84         }
85         
86         if (connectionFacade != null) {
87             LOGGER.debug("Firing onConnectionReady notification");
88             connectionFacade.fireConnectionReadyNotification();
89         }
90         
91         ctx.pipeline().remove(COMPONENT_NAMES.TLS_DETECTOR.name());
92     }
93     
94     /**
95      * @param connectionFacade the connectionFacade to set
96      */
97     public void setConnectionFacade(ConnectionFacade connectionFacade) {
98         this.connectionFacade = connectionFacade;
99     }
100 }