| 1 7 package java.net; 8 import java.io.IOException ; 9 import java.io.InputStream ; 10 import java.io.OutputStream ; 11 import java.io.BufferedOutputStream ; 12 import java.security.AccessController ; 13 import java.security.PrivilegedExceptionAction ; 14 import java.util.prefs.Preferences ; 15 import sun.net.www.ParseUtil; 16 17 18 23 24 class SocksSocketImpl extends PlainSocketImpl implements SocksConsts { 25 private String server = null; 26 private int port = DEFAULT_PORT; 27 private InetSocketAddress external_address; 28 private boolean useV4 = false; 29 private Socket cmdsock = null; 30 private InputStream cmdIn = null; 31 private OutputStream cmdOut = null; 32 33 SocksSocketImpl() { 34 } 36 37 SocksSocketImpl(String server, int port) { 38 this.server = server; 39 this.port = (port == -1 ? DEFAULT_PORT : port); 40 } 41 42 SocksSocketImpl(Proxy proxy) { 43 SocketAddress a = proxy.address(); 44 if (a instanceof InetSocketAddress ) { 45 InetSocketAddress ad = (InetSocketAddress ) a; 46 server = ad.getHostString(); 48 port = ad.getPort(); 49 } 50 } 51 52 void setV4() { 53 useV4 = true; 54 } 55 56 private synchronized void privilegedConnect(final String host, 57 final int port, 58 final int timeout) 59 throws IOException  60 { 61 try { 62 AccessController.doPrivileged( 63 new java.security.PrivilegedExceptionAction () { 64 public Object run() throws IOException { 65 superConnectServer(host, port, timeout); 66 cmdIn = getInputStream(); 67 cmdOut = getOutputStream(); 68 return null; 69 } 70 }); 71 } catch (java.security.PrivilegedActionException pae) { 72 throw (IOException ) pae.getException(); 73 } 74 } 75 76 private void superConnectServer(String host, int port, 77 int timeout) throws IOException { 78 super.connect(new InetSocketAddress (host, port), timeout); 79 } 80 81 private int readSocksReply(InputStream in, byte[] data) throws IOException { 82 int len = data.length; 83 int received = 0; 84 for (int attempts = 0; received < len && attempts < 3; attempts++) { 85 int count = in.read(data, received, len - received); 86 if (count < 0) 87 throw new SocketException ("Malformed reply from SOCKS server"); 88 received += count; 89 } 90 return received; 91 } 92 93 96 private boolean authenticate(byte method, InputStream in, 97 BufferedOutputStream out) throws IOException { 98 byte[] data = null; 99 int i; 100 if (method == NO_AUTH) 102 return true; 103 110 if (method == USER_PASSW) { 111 String userName; 112 String password = null; 113 final InetAddress addr = InetAddress.getByName(server); 114 PasswordAuthentication pw = (PasswordAuthentication ) 115 java.security.AccessController.doPrivileged( 116 new java.security.PrivilegedAction () { 117 public Object run() { 118 return Authenticator.requestPasswordAuthentication( 119 server, addr, port, "SOCKS5", "SOCKS authentication", null); 120 } 121 }); 122 if (pw != null) { 123 userName = pw.getUserName(); 124 password = new String (pw.getPassword()); 125 } else { 126 final Preferences prefs = Preferences.userRoot().node("/java/net/socks"); 127 try { 128 userName = 129 (String ) AccessController.doPrivileged( 130 new java.security.PrivilegedExceptionAction () { 131 public Object run() throws IOException { 132 return prefs.get("username", null); 133 } 134 }); 135 } catch (java.security.PrivilegedActionException pae) { 136 throw (IOException ) pae.getException(); 137 } 138 139 if (userName != null) { 140 try { 141 password = 142 (String ) AccessController.doPrivileged( 143 new java.security.PrivilegedExceptionAction () { 144 public Object run() throws IOException { 145 return prefs.get("password", null); 146 } 147 }); 148 } catch (java.security.PrivilegedActionException pae) { 149 throw (IOException ) pae.getException(); 150 } 151 } else { 152 userName = 153 (String ) java.security.AccessController.doPrivileged( 154 new sun.security.action.GetPropertyAction("user.name")); 155 } 156 } 157 if (userName == null) 158 return false; 159 out.write(1); 160 out.write(userName.length()); 161 try { 162 out.write(userName.getBytes("ISO-8859-1")); 163 } catch (java.io.UnsupportedEncodingException uee) { 164 assert false; 165 } 166 if (password != null) { 167 out.write(password.length()); 168 try { 169 out.write(password.getBytes("ISO-8859-1")); 170 } catch (java.io.UnsupportedEncodingException uee) { 171 assert false; 172 } 173 } else 174 out.write(0); 175 out.flush(); 176 data = new byte[2]; 177 i = readSocksReply(in, data); 178 if (i != 2 || data[1] != 0) { 179 181 out.close(); 182 in.close(); 183 return false; 184 } 185 186 return true; 187 } 188 193 return false; 243 } 244 245 private void connectV4(InputStream in, OutputStream out, 246 InetSocketAddress endpoint) throws IOException { 247 if (!(endpoint.getAddress() instanceof Inet4Address )) { 248 throw new SocketException ("SOCKS V4 requires IPv4 only addresses"); 249 } 250 out.write(PROTO_VERS4); 251 out.write(CONNECT); 252 out.write((endpoint.getPort() >> 8) & 0xff); 253 out.write((endpoint.getPort() >> 0) & 0xff); 254 out.write(endpoint.getAddress().getAddress()); 255 String userName = (String ) java.security.AccessController.doPrivileged( 256 new sun.security.action.GetPropertyAction("user.name")); 257 try { 258 out.write(userName.getBytes("ISO-8859-1")); 259 } catch (java.io.UnsupportedEncodingException uee) { 260 assert false; 261 } 262 out.write(0); 263 out.flush(); 264 byte[] data = new byte[8]; 265 int n = readSocksReply(in, data); 266 if (n != 8) 267 throw new SocketException ("Reply from SOCKS server has bad length: " + n); 268 if (data[0] != 0 && data[0] != 4) 269 throw new SocketException ("Reply from SOCKS server has bad version"); 270 SocketException ex = null; 271 switch (data[1]) { 272 case 90: 273 external_address = endpoint; 275 break; 276 case 91: 277 ex = new SocketException ("SOCKS request rejected"); 278 break; 279 case 92: 280 ex = new SocketException ("SOCKS server couldn't reach destination"); 281 break; 282 case 93: 283 ex = new SocketException ("SOCKS authentication failed"); 284 break; 285 default: 286 ex = new SocketException ("Reply from SOCKS server contains bad status"); 287 break; 288 } 289 if (ex != null) { 290 in.close(); 291 out.close(); 292 throw ex; 293 } 294 } 295 296 310 protected void connect(SocketAddress endpoint, int timeout) throws IOException { 311 SecurityManager security = System.getSecurityManager(); 312 if (endpoint == null || !(endpoint instanceof InetSocketAddress )) 313 throw new IllegalArgumentException ("Unsupported address type"); 314 InetSocketAddress epoint = (InetSocketAddress ) endpoint; 315 if (security != null) { 316 if (epoint.isUnresolved()) 317 security.checkConnect(epoint.getHostName(), 318 epoint.getPort()); 319 else 320 security.checkConnect(epoint.getAddress().getHostAddress(), 321 epoint.getPort()); 322 } 323 if (server == null) { 324 ProxySelector sel = (ProxySelector ) 328 java.security.AccessController.doPrivileged( 329 new java.security.PrivilegedAction () { 330 public Object run() { 331 return ProxySelector.getDefault(); 332 } 333 }); 334 if (sel == null) { 335 338 super.connect(epoint, timeout); 339 return; 340 } 341 URI uri = null; 342 String host = epoint.getHostString(); 344 if (epoint.getAddress() instanceof Inet6Address && 346 (!host.startsWith("[")) && (host.indexOf(":") >= 0)) { 347 host = "[" + host + "]"; 348 } 349 try { 350 uri = new URI ("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort()); 351 } catch (URISyntaxException e) { 352 assert false : e; 354 } 355 Proxy p = null; 356 IOException savedExc = null; 357 java.util.Iterator <Proxy > iProxy = null; 358 iProxy = sel.select(uri).iterator(); 359 if (iProxy == null || !(iProxy.hasNext())) { 360 super.connect(epoint, timeout); 361 return; 362 } 363 while (iProxy.hasNext()) { 364 p = iProxy.next(); 365 if (p == null || p == Proxy.NO_PROXY) { 366 super.connect(epoint, timeout); 367 return; 368 } 369 if (p.type() != Proxy.Type.SOCKS) 370 throw new SocketException ("Unknown proxy type : " + p.type()); 371 if (!(p.address() instanceof InetSocketAddress )) 372 throw new SocketException ("Unknow address type for proxy: " + p); 373 server = ((InetSocketAddress ) p.address()).getHostString(); 375 port = ((InetSocketAddress ) p.address()).getPort(); 376 377 try { 379 privilegedConnect(server, port, timeout); 380 break; 382 } catch (IOException e) { 383 sel.connectFailed(uri,p.address(),e); 385 server = null; 386 port = -1; 387 savedExc = e; 388 } 390 } 391 392 396 if (server == null) { 397 throw new SocketException ("Can't connect to SOCKS proxy:" 398 + savedExc.getMessage()); 399 } 400 } else { 401 try { 403 privilegedConnect(server, port, timeout); 404 } catch (IOException e) { 405 throw new SocketException (e.getMessage()); 406 } 407 } 408 409 BufferedOutputStream out = new BufferedOutputStream (cmdOut, 512); 411 InputStream in = cmdIn; 412 413 if (useV4) { 414 if (epoint.isUnresolved()) 417 throw new UnknownHostException (epoint.toString()); 418 connectV4(in, out, epoint); 419 return; 420 } 421 422 out.write(PROTO_VERS); 424 out.write(2); 425 out.write(NO_AUTH); 426 out.write(USER_PASSW); 427 out.flush(); 428 byte[] data = new byte[2]; 429 int i = readSocksReply(in, data); 430 if (i != 2 || ((int)data[0]) != PROTO_VERS) { 431 if (epoint.isUnresolved()) 436 throw new UnknownHostException (epoint.toString()); 437 connectV4(in, out, epoint); 438 return; 439 } 440 if (((int)data[1]) == NO_METHODS) 441 throw new SocketException ("SOCKS : No acceptable methods"); 442 if (!authenticate(data[1], in, out)) { 443 throw new SocketException ("SOCKS : authentication failed"); 444 } 445 out.write(PROTO_VERS); 446 out.write(CONNECT); 447 out.write(0); 448 449 if (epoint.isUnresolved()) { 450 out.write(DOMAIN_NAME); 451 out.write(epoint.getHostName().length()); 452 try { 453 out.write(epoint.getHostName().getBytes("ISO-8859-1")); 454 } catch (java.io.UnsupportedEncodingException uee) { 455 assert false; 456 } 457 out.write((epoint.getPort() >> 8) & 0xff); 458 out.write((epoint.getPort() >> 0) & 0xff); 459 } else if (epoint.getAddress() instanceof Inet6Address ) { 460 out.write(IPV6); 461 out.write(epoint.getAddress().getAddress()); 462 out.write((epoint.getPort() >> 8) & 0xff); 463 out.write((epoint.getPort() >> 0) & 0xff); 464 } else { 465 out.write(IPV4); 466 out.write(epoint.getAddress().getAddress()); 467 out.write((epoint.getPort() >> 8) & 0xff); 468 out.write((epoint.getPort() >> 0) & 0xff); 469 } 470 out.flush(); 471 data = new byte[4]; 472 i = readSocksReply(in, data); 473 if (i != 4) 474 throw new SocketException ("Reply from SOCKS server has bad length"); 475 SocketException ex = null; 476 int nport, len; 477 byte[] addr; 478 switch (data[1]) { 479 case REQUEST_OK: 480 switch(data[3]) { 482 case IPV4: 483 addr = new byte[4]; 484 i = readSocksReply(in, addr); 485 if (i != 4) 486 throw new SocketException ("Reply from SOCKS server badly formatted"); 487 data = new byte[2]; 488 i = readSocksReply(in, data); 489 if (i != 2) 490 throw new SocketException ("Reply from SOCKS server badly formatted"); 491 nport = ((int)data[0] & 0xff) << 8; 492 nport += ((int)data[1] & 0xff); 493 break; 494 case DOMAIN_NAME: 495 len = data[1]; 496 byte[] host = new byte[len]; 497 i = readSocksReply(in, host); 498 if (i != len) 499 throw new SocketException ("Reply from SOCKS server badly formatted"); 500 data = new byte[2]; 501 i = readSocksReply(in, data); 502 if (i != 2) 503 throw new SocketException ("Reply from SOCKS server badly formatted"); 504 nport = ((int)data[0] & 0xff) << 8; 505 nport += ((int)data[1] & 0xff); 506 break; 507 case IPV6: 508 len = data[1]; 509 addr = new byte[len]; 510 i = readSocksReply(in, addr); 511 if (i != len) 512 throw new SocketException ("Reply from SOCKS server badly formatted"); 513 data = new byte[2]; 514 i = readSocksReply(in, data); 515 if (i != 2) 516 throw new SocketException ("Reply from SOCKS server badly formatted"); 517 nport = ((int)data[0] & 0xff) << 8; 518 nport += ((int)data[1] & 0xff); 519 break; 520 default: 521 ex = new SocketException ("Reply from SOCKS server contains wrong code"); 522 break; 523 } 524 break; 525 case GENERAL_FAILURE: 526 ex = new SocketException ("SOCKS server general failure"); 527 break; 528 case NOT_ALLOWED: 529 ex = new SocketException ("SOCKS: Connection not allowed by ruleset"); 530 break; 531 case NET_UNREACHABLE: 532 ex = new SocketException ("SOCKS: Network unreachable"); 533 break; 534 case HOST_UNREACHABLE: 535 ex = new SocketException ("SOCKS: Host unreachable"); 536 break; 537 case CONN_REFUSED: 538 ex = new SocketException ("SOCKS: Connection refused"); 539 break; 540 case TTL_EXPIRED: 541 ex = new SocketException ("SOCKS: TTL expired"); 542 break; 543 case CMD_NOT_SUPPORTED: 544 ex = new SocketException ("SOCKS: Command not supported"); 545 break; 546 case ADDR_TYPE_NOT_SUP: 547 ex = new SocketException ("SOCKS: address type not supported"); 548 break; 549 } 550 if (ex != null) { 551 in.close(); 552 out.close(); 553 throw ex; 554 } 555 external_address = epoint; 556 } 557 558 private void bindV4(InputStream in, OutputStream out, 559 InetAddress baddr, 560 int lport) throws IOException { 561 if (!(baddr instanceof Inet4Address )) { 562 throw new SocketException ("SOCKS V4 requires IPv4 only addresses"); 563 } 564 super.bind(baddr, lport); 565 byte[] addr1 = baddr.getAddress(); 566 567 InetAddress naddr = baddr; 568 if (naddr.isAnyLocalAddress()) { 569 naddr = cmdsock.getLocalAddress(); 570 addr1 = naddr.getAddress(); 571 } 572 out.write(PROTO_VERS4); 573 out.write(BIND); 574 out.write((super.getLocalPort() >> 8) & 0xff); 575 out.write((super.getLocalPort() >> 0) & 0xff); 576 out.write(addr1); 577 String userName = (String ) java.security.AccessController.doPrivileged( 578 new sun.security.action.GetPropertyAction("user.name")); 579 try { 580 out.write(userName.getBytes("ISO-8859-1")); 581 } catch (java.io.UnsupportedEncodingException uee) { 582 assert false; 583 } 584 out.write(0); 585 out.flush(); 586 byte[] data = new byte[8]; 587 int n = readSocksReply(in, data); 588 if (n != 8) 589 throw new SocketException ("Reply from SOCKS server has bad length: " + n); 590 if (data[0] != 0 && data[0] != 4) 591 throw new SocketException ("Reply from SOCKS server has bad version"); 592 SocketException ex = null; 593 switch (data[1]) { 594 case 90: 595 external_address = new InetSocketAddress (baddr, lport); 597 break; 598 case 91: 599 ex = new SocketException ("SOCKS request rejected"); 600 break; 601 case 92: 602 ex = new SocketException ("SOCKS server couldn't reach destination"); 603 break; 604 case 93: 605 ex = new SocketException ("SOCKS authentication failed"); 606 break; 607 default: 608 ex = new SocketException ("Reply from SOCKS server contains bad status"); 609 break; 610 } 611 if (ex != null) { 612 in.close(); 613 out.close(); 614 throw ex; 615 } 616 617 } 618 619 627 protected synchronized void socksBind(InetSocketAddress saddr) throws IOException { 628 if (socket != null) { 629 return; 632 } 633 634 636 if (server == null) { 637 ProxySelector sel = (ProxySelector ) 641 java.security.AccessController.doPrivileged( 642 new java.security.PrivilegedAction () { 643 public Object run() { 644 return ProxySelector.getDefault(); 645 } 646 }); 647 if (sel == null) { 648 651 return; 652 } 653 URI uri = null; 654 String host = saddr.getHostString(); 656 if (saddr.getAddress() instanceof Inet6Address && 658 (!host.startsWith("[")) && (host.indexOf(":") >= 0)) { 659 host = "[" + host + "]"; 660 } 661 try { 662 uri = new URI ("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort()); 663 } catch (URISyntaxException e) { 664 assert false : e; 666 } 667 Proxy p = null; 668 Exception savedExc = null; 669 java.util.Iterator <Proxy > iProxy = null; 670 iProxy = sel.select(uri).iterator(); 671 if (iProxy == null || !(iProxy.hasNext())) { 672 return; 673 } 674 while (iProxy.hasNext()) { 675 p = iProxy.next(); 676 if (p == null || p == Proxy.NO_PROXY) { 677 return; 678 } 679 if (p.type() != Proxy.Type.SOCKS) 680 throw new SocketException ("Unknown proxy type : " + p.type()); 681 if (!(p.address() instanceof InetSocketAddress )) 682 throw new SocketException ("Unknow address type for proxy: " + p); 683 server = ((InetSocketAddress ) p.address()).getHostString(); 685 port = ((InetSocketAddress ) p.address()).getPort(); 686 687 try { 689 AccessController.doPrivileged(new PrivilegedExceptionAction () { 690 public Object run() throws Exception { 691 cmdsock = new Socket (new PlainSocketImpl ()); 692 cmdsock.connect(new InetSocketAddress (server, port)); 693 cmdIn = cmdsock.getInputStream(); 694 cmdOut = cmdsock.getOutputStream(); 695 return null; 696 } 697 }); 698 } catch (Exception e) { 699 sel.connectFailed(uri,p.address(),new SocketException (e.getMessage())); 701 server = null; 702 port = -1; 703 cmdsock = null; 704 savedExc = e; 705 } 707 } 708 709 713 if (server == null || cmdsock == null) { 714 throw new SocketException ("Can't connect to SOCKS proxy:" 715 + savedExc.getMessage()); 716 } 717 } else { 718 try { 719 AccessController.doPrivileged(new PrivilegedExceptionAction  |