Пример #1
0
  /**
   * Act as a SOCKS 5 client to connect to an outproxy
   *
   * @return open socket or throws error
   * @since 0.8.2
   */
  private I2PSocket outproxyConnect(I2PSOCKSTunnel tun, String proxy)
      throws IOException, SOCKSException, DataFormatException, I2PException {
    Properties overrides = new Properties();
    overrides.setProperty("option.i2p.streaming.connectDelay", "1000");
    I2PSocketOptions proxyOpts = tun.buildOptions(overrides);
    Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(proxy);
    if (dest == null) throw new SOCKSException("Outproxy not found");
    I2PSocket destSock =
        tun.createI2PSocket(
            I2PAppContext.getGlobalContext().namingService().lookup(proxy), proxyOpts);
    try {
      DataOutputStream out = new DataOutputStream(destSock.getOutputStream());
      boolean authAvail =
          Boolean.parseBoolean(props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH));
      String configUser = null;
      String configPW = null;
      if (authAvail) {
        configUser = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_USER_PREFIX + proxy);
        configPW = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW_PREFIX + proxy);
        if (configUser == null || configPW == null) {
          configUser = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_USER);
          configPW = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW);
          if (configUser == null || configPW == null) authAvail = false;
        }
      }

      // send the init
      out.writeByte(SOCKS_VERSION_5);
      if (authAvail) {
        out.writeByte(2);
        out.writeByte(Method.NO_AUTH_REQUIRED);
        out.writeByte(Method.USERNAME_PASSWORD);
      } else {
        out.writeByte(1);
        out.writeByte(Method.NO_AUTH_REQUIRED);
      }
      out.flush();

      // read init reply
      DataInputStream in = new DataInputStream(destSock.getInputStream());
      // is this right or should we not try to do 5-to-4 conversion?
      int hisVersion = in.readByte();
      if (hisVersion != SOCKS_VERSION_5 /* && addrtype == AddressType.DOMAINNAME */)
        throw new SOCKSException("SOCKS Outproxy is not Version 5");
      // else if (hisVersion != 4)
      //    throw new SOCKSException("Unsupported SOCKS Outproxy Version");

      int method = in.readByte();
      if (method == Method.NO_AUTH_REQUIRED) {
        // good
      } else if (method == Method.USERNAME_PASSWORD) {
        if (authAvail) {
          // send the auth
          out.writeByte(AUTH_VERSION);
          byte[] user = configUser.getBytes("UTF-8");
          byte[] pw = configPW.getBytes("UTF-8");
          out.writeByte(user.length);
          out.write(user);
          out.writeByte(pw.length);
          out.write(pw);
          out.flush();
          // read the auth reply
          if (in.readByte() != AUTH_VERSION)
            throw new SOCKSException("Bad auth version from outproxy");
          if (in.readByte() != AUTH_SUCCESS)
            throw new SOCKSException("Outproxy authorization failure");
        } else {
          throw new SOCKSException(
              "Outproxy requires authorization, please configure username/password");
        }
      } else {
        throw new SOCKSException("Outproxy authorization failure");
      }

      // send the connect command
      out.writeByte(SOCKS_VERSION_5);
      out.writeByte(Command.CONNECT);
      out.writeByte(0); // reserved
      out.writeByte(addressType);
      if (addressType == AddressType.IPV4) {
        out.write(InetAddress.getByName(connHostName).getAddress());
      } else if (addressType == AddressType.DOMAINNAME) {
        byte[] d = connHostName.getBytes("ISO-8859-1");
        out.writeByte(d.length);
        out.write(d);
      } else {
        // shouldn't happen
        throw new SOCKSException("Unknown address type for outproxy?");
      }
      out.writeShort(connPort);
      out.flush();

      // read the connect reply
      hisVersion = in.readByte();
      if (hisVersion != SOCKS_VERSION_5)
        throw new SOCKSException("Outproxy response is not Version 5");
      int reply = in.readByte();
      in.readByte(); // reserved
      int type = in.readByte();
      int count = 0;
      if (type == AddressType.IPV4) {
        count = 4;
      } else if (type == AddressType.DOMAINNAME) {
        count = in.readUnsignedByte();
      } else if (type == AddressType.IPV6) {
        count = 16;
      } else {
        throw new SOCKSException("Unsupported address type in outproxy response");
      }
      byte[] addr = new byte[count];
      in.readFully(addr); // address
      in.readUnsignedShort(); // port
      if (reply != Reply.SUCCEEDED)
        throw new SOCKSException("Outproxy rejected request, response = " + reply);
      // throw away the address in the response
      // todo pass the response through?
    } catch (IOException e) {
      try {
        destSock.close();
      } catch (IOException ioe) {
      }
      throw e;
    } catch (SOCKSException e) {
      try {
        destSock.close();
      } catch (IOException ioe) {
      }
      throw e;
    }
    // that's it, caller will send confirmation to our client
    return destSock;
  }
