View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.net;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.IOException;
21  import java.io.OutputStream;
22  import java.io.Serializable;
23  import java.net.InetAddress;
24  import java.net.Socket;
25  import java.net.UnknownHostException;
26  
27  import javax.net.ssl.SSLSocket;
28  import javax.net.ssl.SSLSocketFactory;
29  
30  import org.apache.logging.log4j.Level;
31  import org.apache.logging.log4j.core.Layout;
32  import org.apache.logging.log4j.core.appender.ManagerFactory;
33  import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
34  import org.apache.logging.log4j.util.Strings;
35  
36  /**
37   *
38   */
39  public class SslSocketManager extends TcpSocketManager {
40      public static final int DEFAULT_PORT = 6514;
41      private static final SslSocketManagerFactory FACTORY = new SslSocketManagerFactory();
42      private final SslConfiguration sslConfig;
43  
44      /**
45       *
46       *
47       * @param name          The unique name of this connection.
48       * @param os            The OutputStream.
49       * @param sock          The Socket.
50       * @param inetAddress          The internet address of the host.
51       * @param host          The name of the host.
52       * @param port          The port number on the host.
53       * @param delay         Reconnection interval.
54       * @param immediateFail
55       * @param layout        The Layout.
56       */
57      public SslSocketManager(final String name, final OutputStream os, final Socket sock, final SslConfiguration sslConfig, final InetAddress inetAddress,
58                              final String host, final int port, final int delay, final boolean immediateFail, final Layout<? extends Serializable> layout) {
59          super(name, os, sock, inetAddress, host, port, delay, immediateFail, layout);
60          this.sslConfig = sslConfig;
61      }
62  
63      private static class SslFactoryData {
64          protected SslConfiguration sslConfig;
65          private final String host;
66          private final int port;
67          private final int delayMillis;
68          private final boolean immediateFail;
69          private final Layout<? extends Serializable> layout;
70  
71          public SslFactoryData(final SslConfiguration sslConfig, final String host, final int port, final int delayMillis, final boolean immediateFail,
72                                final Layout<? extends Serializable> layout) {
73              this.host = host;
74              this.port = port;
75              this.delayMillis = delayMillis;
76              this.immediateFail = immediateFail;
77              this.layout = layout;
78              this.sslConfig = sslConfig;
79          }
80      }
81  
82      public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port,
83                                                      int delayMillis, final boolean immediateFail, final Layout<? extends Serializable> layout ) {
84          if (Strings.isEmpty(host)) {
85              throw new IllegalArgumentException("A host name is required");
86          }
87          if (port <= 0) {
88              port = DEFAULT_PORT;
89          }
90          if (delayMillis == 0) {
91              delayMillis = DEFAULT_RECONNECTION_DELAY_MILLIS;
92          }
93          return (SslSocketManager) getManager("TLS:" + host + ':' + port,
94                  new SslFactoryData(sslConfig, host, port, delayMillis, immediateFail, layout), FACTORY);
95      }
96  
97      @Override
98      protected Socket createSocket(final String host, final int port) throws IOException {
99          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 }