001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.net;
018    
019    import java.io.ByteArrayOutputStream;
020    import java.io.IOException;
021    import java.io.OutputStream;
022    import java.io.Serializable;
023    import java.net.InetAddress;
024    import java.net.Socket;
025    import java.net.UnknownHostException;
026    
027    import javax.net.ssl.SSLSocket;
028    import javax.net.ssl.SSLSocketFactory;
029    
030    import org.apache.logging.log4j.Level;
031    import org.apache.logging.log4j.core.Layout;
032    import org.apache.logging.log4j.core.appender.ManagerFactory;
033    import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
034    import org.apache.logging.log4j.util.Strings;
035    
036    /**
037     *
038     */
039    public class SslSocketManager extends TcpSocketManager {
040        public static final int DEFAULT_PORT = 6514;
041        private static final SslSocketManagerFactory FACTORY = new SslSocketManagerFactory();
042        private final SslConfiguration sslConfig;
043    
044        /**
045         *
046         *
047         * @param name          The unique name of this connection.
048         * @param os            The OutputStream.
049         * @param sock          The Socket.
050         * @param inetAddress          The internet address of the host.
051         * @param host          The name of the host.
052         * @param port          The port number on the host.
053         * @param delay         Reconnection interval.
054         * @param immediateFail
055         * @param layout        The Layout.
056         */
057        public SslSocketManager(final String name, final OutputStream os, final Socket sock, final SslConfiguration sslConfig, final InetAddress inetAddress,
058                                final String host, final int port, final int delay, final boolean immediateFail, final Layout<? extends Serializable> layout) {
059            super(name, os, sock, inetAddress, host, port, delay, immediateFail, layout);
060            this.sslConfig = sslConfig;
061        }
062    
063        private static class SslFactoryData {
064            protected SslConfiguration sslConfig;
065            private final String host;
066            private final int port;
067            private final int delayMillis;
068            private final boolean immediateFail;
069            private final Layout<? extends Serializable> layout;
070    
071            public SslFactoryData(final SslConfiguration sslConfig, final String host, final int port, final int delayMillis, final boolean immediateFail,
072                                  final Layout<? extends Serializable> layout) {
073                this.host = host;
074                this.port = port;
075                this.delayMillis = delayMillis;
076                this.immediateFail = immediateFail;
077                this.layout = layout;
078                this.sslConfig = sslConfig;
079            }
080        }
081    
082        public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port,
083                                                        int delayMillis, final boolean immediateFail, final Layout<? extends Serializable> layout ) {
084            if (Strings.isEmpty(host)) {
085                throw new IllegalArgumentException("A host name is required");
086            }
087            if (port <= 0) {
088                port = DEFAULT_PORT;
089            }
090            if (delayMillis == 0) {
091                delayMillis = DEFAULT_RECONNECTION_DELAY_MILLIS;
092            }
093            return (SslSocketManager) getManager("TLS:" + host + ':' + port,
094                    new SslFactoryData(sslConfig, host, port, delayMillis, immediateFail, layout), FACTORY);
095        }
096    
097        @Override
098        protected Socket createSocket(final String host, final int port) throws IOException {
099            final SSLSocketFactory socketFactory = createSslSocketFactory(sslConfig);
100            return socketFactory.createSocket(host, port);
101        }
102    
103        private static SSLSocketFactory createSslSocketFactory(final SslConfiguration sslConf) {
104            SSLSocketFactory socketFactory;
105    
106            if (sslConf != null) {
107                socketFactory = sslConf.getSslSocketFactory();
108            } else {
109                socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
110            }
111    
112            return socketFactory;
113        }
114    
115    
116        private static class SslSocketManagerFactory implements ManagerFactory<SslSocketManager, SslFactoryData> {
117    
118            private class TlsSocketManagerFactoryException extends Exception {
119    
120                private static final long serialVersionUID = 1L;
121            }
122    
123            @Override
124            public SslSocketManager createManager(final String name, final SslFactoryData data) {
125                InetAddress inetAddress = null;
126                OutputStream os = null;
127                Socket socket = null;
128    
129                try {
130                    inetAddress = resolveAddress(data.host);
131                    socket = createSocket(data);
132                    os = socket.getOutputStream();
133                    checkDelay(data.delayMillis, os);
134                }
135                catch (final IOException e) {
136                    LOGGER.error("SslSocketManager ({})", name, e);
137                    os = new ByteArrayOutputStream();
138                }
139                catch (final TlsSocketManagerFactoryException e) {
140                    LOGGER.catching(Level.DEBUG, e);
141                    return null;
142                }
143                return createManager(name, os, socket, data.sslConfig, inetAddress, data.host, data.port, data.delayMillis, data.immediateFail, data.layout);
144            }
145    
146            private InetAddress resolveAddress(final String hostName) throws TlsSocketManagerFactoryException {
147                InetAddress address;
148    
149                try {
150                    address = InetAddress.getByName(hostName);
151                } catch (final UnknownHostException ex) {
152                    LOGGER.error("Could not find address of {}", hostName, ex);
153                    throw new TlsSocketManagerFactoryException();
154                }
155    
156                return address;
157            }
158    
159            private void checkDelay(final int delay, final OutputStream os) throws TlsSocketManagerFactoryException {
160                if (delay == 0 && os == null) {
161                    throw new TlsSocketManagerFactoryException();
162                }
163            }
164    
165            private Socket createSocket(final SslFactoryData data) throws IOException {
166                SSLSocketFactory socketFactory;
167                SSLSocket socket;
168    
169                socketFactory = createSslSocketFactory(data.sslConfig);
170                socket = (SSLSocket) socketFactory.createSocket(data.host, data.port);
171                return socket;
172            }
173    
174            private SslSocketManager createManager(final String name, final OutputStream os, final Socket socket,
175                    final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
176                    final int delay, final boolean immediateFail, final Layout<? extends Serializable> layout) {
177                return new SslSocketManager(name, os, socket, sslConfig, inetAddress, host, port, delay, immediateFail,
178                        layout);
179            }
180        }
181    }