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