View Javadoc
1   /*
2    * Copyright 2016 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.util.internal;
17  
18  import java.io.IOException;
19  import java.net.InetAddress;
20  import java.net.InetSocketAddress;
21  import java.net.NetworkInterface;
22  import java.net.ServerSocket;
23  import java.net.Socket;
24  import java.net.SocketAddress;
25  import java.net.SocketException;
26  import java.net.SocketPermission;
27  import java.net.UnknownHostException;
28  import java.nio.channels.DatagramChannel;
29  import java.nio.channels.ServerSocketChannel;
30  import java.nio.channels.SocketChannel;
31  import java.security.AccessController;
32  import java.security.PrivilegedAction;
33  import java.security.PrivilegedActionException;
34  import java.security.PrivilegedExceptionAction;
35  import java.util.Collections;
36  import java.util.Enumeration;
37  
38  /**
39   * Provides socket operations with privileges enabled. This is necessary for applications that use the
40   * {@link SecurityManager} to restrict {@link SocketPermission} to their application. By asserting that these
41   * operations are privileged, the operations can proceed even if some code in the calling chain lacks the appropriate
42   * {@link SocketPermission}.
43   */
44  public final class SocketUtils {
45  
46      private static final Enumeration<Object> EMPTY = Collections.enumeration(Collections.emptyList());
47  
48      private SocketUtils() {
49      }
50  
51      @SuppressWarnings("unchecked")
52      private static <T> Enumeration<T> empty() {
53          return (Enumeration<T>) EMPTY;
54      }
55  
56      public static void connect(final Socket socket, final SocketAddress remoteAddress, final int timeout)
57              throws IOException {
58          try {
59              AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
60                  @Override
61                  public Void run() throws IOException {
62                      socket.connect(remoteAddress, timeout);
63                      return null;
64                  }
65              });
66          } catch (PrivilegedActionException e) {
67              throw (IOException) e.getCause();
68          }
69      }
70  
71      public static void bind(final Socket socket, final SocketAddress bindpoint) throws IOException {
72          try {
73              AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
74                  @Override
75                  public Void run() throws IOException {
76                      socket.bind(bindpoint);
77                      return null;
78                  }
79              });
80          } catch (PrivilegedActionException e) {
81              throw (IOException) e.getCause();
82          }
83      }
84  
85      public static boolean connect(final SocketChannel socketChannel, final SocketAddress remoteAddress)
86              throws IOException {
87          try {
88              return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
89                  @Override
90                  public Boolean run() throws IOException {
91                      return socketChannel.connect(remoteAddress);
92                  }
93              });
94          } catch (PrivilegedActionException e) {
95              throw (IOException) e.getCause();
96          }
97      }
98  
99      @SuppressJava6Requirement(reason = "Usage guarded by java version check")
100     public static void bind(final SocketChannel socketChannel, final SocketAddress address) throws IOException {
101         try {
102             AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
103                 @Override
104                 public Void run() throws IOException {
105                     socketChannel.bind(address);
106                     return null;
107                 }
108             });
109         } catch (PrivilegedActionException e) {
110             throw (IOException) e.getCause();
111         }
112     }
113 
114     public static SocketChannel accept(final ServerSocketChannel serverSocketChannel) throws IOException {
115         try {
116             return AccessController.doPrivileged(new PrivilegedExceptionAction<SocketChannel>() {
117                 @Override
118                 public SocketChannel run() throws IOException {
119                     return serverSocketChannel.accept();
120                 }
121             });
122         } catch (PrivilegedActionException e) {
123             throw (IOException) e.getCause();
124         }
125     }
126 
127     @SuppressJava6Requirement(reason = "Usage guarded by java version check")
128     public static void bind(final DatagramChannel networkChannel, final SocketAddress address) throws IOException {
129         try {
130             AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
131                 @Override
132                 public Void run() throws IOException {
133                     networkChannel.bind(address);
134                     return null;
135                 }
136             });
137         } catch (PrivilegedActionException e) {
138             throw (IOException) e.getCause();
139         }
140     }
141 
142     public static SocketAddress localSocketAddress(final ServerSocket socket) {
143         return AccessController.doPrivileged(new PrivilegedAction<SocketAddress>() {
144             @Override
145             public SocketAddress run() {
146                 return socket.getLocalSocketAddress();
147             }
148         });
149     }
150 
151     public static InetAddress addressByName(final String hostname) throws UnknownHostException {
152         try {
153             return AccessController.doPrivileged(new PrivilegedExceptionAction<InetAddress>() {
154                 @Override
155                 public InetAddress run() throws UnknownHostException {
156                     return InetAddress.getByName(hostname);
157                 }
158             });
159         } catch (PrivilegedActionException e) {
160             throw (UnknownHostException) e.getCause();
161         }
162     }
163 
164     public static InetAddress[] allAddressesByName(final String hostname) throws UnknownHostException {
165         try {
166             return AccessController.doPrivileged(new PrivilegedExceptionAction<InetAddress[]>() {
167                 @Override
168                 public InetAddress[] run() throws UnknownHostException {
169                     return InetAddress.getAllByName(hostname);
170                 }
171             });
172         } catch (PrivilegedActionException e) {
173             throw (UnknownHostException) e.getCause();
174         }
175     }
176 
177     public static InetSocketAddress socketAddress(final String hostname, final int port) {
178         return AccessController.doPrivileged(new PrivilegedAction<InetSocketAddress>() {
179             @Override
180             public InetSocketAddress run() {
181                 return new InetSocketAddress(hostname, port);
182             }
183         });
184     }
185 
186     public static Enumeration<InetAddress> addressesFromNetworkInterface(final NetworkInterface intf) {
187         Enumeration<InetAddress> addresses =
188                 AccessController.doPrivileged(new PrivilegedAction<Enumeration<InetAddress>>() {
189             @Override
190             public Enumeration<InetAddress> run() {
191                 return intf.getInetAddresses();
192             }
193         });
194         // Android seems to sometimes return null even if this is not a valid return value by the api docs.
195         // Just return an empty Enumeration in this case.
196         // See https://github.com/netty/netty/issues/10045
197         if (addresses == null) {
198             return empty();
199         }
200         return addresses;
201     }
202 
203     @SuppressJava6Requirement(reason = "Usage guarded by java version check")
204     public static InetAddress loopbackAddress() {
205         return AccessController.doPrivileged(new PrivilegedAction<InetAddress>() {
206             @Override
207             public InetAddress run() {
208                 if (PlatformDependent.javaVersion() >= 7) {
209                     return InetAddress.getLoopbackAddress();
210                 }
211                 try {
212                     return InetAddress.getByName(null);
213                 } catch (UnknownHostException e) {
214                     throw new IllegalStateException(e);
215                 }
216             }
217         });
218     }
219 
220     public static byte[] hardwareAddressFromNetworkInterface(final NetworkInterface intf) throws SocketException {
221         try {
222             return AccessController.doPrivileged(new PrivilegedExceptionAction<byte[]>() {
223                 @Override
224                 public byte[] run() throws SocketException {
225                     return intf.getHardwareAddress();
226                 }
227             });
228         } catch (PrivilegedActionException e) {
229             throw (SocketException) e.getCause();
230         }
231     }
232 }