KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > net > SocksSocketImpl


1 /*
2  * @(#)SocksSocketImpl.java 1.21 06/06/12
3  *
4  * Copyright 2006 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 JavaDoc;
9 import java.io.InputStream JavaDoc;
10 import java.io.OutputStream JavaDoc;
11 import java.io.BufferedOutputStream JavaDoc;
12 import java.security.AccessController JavaDoc;
13 import java.security.PrivilegedExceptionAction JavaDoc;
14 import java.util.prefs.Preferences JavaDoc;
15 import sun.net.www.ParseUtil;
16 /* import org.ietf.jgss.*; */
17
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
24 class SocksSocketImpl extends PlainSocketImpl JavaDoc implements SocksConsts JavaDoc {
25     private String JavaDoc server = null;
26     private int port = DEFAULT_PORT;
27     private InetSocketAddress JavaDoc external_address;
28     private boolean useV4 = false;
29     private Socket JavaDoc cmdsock = null;
30     private InputStream JavaDoc cmdIn = null;
31     private OutputStream JavaDoc cmdOut = null;
32
33     SocksSocketImpl() {
34     // Nothing needed
35
}
36
37     SocksSocketImpl(String JavaDoc server, int port) {
38     this.server = server;
39     this.port = (port == -1 ? DEFAULT_PORT : port);
40     }
41
42     SocksSocketImpl(Proxy JavaDoc proxy) {
43     SocketAddress JavaDoc a = proxy.address();
44     if (a instanceof InetSocketAddress JavaDoc) {
45         InetSocketAddress JavaDoc ad = (InetSocketAddress JavaDoc) a;
46         // Use getHostString() to avoid reverse lookups
47
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 JavaDoc host,
57                           final int port,
58                           final int timeout)
59      throws IOException JavaDoc
60     {
61     try {
62         AccessController.doPrivileged(
63           new java.security.PrivilegedExceptionAction JavaDoc() {
64               public Object JavaDoc run() throws IOException JavaDoc {
65                   superConnectServer(host, port, timeout);
66                   cmdIn = getInputStream();
67                   cmdOut = getOutputStream();
68                   return null;
69               }
70               });
71     } catch (java.security.PrivilegedActionException JavaDoc pae) {
72         throw (IOException JavaDoc) pae.getException();
73     }
74     }
75
76     private void superConnectServer(String JavaDoc host, int port,
77                     int timeout) throws IOException JavaDoc {
78     super.connect(new InetSocketAddress JavaDoc(host, port), timeout);
79     }
80
81     private int readSocksReply(InputStream JavaDoc in, byte[] data) throws IOException JavaDoc {
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 JavaDoc("Malformed reply from SOCKS server");
88         received += count;
89     }
90     return received;
91     }
92
93     /**
94      * Provides the authentication machanism required by the proxy.
95      */

96     private boolean authenticate(byte method, InputStream JavaDoc in,
97                  BufferedOutputStream JavaDoc out) throws IOException JavaDoc {
98     byte[] data = null;
99     int i;
100     // No Authentication required. We're done then!
101
if (method == NO_AUTH)
102         return true;
103     /**
104      * User/Password authentication. Try, in that order :
105      * - The application provided Authenticator, if any
106      * - The user preferences java.net.socks.username &
107      * java.net.socks.password
108      * - the user.name & no password (backward compatibility behavior).
109      */

110     if (method == USER_PASSW) {
111         String JavaDoc userName;
112         String JavaDoc password = null;
113         final InetAddress JavaDoc addr = InetAddress.getByName(server);
114         PasswordAuthentication JavaDoc pw = (PasswordAuthentication JavaDoc)
115         java.security.AccessController.doPrivileged(
116             new java.security.PrivilegedAction JavaDoc() {
117                 public Object JavaDoc 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 JavaDoc(pw.getPassword());
125         } else {
126         final Preferences JavaDoc prefs = Preferences.userRoot().node("/java/net/socks");
127         try {
128             userName =
129             (String JavaDoc) AccessController.doPrivileged(
130                    new java.security.PrivilegedExceptionAction JavaDoc() {
131                        public Object JavaDoc run() throws IOException JavaDoc {
132                        return prefs.get("username", null);
133                        }
134                    });
135         } catch (java.security.PrivilegedActionException JavaDoc pae) {
136             throw (IOException JavaDoc) pae.getException();
137         }
138
139         if (userName != null) {
140             try {
141             password =
142                 (String JavaDoc) AccessController.doPrivileged(
143                    new java.security.PrivilegedExceptionAction JavaDoc() {
144                        public Object JavaDoc run() throws IOException JavaDoc {
145                            return prefs.get("password", null);
146                        }
147                        });
148             } catch (java.security.PrivilegedActionException JavaDoc pae) {
149             throw (IOException JavaDoc) pae.getException();
150             }
151         } else {
152             userName =
153             (String JavaDoc) 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 JavaDoc 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 JavaDoc 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         /* RFC 1929 specifies that the connection MUST be closed if
180            authentication fails */

181         out.close();
182         in.close();
183         return false;
184         }
185         /* Authentication succeeded */
186         return true;
187     }
188     /**
189      * GSSAPI authentication mechanism.
190      * Unfortunately the RFC seems out of sync with the Reference
191      * implementation. I'll leave this in for future completion.
192      */

193 // if (method == GSSAPI) {
194
// try {
195
// GSSManager manager = GSSManager.getInstance();
196
// GSSName name = manager.createName("SERVICE:socks@"+server,
197
// null);
198
// GSSContext context = manager.createContext(name, null, null,
199
// GSSContext.DEFAULT_LIFETIME);
200
// context.requestMutualAuth(true);
201
// context.requestReplayDet(true);
202
// context.requestSequenceDet(true);
203
// context.requestCredDeleg(true);
204
// byte []inToken = new byte[0];
205
// while (!context.isEstablished()) {
206
// byte[] outToken
207
// = context.initSecContext(inToken, 0, inToken.length);
208
// // send the output token if generated
209
// if (outToken != null) {
210
// out.write(1);
211
// out.write(1);
212
// out.writeShort(outToken.length);
213
// out.write(outToken);
214
// out.flush();
215
// data = new byte[2];
216
// i = readSocksReply(in, data);
217
// if (i != 2 || data[1] == 0xff) {
218
// in.close();
219
// out.close();
220
// return false;
221
// }
222
// i = readSocksReply(in, data);
223
// int len = 0;
224
// len = ((int)data[0] & 0xff) << 8;
225
// len += data[1];
226
// data = new byte[len];
227
// i = readSocksReply(in, data);
228
// if (i == len)
229
// return true;
230
// in.close();
231
// out.close();
232
// }
233
// }
234
// } catch (GSSException e) {
235
// /* RFC 1961 states that if Context initialisation fails the connection
236
// MUST be closed */
237
// e.printStackTrace();
238
// in.close();
239
// out.close();
240
// }
241
// }
242
return false;
243     }
244
245     private void connectV4(InputStream JavaDoc in, OutputStream JavaDoc out,
246                InetSocketAddress JavaDoc endpoint) throws IOException JavaDoc {
247     if (!(endpoint.getAddress() instanceof Inet4Address JavaDoc)) {
248         throw new SocketException JavaDoc("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 JavaDoc userName = (String JavaDoc) 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 JavaDoc 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 JavaDoc("Reply from SOCKS server has bad length: " + n);
268     if (data[0] != 0 && data[0] != 4)
269         throw new SocketException JavaDoc("Reply from SOCKS server has bad version");
270     SocketException JavaDoc ex = null;
271     switch (data[1]) {
272     case 90:
273         // Success!
274
external_address = endpoint;
275         break;
276     case 91:
277         ex = new SocketException JavaDoc("SOCKS request rejected");
278         break;
279     case 92:
280         ex = new SocketException JavaDoc("SOCKS server couldn't reach destination");
281         break;
282     case 93:
283         ex = new SocketException JavaDoc("SOCKS authentication failed");
284         break;
285     default:
286         ex = new SocketException JavaDoc("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     /**
297      * Connects the Socks Socket to the specified endpoint. It will first
298      * connect to the SOCKS proxy and negotiate the access. If the proxy
299      * grants the connections, then the connect is successful and all
300      * further traffic will go to the "real" endpoint.
301      *
302      * @param endpoint the <code>SocketAddress</code> to connect to.
303      * @param timeout the timeout value in milliseconds
304      * @throws IOException if the connection can't be established.
305      * @throws SecurityException if there is a security manager and it
306      * doesn't allow the connection
307      * @throws IllegalArgumentException if endpoint is null or a
308      * SocketAddress subclass not supported by this socket
309      */

310     protected void connect(SocketAddress JavaDoc endpoint, int timeout) throws IOException JavaDoc {
311     SecurityManager JavaDoc security = System.getSecurityManager();
312     if (endpoint == null || !(endpoint instanceof InetSocketAddress JavaDoc))
313         throw new IllegalArgumentException JavaDoc("Unsupported address type");
314     InetSocketAddress JavaDoc epoint = (InetSocketAddress JavaDoc) 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         // This is the general case
325
// server is not null only when the socket was created with a
326
// specified proxy in which case it does bypass the ProxySelector
327
ProxySelector JavaDoc sel = (ProxySelector JavaDoc)
328         java.security.AccessController.doPrivileged(
329             new java.security.PrivilegedAction JavaDoc() {
330             public Object JavaDoc run() {
331                 return ProxySelector.getDefault();
332             }
333             });
334         if (sel == null) {
335         /*
336          * No default proxySelector --> direct connection
337          */

338         super.connect(epoint, timeout);
339         return;
340         }
341         URI JavaDoc uri = null;
342         // Use getHostString() to avoid reverse lookups
343
String JavaDoc host = epoint.getHostString();
344         // IPv6 litteral?
345
if (epoint.getAddress() instanceof Inet6Address JavaDoc &&
346         (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
347         host = "[" + host + "]";
348         }
349         try {
350         uri = new URI JavaDoc("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort());
351         } catch (URISyntaxException JavaDoc e) {
352         // This shouldn't happen
353
assert false : e;
354         }
355         Proxy JavaDoc p = null;
356         IOException JavaDoc savedExc = null;
357         java.util.Iterator JavaDoc<Proxy JavaDoc> 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 JavaDoc("Unknown proxy type : " + p.type());
371         if (!(p.address() instanceof InetSocketAddress JavaDoc))
372             throw new SocketException JavaDoc("Unknow address type for proxy: " + p);
373         // Use getHostString() to avoid reverse lookups
374
server = ((InetSocketAddress JavaDoc) p.address()).getHostString();
375         port = ((InetSocketAddress JavaDoc) p.address()).getPort();
376         
377         // Connects to the SOCKS server
378
try {
379             privilegedConnect(server, port, timeout);
380             // Worked, let's get outta here
381
break;
382         } catch (IOException JavaDoc e) {
383             // Ooops, let's notify the ProxySelector
384
sel.connectFailed(uri,p.address(),e);
385             server = null;
386             port = -1;
387             savedExc = e;
388             // Will continue the while loop and try the next proxy
389
}
390         }
391
392         /*
393          * If server is still null at this point, none of the proxy
394          * worked
395          */

396         if (server == null) {
397         throw new SocketException JavaDoc("Can't connect to SOCKS proxy:"
398                       + savedExc.getMessage());
399         }
400     } else {
401         // Connects to the SOCKS server
402
try {
403         privilegedConnect(server, port, timeout);
404         } catch (IOException JavaDoc e) {
405         throw new SocketException JavaDoc(e.getMessage());
406         }
407     }
408
409     // cmdIn & cmdOut were intialized during the privilegedConnect() call
410
BufferedOutputStream JavaDoc out = new BufferedOutputStream JavaDoc(cmdOut, 512);
411     InputStream JavaDoc in = cmdIn;
412
413     if (useV4) {
414         // SOCKS Protocol version 4 doesn't know how to deal with
415
// DOMAIN type of addresses (unresolved addresses here)
416
if (epoint.isUnresolved())
417         throw new UnknownHostException JavaDoc(epoint.toString());
418         connectV4(in, out, epoint);
419         return;
420     }
421
422     // This is SOCKS V5
423
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         // Maybe it's not a V5 sever after all
432
// Let's try V4 before we give up
433
// SOCKS Protocol version 4 doesn't know how to deal with
434
// DOMAIN type of addresses (unresolved addresses here)
435
if (epoint.isUnresolved())
436         throw new UnknownHostException JavaDoc(epoint.toString());
437         connectV4(in, out, epoint);
438         return;
439     }
440     if (((int)data[1]) == NO_METHODS)
441         throw new SocketException JavaDoc("SOCKS : No acceptable methods");
442     if (!authenticate(data[1], in, out)) {
443         throw new SocketException JavaDoc("SOCKS : authentication failed");
444     }
445     out.write(PROTO_VERS);
446     out.write(CONNECT);
447     out.write(0);
448     /* Test for IPV4/IPV6/Unresolved */
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 JavaDoc 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 JavaDoc) {
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 JavaDoc("Reply from SOCKS server has bad length");
475     SocketException JavaDoc ex = null;
476     int nport, len;
477     byte[] addr;
478     switch (data[1]) {
479     case REQUEST_OK:
480         // success!
481
switch(data[3]) {
482         case IPV4:
483         addr = new byte[4];
484         i = readSocksReply(in, addr);
485         if (i != 4)
486             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
487         data = new byte[2];
488         i = readSocksReply(in, data);
489         if (i != 2)
490             throw new SocketException JavaDoc("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 JavaDoc("Reply from SOCKS server badly formatted");
500         data = new byte[2];
501         i = readSocksReply(in, data);
502         if (i != 2)
503             throw new SocketException JavaDoc("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 JavaDoc("Reply from SOCKS server badly formatted");
513         data = new byte[2];
514         i = readSocksReply(in, data);
515         if (i != 2)
516             throw new SocketException JavaDoc("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 JavaDoc("Reply from SOCKS server contains wrong code");
522         break;
523         }
524         break;
525     case GENERAL_FAILURE:
526         ex = new SocketException JavaDoc("SOCKS server general failure");
527         break;
528     case NOT_ALLOWED:
529         ex = new SocketException JavaDoc("SOCKS: Connection not allowed by ruleset");
530         break;
531     case NET_UNREACHABLE:
532         ex = new SocketException JavaDoc("SOCKS: Network unreachable");
533         break;
534     case HOST_UNREACHABLE:
535         ex = new SocketException JavaDoc("SOCKS: Host unreachable");
536         break;
537     case CONN_REFUSED:
538         ex = new SocketException JavaDoc("SOCKS: Connection refused");
539         break;
540     case TTL_EXPIRED:
541         ex = new SocketException JavaDoc("SOCKS: TTL expired");
542         break;
543     case CMD_NOT_SUPPORTED:
544         ex = new SocketException JavaDoc("SOCKS: Command not supported");
545         break;
546     case ADDR_TYPE_NOT_SUP:
547         ex = new SocketException JavaDoc("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 JavaDoc in, OutputStream JavaDoc out,
559             InetAddress JavaDoc baddr,
560             int lport) throws IOException JavaDoc {
561     if (!(baddr instanceof Inet4Address JavaDoc)) {
562         throw new SocketException JavaDoc("SOCKS V4 requires IPv4 only addresses");
563     }
564     super.bind(baddr, lport);
565     byte[] addr1 = baddr.getAddress();
566     /* Test for AnyLocal */
567     InetAddress JavaDoc 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 JavaDoc userName = (String JavaDoc) 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 JavaDoc 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 JavaDoc("Reply from SOCKS server has bad length: " + n);
590     if (data[0] != 0 && data[0] != 4)
591         throw new SocketException JavaDoc("Reply from SOCKS server has bad version");
592     SocketException JavaDoc ex = null;
593     switch (data[1]) {
594     case 90:
595         // Success!
596
external_address = new InetSocketAddress JavaDoc(baddr, lport);
597         break;
598     case 91:
599         ex = new SocketException JavaDoc("SOCKS request rejected");
600         break;
601     case 92:
602         ex = new SocketException JavaDoc("SOCKS server couldn't reach destination");
603         break;
604     case 93:
605         ex = new SocketException JavaDoc("SOCKS authentication failed");
606         break;
607     default:
608         ex = new SocketException JavaDoc("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     /**
620      * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
621      * means "accept incoming connection from", so the SocketAddress is the
622      * the one of the host we do accept connection from.
623      *
624      * @param addr the Socket address of the remote host.
625      * @exception IOException if an I/O error occurs when binding this socket.
626      */

627     protected synchronized void socksBind(InetSocketAddress JavaDoc saddr) throws IOException JavaDoc {
628     if (socket != null) {
629         // this is a client socket, not a server socket, don't
630
// call the SOCKS proxy for a bind!
631
return;
632     }
633
634     // Connects to the SOCKS server
635

636     if (server == null) {
637         // This is the general case
638
// server is not null only when the socket was created with a
639
// specified proxy in which case it does bypass the ProxySelector
640
ProxySelector JavaDoc sel = (ProxySelector JavaDoc)
641         java.security.AccessController.doPrivileged(
642             new java.security.PrivilegedAction JavaDoc() {
643             public Object JavaDoc run() {
644                 return ProxySelector.getDefault();
645             }
646             });
647         if (sel == null) {
648         /*
649          * No default proxySelector --> direct connection
650          */

651         return;
652         }
653         URI JavaDoc uri = null;
654         // Use getHostString() to avoid reverse lookups
655
String JavaDoc host = saddr.getHostString();
656         // IPv6 litteral?
657
if (saddr.getAddress() instanceof Inet6Address JavaDoc &&
658         (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
659         host = "[" + host + "]";
660         }
661         try {
662         uri = new URI JavaDoc("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort());
663         } catch (URISyntaxException JavaDoc e) {
664         // This shouldn't happen
665
assert false : e;
666         }
667         Proxy JavaDoc p = null;
668         Exception JavaDoc savedExc = null;
669         java.util.Iterator JavaDoc<Proxy JavaDoc> 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 JavaDoc("Unknown proxy type : " + p.type());
681         if (!(p.address() instanceof InetSocketAddress JavaDoc))
682             throw new SocketException JavaDoc("Unknow address type for proxy: " + p);
683         // Use getHostString() to avoid reverse lookups
684
server = ((InetSocketAddress JavaDoc) p.address()).getHostString();
685         port = ((InetSocketAddress JavaDoc) p.address()).getPort();
686         
687         // Connects to the SOCKS server
688
try {
689             AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc() {
690                 public Object JavaDoc run() throws Exception JavaDoc {
691                 cmdsock = new Socket JavaDoc(new PlainSocketImpl JavaDoc());
692                 cmdsock.connect(new InetSocketAddress JavaDoc(server, port));
693                 cmdIn = cmdsock.getInputStream();
694                 cmdOut = cmdsock.getOutputStream();
695                 return null;
696                 }
697             });
698         } catch (Exception JavaDoc e) {
699             // Ooops, let's notify the ProxySelector
700
sel.connectFailed(uri,p.address(),new SocketException JavaDoc(e.getMessage()));
701             server = null;
702             port = -1;
703             cmdsock = null;
704             savedExc = e;
705             // Will continue the while loop and try the next proxy
706
}
707         }
708
709         /*
710          * If server is still null at this point, none of the proxy
711          * worked
712          */

713         if (server == null || cmdsock == null) {
714         throw new SocketException JavaDoc("Can't connect to SOCKS proxy:"
715                       + savedExc.getMessage());
716         }
717     } else {
718         try {
719         AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc() {
720             public Object JavaDoc run() throws Exception JavaDoc {
721                 cmdsock = new Socket JavaDoc(new PlainSocketImpl JavaDoc());
722                 cmdsock.connect(new InetSocketAddress JavaDoc(server, port));
723                 cmdIn = cmdsock.getInputStream();
724                 cmdOut = cmdsock.getOutputStream();
725                 return null;
726             }
727             });
728         } catch (Exception JavaDoc e) {
729         throw new SocketException JavaDoc(e.getMessage());
730         }
731     }
732     BufferedOutputStream JavaDoc out = new BufferedOutputStream JavaDoc(cmdOut, 512);
733     InputStream JavaDoc in = cmdIn;
734     if (useV4) {
735         bindV4(in, out, saddr.getAddress(), saddr.getPort());
736         return;
737     }
738     out.write(PROTO_VERS);
739     out.write(2);
740     out.write(NO_AUTH);
741     out.write(USER_PASSW);
742     out.flush();
743     byte[] data = new byte[2];
744     int i = readSocksReply(in, data);
745     if (i != 2 || ((int)data[0]) != PROTO_VERS) {
746         // Maybe it's not a V5 sever after all
747
// Let's try V4 before we give up
748
bindV4(in, out, saddr.getAddress(), saddr.getPort());
749         return;
750     }
751     if (((int)data[1]) == NO_METHODS)
752         throw new SocketException JavaDoc("SOCKS : No acceptable methods");
753     if (!authenticate(data[1], in, out)) {
754         throw new SocketException JavaDoc("SOCKS : authentication failed");
755     }
756     // We're OK. Let's issue the BIND command.
757
out.write(PROTO_VERS);
758     out.write(BIND);
759     out.write(0);
760     int lport = saddr.getPort();
761     if (saddr.isUnresolved()) {
762         out.write(DOMAIN_NAME);
763         out.write(saddr.getHostName().length());
764         try {
765         out.write(saddr.getHostName().getBytes("ISO-8859-1"));
766         } catch (java.io.UnsupportedEncodingException JavaDoc uee) {
767         assert false;
768         }
769         out.write((lport >> 8) & 0xff);
770         out.write((lport >> 0) & 0xff);
771     } else if (saddr.getAddress() instanceof Inet4Address JavaDoc) {
772         byte[] addr1 = saddr.getAddress().getAddress();
773         out.write(IPV4);
774         out.write(addr1);
775         out.write((lport >> 8) & 0xff);
776         out.write((lport >> 0) & 0xff);
777         out.flush();
778     } else if (saddr.getAddress() instanceof Inet6Address JavaDoc) {
779         byte[] addr1 = saddr.getAddress().getAddress();
780         out.write(IPV6);
781         out.write(addr1);
782         out.write((lport >> 8) & 0xff);
783         out.write((lport >> 0) & 0xff);
784         out.flush();
785     } else {
786         cmdsock.close();
787         throw new SocketException JavaDoc("unsupported address type : " + saddr);
788     }
789     data = new byte[4];
790     i = readSocksReply(in, data);
791     SocketException JavaDoc ex = null;
792     int len, nport;
793     byte[] addr;
794     switch (data[1]) {
795     case REQUEST_OK:
796         // success!
797
InetSocketAddress JavaDoc real_end = null;
798         switch(data[3]) {
799         case IPV4:
800         addr = new byte[4];
801         i = readSocksReply(in, addr);
802         if (i != 4)
803             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
804         data = new byte[2];
805         i = readSocksReply(in, data);
806         if (i != 2)
807             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
808         nport = ((int)data[0] & 0xff) << 8;
809         nport += ((int)data[1] & 0xff);
810         external_address =
811             new InetSocketAddress JavaDoc(new Inet4Address JavaDoc("", addr) , nport);
812         break;
813         case DOMAIN_NAME:
814         len = data[1];
815         byte[] host = new byte[len];
816         i = readSocksReply(in, host);
817         if (i != len)
818             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
819         data = new byte[2];
820         i = readSocksReply(in, data);
821         if (i != 2)
822             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
823         nport = ((int)data[0] & 0xff) << 8;
824         nport += ((int)data[1] & 0xff);
825         external_address = new InetSocketAddress JavaDoc(new String JavaDoc(host), nport);
826         break;
827         case IPV6:
828         len = data[1];
829         addr = new byte[len];
830         i = readSocksReply(in, addr);
831         if (i != len)
832             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
833         data = new byte[2];
834         i = readSocksReply(in, data);
835         if (i != 2)
836             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
837         nport = ((int)data[0] & 0xff) << 8;
838         nport += ((int)data[1] & 0xff);
839         external_address =
840             new InetSocketAddress JavaDoc(new Inet6Address JavaDoc("", addr), nport);
841         break;
842         }
843         break;
844     case GENERAL_FAILURE:
845         ex = new SocketException JavaDoc("SOCKS server general failure");
846         break;
847     case NOT_ALLOWED:
848         ex = new SocketException JavaDoc("SOCKS: Bind not allowed by ruleset");
849         break;
850     case NET_UNREACHABLE:
851         ex = new SocketException JavaDoc("SOCKS: Network unreachable");
852         break;
853     case HOST_UNREACHABLE:
854         ex = new SocketException JavaDoc("SOCKS: Host unreachable");
855         break;
856     case CONN_REFUSED:
857         ex = new SocketException JavaDoc("SOCKS: Connection refused");
858         break;
859     case TTL_EXPIRED:
860         ex = new SocketException JavaDoc("SOCKS: TTL expired");
861         break;
862     case CMD_NOT_SUPPORTED:
863         ex = new SocketException JavaDoc("SOCKS: Command not supported");
864         break;
865     case ADDR_TYPE_NOT_SUP:
866         ex = new SocketException JavaDoc("SOCKS: address type not supported");
867         break;
868     }
869     if (ex != null) {
870         in.close();
871         out.close();
872         cmdsock.close();
873         cmdsock = null;
874         throw ex;
875     }
876     cmdIn = in;
877     cmdOut = out;
878     }
879
880     /**
881      * Accepts a connection from a specific host.
882      *
883      * @param s the accepted connection.
884      * @param saddr the socket address of the host we do accept
885      * connection from
886      * @exception IOException if an I/O error occurs when accepting the
887      * connection.
888      */

889     protected void acceptFrom(SocketImpl JavaDoc s, InetSocketAddress JavaDoc saddr) throws IOException JavaDoc {
890     if (cmdsock == null) {
891         // Not a Socks ServerSocket.
892
return;
893     }
894     InputStream JavaDoc in = cmdIn;
895     // Sends the "SOCKS BIND" request.
896
socksBind(saddr);
897     in.read();
898     int i = in.read();
899     in.read();
900     SocketException JavaDoc ex = null;
901     int nport;
902     byte[] addr;
903     InetSocketAddress JavaDoc real_end = null;
904     switch (i) {
905     case REQUEST_OK:
906         // success!
907
i = in.read();
908         switch(i) {
909         case IPV4:
910         addr = new byte[4];
911         readSocksReply(in, addr);
912         nport = in.read() << 8;
913         nport += in.read();
914         real_end =
915             new InetSocketAddress JavaDoc(new Inet4Address JavaDoc("", addr) , nport);
916         break;
917         case DOMAIN_NAME:
918         int len = in.read();
919         addr = new byte[len];
920         readSocksReply(in, addr);
921         nport = in.read() << 8;
922         nport += in.read();
923         real_end = new InetSocketAddress JavaDoc(new String JavaDoc(addr), nport);
924         break;
925         case IPV6:
926         addr = new byte[16];
927         readSocksReply(in, addr);
928         nport = in.read() << 8;
929         nport += in.read();
930         real_end =
931             new InetSocketAddress JavaDoc(new Inet6Address JavaDoc("", addr), nport);
932         break;
933         }
934         break;
935     case GENERAL_FAILURE:
936         ex = new SocketException JavaDoc("SOCKS server general failure");
937         break;
938     case NOT_ALLOWED:
939         ex = new SocketException JavaDoc("SOCKS: Accept not allowed by ruleset");
940         break;
941     case NET_UNREACHABLE:
942         ex = new SocketException JavaDoc("SOCKS: Network unreachable");
943         break;
944     case HOST_UNREACHABLE:
945         ex = new SocketException JavaDoc("SOCKS: Host unreachable");
946         break;
947     case CONN_REFUSED:
948         ex = new SocketException JavaDoc("SOCKS: Connection refused");
949         break;
950     case TTL_EXPIRED:
951         ex = new SocketException JavaDoc("SOCKS: TTL expired");
952         break;
953     case CMD_NOT_SUPPORTED:
954         ex = new SocketException JavaDoc("SOCKS: Command not supported");
955         break;
956     case ADDR_TYPE_NOT_SUP:
957         ex = new SocketException JavaDoc("SOCKS: address type not supported");
958         break;
959     }
960     if (ex != null) {
961         cmdIn.close();
962         cmdOut.close();
963         cmdsock.close();
964         cmdsock = null;
965         throw ex;
966     }
967     
968     /**
969      * This is where we have to do some fancy stuff.
970      * The datastream from the socket "accepted" by the proxy will
971      * come through the cmdSocket. So we have to swap the socketImpls
972      */

973     if (s instanceof SocksSocketImpl JavaDoc) {
974         ((SocksSocketImpl JavaDoc)s).external_address = real_end;
975     }
976     if (s instanceof PlainSocketImpl JavaDoc) {
977         ((PlainSocketImpl JavaDoc)s).setInputStream((SocketInputStream JavaDoc) in);
978     }
979     s.fd = cmdsock.getImpl().fd;
980     s.address = cmdsock.getImpl().address;
981     s.port = cmdsock.getImpl().port;
982     s.localport = cmdsock.getImpl().localport;
983     // Need to do that so that the socket won't be closed
984
// when the ServerSocket is closed by the user.
985
// It kinds of detaches the Socket because it is now
986
// used elsewhere.
987
cmdsock = null;
988     }
989
990     
991     /**
992      * Returns the value of this socket's <code>address</code> field.
993      *
994      * @return the value of this socket's <code>address</code> field.
995      * @see java.net.SocketImpl#address
996      */

997     protected InetAddress JavaDoc getInetAddress() {
998     if (external_address != null)
999         return external_address.getAddress();
1000    else
1001        return super.getInetAddress();
1002    }
1003
1004    /**
1005     * Returns the value of this socket's <code>port</code> field.
1006     *
1007     * @return the value of this socket's <code>port</code> field.
1008     * @see java.net.SocketImpl#port
1009     */

1010    protected int getPort() {
1011    if (external_address != null)
1012        return external_address.getPort();
1013    else
1014        return super.getPort();
1015    }
1016
1017    protected int getLocalPort() {
1018    if (socket != null)
1019        return super.getLocalPort();
1020    if (external_address != null)
1021        return external_address.getPort();
1022    else
1023        return super.getLocalPort();
1024    }
1025
1026    protected void close() throws IOException JavaDoc {
1027    if (cmdsock != null)
1028        cmdsock.close();
1029    cmdsock = null;
1030    super.close();
1031    }
1032
1033}
1034
Popular Tags