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      public static void bind(final SocketChannel socketChannel, final SocketAddress address) throws IOException {
100         try {
101             AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
102                 @Override
103                 public Void run() throws IOException {
104                     socketChannel.bind(address);
105                     return null;
106                 }
107             });
108         } catch (PrivilegedActionException e) {
109             throw (IOException) e.getCause();
110         }
111     }
112 
113     public static SocketChannel accept(final ServerSocketChannel serverSocketChannel) throws IOException {
114         try {
115             return AccessController.doPrivileged(new PrivilegedExceptionAction<SocketChannel>() {
116                 @Override
117                 public SocketChannel run() throws IOException {
118                     return serverSocketChannel.accept();
119                 }
120             });
121         } catch (PrivilegedActionException e) {
122             throw (IOException) e.getCause();
123         }
124     }
125 
126     public static void bind(final DatagramChannel networkChannel, final SocketAddress address) throws IOException {
127         try {
128             AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
129                 @Override
130                 public Void run() throws IOException {
131                     networkChannel.bind(address);
132                     return null;
133                 }
134             });
135         } catch (PrivilegedActionException e) {
136             throw (IOException) e.getCause();
137         }
138     }
139 
140     public static SocketAddress localSocketAddress(final ServerSocket socket) {
141         return AccessController.doPrivileged(new PrivilegedAction<SocketAddress>() {
142             @Override
143             public SocketAddress run() {
144                 return socket.getLocalSocketAddress();
145             }
146         });
147     }
148 
149     public static InetAddress addressByName(final String hostname) throws UnknownHostException {
150         try {
151             return AccessController.doPrivileged(new PrivilegedExceptionAction<InetAddress>() {
152                 @Override
153                 public InetAddress run() throws UnknownHostException {
154                     return InetAddress.getByName(hostname);
155                 }
156             });
157         } catch (PrivilegedActionException e) {
158             throw (UnknownHostException) e.getCause();
159         }
160     }
161 
162     public static InetAddress[] allAddressesByName(final String hostname) throws UnknownHostException {
163         try {
164             return AccessController.doPrivileged(new PrivilegedExceptionAction<InetAddress[]>() {
165                 @Override
166                 public InetAddress[] run() throws UnknownHostException {
167                     return InetAddress.getAllByName(hostname);
168                 }
169             });
170         } catch (PrivilegedActionException e) {
171             throw (UnknownHostException) e.getCause();
172         }
173     }
174 
175     public static InetSocketAddress socketAddress(final String hostname, final int port) {
176         return AccessController.doPrivileged(new PrivilegedAction<InetSocketAddress>() {
177             @Override
178             public InetSocketAddress run() {
179                 return new InetSocketAddress(hostname, port);
180             }
181         });
182     }
183 
184     public static Enumeration<InetAddress> addressesFromNetworkInterface(final NetworkInterface intf) {
185         Enumeration<InetAddress> addresses =
186                 AccessController.doPrivileged(new PrivilegedAction<Enumeration<InetAddress>>() {
187             @Override
188             public Enumeration<InetAddress> run() {
189                 return intf.getInetAddresses();
190             }
191         });
192         // Android seems to sometimes return null even if this is not a valid return value by the api docs.
193         // Just return an empty Enumeration in this case.
194         // See https://github.com/netty/netty/issues/10045
195         if (addresses == null) {
196             return empty();
197         }
198         return addresses;
199     }
200 
201     public static InetAddress loopbackAddress() {
202         return AccessController.doPrivileged(new PrivilegedAction<InetAddress>() {
203             @Override
204             public InetAddress run() {
205                 return InetAddress.getLoopbackAddress();
206             }
207         });
208     }
209 
210     public static byte[] hardwareAddressFromNetworkInterface(final NetworkInterface intf) throws SocketException {
211         try {
212             return AccessController.doPrivileged(new PrivilegedExceptionAction<byte[]>() {
213                 @Override
214                 public byte[] run() throws SocketException {
215                     return intf.getHardwareAddress();
216                 }
217             });
218         } catch (PrivilegedActionException e) {
219             throw (SocketException) e.getCause();
220         }
221     }
222 }