1. /*
  2. * @(#)SocksSocketImpl.java 1.8 03/01/23
  3. *
  4. * Copyright 2003 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.DataOutputStream;
  12. import java.io.BufferedReader;
  13. import java.io.InputStreamReader;
  14. import java.security.AccessController;
  15. import java.security.PrivilegedExceptionAction;
  16. import java.util.prefs.Preferences;
  17. /* import org.ietf.jgss.*; */
  18. /**
  19. * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
  20. * This is a subclass of PlainSocketImpl.
  21. * Note this class should <b>NOT</b> be public.
  22. */
  23. class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
  24. private String server = null;
  25. private int port = DEFAULT_PORT;
  26. private InetSocketAddress external_address;
  27. private boolean useV4 = false;
  28. private Socket cmdsock = null;
  29. private InputStream cmdIn = null;
  30. private OutputStream cmdOut = null;
  31. SocksSocketImpl(String server, int port) {
  32. this.server = server;
  33. this.port = (port == -1 ? DEFAULT_PORT : port);
  34. }
  35. void setV4() {
  36. useV4 = true;
  37. }
  38. private synchronized void privilegedConnect(final String host,
  39. final int port,
  40. final int timeout)
  41. throws IOException
  42. {
  43. try {
  44. AccessController.doPrivileged(
  45. new java.security.PrivilegedExceptionAction() {
  46. public Object run() throws IOException {
  47. superConnectServer(host, port, timeout);
  48. cmdIn = getInputStream();
  49. cmdOut = getOutputStream();
  50. return null;
  51. }
  52. });
  53. } catch (java.security.PrivilegedActionException pae) {
  54. throw (IOException) pae.getException();
  55. }
  56. }
  57. private void superConnectServer(String host, int port,
  58. int timeout) throws IOException {
  59. super.connect(new InetSocketAddress(host, port), timeout);
  60. }
  61. private int readSocksReply(InputStream in, byte[] data) throws IOException {
  62. int len = data.length;
  63. int received = 0;
  64. for (int attempts = 0; received < len && attempts < 3; attempts++) {
  65. int count = in.read(data, received, len - received);
  66. if (count < 0)
  67. throw new SocketException("Malformed reply from SOCKS server");
  68. received += count;
  69. }
  70. return received;
  71. }
  72. /**
  73. * Provides the authentication machanism required by the proxy.
  74. */
  75. private boolean authenticate(byte method, InputStream in,
  76. DataOutputStream out) throws IOException {
  77. byte[] data = null;
  78. int i;
  79. // No Authentication required. We're done then!
  80. if (method == NO_AUTH)
  81. return true;
  82. /**
  83. * User/Password authentication. Try, in that order :
  84. * - The application provided Authenticator, if any
  85. * - The user preferences java.net.socks.username &
  86. * java.net.socks.password
  87. * - the user.name & no password (backward compatibility behavior).
  88. */
  89. if (method == USER_PASSW) {
  90. String userName;
  91. String password = null;
  92. final InetAddress addr = InetAddress.getByName(server);
  93. PasswordAuthentication pw = (PasswordAuthentication)
  94. java.security.AccessController.doPrivileged(
  95. new java.security.PrivilegedAction() {
  96. public Object run() {
  97. return Authenticator.requestPasswordAuthentication(
  98. server, addr, port, "SOCKS5", "SOCKS authentication", null);
  99. }
  100. });
  101. if (pw != null) {
  102. userName = pw.getUserName();
  103. password = new String(pw.getPassword());
  104. } else {
  105. final Preferences prefs = Preferences.userRoot().node("/java/net/socks");
  106. try {
  107. userName =
  108. (String) AccessController.doPrivileged(
  109. new java.security.PrivilegedExceptionAction() {
  110. public Object run() throws IOException {
  111. return prefs.get("username", null);
  112. }
  113. });
  114. } catch (java.security.PrivilegedActionException pae) {
  115. throw (IOException) pae.getException();
  116. }
  117. if (userName != null) {
  118. try {
  119. password =
  120. (String) AccessController.doPrivileged(
  121. new java.security.PrivilegedExceptionAction() {
  122. public Object run() throws IOException {
  123. return prefs.get("password", null);
  124. }
  125. });
  126. } catch (java.security.PrivilegedActionException pae) {
  127. throw (IOException) pae.getException();
  128. }
  129. } else {
  130. userName =
  131. (String) java.security.AccessController.doPrivileged(
  132. new sun.security.action.GetPropertyAction("user.name"));
  133. }
  134. }
  135. if (userName == null)
  136. return false;
  137. out.write(1);
  138. out.write(userName.length());
  139. out.write(userName.getBytes());
  140. if (password != null) {
  141. out.write(password.length());
  142. out.write(password.getBytes());
  143. } else
  144. out.write(0);
  145. out.flush();
  146. data = new byte[2];
  147. i = readSocksReply(in, data);
  148. if (i != 2 || data[1] != 0) {
  149. /* RFC 1929 specifies that the connection MUST be closed if
  150. authentication fails */
  151. out.close();
  152. in.close();
  153. return false;
  154. }
  155. /* Authentication succeeded */
  156. return true;
  157. }
  158. /**
  159. * GSSAPI authentication mechanism.
  160. * Unfortunately the RFC seems out of sync with the Reference
  161. * implementation. I'll leave this in for future completion.
  162. */
  163. // if (method == GSSAPI) {
  164. // try {
  165. // GSSManager manager = GSSManager.getInstance();
  166. // GSSName name = manager.createName("SERVICE:socks@"+server,
  167. // null);
  168. // GSSContext context = manager.createContext(name, null, null,
  169. // GSSContext.DEFAULT_LIFETIME);
  170. // context.requestMutualAuth(true);
  171. // context.requestReplayDet(true);
  172. // context.requestSequenceDet(true);
  173. // context.requestCredDeleg(true);
  174. // byte []inToken = new byte[0];
  175. // while (!context.isEstablished()) {
  176. // byte[] outToken
  177. // = context.initSecContext(inToken, 0, inToken.length);
  178. // // send the output token if generated
  179. // if (outToken != null) {
  180. // out.write(1);
  181. // out.write(1);
  182. // out.writeShort(outToken.length);
  183. // out.write(outToken);
  184. // out.flush();
  185. // data = new byte[2];
  186. // i = readSocksReply(in, data);
  187. // if (i != 2 || data[1] == 0xff) {
  188. // in.close();
  189. // out.close();
  190. // return false;
  191. // }
  192. // i = readSocksReply(in, data);
  193. // int len = 0;
  194. // len = ((int)data[0] & 0xff) << 8;
  195. // len += data[1];
  196. // data = new byte[len];
  197. // i = readSocksReply(in, data);
  198. // if (i == len)
  199. // return true;
  200. // in.close();
  201. // out.close();
  202. // }
  203. // }
  204. // } catch (GSSException e) {
  205. // /* RFC 1961 states that if Context initialisation fails the connection
  206. // MUST be closed */
  207. // e.printStackTrace();
  208. // in.close();
  209. // out.close();
  210. // }
  211. // }
  212. return false;
  213. }
  214. private void connectV4(InputStream in, OutputStream out,
  215. InetSocketAddress endpoint) throws IOException {
  216. out.write(PROTO_VERS4);
  217. out.write(CONNECT);
  218. out.write((endpoint.getPort() >> 8) & 0xff);
  219. out.write((endpoint.getPort() >> 0) & 0xff);
  220. out.write(endpoint.getAddress().getAddress());
  221. String userName = (String) java.security.AccessController.doPrivileged(
  222. new sun.security.action.GetPropertyAction("user.name"));
  223. out.write(userName.getBytes());
  224. out.write(0);
  225. out.flush();
  226. byte[] data = new byte[8];
  227. int n = readSocksReply(in, data);
  228. if (n != 8)
  229. throw new SocketException("Reply from SOCKS server has bad length: " + n);
  230. if (data[0] != 0 && data[0] != 4)
  231. throw new SocketException("Reply from SOCKS server has bad version");
  232. SocketException ex = null;
  233. switch (data[1]) {
  234. case 90:
  235. // Success!
  236. external_address = endpoint;
  237. break;
  238. case 91:
  239. ex = new SocketException("SOCKS request rejected");
  240. break;
  241. case 92:
  242. ex = new SocketException("SOCKS server couldn't reach destination");
  243. break;
  244. case 93:
  245. ex = new SocketException("SOCKS authentication failed");
  246. break;
  247. default:
  248. ex = new SocketException("Replay from SOCKS server contains bad status");
  249. break;
  250. }
  251. if (ex != null) {
  252. in.close();
  253. out.close();
  254. throw ex;
  255. }
  256. }
  257. /**
  258. * Connects the Socks Socket to the specified endpoint. It will first
  259. * connect to the SOCKS proxy and negotiate the access. If the proxy
  260. * grants the connections, then the connect is successful and all
  261. * further traffic will go to the "real" endpoint.
  262. *
  263. * @param endpoint the <code>SocketAddress</code> to connect to.
  264. * @param timeout the timeout value in milliseconds
  265. * @throws IOException if the connection can't be established.
  266. * @throws SecurityException if there is a security manager and it
  267. * doesn't allow the connection
  268. * @throws IllegalArgumentException if endpoint is null or a
  269. * SocketAddress subclass not supported by this socket
  270. */
  271. protected void connect(SocketAddress endpoint, int timeout) throws IOException {
  272. SecurityManager security = System.getSecurityManager();
  273. if (endpoint == null || !(endpoint instanceof InetSocketAddress))
  274. throw new IllegalArgumentException("Unsupported address type");
  275. InetSocketAddress epoint = (InetSocketAddress) endpoint;
  276. if (security != null) {
  277. if (epoint.isUnresolved())
  278. security.checkConnect(epoint.getHostName(),
  279. epoint.getPort());
  280. else
  281. security.checkConnect(epoint.getAddress().getHostAddress(),
  282. epoint.getPort());
  283. }
  284. // Connects to the SOCKS server
  285. try {
  286. privilegedConnect(server, port, timeout);
  287. } catch (Exception e) {
  288. throw new SocketException(e.getMessage());
  289. }
  290. // cmdIn & cmdOut were intialized during the privilegedConnect() call
  291. DataOutputStream out = new DataOutputStream(cmdOut);
  292. InputStream in = cmdIn;
  293. if (useV4) {
  294. // SOCKS Protocol version 4 doesn't know how to deal with
  295. // DOMAIN type of addresses (unresolved addresses here)
  296. if (epoint.isUnresolved())
  297. throw new UnknownHostException(epoint.toString());
  298. connectV4(in, out, epoint);
  299. return;
  300. }
  301. // This is SOCKS V5
  302. out.write(PROTO_VERS);
  303. out.write(2);
  304. out.write(NO_AUTH);
  305. out.write(USER_PASSW);
  306. out.flush();
  307. byte[] data = new byte[2];
  308. int i = readSocksReply(in, data);
  309. if (i != 2 || ((int)data[1]) == NO_METHODS)
  310. throw new SocketException("SOCKS : No acceptable methods");
  311. if (!authenticate(data[1], in, out)) {
  312. throw new SocketException("SOCKS : authentication failed");
  313. }
  314. out.write(PROTO_VERS);
  315. out.write(CONNECT);
  316. out.write(0);
  317. /* Test for IPV4/IPV6/Unresolved */
  318. if (epoint.isUnresolved()) {
  319. out.write(DOMAIN_NAME);
  320. out.write(epoint.getHostName().length());
  321. out.write(epoint.getHostName().getBytes());
  322. out.write((epoint.getPort() >> 8) & 0xff);
  323. out.write((epoint.getPort() >> 0) & 0xff);
  324. } else if (epoint.getAddress() instanceof Inet6Address) {
  325. out.write(IPV6);
  326. out.write(epoint.getAddress().getAddress());
  327. out.write((epoint.getPort() >> 8) & 0xff);
  328. out.write((epoint.getPort() >> 0) & 0xff);
  329. } else {
  330. out.write(IPV4);
  331. out.write(epoint.getAddress().getAddress());
  332. out.write((epoint.getPort() >> 8) & 0xff);
  333. out.write((epoint.getPort() >> 0) & 0xff);
  334. }
  335. out.flush();
  336. data = new byte[4];
  337. i = readSocksReply(in, data);
  338. if (i != 4)
  339. throw new SocketException("Reply from SOCKS server has bad length");
  340. SocketException ex = null;
  341. int nport, len;
  342. byte[] addr;
  343. switch (data[1]) {
  344. case REQUEST_OK:
  345. // success!
  346. switch(data[3]) {
  347. case IPV4:
  348. addr = new byte[4];
  349. i = readSocksReply(in, addr);
  350. if (i != 4)
  351. throw new SocketException("Reply from SOCKS server badly formatted");
  352. data = new byte[2];
  353. i = readSocksReply(in, data);
  354. if (i != 2)
  355. throw new SocketException("Reply from SOCKS server badly formatted");
  356. nport = ((int)data[0] & 0xff) << 8;
  357. nport += ((int)data[1] & 0xff);
  358. break;
  359. case DOMAIN_NAME:
  360. len = data[1];
  361. byte[] host = new byte[len];
  362. i = readSocksReply(in, host);
  363. if (i != len)
  364. throw new SocketException("Reply from SOCKS server badly formatted");
  365. data = new byte[2];
  366. i = readSocksReply(in, data);
  367. if (i != 2)
  368. throw new SocketException("Reply from SOCKS server badly formatted");
  369. nport = ((int)data[0] & 0xff) << 8;
  370. nport += ((int)data[1] & 0xff);
  371. break;
  372. case IPV6:
  373. len = data[1];
  374. addr = new byte[len];
  375. i = readSocksReply(in, addr);
  376. if (i != len)
  377. throw new SocketException("Reply from SOCKS server badly formatted");
  378. data = new byte[2];
  379. i = readSocksReply(in, data);
  380. if (i != 2)
  381. throw new SocketException("Reply from SOCKS server badly formatted");
  382. nport = ((int)data[0] & 0xff) << 8;
  383. nport += ((int)data[1] & 0xff);
  384. break;
  385. default:
  386. ex = new SocketException("Reply from SOCKS server contains wrong code");
  387. break;
  388. }
  389. break;
  390. case GENERAL_FAILURE:
  391. ex = new SocketException("SOCKS server general failure");
  392. break;
  393. case NOT_ALLOWED:
  394. ex = new SocketException("SOCKS: Connection not allowed by ruleset");
  395. break;
  396. case NET_UNREACHABLE:
  397. ex = new SocketException("SOCKS: Network unreachable");
  398. break;
  399. case HOST_UNREACHABLE:
  400. ex = new SocketException("SOCKS: Host unreachable");
  401. break;
  402. case CONN_REFUSED:
  403. ex = new SocketException("SOCKS: Connection refused");
  404. break;
  405. case TTL_EXPIRED:
  406. ex = new SocketException("SOCKS: TTL expired");
  407. break;
  408. case CMD_NOT_SUPPORTED:
  409. ex = new SocketException("SOCKS: Command not supported");
  410. break;
  411. case ADDR_TYPE_NOT_SUP:
  412. ex = new SocketException("SOCKS: address type not supported");
  413. break;
  414. }
  415. if (ex != null) {
  416. in.close();
  417. out.close();
  418. throw ex;
  419. }
  420. external_address = epoint;
  421. }
  422. private void bindV4(InputStream in, OutputStream out,
  423. InetAddress baddr,
  424. int lport) throws IOException {
  425. super.bind(baddr, lport);
  426. /* FIXME Test for IPV4/IPV6 */
  427. byte[] addr1 = baddr.getAddress();
  428. /* Test for AnyLocal */
  429. InetAddress naddr = baddr;
  430. if (naddr.isAnyLocalAddress()) {
  431. naddr = cmdsock.getLocalAddress();
  432. addr1 = naddr.getAddress();
  433. }
  434. out.write(PROTO_VERS4);
  435. out.write(BIND);
  436. out.write((super.getLocalPort() >> 8) & 0xff);
  437. out.write((super.getLocalPort() >> 0) & 0xff);
  438. out.write(addr1);
  439. String userName = (String) java.security.AccessController.doPrivileged(
  440. new sun.security.action.GetPropertyAction("user.name"));
  441. out.write(userName.getBytes());
  442. out.write(0);
  443. out.flush();
  444. byte[] data = new byte[8];
  445. int n = readSocksReply(in, data);
  446. if (n != 8)
  447. throw new SocketException("Reply from SOCKS server has bad length: " + n);
  448. if (data[0] != 0 && data[0] != 4)
  449. throw new SocketException("Reply from SOCKS server has bad version");
  450. SocketException ex = null;
  451. switch (data[1]) {
  452. case 90:
  453. // Success!
  454. external_address = new InetSocketAddress(baddr, lport);
  455. break;
  456. case 91:
  457. ex = new SocketException("SOCKS request rejected");
  458. break;
  459. case 92:
  460. ex = new SocketException("SOCKS server couldn't reach destination");
  461. break;
  462. case 93:
  463. ex = new SocketException("SOCKS authentication failed");
  464. break;
  465. default:
  466. ex = new SocketException("Replay from SOCKS server contains bad status");
  467. break;
  468. }
  469. if (ex != null) {
  470. in.close();
  471. out.close();
  472. throw ex;
  473. }
  474. }
  475. /**
  476. * Binds this socket to the specified port number on the specified host.
  477. *
  478. * @param baddr the IP address of the remote host.
  479. * @param lport the port number.
  480. * @exception IOException if an I/O error occurs when binding this socket.
  481. */
  482. protected synchronized void bind(InetAddress baddr, int lport) throws IOException {
  483. if (socket != null) {
  484. // this is a client socket, not a server socket, don't
  485. // call the SOCKS proxy for a bind!
  486. super.bind(baddr, lport);
  487. return;
  488. }
  489. // Connects to the SOCKS server
  490. try {
  491. AccessController.doPrivileged(new PrivilegedExceptionAction() {
  492. public Object run() throws Exception {
  493. cmdsock = new Socket(new PlainSocketImpl());
  494. cmdsock.connect(new InetSocketAddress(server, port));
  495. cmdIn = cmdsock.getInputStream();
  496. cmdOut = cmdsock.getOutputStream();
  497. return null;
  498. }
  499. });
  500. } catch (Exception e) {
  501. throw new SocketException(e.getMessage());
  502. }
  503. DataOutputStream out = new DataOutputStream(cmdOut);
  504. InputStream in = cmdIn;
  505. if (useV4) {
  506. bindV4(in, out, baddr, lport);
  507. return;
  508. }
  509. out.write(PROTO_VERS);
  510. out.write(2);
  511. out.write(NO_AUTH);
  512. out.write(USER_PASSW);
  513. out.flush();
  514. byte[] data = new byte[2];
  515. int i = readSocksReply(in, data);
  516. if (i != 2 || ((int)data[1]) == NO_METHODS)
  517. throw new SocketException("SOCKS : No acceptable methods");
  518. if (!authenticate(data[1], in, out)) {
  519. throw new SocketException("SOCKS : authentication failed");
  520. }
  521. // We're OK. Let's issue the BIND command after we've bound ourself localy
  522. super.bind(baddr, lport);
  523. out.write(PROTO_VERS);
  524. out.write(BIND);
  525. out.write(0);
  526. InetAddress naddr = baddr;
  527. if (naddr.isAnyLocalAddress())
  528. naddr = cmdsock.getLocalAddress();
  529. byte[] addr1 = naddr.getAddress();
  530. if (naddr.family == InetAddress.IPv4) {
  531. out.write(IPV4);
  532. out.write(addr1);
  533. out.write((super.getLocalPort() >> 8) & 0xff);
  534. out.write((super.getLocalPort() >> 0) & 0xff);
  535. out.flush();
  536. } else if (naddr.family == InetAddress.IPv6) {
  537. /* Test for AnyLocal */
  538. out.write(IPV6);
  539. out.write(addr1);
  540. out.write((super.getLocalPort() >> 8) & 0xff);
  541. out.write((super.getLocalPort() >> 0) & 0xff);
  542. out.flush();
  543. } else {
  544. cmdsock.close();
  545. throw new SocketException("unsupported address type : " + naddr);
  546. }
  547. data = new byte[4];
  548. i = readSocksReply(in, data);
  549. SocketException ex = null;
  550. int len, nport;
  551. byte[] addr;
  552. switch (data[1]) {
  553. case REQUEST_OK:
  554. // success!
  555. InetSocketAddress real_end = null;
  556. switch(data[3]) {
  557. case IPV4:
  558. addr = new byte[4];
  559. i = readSocksReply(in, addr);
  560. if (i != 4)
  561. throw new SocketException("Reply from SOCKS server badly formatted");
  562. data = new byte[2];
  563. i = readSocksReply(in, data);
  564. if (i != 2)
  565. throw new SocketException("Reply from SOCKS server badly formatted");
  566. nport = ((int)data[0] & 0xff) << 8;
  567. nport += ((int)data[1] & 0xff);
  568. external_address =
  569. new InetSocketAddress(new Inet4Address("", addr) , nport);
  570. break;
  571. case DOMAIN_NAME:
  572. len = data[1];
  573. byte[] host = new byte[len];
  574. i = readSocksReply(in, host);
  575. if (i != len)
  576. throw new SocketException("Reply from SOCKS server badly formatted");
  577. data = new byte[2];
  578. i = readSocksReply(in, data);
  579. if (i != 2)
  580. throw new SocketException("Reply from SOCKS server badly formatted");
  581. nport = ((int)data[0] & 0xff) << 8;
  582. nport += ((int)data[1] & 0xff);
  583. external_address = new InetSocketAddress(new String(host), nport);
  584. break;
  585. case IPV6:
  586. len = data[1];
  587. addr = new byte[len];
  588. i = readSocksReply(in, addr);
  589. if (i != len)
  590. throw new SocketException("Reply from SOCKS server badly formatted");
  591. data = new byte[2];
  592. i = readSocksReply(in, data);
  593. if (i != 2)
  594. throw new SocketException("Reply from SOCKS server badly formatted");
  595. nport = ((int)data[0] & 0xff) << 8;
  596. nport += ((int)data[1] & 0xff);
  597. external_address =
  598. new InetSocketAddress(new Inet6Address("", addr), nport);
  599. break;
  600. }
  601. break;
  602. case GENERAL_FAILURE:
  603. ex = new SocketException("SOCKS server general failure");
  604. break;
  605. case NOT_ALLOWED:
  606. ex = new SocketException("SOCKS: Bind not allowed by ruleset");
  607. break;
  608. case NET_UNREACHABLE:
  609. ex = new SocketException("SOCKS: Network unreachable");
  610. break;
  611. case HOST_UNREACHABLE:
  612. ex = new SocketException("SOCKS: Host unreachable");
  613. break;
  614. case CONN_REFUSED:
  615. ex = new SocketException("SOCKS: Connection refused");
  616. break;
  617. case TTL_EXPIRED:
  618. ex = new SocketException("SOCKS: TTL expired");
  619. break;
  620. case CMD_NOT_SUPPORTED:
  621. ex = new SocketException("SOCKS: Command not supported");
  622. break;
  623. case ADDR_TYPE_NOT_SUP:
  624. ex = new SocketException("SOCKS: address type not supported");
  625. break;
  626. }
  627. if (ex != null) {
  628. in.close();
  629. out.close();
  630. cmdsock.close();
  631. cmdsock = null;
  632. throw ex;
  633. }
  634. cmdIn = in;
  635. cmdOut = out;
  636. }
  637. /**
  638. * Accepts a connection.
  639. *
  640. * @param s the accepted connection.
  641. * @exception IOException if an I/O error occurs when accepting the
  642. * connection.
  643. */
  644. protected void accept(SocketImpl s) throws IOException {
  645. if (cmdsock == null)
  646. throw new SocketException("Socks channel closed");
  647. InputStream in = cmdIn;
  648. in.read();
  649. int i = in.read();
  650. in.read();
  651. SocketException ex = null;
  652. int nport;
  653. byte[] addr;
  654. InetSocketAddress real_end = null;
  655. switch (i) {
  656. case REQUEST_OK:
  657. // success!
  658. i = in.read();
  659. switch(i) {
  660. case IPV4:
  661. addr = new byte[4];
  662. readSocksReply(in, addr);
  663. nport = in.read() << 8;
  664. nport += in.read();
  665. real_end =
  666. new InetSocketAddress(new Inet4Address("", addr) , nport);
  667. break;
  668. case DOMAIN_NAME:
  669. int len = in.read();
  670. addr = new byte[len];
  671. readSocksReply(in, addr);
  672. nport = in.read() << 8;
  673. nport += in.read();
  674. real_end = new InetSocketAddress(new String(addr), nport);
  675. break;
  676. case IPV6:
  677. addr = new byte[16];
  678. readSocksReply(in, addr);
  679. nport = in.read() << 8;
  680. nport += in.read();
  681. real_end =
  682. new InetSocketAddress(new Inet6Address("", addr), nport);
  683. break;
  684. }
  685. break;
  686. case GENERAL_FAILURE:
  687. ex = new SocketException("SOCKS server general failure");
  688. break;
  689. case NOT_ALLOWED:
  690. ex = new SocketException("SOCKS: Accept not allowed by ruleset");
  691. break;
  692. case NET_UNREACHABLE:
  693. ex = new SocketException("SOCKS: Network unreachable");
  694. break;
  695. case HOST_UNREACHABLE:
  696. ex = new SocketException("SOCKS: Host unreachable");
  697. break;
  698. case CONN_REFUSED:
  699. ex = new SocketException("SOCKS: Connection refused");
  700. break;
  701. case TTL_EXPIRED:
  702. ex = new SocketException("SOCKS: TTL expired");
  703. break;
  704. case CMD_NOT_SUPPORTED:
  705. ex = new SocketException("SOCKS: Command not supported");
  706. break;
  707. case ADDR_TYPE_NOT_SUP:
  708. ex = new SocketException("SOCKS: address type not supported");
  709. break;
  710. }
  711. if (ex != null) {
  712. cmdIn.close();
  713. cmdOut.close();
  714. cmdsock.close();
  715. cmdsock = null;
  716. throw ex;
  717. }
  718. /**
  719. * This is where we have to do some fancy stuff.
  720. * The datastream from the socket "accepted" by the proxy will
  721. * come through the cmdSocket. So we have to swap the socketImpls
  722. */
  723. if (s instanceof SocksSocketImpl) {
  724. ((SocksSocketImpl)s).external_address = real_end;
  725. }
  726. if (s instanceof PlainSocketImpl) {
  727. ((PlainSocketImpl)s).setInputStream((SocketInputStream) in);
  728. }
  729. s.fd = cmdsock.getImpl().fd;
  730. s.address = cmdsock.getImpl().address;
  731. s.port = cmdsock.getImpl().port;
  732. s.localport = cmdsock.getImpl().localport;
  733. // Need to do that so that the socket won't be closed
  734. // when the ServerSocket is closed by the user.
  735. // It kinds of detaches the Socket because it is now
  736. // used elsewhere.
  737. cmdsock = null;
  738. }
  739. /**
  740. * Returns the value of this socket's <code>address</code> field.
  741. *
  742. * @return the value of this socket's <code>address</code> field.
  743. * @see java.net.SocketImpl#address
  744. */
  745. protected InetAddress getInetAddress() {
  746. if (external_address != null)
  747. return external_address.getAddress();
  748. else
  749. return super.getInetAddress();
  750. }
  751. /**
  752. * Returns the value of this socket's <code>port</code> field.
  753. *
  754. * @return the value of this socket's <code>port</code> field.
  755. * @see java.net.SocketImpl#port
  756. */
  757. protected int getPort() {
  758. if (external_address != null)
  759. return external_address.getPort();
  760. else
  761. return super.getPort();
  762. }
  763. protected int getLocalPort() {
  764. if (socket != null)
  765. return super.getLocalPort();
  766. if (external_address != null)
  767. return external_address.getPort();
  768. else
  769. return super.getLocalPort();
  770. }
  771. protected void close() throws IOException {
  772. if (cmdsock != null)
  773. cmdsock.close();
  774. cmdsock = null;
  775. super.close();
  776. }
  777. }