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

Save This Page
Home » openjdk-7 » java » net » [javadoc | source]