1 19 20 package org.netbeans.modules.proxy; 21 22 import javax.net.SocketFactory; 23 import java.io.*; 24 import java.net.*; 25 import java.util.regex.*; 26 import java.nio.channels.SocketChannel ; 27 28 36 public class ClientSocketFactory extends SocketFactory { 37 private static final int CONNECT_TIMEOUT = 1000 * 20; 39 private static final String AUTH_NONE = "<none>"; 40 private static final String AUTH_BASIC = "Basic"; 41 private static final Pattern sConnectionEstablishedPattern = Pattern.compile("HTTP\\/\\d+\\.\\d+\\s+200\\s+"); 42 private static final Pattern sProxyAuthRequiredPattern = Pattern.compile("HTTP\\/\\d+\\.\\d+\\s+407\\s+"); 43 44 private ConnectivitySettings mSettings; 45 46 51 public ClientSocketFactory(ConnectivitySettings settings) { 52 mSettings = settings; 53 } 54 55 59 public Socket createSocket() throws IOException { 60 return new Socket() { 61 public void connect(SocketAddress endpoint, int timeout) throws IOException { 62 Socket s = createSocket((InetSocketAddress)endpoint, timeout); 63 s.close(); 64 } 65 66 public void bind(SocketAddress bindpoint) { 67 throw new UnsupportedOperationException (); 68 } 69 70 protected Object clone() { 71 throw new UnsupportedOperationException (); 72 } 73 74 public synchronized void close() { 75 } 76 77 public void connect(SocketAddress endpoint) { 78 throw new UnsupportedOperationException (); 79 } 80 81 public SocketChannel getChannel() { 82 throw new UnsupportedOperationException (); 83 } 84 85 public InetAddress getInetAddress() { 86 throw new UnsupportedOperationException (); 87 } 88 89 public InputStream getInputStream() { 90 throw new UnsupportedOperationException (); 91 } 92 93 public boolean getKeepAlive() { 94 throw new UnsupportedOperationException (); 95 } 96 97 public InetAddress getLocalAddress() { 98 throw new UnsupportedOperationException (); 99 } 100 101 public int getLocalPort() { 102 throw new UnsupportedOperationException (); 103 } 104 105 public SocketAddress getLocalSocketAddress() { 106 throw new UnsupportedOperationException (); 107 } 108 109 public boolean getOOBInline() { 110 throw new UnsupportedOperationException (); 111 } 112 113 public OutputStream getOutputStream() { 114 throw new UnsupportedOperationException (); 115 } 116 117 public int getPort() { 118 throw new UnsupportedOperationException (); 119 } 120 121 public synchronized int getReceiveBufferSize() { 122 throw new UnsupportedOperationException (); 123 } 124 125 public SocketAddress getRemoteSocketAddress() { 126 throw new UnsupportedOperationException (); 127 } 128 129 public boolean getReuseAddress() { 130 throw new UnsupportedOperationException (); 131 } 132 133 public synchronized int getSendBufferSize() { 134 throw new UnsupportedOperationException (); 135 } 136 137 public int getSoLinger() { 138 throw new UnsupportedOperationException (); 139 } 140 141 public synchronized int getSoTimeout() { 142 throw new UnsupportedOperationException (); 143 } 144 145 public boolean getTcpNoDelay() { 146 throw new UnsupportedOperationException (); 147 } 148 149 public int getTrafficClass() { 150 throw new UnsupportedOperationException (); 151 } 152 153 public boolean isBound() { 154 throw new UnsupportedOperationException (); 155 } 156 157 public boolean isClosed() { 158 throw new UnsupportedOperationException (); 159 } 160 161 public boolean isConnected() { 162 throw new UnsupportedOperationException (); 163 } 164 165 public boolean isInputShutdown() { 166 throw new UnsupportedOperationException (); 167 } 168 169 public boolean isOutputShutdown() { 170 throw new UnsupportedOperationException (); 171 } 172 173 public void sendUrgentData(int data) { 174 throw new UnsupportedOperationException (); 175 } 176 177 public void setKeepAlive(boolean on) { 178 throw new UnsupportedOperationException (); 179 } 180 181 public void setOOBInline(boolean on) { 182 throw new UnsupportedOperationException (); 183 } 184 185 public synchronized void setReceiveBufferSize(int size) { 186 throw new UnsupportedOperationException (); 187 } 188 189 public void setReuseAddress(boolean on) { 190 throw new UnsupportedOperationException (); 191 } 192 193 public synchronized void setSendBufferSize(int size) { 194 throw new UnsupportedOperationException (); 195 } 196 197 public void setSoLinger(boolean on, int linger) { 198 throw new UnsupportedOperationException (); 199 } 200 201 public synchronized void setSoTimeout(int timeout) { 202 throw new UnsupportedOperationException (); 203 } 204 205 public void setTcpNoDelay(boolean on) { 206 throw new UnsupportedOperationException (); 207 } 208 209 public void setTrafficClass(int tc) { 210 throw new UnsupportedOperationException (); 211 } 212 213 public void shutdownInput() { 214 throw new UnsupportedOperationException (); 215 } 216 217 public void shutdownOutput() { 218 throw new UnsupportedOperationException (); 219 } 220 }; 221 } 222 223 public Socket createSocket(String host, int port) throws IOException, UnknownHostException { 224 return createSocket(new InetSocketAddress(host, port), CONNECT_TIMEOUT); 225 } 226 227 public Socket createSocket(InetAddress inetAddress, int port) throws IOException { 228 return createSocket(new InetSocketAddress(inetAddress, port), CONNECT_TIMEOUT); 229 } 230 231 public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, 232 UnknownHostException { 233 throw new IOException("Unsupported operation"); 234 } 235 236 public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { 237 throw new IOException("Unsupported operation"); 238 } 239 240 249 private Socket getHttpsTunnelSocket(InetSocketAddress address, int timeout) throws UnknownHostException, IOException { 250 Socket proxy = new Socket(); 251 proxy.connect(new InetSocketAddress(mSettings.getProxyHost(), mSettings.getProxyPort()), timeout); 252 BufferedReader r = new BufferedReader(new InputStreamReader(new InterruptibleInputStream(proxy.getInputStream()))); 253 DataOutputStream dos = new DataOutputStream(proxy.getOutputStream()); 254 255 dos.writeBytes("CONNECT "); 256 dos.writeBytes(address.getHostName() + ":" + address.getPort()); 257 dos.writeBytes(" HTTP/1.0\r\n"); 258 dos.writeBytes("Connection: Keep-Alive\r\n\r\n"); 259 dos.flush(); 260 261 String line; 262 line = r.readLine(); 263 264 if (sConnectionEstablishedPattern.matcher(line).find()) { 265 for (; ;) { 266 line = r.readLine(); 267 if (line.length() == 0) break; 268 } 269 return proxy; 270 } else if (sProxyAuthRequiredPattern.matcher(line).find()) { 271 boolean authMethodSelected = false; 272 String authMethod = AUTH_NONE; 273 for (; ;) { 274 line = r.readLine(); 275 if (line.length() == 0) break; 276 if (line.startsWith("Proxy-Authenticate:") && !authMethodSelected) { 277 authMethod = line.substring(19).trim(); 278 if (authMethod.equals(AUTH_BASIC)) { 279 authMethodSelected = true; 280 } 281 } 282 } 283 proxy.close(); 285 286 if (authMethod.startsWith(AUTH_BASIC)) { 287 return authenticateBasic(address); 288 } else { 289 throw new IOException("Unsupported authentication method: " + authMethod); 290 } 291 } else { 292 proxy.close(); 293 throw new IOException("HTTP proxy does not support CONNECT command. Received reply: " + line); 294 } 295 } 296 297 305 private Socket authenticateBasic(InetSocketAddress address) throws IOException { 306 Socket proxy = new Socket(mSettings.getProxyHost(), mSettings.getProxyPort()); 307 BufferedReader r = new BufferedReader(new InputStreamReader(new InterruptibleInputStream(proxy.getInputStream()))); 308 DataOutputStream dos = new DataOutputStream(proxy.getOutputStream()); 309 310 String username = mSettings.getProxyUsername() == null ? "" : mSettings.getProxyUsername(); 311 String password = mSettings.getProxyPassword() == null ? "" : String.valueOf(mSettings.getProxyPassword()); 312 String credentials = username + ":" + password; 313 String basicCookie = Base64Encoder.encode(credentials.getBytes("US-ASCII")); 314 315 dos.writeBytes("CONNECT "); 316 dos.writeBytes(address.getHostName() + ":" + address.getPort()); 317 dos.writeBytes(" HTTP/1.0\r\n"); 318 dos.writeBytes("Connection: Keep-Alive\r\n"); 319 dos.writeBytes("Proxy-Authorization: Basic " + basicCookie + "\r\n"); 320 dos.writeBytes("\r\n"); 321 dos.flush(); 322 323 String line = r.readLine(); 324 if (sConnectionEstablishedPattern.matcher(line).find()) { 325 for (; ;) { 326 line = r.readLine(); 327 if (line.length() == 0) break; 328 } 329 return proxy; 330 } 331 throw new IOException("Basic authentication failed: " + line); 332 } 333 334 private Socket getSocks4TunnelSocket(InetSocketAddress address, int timeout) throws IOException { 335 boolean success = false; 336 Socket proxy = new Socket(); 337 proxy.connect(new InetSocketAddress(mSettings.getProxyHost(), mSettings.getProxyPort()), timeout); 338 try { 339 DataInputStream din = new DataInputStream(new InterruptibleInputStream(proxy.getInputStream())); 340 DataOutputStream dos = new DataOutputStream(proxy.getOutputStream()); 341 342 dos.writeByte(4); dos.writeByte(1); dos.writeShort(address.getPort()); 345 InetAddress addr = address.getAddress(); 346 if (addr == null) throw new UnknownHostException(address.getHostName()); 347 byte[] byteAddress = addr.getAddress(); 348 for (int i = 0; i < byteAddress.length; i++) { 349 dos.writeByte(byteAddress[i]); 350 } 351 String uname = mSettings.getProxyUsername(); 352 if (uname != null) { 353 byte[] unamebytes = uname.getBytes(); 354 for (int i = 0; i < unamebytes.length; i++) { 355 dos.writeByte(unamebytes[i]); 356 } 357 } 358 dos.writeByte(0); 359 360 int replyVersion = din.read(); 361 if (replyVersion != 0) throw new IOException("socks4.not.available." + replyVersion); 362 int retCode = din.read(); 363 if (retCode != 90) throw new IOException("socks4.error." + retCode); 364 while (din.available() > 0) din.read(); 365 success = true; 366 return proxy; 367 } finally { 368 if (!success) proxy.close(); 369 } 370 } 371 372 private Socket getSocks5TunnelSocket(InetSocketAddress address, int timeout) throws IOException { 373 boolean success = false; 374 int tmp; 375 376 Socket proxy = new Socket(); 377 proxy.connect(new InetSocketAddress(mSettings.getProxyHost(), mSettings.getProxyPort()), timeout); 378 try { 379 DataInputStream din = new DataInputStream(new InterruptibleInputStream(proxy.getInputStream())); 380 DataOutputStream dos = new DataOutputStream(proxy.getOutputStream()); 381 382 dos.write(new byte[]{5, 2, 0, 2}); 384 385 int serverVersion = din.read(); 386 if (serverVersion != 5) throw new IOException("SOCKS5 protocol error: version: " + serverVersion); 387 int authMethod = din.read(); 388 if (authMethod == 0xFF) throw new IOException("SOCKS5 authentication failure: no supported method acccepted by server"); 389 390 if (authMethod == 2) { 391 dos.writeByte(1); String uname = mSettings.getProxyUsername(); 393 byte[] unamebytes = (uname == null) ? new byte[]{} : uname.getBytes(); 394 dos.writeByte(unamebytes.length); 395 for (int i = 0; i < unamebytes.length; i++) { 396 dos.writeByte(unamebytes[i]); 397 } 398 String pwd = null; 399 if (mSettings.getProxyPassword() != null) { 400 pwd = new String (mSettings.getProxyPassword()); 401 } 402 byte[] pwdbytes = (pwd == null) ? new byte[]{} : pwd.getBytes(); 403 dos.writeByte(pwdbytes.length); 404 for (int i = 0; i < pwdbytes.length; i++) { 405 dos.writeByte(pwdbytes[i]); 406 } 407 408 tmp = din.read(); 409 if (tmp != 1) throw new IOException("socks5.auth.error." + tmp); 410 tmp = din.read(); 411 if (tmp != 0) throw new IOException("socks5.auth.error." + tmp); 412 } 413 414 String hostName = address.getHostName(); 415 dos.write(new byte[]{5, 1, 0, 3, (byte) hostName.length()}); 417 dos.writeBytes(hostName); 418 dos.writeShort(address.getPort()); 419 420 serverVersion = din.read(); 421 if (serverVersion != 5) throw new IOException("SOCKS5 protocol error: version: " + serverVersion); 422 tmp = din.read(); 423 if (tmp != 0) throw new IOException("SOCKS5 protocol error: " + tmp); 424 tmp = din.read(); 425 if (tmp != 0) throw new IOException("SOCKS5 protocol error: " + tmp); 426 int addrType = din.read(); 427 if (addrType == -1) throw new IOException("SOCKS5 protocol error: " + addrType); 428 for (int i = 0; i < 4; i++) { 430 tmp = din.read(); 431 if (tmp == -1) throw new IOException("SOCKS5 error: " + tmp); 432 } 433 tmp = din.read(); 435 tmp = din.read(); 436 success = true; 437 return proxy; 438 } finally { 439 if (!success) proxy.close(); 440 } 441 } 442 443 452 private Socket createSocket(InetSocketAddress address, int timeout) throws UnknownHostException, IOException { 453 String socksProxyHost = System.getProperty("socksProxyHost"); 454 System.getProperties().remove("socksProxyHost"); 455 try 456 { 457 switch (mSettings.getConnectionType()) { 458 case ConnectivitySettings.CONNECTION_VIA_SOCKS: 459 try { 460 return getSocks5TunnelSocket(address, timeout); 461 } catch (IOException e) { 462 return getSocks4TunnelSocket(address, timeout); 463 } 464 465 case ConnectivitySettings.CONNECTION_DIRECT: 466 Socket s = new Socket(); 467 s.connect(address, timeout); 468 return s; 469 470 case ConnectivitySettings.CONNECTION_VIA_HTTPS: 471 return getHttpsTunnelSocket(address, timeout); 472 473 default: 474 throw new IOException("Illegal connection type: " + mSettings.getConnectionType()); 475 } 476 } finally { 477 if (socksProxyHost != null) { 478 System.setProperty("socksProxyHost", socksProxyHost); 479 } 480 } 481 } 482 483 } 484 | Popular Tags |