Пример #2
0
  /**
   * Get an I2PSocket that can be used to send/receive 8-bit clean data to/from the destination of
   * the SOCKS connection.
   *
   * @return an I2PSocket connected with the destination
   */
  public I2PSocket getDestinationI2PSocket(I2PSOCKSTunnel t) throws SOCKSException {
    setupServer();

    if (connHostName == null) {
      _log.error("BUG: destination host name has not been initialized!");
      throw new SOCKSException("BUG! See the logs!");
    }
    if (connPort == 0) {
      _log.error("BUG: destination port has not been initialized!");
      throw new SOCKSException("BUG! See the logs!");
    }

    DataOutputStream out; // for errors
    try {
      out = new DataOutputStream(clientSock.getOutputStream());
    } catch (IOException e) {
      throw new SOCKSException("Connection error: " + e);
    }

    // FIXME: here we should read our config file, select an
    // outproxy, and instantiate the proper socket class that
    // handles the outproxy itself (SOCKS4a, SOCKS5, HTTP CONNECT...).
    I2PSocket destSock;

    try {
      if (connHostName.toLowerCase(Locale.US).endsWith(".i2p")) {
        _log.debug("connecting to " + connHostName + "...");
        // Let's not due a new Dest for every request, huh?
        // I2PSocketManager sm = I2PSocketManagerFactory.createManager();
        // destSock = sm.connect(I2PTunnel.destFromName(connHostName), null);
        Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(connHostName);
        if (dest == null) {
          try {
            sendRequestReply(
                Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
          } catch (IOException ioe) {
          }
          throw new SOCKSException("Host not found");
        }
        Properties overrides = new Properties();
        I2PSocketOptions sktOpts = t.buildOptions(overrides);
        sktOpts.setPort(connPort);
        destSock =
            t.createI2PSocket(
                I2PAppContext.getGlobalContext().namingService().lookup(connHostName), sktOpts);
      } else if ("localhost".equals(connHostName) || "127.0.0.1".equals(connHostName)) {
        String err = "No localhost accesses allowed through the Socks Proxy";
        _log.error(err);
        try {
          sendRequestReply(
              Reply.CONNECTION_NOT_ALLOWED_BY_RULESET,
              AddressType.DOMAINNAME,
              null,
              "0.0.0.0",
              0,
              out);
        } catch (IOException ioe) {
        }
        throw new SOCKSException(err);
        /**
         * ** } else if (connPort == 80) { // rewrite GET line to include hostname??? or add Host:
         * line??? // or forward to local eepProxy (but that's a Socket not an I2PSocket) // use
         * eepProxy configured outproxies? String err = "No handler for HTTP outproxy implemented";
         * _log.error(err); try { sendRequestReply(Reply.CONNECTION_NOT_ALLOWED_BY_RULESET,
         * AddressType.DOMAINNAME, null, "0.0.0.0", 0, out); } catch (IOException ioe) {} throw new
         * SOCKSException(err); **
         */
      } else {
        List<String> proxies = t.getProxies(connPort);
        if (proxies == null || proxies.isEmpty()) {
          String err =
              "No outproxy configured for port " + connPort + " and no default configured either";
          _log.error(err);
          try {
            sendRequestReply(
                Reply.CONNECTION_NOT_ALLOWED_BY_RULESET,
                AddressType.DOMAINNAME,
                null,
                "0.0.0.0",
                0,
                out);
          } catch (IOException ioe) {
          }
          throw new SOCKSException(err);
        }
        int p = I2PAppContext.getGlobalContext().random().nextInt(proxies.size());
        String proxy = proxies.get(p);
        if (_log.shouldLog(Log.DEBUG))
          _log.debug("connecting to proxy " + proxy + " for " + connHostName + " port " + connPort);

        try {
          destSock = outproxyConnect(t, proxy);
        } catch (SOCKSException se) {
          try {
            sendRequestReply(
                Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
          } catch (IOException ioe) {
          }
          throw se;
        }
      }
      confirmConnection();
      _log.debug("connection confirmed - exchanging data...");
    } catch (DataFormatException e) {
      if (_log.shouldLog(Log.WARN)) _log.warn("socks error", e);
      try {
        sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
      } catch (IOException ioe) {
      }
      throw new SOCKSException("Error in destination format");
    } catch (SocketException e) {
      if (_log.shouldLog(Log.WARN)) _log.warn("socks error", e);
      try {
        sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
      } catch (IOException ioe) {
      }
      throw new SOCKSException("Error connecting: " + e);
    } catch (IOException e) {
      if (_log.shouldLog(Log.WARN)) _log.warn("socks error", e);
      try {
        sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
      } catch (IOException ioe) {
      }
      throw new SOCKSException("Error connecting: " + e);
    } catch (I2PException e) {
      if (_log.shouldLog(Log.WARN)) _log.warn("socks error", e);
      try {
        sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
      } catch (IOException ioe) {
      }
      throw new SOCKSException("Error connecting: " + e);
    }

    return destSock;
  }