1. /*
  2. * @(#)SocksSocketImpl.java 1.17 04/04/29
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  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. /* import org.ietf.jgss.*; */
  17. /**
  18. * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
  19. * This is a subclass of PlainSocketImpl.
  20. * Note this class should <b>NOT</b> be public.
  21. */
  22. class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
  23. private String server = null;
  24. private int port = DEFAULT_PORT;
  25. private InetSocketAddress external_address;
  26. private boolean useV4 = false;
  27. private Socket cmdsock = null;
  28. private InputStream cmdIn = null;
  29. private OutputStream cmdOut = null;
  30. SocksSocketImpl() {
  31. // Nothing needed
  32. }
  33. SocksSocketImpl(String server, int port) {
  34. this.server = server;
  35. this.port = (port == -1 ? DEFAULT_PORT : port);
  36. }
  37. SocksSocketImpl(Proxy proxy) {
  38. SocketAddress a = proxy.address();
  39. if (a instanceof InetSocketAddress) {
  40. InetSocketAddress ad = (InetSocketAddress) a;
  41. server = ad.getHostName();
  42. port = ad.getPort();
  43. }
  44. }
  45. void setV4() {
  46. useV4 = true;
  47. }
  48. private synchronized void privilegedConnect(final String host,
  49. final int port,
  50. final int timeout)
  51. throws IOException
  52. {
  53. try {
  54. AccessController.doPrivileged(
  55. new java.security.PrivilegedExceptionAction() {
  56. public Object run() throws IOException {
  57. superConnectServer(host, port, timeout);
  58. cmdIn = getInputStream();
  59. cmdOut = getOutputStream();
  60. return null;
  61. }
  62. });
  63. } catch (java.security.PrivilegedActionException pae) {
  64. throw (IOException) pae.getException();
  65. }
  66. }
  67. private void superConnectServer(String host, int port,
  68. int timeout) throws IOException {
  69. super.connect(new InetSocketAddress(host, port), timeout);
  70. }
  71. private int readSocksReply(InputStream in, byte[] data) throws IOException {
  72. int len = data.length;
  73. int received = 0;
  74. for (int attempts = 0; received < len && attempts < 3; attempts++) {
  75. int count = in.read(data, received, len - received);
  76. if (count < 0)
  77. throw new SocketException("Malformed reply from SOCKS server");
  78. received += count;
  79. }
  80. return received;
  81. }
  82. /**
  83. * Provides the authentication machanism required by the proxy.
  84. */
  85. private boolean authenticate(byte method, InputStream in,
  86. BufferedOutputStream out) throws IOException {
  87. byte[] data = null;
  88. int i;
  89. // No Authentication required. We're done then!
  90. if (method == NO_AUTH)
  91. return true;
  92. /**
  93. * User/Password authentication. Try, in that order :
  94. * - The application provided Authenticator, if any
  95. * - The user preferences java.net.socks.username &
  96. * java.net.socks.password
  97. * - the user.name & no password (backward compatibility behavior).
  98. */
  99. if (method == USER_PASSW) {
  100. String userName;
  101. String password = null;
  102. final InetAddress addr = InetAddress.getByName(server);
  103. PasswordAuthentication pw = (PasswordAuthentication)
  104. java.security.AccessController.doPrivileged(
  105. new java.security.PrivilegedAction() {
  106. public Object run() {
  107. return Authenticator.requestPasswordAuthentication(
  108. server, addr, port, "SOCKS5", "SOCKS authentication", null);
  109. }
  110. });
  111. if (pw != null) {
  112. userName = pw.getUserName();
  113. password = new String(pw.getPassword());
  114. } else {
  115. final Preferences prefs = Preferences.userRoot().node("/java/net/socks");
  116. try {
  117. userName =
  118. (String) AccessController.doPrivileged(
  119. new java.security.PrivilegedExceptionAction() {
  120. public Object run() throws IOException {
  121. return prefs.get("username", null);
  122. }
  123. });
  124. } catch (java.security.PrivilegedActionException pae) {
  125. throw (IOException) pae.getException();
  126. }
  127. if (userName != null) {
  128. try {
  129. password =
  130. (String) AccessController.doPrivileged(
  131. new java.security.PrivilegedExceptionAction() {
  132. public Object run() throws IOException {
  133. return prefs.get("password", null);
  134. }
  135. });
  136. } catch (java.security.PrivilegedActionException pae) {
  137. throw (IOException) pae.getException();
  138. }
  139. } else {
  140. userName =
  141. (String) java.security.AccessController.doPrivileged(
  142. new sun.security.action.GetPropertyAction("user.name"));
  143. }
  144. }
  145. if (userName == null)
  146. return false;
  147. out.write(1);
  148. out.write(userName.length());
  149. try {
  150. out.write(userName.getBytes("ISO-8859-1"));
  151. } catch (java.io.UnsupportedEncodingException uee) {
  152. assert false;
  153. }
  154. if (password != null) {
  155. out.write(password.length());
  156. try {
  157. out.write(password.getBytes("ISO-8859-1"));
  158. } catch (java.io.UnsupportedEncodingException uee) {
  159. assert false;
  160. }
  161. } else
  162. out.write(0);
  163. out.flush();
  164. data = new byte[2];
  165. i = readSocksReply(in, data);
  166. if (i != 2 || data[1] != 0) {
  167. /* RFC 1929 specifies that the connection MUST be closed if
  168. authentication fails */
  169. out.close();
  170. in.close();
  171. return false;
  172. }
  173. /* Authentication succeeded */
  174. return true;
  175. }
  176. /**
  177. * GSSAPI authentication mechanism.
  178. * Unfortunately the RFC seems out of sync with the Reference
  179. * implementation. I'll leave this in for future completion.
  180. */
  181. // if (method == GSSAPI) {
  182. // try {
  183. // GSSManager manager = GSSManager.getInstance();
  184. // GSSName name = manager.createName("SERVICE:socks@"+server,
  185. // null);
  186. // GSSContext context = manager.createContext(name, null, null,
  187. // GSSContext.DEFAULT_LIFETIME);
  188. // context.requestMutualAuth(true);
  189. // context.requestReplayDet(true);
  190. // context.requestSequenceDet(true);
  191. // context.requestCredDeleg(true);
  192. // byte []inToken = new byte[0];
  193. // while (!context.isEstablished()) {
  194. // byte[] outToken
  195. // = context.initSecContext(inToken, 0, inToken.length);
  196. // // send the output token if generated
  197. // if (outToken != null) {
  198. // out.write(1);
  199. // out.write(1);
  200. // out.writeShort(outToken.length);
  201. // out.write(outToken);
  202. // out.flush();
  203. // data = new byte[2];
  204. // i = readSocksReply(in, data);
  205. // if (i != 2 || data[1] == 0xff) {
  206. // in.close();
  207. // out.close();
  208. // return false;
  209. // }
  210. // i = readSocksReply(in, data);
  211. // int len = 0;
  212. // len = ((int)data[0] & 0xff) << 8;
  213. // len += data[1];
  214. // data = new byte[len];
  215. // i = readSocksReply(in, data);
  216. // if (i == len)
  217. // return true;
  218. // in.close();
  219. // out.close();
  220. // }
  221. // }
  222. // } catch (GSSException e) {
  223. // /* RFC 1961 states that if Context initialisation fails the connection
  224. // MUST be closed */
  225. // e.printStackTrace();
  226. // in.close();
  227. // out.close();
  228. // }
  229. // }
  230. return false;
  231. }
  232. private void connectV4(InputStream in, OutputStream out,
  233. InetSocketAddress endpoint) throws IOException {
  234. if (!(endpoint.getAddress() instanceof Inet4Address)) {
  235. throw new SocketException("SOCKS V4 requires IPv4 only addresses");
  236. }
  237. out.write(PROTO_VERS4);
  238. out.write(CONNECT);
  239. out.write((endpoint.getPort() >> 8) & 0xff);
  240. out.write((endpoint.getPort() >> 0) & 0xff);
  241. out.write(endpoint.getAddress().getAddress());
  242. String userName = (String) java.security.AccessController.doPrivileged(
  243. new sun.security.action.GetPropertyAction("user.name"));
  244. try {
  245. out.write(userName.getBytes("ISO-8859-1"));
  246. } catch (java.io.UnsupportedEncodingException uee) {
  247. assert false;
  248. }
  249. out.write(0);
  250. out.flush();
  251. byte[] data = new byte[8];
  252. int n = readSocksReply(in, data);
  253. if (n != 8)
  254. throw new SocketException("Reply from SOCKS server has bad length: " + n);
  255. if (data[0] != 0 && data[0] != 4)
  256. throw new SocketException("Reply from SOCKS server has bad version");
  257. SocketException ex = null;
  258. switch (data[1]) {
  259. case 90:
  260. // Success!
  261. external_address = endpoint;
  262. break;
  263. case 91:
  264. ex = new SocketException("SOCKS request rejected");
  265. break;
  266. case 92:
  267. ex = new SocketException("SOCKS server couldn't reach destination");
  268. break;
  269. case 93:
  270. ex = new SocketException("SOCKS authentication failed");
  271. break;
  272. default:
  273. ex = new SocketException("Reply from SOCKS server contains bad status");
  274. break;
  275. }
  276. if (ex != null) {
  277. in.close();
  278. out.close();
  279. throw ex;
  280. }
  281. }
  282. /**
  283. * Connects the Socks Socket to the specified endpoint. It will first
  284. * connect to the SOCKS proxy and negotiate the access. If the proxy
  285. * grants the connections, then the connect is successful and all
  286. * further traffic will go to the "real" endpoint.
  287. *
  288. * @param endpoint the <code>SocketAddress</code> to connect to.
  289. * @param timeout the timeout value in milliseconds
  290. * @throws IOException if the connection can't be established.
  291. * @throws SecurityException if there is a security manager and it
  292. * doesn't allow the connection
  293. * @throws IllegalArgumentException if endpoint is null or a
  294. * SocketAddress subclass not supported by this socket
  295. */
  296. protected void connect(SocketAddress endpoint, int timeout) throws IOException {
  297. SecurityManager security = System.getSecurityManager();
  298. if (endpoint == null || !(endpoint instanceof InetSocketAddress))
  299. throw new IllegalArgumentException("Unsupported address type");
  300. InetSocketAddress epoint = (InetSocketAddress) endpoint;
  301. if (security != null) {
  302. if (epoint.isUnresolved())
  303. security.checkConnect(epoint.getHostName(),
  304. epoint.getPort());
  305. else
  306. security.checkConnect(epoint.getAddress().getHostAddress(),
  307. epoint.getPort());
  308. }
  309. if (server == null) {
  310. // This is the general case
  311. // server is not null only when the socket was created with a
  312. // specified proxy in which case it does bypass the ProxySelector
  313. ProxySelector sel = (ProxySelector)
  314. java.security.AccessController.doPrivileged(
  315. new java.security.PrivilegedAction() {
  316. public Object run() {
  317. return ProxySelector.getDefault();
  318. }
  319. });
  320. if (sel == null) {
  321. /*
  322. * No default proxySelector --> direct connection
  323. */
  324. super.connect(epoint, timeout);
  325. return;
  326. }
  327. URI uri = null;
  328. String host = epoint.getHostName();
  329. // IPv6 litteral?
  330. if (epoint.getAddress() instanceof Inet6Address &&
  331. (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
  332. host = "[" + host + "]";
  333. }
  334. try {
  335. uri = new URI("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort());
  336. } catch (URISyntaxException e) {
  337. // This shouldn't happen
  338. assert false : e;
  339. }
  340. Proxy p = null;
  341. IOException savedExc = null;
  342. java.util.Iterator<Proxy> iProxy = null;
  343. iProxy = sel.select(uri).iterator();
  344. if (iProxy == null || !(iProxy.hasNext())) {
  345. super.connect(epoint, timeout);
  346. return;
  347. }
  348. while (iProxy.hasNext()) {
  349. p = iProxy.next();
  350. if (p == null || p == Proxy.NO_PROXY) {
  351. super.connect(epoint, timeout);
  352. return;
  353. }
  354. if (p.type() != Proxy.Type.SOCKS)
  355. throw new SocketException("Unknown proxy type : " + p.type());
  356. if (!(p.address() instanceof InetSocketAddress))
  357. throw new SocketException("Unknow address type for proxy: " + p);
  358. server = ((InetSocketAddress) p.address()).getHostName();
  359. port = ((InetSocketAddress) p.address()).getPort();
  360. // Connects to the SOCKS server
  361. try {
  362. privilegedConnect(server, port, timeout);
  363. // Worked, let's get outta here
  364. break;
  365. } catch (IOException e) {
  366. // Ooops, let's notify the ProxySelector
  367. sel.connectFailed(uri,p.address(),e);
  368. server = null;
  369. port = -1;
  370. savedExc = e;
  371. // Will continue the while loop and try the next proxy
  372. }
  373. }
  374. /*
  375. * If server is still null at this point, none of the proxy
  376. * worked
  377. */
  378. if (server == null) {
  379. throw new SocketException("Can't connect to SOCKS proxy:"
  380. + savedExc.getMessage());
  381. }
  382. } else {
  383. // Connects to the SOCKS server
  384. try {
  385. privilegedConnect(server, port, timeout);
  386. } catch (IOException e) {
  387. throw new SocketException(e.getMessage());
  388. }
  389. }
  390. // cmdIn & cmdOut were intialized during the privilegedConnect() call
  391. BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
  392. InputStream in = cmdIn;
  393. if (useV4) {
  394. // SOCKS Protocol version 4 doesn't know how to deal with
  395. // DOMAIN type of addresses (unresolved addresses here)
  396. if (epoint.isUnresolved())
  397. throw new UnknownHostException(epoint.toString());
  398. connectV4(in, out, epoint);
  399. return;
  400. }
  401. // This is SOCKS V5
  402. out.write(PROTO_VERS);
  403. out.write(2);
  404. out.write(NO_AUTH);
  405. out.write(USER_PASSW);
  406. out.flush();
  407. byte[] data = new byte[2];
  408. int i = readSocksReply(in, data);
  409. if (i != 2 || ((int)data[0]) != PROTO_VERS) {
  410. // Maybe it's not a V5 sever after all
  411. // Let's try V4 before we give up
  412. // SOCKS Protocol version 4 doesn't know how to deal with
  413. // DOMAIN type of addresses (unresolved addresses here)
  414. if (epoint.isUnresolved())
  415. throw new UnknownHostException(epoint.toString());
  416. connectV4(in, out, epoint);
  417. return;
  418. }
  419. if (((int)data[1]) == NO_METHODS)
  420. throw new SocketException("SOCKS : No acceptable methods");
  421. if (!authenticate(data[1], in, out)) {
  422. throw new SocketException("SOCKS : authentication failed");
  423. }
  424. out.write(PROTO_VERS);
  425. out.write(CONNECT);
  426. out.write(0);
  427. /* Test for IPV4/IPV6/Unresolved */
  428. if (epoint.isUnresolved()) {
  429. out.write(DOMAIN_NAME);
  430. out.write(epoint.getHostName().length());
  431. try {
  432. out.write(epoint.getHostName().getBytes("ISO-8859-1"));
  433. } catch (java.io.UnsupportedEncodingException uee) {
  434. assert false;
  435. }
  436. out.write((epoint.getPort() >> 8) & 0xff);
  437. out.write((epoint.getPort() >> 0) & 0xff);
  438. } else if (epoint.getAddress() instanceof Inet6Address) {
  439. out.write(IPV6);
  440. out.write(epoint.getAddress().getAddress());
  441. out.write((epoint.getPort() >> 8) & 0xff);
  442. out.write((epoint.getPort() >> 0) & 0xff);
  443. } else {
  444. out.write(IPV4);
  445. out.write(epoint.getAddress().getAddress());
  446. out.write((epoint.getPort() >> 8) & 0xff);
  447. out.write((epoint.getPort() >> 0) & 0xff);
  448. }
  449. out.flush();
  450. data = new byte[4];
  451. i = readSocksReply(in, data);
  452. if (i != 4)
  453. throw new SocketException("Reply from SOCKS server has bad length");
  454. SocketException ex = null;
  455. int nport, len;
  456. byte[] addr;
  457. switch (data[1]) {
  458. case REQUEST_OK:
  459. // success!
  460. switch(data[3]) {
  461. case IPV4:
  462. addr = new byte[4];
  463. i = readSocksReply(in, addr);
  464. if (i != 4)
  465. throw new SocketException("Reply from SOCKS server badly formatted");
  466. data = new byte[2];
  467. i = readSocksReply(in, data);
  468. if (i != 2)
  469. throw new SocketException("Reply from SOCKS server badly formatted");
  470. nport = ((int)data[0] & 0xff) << 8;
  471. nport += ((int)data[1] & 0xff);
  472. break;
  473. case DOMAIN_NAME:
  474. len = data[1];
  475. byte[] host = new byte[len];
  476. i = readSocksReply(in, host);
  477. if (i != len)
  478. throw new SocketException("Reply from SOCKS server badly formatted");
  479. data = new byte[2];
  480. i = readSocksReply(in, data);
  481. if (i != 2)
  482. throw new SocketException("Reply from SOCKS server badly formatted");
  483. nport = ((int)data[0] & 0xff) << 8;
  484. nport += ((int)data[1] & 0xff);
  485. break;
  486. case IPV6:
  487. len = data[1];
  488. addr = new byte[len];
  489. i = readSocksReply(in, addr);
  490. if (i != len)
  491. throw new SocketException("Reply from SOCKS server badly formatted");
  492. data = new byte[2];
  493. i = readSocksReply(in, data);
  494. if (i != 2)
  495. throw new SocketException("Reply from SOCKS server badly formatted");
  496. nport = ((int)data[0] & 0xff) << 8;
  497. nport += ((int)data[1] & 0xff);
  498. break;
  499. default:
  500. ex = new SocketException("Reply from SOCKS server contains wrong code");
  501. break;
  502. }
  503. break;
  504. case GENERAL_FAILURE:
  505. ex = new SocketException("SOCKS server general failure");
  506. break;
  507. case NOT_ALLOWED:
  508. ex = new SocketException("SOCKS: Connection not allowed by ruleset");
  509. break;
  510. case NET_UNREACHABLE:
  511. ex = new SocketException("SOCKS: Network unreachable");
  512. break;
  513. case HOST_UNREACHABLE:
  514. ex = new SocketException("SOCKS: Host unreachable");
  515. break;
  516. case CONN_REFUSED:
  517. ex = new SocketException("SOCKS: Connection refused");
  518. break;
  519. case TTL_EXPIRED:
  520. ex = new SocketException("SOCKS: TTL expired");
  521. break;
  522. case CMD_NOT_SUPPORTED:
  523. ex = new SocketException("SOCKS: Command not supported");
  524. break;
  525. case ADDR_TYPE_NOT_SUP:
  526. ex = new SocketException("SOCKS: address type not supported");
  527. break;
  528. }
  529. if (ex != null) {
  530. in.close();
  531. out.close();
  532. throw ex;
  533. }
  534. external_address = epoint;
  535. }
  536. private void bindV4(InputStream in, OutputStream out,
  537. InetAddress baddr,
  538. int lport) throws IOException {
  539. if (!(baddr instanceof Inet4Address)) {
  540. throw new SocketException("SOCKS V4 requires IPv4 only addresses");
  541. }
  542. super.bind(baddr, lport);
  543. byte[] addr1 = baddr.getAddress();
  544. /* Test for AnyLocal */
  545. InetAddress naddr = baddr;
  546. if (naddr.isAnyLocalAddress()) {
  547. naddr = cmdsock.getLocalAddress();
  548. addr1 = naddr.getAddress();
  549. }
  550. out.write(PROTO_VERS4);
  551. out.write(BIND);
  552. out.write((super.getLocalPort() >> 8) & 0xff);
  553. out.write((super.getLocalPort() >> 0) & 0xff);
  554. out.write(addr1);
  555. String userName = (String) java.security.AccessController.doPrivileged(
  556. new sun.security.action.GetPropertyAction("user.name"));
  557. try {
  558. out.write(userName.getBytes("ISO-8859-1"));
  559. } catch (java.io.UnsupportedEncodingException uee) {
  560. assert false;
  561. }
  562. out.write(0);
  563. out.flush();
  564. byte[] data = new byte[8];
  565. int n = readSocksReply(in, data);
  566. if (n != 8)
  567. throw new SocketException("Reply from SOCKS server has bad length: " + n);
  568. if (data[0] != 0 && data[0] != 4)
  569. throw new SocketException("Reply from SOCKS server has bad version");
  570. SocketException ex = null;
  571. switch (data[1]) {
  572. case 90:
  573. // Success!
  574. external_address = new InetSocketAddress(baddr, lport);
  575. break;
  576. case 91:
  577. ex = new SocketException("SOCKS request rejected");
  578. break;
  579. case 92:
  580. ex = new SocketException("SOCKS server couldn't reach destination");
  581. break;
  582. case 93:
  583. ex = new SocketException("SOCKS authentication failed");
  584. break;
  585. default:
  586. ex = new SocketException("Reply from SOCKS server contains bad status");
  587. break;
  588. }
  589. if (ex != null) {
  590. in.close();
  591. out.close();
  592. throw ex;
  593. }
  594. }
  595. /**
  596. * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
  597. * means "accept incoming connection from", so the SocketAddress is the
  598. * the one of the host we do accept connection from.
  599. *
  600. * @param addr the Socket address of the remote host.
  601. * @exception IOException if an I/O error occurs when binding this socket.
  602. */
  603. protected synchronized void socksBind(InetSocketAddress saddr) throws IOException {
  604. if (socket != null) {
  605. // this is a client socket, not a server socket, don't
  606. // call the SOCKS proxy for a bind!
  607. return;
  608. }
  609. // Connects to the SOCKS server
  610. if (server == null) {
  611. // This is the general case
  612. // server is not null only when the socket was created with a
  613. // specified proxy in which case it does bypass the ProxySelector
  614. ProxySelector sel = (ProxySelector)
  615. java.security.AccessController.doPrivileged(
  616. new java.security.PrivilegedAction() {
  617. public Object run() {
  618. return ProxySelector.getDefault();
  619. }
  620. });
  621. if (sel == null) {
  622. /*
  623. * No default proxySelector --> direct connection
  624. */
  625. return;
  626. }
  627. URI uri = null;
  628. String host = saddr.getHostName();
  629. // IPv6 litteral?
  630. if (saddr.getAddress() instanceof Inet6Address &&
  631. (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
  632. host = "[" + host + "]";
  633. }
  634. try {
  635. uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort());
  636. } catch (URISyntaxException e) {
  637. // This shouldn't happen
  638. assert false : e;
  639. }
  640. Proxy p = null;
  641. Exception savedExc = null;
  642. java.util.Iterator<Proxy> iProxy = null;
  643. iProxy = sel.select(uri).iterator();
  644. if (iProxy == null || !(iProxy.hasNext())) {
  645. return;
  646. }
  647. while (iProxy.hasNext()) {
  648. p = iProxy.next();
  649. if (p == null || p == Proxy.NO_PROXY) {
  650. return;
  651. }
  652. if (p.type() != Proxy.Type.SOCKS)
  653. throw new SocketException("Unknown proxy type : " + p.type());
  654. if (!(p.address() instanceof InetSocketAddress))
  655. throw new SocketException("Unknow address type for proxy: " + p);
  656. server = ((InetSocketAddress) p.address()).getHostName();
  657. port = ((InetSocketAddress) p.address()).getPort();
  658. // Connects to the SOCKS server
  659. try {
  660. AccessController.doPrivileged(new PrivilegedExceptionAction() {
  661. public Object run() throws Exception {
  662. cmdsock = new Socket(new PlainSocketImpl());
  663. cmdsock.connect(new InetSocketAddress(server, port));
  664. cmdIn = cmdsock.getInputStream();
  665. cmdOut = cmdsock.getOutputStream();
  666. return null;
  667. }
  668. });
  669. } catch (Exception e) {
  670. // Ooops, let's notify the ProxySelector
  671. sel.connectFailed(uri,p.address(),new SocketException(e.getMessage()));
  672. server = null;
  673. port = -1;
  674. cmdsock = null;
  675. savedExc = e;
  676. // Will continue the while loop and try the next proxy
  677. }
  678. }
  679. /*
  680. * If server is still null at this point, none of the proxy
  681. * worked
  682. */
  683. if (server == null || cmdsock == null) {
  684. throw new SocketException("Can't connect to SOCKS proxy:"
  685. + savedExc.getMessage());
  686. }
  687. } else {
  688. 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. throw new SocketException(e.getMessage());
  700. }
  701. }
  702. BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
  703. InputStream in = cmdIn;
  704. if (useV4) {
  705. bindV4(in, out, saddr.getAddress(), saddr.getPort());
  706. return;
  707. }
  708. out.write(PROTO_VERS);
  709. out.write(2);
  710. out.write(NO_AUTH);
  711. out.write(USER_PASSW);
  712. out.flush();
  713. byte[] data = new byte[2];
  714. int i = readSocksReply(in, data);
  715. if (i != 2 || ((int)data[0]) != PROTO_VERS) {
  716. // Maybe it's not a V5 sever after all
  717. // Let's try V4 before we give up
  718. bindV4(in, out, saddr.getAddress(), saddr.getPort());
  719. return;
  720. }
  721. if (((int)data[1]) == NO_METHODS)
  722. throw new SocketException("SOCKS : No acceptable methods");
  723. if (!authenticate(data[1], in, out)) {
  724. throw new SocketException("SOCKS : authentication failed");
  725. }
  726. // We're OK. Let's issue the BIND command.
  727. out.write(PROTO_VERS);
  728. out.write(BIND);
  729. out.write(0);
  730. int lport = saddr.getPort();
  731. if (saddr.isUnresolved()) {
  732. out.write(DOMAIN_NAME);
  733. out.write(saddr.getHostName().length());
  734. try {
  735. out.write(saddr.getHostName().getBytes("ISO-8859-1"));
  736. } catch (java.io.UnsupportedEncodingException uee) {
  737. assert false;
  738. }
  739. out.write((lport >> 8) & 0xff);
  740. out.write((lport >> 0) & 0xff);
  741. } else if (saddr.getAddress() instanceof Inet4Address) {
  742. byte[] addr1 = saddr.getAddress().getAddress();
  743. out.write(IPV4);
  744. out.write(addr1);
  745. out.write((lport >> 8) & 0xff);
  746. out.write((lport >> 0) & 0xff);
  747. out.flush();
  748. } else if (saddr.getAddress() instanceof Inet6Address) {
  749. byte[] addr1 = saddr.getAddress().getAddress();
  750. out.write(IPV6);
  751. out.write(addr1);
  752. out.write((lport >> 8) & 0xff);
  753. out.write((lport >> 0) & 0xff);
  754. out.flush();
  755. } else {
  756. cmdsock.close();
  757. throw new SocketException("unsupported address type : " + saddr);
  758. }
  759. data = new byte[4];
  760. i = readSocksReply(in, data);
  761. SocketException ex = null;
  762. int len, nport;
  763. byte[] addr;
  764. switch (data[1]) {
  765. case REQUEST_OK:
  766. // success!
  767. InetSocketAddress real_end = null;
  768. switch(data[3]) {
  769. case IPV4:
  770. addr = new byte[4];
  771. i = readSocksReply(in, addr);
  772. if (i != 4)
  773. throw new SocketException("Reply from SOCKS server badly formatted");
  774. data = new byte[2];
  775. i = readSocksReply(in, data);
  776. if (i != 2)
  777. throw new SocketException("Reply from SOCKS server badly formatted");
  778. nport = ((int)data[0] & 0xff) << 8;
  779. nport += ((int)data[1] & 0xff);
  780. external_address =
  781. new InetSocketAddress(new Inet4Address("", addr) , nport);
  782. break;
  783. case DOMAIN_NAME:
  784. len = data[1];
  785. byte[] host = new byte[len];
  786. i = readSocksReply(in, host);
  787. if (i != len)
  788. throw new SocketException("Reply from SOCKS server badly formatted");
  789. data = new byte[2];
  790. i = readSocksReply(in, data);
  791. if (i != 2)
  792. throw new SocketException("Reply from SOCKS server badly formatted");
  793. nport = ((int)data[0] & 0xff) << 8;
  794. nport += ((int)data[1] & 0xff);
  795. external_address = new InetSocketAddress(new String(host), nport);
  796. break;
  797. case IPV6:
  798. len = data[1];
  799. addr = new byte[len];
  800. i = readSocksReply(in, addr);
  801. if (i != len)
  802. throw new SocketException("Reply from SOCKS server badly formatted");
  803. data = new byte[2];
  804. i = readSocksReply(in, data);
  805. if (i != 2)
  806. throw new SocketException("Reply from SOCKS server badly formatted");
  807. nport = ((int)data[0] & 0xff) << 8;
  808. nport += ((int)data[1] & 0xff);
  809. external_address =
  810. new InetSocketAddress(new Inet6Address("", addr), nport);
  811. break;
  812. }
  813. break;
  814. case GENERAL_FAILURE:
  815. ex = new SocketException("SOCKS server general failure");
  816. break;
  817. case NOT_ALLOWED:
  818. ex = new SocketException("SOCKS: Bind not allowed by ruleset");
  819. break;
  820. case NET_UNREACHABLE:
  821. ex = new SocketException("SOCKS: Network unreachable");
  822. break;
  823. case HOST_UNREACHABLE:
  824. ex = new SocketException("SOCKS: Host unreachable");
  825. break;
  826. case CONN_REFUSED:
  827. ex = new SocketException("SOCKS: Connection refused");
  828. break;
  829. case TTL_EXPIRED:
  830. ex = new SocketException("SOCKS: TTL expired");
  831. break;
  832. case CMD_NOT_SUPPORTED:
  833. ex = new SocketException("SOCKS: Command not supported");
  834. break;
  835. case ADDR_TYPE_NOT_SUP:
  836. ex = new SocketException("SOCKS: address type not supported");
  837. break;
  838. }
  839. if (ex != null) {
  840. in.close();
  841. out.close();
  842. cmdsock.close();
  843. cmdsock = null;
  844. throw ex;
  845. }
  846. cmdIn = in;
  847. cmdOut = out;
  848. }
  849. /**
  850. * Accepts a connection from a specific host.
  851. *
  852. * @param s the accepted connection.
  853. * @param saddr the socket address of the host we do accept
  854. * connection from
  855. * @exception IOException if an I/O error occurs when accepting the
  856. * connection.
  857. */
  858. protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException {
  859. if (cmdsock == null) {
  860. // Not a Socks ServerSocket.
  861. return;
  862. }
  863. InputStream in = cmdIn;
  864. // Sends the "SOCKS BIND" request.
  865. socksBind(saddr);
  866. in.read();
  867. int i = in.read();
  868. in.read();
  869. SocketException ex = null;
  870. int nport;
  871. byte[] addr;
  872. InetSocketAddress real_end = null;
  873. switch (i) {
  874. case REQUEST_OK:
  875. // success!
  876. i = in.read();
  877. switch(i) {
  878. case IPV4:
  879. addr = new byte[4];
  880. readSocksReply(in, addr);
  881. nport = in.read() << 8;
  882. nport += in.read();
  883. real_end =
  884. new InetSocketAddress(new Inet4Address("", addr) , nport);
  885. break;
  886. case DOMAIN_NAME:
  887. int len = in.read();
  888. addr = new byte[len];
  889. readSocksReply(in, addr);
  890. nport = in.read() << 8;
  891. nport += in.read();
  892. real_end = new InetSocketAddress(new String(addr), nport);
  893. break;
  894. case IPV6:
  895. addr = new byte[16];
  896. readSocksReply(in, addr);
  897. nport = in.read() << 8;
  898. nport += in.read();
  899. real_end =
  900. new InetSocketAddress(new Inet6Address("", addr), nport);
  901. break;
  902. }
  903. break;
  904. case GENERAL_FAILURE:
  905. ex = new SocketException("SOCKS server general failure");
  906. break;
  907. case NOT_ALLOWED:
  908. ex = new SocketException("SOCKS: Accept not allowed by ruleset");
  909. break;
  910. case NET_UNREACHABLE:
  911. ex = new SocketException("SOCKS: Network unreachable");
  912. break;
  913. case HOST_UNREACHABLE:
  914. ex = new SocketException("SOCKS: Host unreachable");
  915. break;
  916. case CONN_REFUSED:
  917. ex = new SocketException("SOCKS: Connection refused");
  918. break;
  919. case TTL_EXPIRED:
  920. ex = new SocketException("SOCKS: TTL expired");
  921. break;
  922. case CMD_NOT_SUPPORTED:
  923. ex = new SocketException("SOCKS: Command not supported");
  924. break;
  925. case ADDR_TYPE_NOT_SUP:
  926. ex = new SocketException("SOCKS: address type not supported");
  927. break;
  928. }
  929. if (ex != null) {
  930. cmdIn.close();
  931. cmdOut.close();
  932. cmdsock.close();
  933. cmdsock = null;
  934. throw ex;
  935. }
  936. /**
  937. * This is where we have to do some fancy stuff.
  938. * The datastream from the socket "accepted" by the proxy will
  939. * come through the cmdSocket. So we have to swap the socketImpls
  940. */
  941. if (s instanceof SocksSocketImpl) {
  942. ((SocksSocketImpl)s).external_address = real_end;
  943. }
  944. if (s instanceof PlainSocketImpl) {
  945. ((PlainSocketImpl)s).setInputStream((SocketInputStream) in);
  946. }
  947. s.fd = cmdsock.getImpl().fd;
  948. s.address = cmdsock.getImpl().address;
  949. s.port = cmdsock.getImpl().port;
  950. s.localport = cmdsock.getImpl().localport;
  951. // Need to do that so that the socket won't be closed
  952. // when the ServerSocket is closed by the user.
  953. // It kinds of detaches the Socket because it is now
  954. // used elsewhere.
  955. cmdsock = null;
  956. }
  957. /**
  958. * Returns the value of this socket's <code>address</code> field.
  959. *
  960. * @return the value of this socket's <code>address</code> field.
  961. * @see java.net.SocketImpl#address
  962. */
  963. protected InetAddress getInetAddress() {
  964. if (external_address != null)
  965. return external_address.getAddress();
  966. else
  967. return super.getInetAddress();
  968. }
  969. /**
  970. * Returns the value of this socket's <code>port</code> field.
  971. *
  972. * @return the value of this socket's <code>port</code> field.
  973. * @see java.net.SocketImpl#port
  974. */
  975. protected int getPort() {
  976. if (external_address != null)
  977. return external_address.getPort();
  978. else
  979. return super.getPort();
  980. }
  981. protected int getLocalPort() {
  982. if (socket != null)
  983. return super.getLocalPort();
  984. if (external_address != null)
  985. return external_address.getPort();
  986. else
  987. return super.getLocalPort();
  988. }
  989. protected void close() throws IOException {
  990. if (cmdsock != null)
  991. cmdsock.close();
  992. cmdsock = null;
  993. super.close();
  994. }
  995. }