/** * Handle a SOCKS v5 response from the proxy server. * * @param nextFilter the next filter * @param buf the buffered data received * @param step the current step in the authentication process */ protected void handleResponse(final NextFilter nextFilter, final IoBuffer buf, int step) throws Exception { int len = 2; if (step == SocksProxyConstants.SOCKS5_GREETING_STEP) { // Send greeting message byte method = buf.get(1); if (method == SocksProxyConstants.NO_ACCEPTABLE_AUTH_METHOD) { throw new IllegalStateException( "No acceptable authentication method to use with " + "the socks proxy server"); } getSession().setAttribute(SELECTED_AUTH_METHOD, method); } else if (step == SocksProxyConstants.SOCKS5_AUTH_STEP) { // Authentication to the SOCKS server byte method = (Byte) getSession().getAttribute(Socks5LogicHandler.SELECTED_AUTH_METHOD); if (method == SocksProxyConstants.GSSAPI_AUTH) { int oldPos = buf.position(); if (buf.get(0) != 0x01) { throw new IllegalStateException("Authentication failed"); } if (buf.get(1) == 0xFF) { throw new IllegalStateException( "Authentication failed: GSS API Security Context Failure"); } if (buf.remaining() >= 2) { byte[] size = new byte[2]; buf.get(size); int s = ByteUtilities.makeIntFromByte2(size); if (buf.remaining() >= s) { byte[] token = new byte[s]; buf.get(token); getSession().setAttribute(GSS_TOKEN, token); len = 0; } else { // buf.position(oldPos); return; } } else { buf.position(oldPos); return; } } else if (buf.get(1) != SocksProxyConstants.V5_REPLY_SUCCEEDED) { throw new IllegalStateException("Authentication failed"); } } else if (step == SocksProxyConstants.SOCKS5_REQUEST_STEP) { // Send the request byte addressType = buf.get(3); len = 6; if (addressType == SocksProxyConstants.IPV6_ADDRESS_TYPE) { len += 16; } else if (addressType == SocksProxyConstants.IPV4_ADDRESS_TYPE) { len += 4; } else if (addressType == SocksProxyConstants.DOMAIN_NAME_ADDRESS_TYPE) { len += 1 + (buf.get(4)); } else { throw new IllegalStateException("Unknwon address type"); } if (buf.remaining() >= len) { // handle response byte status = buf.get(1); LOGGER.debug(" response status: {}", SocksProxyConstants.getReplyCodeAsString(status)); if (status == SocksProxyConstants.V5_REPLY_SUCCEEDED) { buf.position(buf.position() + len); setHandshakeComplete(); return; } throw new Exception( "Proxy handshake failed - Code: 0x" + ByteUtilities.asHex(new byte[] {status})); } return; } if (len > 0) { buf.position(buf.position() + len); } // Move to the handshaking next step if not in the middle of // the authentication process boolean isAuthenticating = false; if (step == SocksProxyConstants.SOCKS5_AUTH_STEP) { byte method = (Byte) getSession().getAttribute(Socks5LogicHandler.SELECTED_AUTH_METHOD); if (method == SocksProxyConstants.GSSAPI_AUTH) { GSSContext ctx = (GSSContext) getSession().getAttribute(GSS_CONTEXT); if (ctx == null || !ctx.isEstablished()) { isAuthenticating = true; } } } if (!isAuthenticating) { getSession().setAttribute(HANDSHAKE_STEP, ++step); } doHandshake(nextFilter); }