001: /*
002: * @(#)SocksSocketImpl.java 1.15 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package java.net;
027:
028: import java.io.IOException;
029: import java.io.InputStream;
030: import java.io.OutputStream;
031: import java.io.DataOutputStream;
032: import java.io.BufferedReader;
033: import java.io.InputStreamReader;
034: import java.security.AccessController;
035: import java.security.PrivilegedExceptionAction;
036:
037: /* import org.ietf.jgss.*; */
038:
039: /**
040: * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
041: * This is a subclass of PlainSocketImpl.
042: * Note this class should <b>NOT</b> be public.
043: */
044:
045: class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
046: private String server = null;
047: private int port = DEFAULT_PORT;
048: private InetSocketAddress external_address;
049: private boolean useV4 = false;
050: private Socket cmdsock = null;
051: private InputStream cmdIn = null;
052: private OutputStream cmdOut = null;
053:
054: SocksSocketImpl(String server, int port) {
055: this .server = server;
056: this .port = (port == -1 ? DEFAULT_PORT : port);
057: }
058:
059: void setV4() {
060: useV4 = true;
061: }
062:
063: private synchronized void privilegedConnect(final String host,
064: final int port, final int timeout) throws IOException {
065: try {
066: AccessController
067: .doPrivileged(new java.security.PrivilegedExceptionAction() {
068: public Object run() throws IOException {
069: super ConnectServer(host, port, timeout);
070: cmdIn = getInputStream();
071: cmdOut = getOutputStream();
072: return null;
073: }
074: });
075: } catch (java.security.PrivilegedActionException pae) {
076: throw (IOException) pae.getException();
077: }
078: }
079:
080: private void super ConnectServer(String host, int port, int timeout)
081: throws IOException {
082: super .connect(new InetSocketAddress(host, port), timeout);
083: }
084:
085: private int readSocksReply(InputStream in, byte[] data)
086: throws IOException {
087: int len = data.length;
088: int received = 0;
089: for (int attempts = 0; received < len && attempts < 3; attempts++) {
090: int count = in.read(data, received, len - received);
091: if (count < 0)
092: throw new SocketException(
093: "Malformed reply from SOCKS server");
094: received += count;
095: }
096: return received;
097: }
098:
099: /**
100: * Provides the authentication machanism required by the proxy.
101: */
102: private boolean authenticate(byte method, InputStream in,
103: DataOutputStream out) throws IOException {
104: byte[] data = null;
105: int i;
106: // No Authentication required. We're done then!
107: if (method == NO_AUTH)
108: return true;
109: /**
110: * User/Password authentication. Try, in that order :
111: * - The application provided Authenticator, if any
112: * - The user preferences java.net.socks.username &
113: * java.net.socks.password
114: * - the user.name & no password (backward compatibility behavior).
115: */
116: if (method == USER_PASSW) {
117: String userName;
118: String password = null;
119: final InetAddress addr = InetAddress.getByName(server);
120: PasswordAuthentication pw = (PasswordAuthentication) java.security.AccessController
121: .doPrivileged(new java.security.PrivilegedAction() {
122: public Object run() {
123: return Authenticator
124: .requestPasswordAuthentication(
125: server, addr, port,
126: "SOCKS5",
127: "SOCKS authentication",
128: null);
129: }
130: });
131: if (pw != null) {
132: userName = pw.getUserName();
133: password = new String(pw.getPassword());
134: } else {
135: try {
136: userName = (String) AccessController
137: .doPrivileged(new java.security.PrivilegedExceptionAction() {
138: public Object run() throws IOException {
139: return null;
140: }
141: });
142: } catch (java.security.PrivilegedActionException pae) {
143: throw (IOException) pae.getException();
144: }
145:
146: if (userName != null) {
147: try {
148: password = (String) AccessController
149: .doPrivileged(new java.security.PrivilegedExceptionAction() {
150: public Object run()
151: throws IOException {
152: return null;
153: }
154: });
155: } catch (java.security.PrivilegedActionException pae) {
156: throw (IOException) pae.getException();
157: }
158: } else {
159: userName = (String) java.security.AccessController
160: .doPrivileged(new sun.security.action.GetPropertyAction(
161: "user.name"));
162: }
163: }
164: if (userName == null)
165: return false;
166: out.write(1);
167: out.write(userName.length());
168: out.write(userName.getBytes());
169: if (password != null) {
170: out.write(password.length());
171: out.write(password.getBytes());
172: } else
173: out.write(0);
174: out.flush();
175: data = new byte[2];
176: i = readSocksReply(in, data);
177: if (i != 2 || data[1] != 0) {
178: /* RFC 1929 specifies that the connection MUST be closed if
179: authentication fails */
180: out.close();
181: in.close();
182: return false;
183: }
184: /* Authentication succeeded */
185: return true;
186: }
187: /**
188: * GSSAPI authentication mechanism.
189: * Unfortunately the RFC seems out of sync with the Reference
190: * implementation. I'll leave this in for future completion.
191: */
192: // if (method == GSSAPI) {
193: // try {
194: // GSSManager manager = GSSManager.getInstance();
195: // GSSName name = manager.createName("SERVICE:socks@"+server,
196: // null);
197: // GSSContext context = manager.createContext(name, null, null,
198: // GSSContext.DEFAULT_LIFETIME);
199: // context.requestMutualAuth(true);
200: // context.requestReplayDet(true);
201: // context.requestSequenceDet(true);
202: // context.requestCredDeleg(true);
203: // byte []inToken = new byte[0];
204: // while (!context.isEstablished()) {
205: // byte[] outToken
206: // = context.initSecContext(inToken, 0, inToken.length);
207: // // send the output token if generated
208: // if (outToken != null) {
209: // out.write(1);
210: // out.write(1);
211: // out.writeShort(outToken.length);
212: // out.write(outToken);
213: // out.flush();
214: // data = new byte[2];
215: // i = readSocksReply(in, data);
216: // if (i != 2 || data[1] == 0xff) {
217: // in.close();
218: // out.close();
219: // return false;
220: // }
221: // i = readSocksReply(in, data);
222: // int len = 0;
223: // len = ((int)data[0] & 0xff) << 8;
224: // len += data[1];
225: // data = new byte[len];
226: // i = readSocksReply(in, data);
227: // if (i == len)
228: // return true;
229: // in.close();
230: // out.close();
231: // }
232: // }
233: // } catch (GSSException e) {
234: // /* RFC 1961 states that if Context initialisation fails the connection
235: // MUST be closed */
236: // e.printStackTrace();
237: // in.close();
238: // out.close();
239: // }
240: // }
241: return false;
242: }
243:
244: private void connectV4(InputStream in, OutputStream out,
245: InetSocketAddress endpoint) throws IOException {
246: out.write(PROTO_VERS4);
247: out.write(CONNECT);
248: out.write((endpoint.getPort() >> 8) & 0xff);
249: out.write((endpoint.getPort() >> 0) & 0xff);
250: out.write(endpoint.getAddress().getAddress());
251: String userName = (String) java.security.AccessController
252: .doPrivileged(new sun.security.action.GetPropertyAction(
253: "user.name"));
254: out.write(userName.getBytes());
255: out.write(0);
256: out.flush();
257: byte[] data = new byte[8];
258: int n = readSocksReply(in, data);
259: if (n != 8)
260: throw new SocketException(
261: "Reply from SOCKS server has bad length: " + n);
262: if (data[0] != 0 && data[0] != 4)
263: throw new SocketException(
264: "Reply from SOCKS server has bad version");
265: SocketException ex = null;
266: switch (data[1]) {
267: case 90:
268: // Success!
269: external_address = endpoint;
270: break;
271: case 91:
272: ex = new SocketException("SOCKS request rejected");
273: break;
274: case 92:
275: ex = new SocketException(
276: "SOCKS server couldn't reach destination");
277: break;
278: case 93:
279: ex = new SocketException("SOCKS authentication failed");
280: break;
281: default:
282: ex = new SocketException(
283: "Replay from SOCKS server contains bad status");
284: break;
285: }
286: if (ex != null) {
287: in.close();
288: out.close();
289: throw ex;
290: }
291: }
292:
293: /**
294: * Connects the Socks Socket to the specified endpoint. It will first
295: * connect to the SOCKS proxy and negotiate the access. If the proxy
296: * grants the connections, then the connect is successful and all
297: * further traffic will go to the "real" endpoint.
298: *
299: * @param endpoint the <code>SocketAddress</code> to connect to.
300: * @param timeout the timeout value in milliseconds
301: * @throws IOException if the connection can't be established.
302: * @throws SecurityException if there is a security manager and it
303: * doesn't allow the connection
304: * @throws IllegalArgumentException if endpoint is null or a
305: * SocketAddress subclass not supported by this socket
306: */
307: protected void connect(SocketAddress endpoint, int timeout)
308: throws IOException {
309: SecurityManager security = System.getSecurityManager();
310: if (endpoint == null
311: || !(endpoint instanceof InetSocketAddress))
312: throw new IllegalArgumentException(
313: "Unsupported address type");
314: InetSocketAddress epoint = (InetSocketAddress) endpoint;
315: if (security != null) {
316: if (epoint.isUnresolved())
317: security.checkConnect(epoint.getHostName(), epoint
318: .getPort());
319: else
320: security.checkConnect(epoint.getAddress()
321: .getHostAddress(), epoint.getPort());
322: }
323:
324: // Connects to the SOCKS server
325:
326: try {
327: privilegedConnect(server, port, timeout);
328: } catch (Exception e) {
329: throw new SocketException(e.getMessage());
330: }
331: // cmdIn & cmdOut were intialized during the privilegedConnect() call
332: DataOutputStream out = new DataOutputStream(cmdOut);
333: InputStream in = cmdIn;
334:
335: if (useV4) {
336: // SOCKS Protocol version 4 doesn't know how to deal with
337: // DOMAIN type of addresses (unresolved addresses here)
338: if (epoint.isUnresolved())
339: throw new UnknownHostException(epoint.toString());
340: connectV4(in, out, epoint);
341: return;
342: }
343:
344: // This is SOCKS V5
345: out.write(PROTO_VERS);
346: out.write(2);
347: out.write(NO_AUTH);
348: out.write(USER_PASSW);
349: out.flush();
350: byte[] data = new byte[2];
351: int i = readSocksReply(in, data);
352: if (i != 2 || ((int) data[1]) == NO_METHODS)
353: throw new SocketException("SOCKS : No acceptable methods");
354: if (!authenticate(data[1], in, out)) {
355: throw new SocketException("SOCKS : authentication failed");
356: }
357: out.write(PROTO_VERS);
358: out.write(CONNECT);
359: out.write(0);
360: /* Test for IPV4/IPV6/Unresolved */
361: if (epoint.isUnresolved()) {
362: out.write(DOMAIN_NAME);
363: out.write(epoint.getHostName().length());
364: out.write(epoint.getHostName().getBytes());
365: out.write((epoint.getPort() >> 8) & 0xff);
366: out.write((epoint.getPort() >> 0) & 0xff);
367: } else if (epoint.getAddress() instanceof Inet6Address) {
368: out.write(IPV6);
369: out.write(epoint.getAddress().getAddress());
370: out.write((epoint.getPort() >> 8) & 0xff);
371: out.write((epoint.getPort() >> 0) & 0xff);
372: } else {
373: out.write(IPV4);
374: out.write(epoint.getAddress().getAddress());
375: out.write((epoint.getPort() >> 8) & 0xff);
376: out.write((epoint.getPort() >> 0) & 0xff);
377: }
378: out.flush();
379: data = new byte[4];
380: i = readSocksReply(in, data);
381: if (i != 4)
382: throw new SocketException(
383: "Reply from SOCKS server has bad length");
384: SocketException ex = null;
385: int nport, len;
386: byte[] addr;
387: switch (data[1]) {
388: case REQUEST_OK:
389: // success!
390: switch (data[3]) {
391: case IPV4:
392: addr = new byte[4];
393: i = readSocksReply(in, addr);
394: if (i != 4)
395: throw new SocketException(
396: "Reply from SOCKS server badly formatted");
397: data = new byte[2];
398: i = readSocksReply(in, data);
399: if (i != 2)
400: throw new SocketException(
401: "Reply from SOCKS server badly formatted");
402: nport = ((int) data[0] & 0xff) << 8;
403: nport += ((int) data[1] & 0xff);
404: break;
405: case DOMAIN_NAME:
406: len = data[1];
407: byte[] host = new byte[len];
408: i = readSocksReply(in, host);
409: if (i != len)
410: throw new SocketException(
411: "Reply from SOCKS server badly formatted");
412: data = new byte[2];
413: i = readSocksReply(in, data);
414: if (i != 2)
415: throw new SocketException(
416: "Reply from SOCKS server badly formatted");
417: nport = ((int) data[0] & 0xff) << 8;
418: nport += ((int) data[1] & 0xff);
419: break;
420: case IPV6:
421: len = data[1];
422: addr = new byte[len];
423: i = readSocksReply(in, addr);
424: if (i != len)
425: throw new SocketException(
426: "Reply from SOCKS server badly formatted");
427: data = new byte[2];
428: i = readSocksReply(in, data);
429: if (i != 2)
430: throw new SocketException(
431: "Reply from SOCKS server badly formatted");
432: nport = ((int) data[0] & 0xff) << 8;
433: nport += ((int) data[1] & 0xff);
434: break;
435: default:
436: ex = new SocketException(
437: "Reply from SOCKS server contains wrong code");
438: break;
439: }
440: break;
441: case GENERAL_FAILURE:
442: ex = new SocketException("SOCKS server general failure");
443: break;
444: case NOT_ALLOWED:
445: ex = new SocketException(
446: "SOCKS: Connection not allowed by ruleset");
447: break;
448: case NET_UNREACHABLE:
449: ex = new SocketException("SOCKS: Network unreachable");
450: break;
451: case HOST_UNREACHABLE:
452: ex = new SocketException("SOCKS: Host unreachable");
453: break;
454: case CONN_REFUSED:
455: ex = new SocketException("SOCKS: Connection refused");
456: break;
457: case TTL_EXPIRED:
458: ex = new SocketException("SOCKS: TTL expired");
459: break;
460: case CMD_NOT_SUPPORTED:
461: ex = new SocketException("SOCKS: Command not supported");
462: break;
463: case ADDR_TYPE_NOT_SUP:
464: ex = new SocketException(
465: "SOCKS: address type not supported");
466: break;
467: }
468: if (ex != null) {
469: in.close();
470: out.close();
471: throw ex;
472: }
473: external_address = epoint;
474: }
475:
476: private void bindV4(InputStream in, OutputStream out,
477: InetAddress baddr, int lport) throws IOException {
478: super .bind(baddr, lport);
479: /* NOTE: Can test here for IPV4/IPV6 */
480: byte[] addr1 = baddr.getAddress();
481: /* Test for AnyLocal */
482: InetAddress naddr = baddr;
483: if (naddr.isAnyLocalAddress()) {
484: naddr = cmdsock.getLocalAddress();
485: addr1 = naddr.getAddress();
486: }
487: out.write(PROTO_VERS4);
488: out.write(BIND);
489: out.write((super .getLocalPort() >> 8) & 0xff);
490: out.write((super .getLocalPort() >> 0) & 0xff);
491: out.write(addr1);
492: String userName = (String) java.security.AccessController
493: .doPrivileged(new sun.security.action.GetPropertyAction(
494: "user.name"));
495: out.write(userName.getBytes());
496: out.write(0);
497: out.flush();
498: byte[] data = new byte[8];
499: int n = readSocksReply(in, data);
500: if (n != 8)
501: throw new SocketException(
502: "Reply from SOCKS server has bad length: " + n);
503: if (data[0] != 0 && data[0] != 4)
504: throw new SocketException(
505: "Reply from SOCKS server has bad version");
506: SocketException ex = null;
507: switch (data[1]) {
508: case 90:
509: // Success!
510: external_address = new InetSocketAddress(baddr, lport);
511: break;
512: case 91:
513: ex = new SocketException("SOCKS request rejected");
514: break;
515: case 92:
516: ex = new SocketException(
517: "SOCKS server couldn't reach destination");
518: break;
519: case 93:
520: ex = new SocketException("SOCKS authentication failed");
521: break;
522: default:
523: ex = new SocketException(
524: "Replay from SOCKS server contains bad status");
525: break;
526: }
527: if (ex != null) {
528: in.close();
529: out.close();
530: throw ex;
531: }
532:
533: }
534:
535: /**
536: * Binds this socket to the specified port number on the specified host.
537: *
538: * @param baddr the IP address of the remote host.
539: * @param lport the port number.
540: * @exception IOException if an I/O error occurs when binding this socket.
541: */
542: protected synchronized void bind(InetAddress baddr, int lport)
543: throws IOException {
544: if (socket != null) {
545: // this is a client socket, not a server socket, don't
546: // call the SOCKS proxy for a bind!
547: super .bind(baddr, lport);
548: return;
549: }
550:
551: // Connects to the SOCKS server
552:
553: try {
554: AccessController
555: .doPrivileged(new PrivilegedExceptionAction() {
556: public Object run() throws Exception {
557: cmdsock = new Socket(new PlainSocketImpl());
558: cmdsock.connect(new InetSocketAddress(
559: server, port));
560: cmdIn = cmdsock.getInputStream();
561: cmdOut = cmdsock.getOutputStream();
562: return null;
563: }
564: });
565: } catch (Exception e) {
566: throw new SocketException(e.getMessage());
567: }
568: DataOutputStream out = new DataOutputStream(cmdOut);
569: InputStream in = cmdIn;
570: if (useV4) {
571: bindV4(in, out, baddr, lport);
572: return;
573: }
574: out.write(PROTO_VERS);
575: out.write(2);
576: out.write(NO_AUTH);
577: out.write(USER_PASSW);
578: out.flush();
579: byte[] data = new byte[2];
580: int i = readSocksReply(in, data);
581: if (i != 2 || ((int) data[1]) == NO_METHODS)
582: throw new SocketException("SOCKS : No acceptable methods");
583: if (!authenticate(data[1], in, out)) {
584: throw new SocketException("SOCKS : authentication failed");
585: }
586: // We're OK. Let's issue the BIND command after we've bound ourself localy
587: super .bind(baddr, lport);
588: out.write(PROTO_VERS);
589: out.write(BIND);
590: out.write(0);
591: InetAddress naddr = baddr;
592: if (naddr.isAnyLocalAddress())
593: naddr = cmdsock.getLocalAddress();
594: byte[] addr1 = naddr.getAddress();
595: if (naddr.family == InetAddress.IPv4) {
596: out.write(IPV4);
597: out.write(addr1);
598: out.write((super .getLocalPort() >> 8) & 0xff);
599: out.write((super .getLocalPort() >> 0) & 0xff);
600: out.flush();
601: } else if (naddr.family == InetAddress.IPv6) {
602: /* Test for AnyLocal */
603: out.write(IPV6);
604: out.write(addr1);
605: out.write((super .getLocalPort() >> 8) & 0xff);
606: out.write((super .getLocalPort() >> 0) & 0xff);
607: out.flush();
608: } else {
609: cmdsock.close();
610: throw new SocketException("unsupported address type : "
611: + naddr);
612: }
613: data = new byte[4];
614: i = readSocksReply(in, data);
615: SocketException ex = null;
616: int len, nport;
617: byte[] addr;
618: switch (data[1]) {
619: case REQUEST_OK:
620: // success!
621: InetSocketAddress real_end = null;
622: switch (data[3]) {
623: case IPV4:
624: addr = new byte[4];
625: i = readSocksReply(in, addr);
626: if (i != 4)
627: throw new SocketException(
628: "Reply from SOCKS server badly formatted");
629: data = new byte[2];
630: i = readSocksReply(in, data);
631: if (i != 2)
632: throw new SocketException(
633: "Reply from SOCKS server badly formatted");
634: nport = ((int) data[0] & 0xff) << 8;
635: nport += ((int) data[1] & 0xff);
636: external_address = new InetSocketAddress(
637: new Inet4Address("", addr), nport);
638: break;
639: case DOMAIN_NAME:
640: len = data[1];
641: byte[] host = new byte[len];
642: i = readSocksReply(in, host);
643: if (i != len)
644: throw new SocketException(
645: "Reply from SOCKS server badly formatted");
646: data = new byte[2];
647: i = readSocksReply(in, data);
648: if (i != 2)
649: throw new SocketException(
650: "Reply from SOCKS server badly formatted");
651: nport = ((int) data[0] & 0xff) << 8;
652: nport += ((int) data[1] & 0xff);
653: external_address = new InetSocketAddress(new String(
654: host), nport);
655: break;
656: case IPV6:
657: len = data[1];
658: addr = new byte[len];
659: i = readSocksReply(in, addr);
660: if (i != len)
661: throw new SocketException(
662: "Reply from SOCKS server badly formatted");
663: data = new byte[2];
664: i = readSocksReply(in, data);
665: if (i != 2)
666: throw new SocketException(
667: "Reply from SOCKS server badly formatted");
668: nport = ((int) data[0] & 0xff) << 8;
669: nport += ((int) data[1] & 0xff);
670: external_address = new InetSocketAddress(
671: new Inet6Address("", addr), nport);
672: break;
673: }
674: break;
675: case GENERAL_FAILURE:
676: ex = new SocketException("SOCKS server general failure");
677: break;
678: case NOT_ALLOWED:
679: ex = new SocketException(
680: "SOCKS: Bind not allowed by ruleset");
681: break;
682: case NET_UNREACHABLE:
683: ex = new SocketException("SOCKS: Network unreachable");
684: break;
685: case HOST_UNREACHABLE:
686: ex = new SocketException("SOCKS: Host unreachable");
687: break;
688: case CONN_REFUSED:
689: ex = new SocketException("SOCKS: Connection refused");
690: break;
691: case TTL_EXPIRED:
692: ex = new SocketException("SOCKS: TTL expired");
693: break;
694: case CMD_NOT_SUPPORTED:
695: ex = new SocketException("SOCKS: Command not supported");
696: break;
697: case ADDR_TYPE_NOT_SUP:
698: ex = new SocketException(
699: "SOCKS: address type not supported");
700: break;
701: }
702: if (ex != null) {
703: in.close();
704: out.close();
705: cmdsock.close();
706: cmdsock = null;
707: throw ex;
708: }
709: cmdIn = in;
710: cmdOut = out;
711: }
712:
713: /**
714: * Accepts a connection.
715: *
716: * @param s the accepted connection.
717: * @exception IOException if an I/O error occurs when accepting the
718: * connection.
719: */
720: protected void accept(SocketImpl s) throws IOException {
721: if (cmdsock == null)
722: throw new SocketException("Socks channel closed");
723: InputStream in = cmdIn;
724: in.read();
725: int i = in.read();
726: in.read();
727: SocketException ex = null;
728: int nport;
729: byte[] addr;
730: InetSocketAddress real_end = null;
731: switch (i) {
732: case REQUEST_OK:
733: // success!
734: i = in.read();
735: switch (i) {
736: case IPV4:
737: addr = new byte[4];
738: readSocksReply(in, addr);
739: nport = in.read() << 8;
740: nport += in.read();
741: real_end = new InetSocketAddress(new Inet4Address("",
742: addr), nport);
743: break;
744: case DOMAIN_NAME:
745: int len = in.read();
746: addr = new byte[len];
747: readSocksReply(in, addr);
748: nport = in.read() << 8;
749: nport += in.read();
750: real_end = new InetSocketAddress(new String(addr),
751: nport);
752: break;
753: case IPV6:
754: addr = new byte[16];
755: readSocksReply(in, addr);
756: nport = in.read() << 8;
757: nport += in.read();
758: real_end = new InetSocketAddress(new Inet6Address("",
759: addr), nport);
760: break;
761: }
762: break;
763: case GENERAL_FAILURE:
764: ex = new SocketException("SOCKS server general failure");
765: break;
766: case NOT_ALLOWED:
767: ex = new SocketException(
768: "SOCKS: Accept not allowed by ruleset");
769: break;
770: case NET_UNREACHABLE:
771: ex = new SocketException("SOCKS: Network unreachable");
772: break;
773: case HOST_UNREACHABLE:
774: ex = new SocketException("SOCKS: Host unreachable");
775: break;
776: case CONN_REFUSED:
777: ex = new SocketException("SOCKS: Connection refused");
778: break;
779: case TTL_EXPIRED:
780: ex = new SocketException("SOCKS: TTL expired");
781: break;
782: case CMD_NOT_SUPPORTED:
783: ex = new SocketException("SOCKS: Command not supported");
784: break;
785: case ADDR_TYPE_NOT_SUP:
786: ex = new SocketException(
787: "SOCKS: address type not supported");
788: break;
789: }
790: if (ex != null) {
791: cmdIn.close();
792: cmdOut.close();
793: cmdsock.close();
794: cmdsock = null;
795: throw ex;
796: }
797:
798: /**
799: * This is where we have to do some fancy stuff.
800: * The datastream from the socket "accepted" by the proxy will
801: * come through the cmdSocket. So we have to swap the socketImpls
802: */
803: if (s instanceof SocksSocketImpl) {
804: ((SocksSocketImpl) s).external_address = real_end;
805: }
806: if (s instanceof PlainSocketImpl) {
807: ((PlainSocketImpl) s)
808: .setInputStream((SocketInputStream) in);
809: }
810: s.fd = cmdsock.getImpl().fd;
811: s.address = cmdsock.getImpl().address;
812: s.port = cmdsock.getImpl().port;
813: s.localport = cmdsock.getImpl().localport;
814: // Need to do that so that the socket won't be closed
815: // when the ServerSocket is closed by the user.
816: // It kinds of detaches the Socket because it is now
817: // used elsewhere.
818: cmdsock = null;
819: }
820:
821: /**
822: * Returns the value of this socket's <code>address</code> field.
823: *
824: * @return the value of this socket's <code>address</code> field.
825: * @see java.net.SocketImpl#address
826: */
827: protected InetAddress getInetAddress() {
828: if (external_address != null)
829: return external_address.getAddress();
830: else
831: return super .getInetAddress();
832: }
833:
834: /**
835: * Returns the value of this socket's <code>port</code> field.
836: *
837: * @return the value of this socket's <code>port</code> field.
838: * @see java.net.SocketImpl#port
839: */
840: protected int getPort() {
841: if (external_address != null)
842: return external_address.getPort();
843: else
844: return super .getPort();
845: }
846:
847: protected int getLocalPort() {
848: if (socket != null)
849: return super .getLocalPort();
850: if (external_address != null)
851: return external_address.getPort();
852: else
853: return super .getLocalPort();
854: }
855:
856: protected void close() throws IOException {
857: if (cmdsock != null)
858: cmdsock.close();
859: cmdsock = null;
860: super.close();
861: }
862:
863: }
|