/** * Encodes the authentication packet for supported authentication methods. * * @param request the socks proxy request data * @return the encoded buffer, if null then authentication step is over and handshake process can * jump immediately to the next step without waiting for a server reply. * @throws UnsupportedEncodingException if some string charset convertion fails * @throws GSSException when something fails while using GSSAPI */ private IoBuffer encodeAuthenticationPacket(final SocksProxyRequest request) throws UnsupportedEncodingException, GSSException { byte method = (Byte) getSession().getAttribute(Socks5LogicHandler.SELECTED_AUTH_METHOD); switch (method) { case SocksProxyConstants.NO_AUTH: // In this case authentication is immediately considered as successfull // Next writeRequest() call will send the proxy request getSession().setAttribute(HANDSHAKE_STEP, SocksProxyConstants.SOCKS5_REQUEST_STEP); break; case SocksProxyConstants.GSSAPI_AUTH: return encodeGSSAPIAuthenticationPacket(request); case SocksProxyConstants.BASIC_AUTH: // The basic auth scheme packet is sent byte[] user = request.getUserName().getBytes("ASCII"); byte[] pwd = request.getPassword().getBytes("ASCII"); IoBuffer buf = IoBuffer.allocate(3 + user.length + pwd.length); buf.put(SocksProxyConstants.BASIC_AUTH_SUBNEGOTIATION_VERSION); buf.put((byte) user.length); buf.put(user); buf.put((byte) pwd.length); buf.put(pwd); return buf; } return null; }
/** * Encodes the initial greeting packet. * * @param request the socks proxy request data * @return the encoded buffer */ private IoBuffer encodeInitialGreetingPacket(final SocksProxyRequest request) { byte nbMethods = (byte) SocksProxyConstants.SUPPORTED_AUTH_METHODS.length; IoBuffer buf = IoBuffer.allocate(2 + nbMethods); buf.put(request.getProtocolVersion()); buf.put(nbMethods); buf.put(SocksProxyConstants.SUPPORTED_AUTH_METHODS); return buf; }
/** * Encodes the proxy authorization request packet. * * @param request the socks proxy request data * @return the encoded buffer * @throws UnsupportedEncodingException if request's hostname charset can't be converted to ASCII. */ private IoBuffer encodeProxyRequestPacket(final SocksProxyRequest request) throws UnsupportedEncodingException { int len = 6; InetSocketAddress adr = request.getEndpointAddress(); byte addressType = 0; byte[] host = null; if (adr != null && !adr.isUnresolved()) { if (adr.getAddress() instanceof Inet6Address) { len += 16; addressType = SocksProxyConstants.IPV6_ADDRESS_TYPE; } else if (adr.getAddress() instanceof Inet4Address) { len += 4; addressType = SocksProxyConstants.IPV4_ADDRESS_TYPE; } } else { host = request.getHost() != null ? request.getHost().getBytes("ASCII") : null; if (host != null) { len += 1 + host.length; addressType = SocksProxyConstants.DOMAIN_NAME_ADDRESS_TYPE; } else { throw new IllegalArgumentException( "SocksProxyRequest object " + "has no suitable endpoint information"); } } IoBuffer buf = IoBuffer.allocate(len); buf.put(request.getProtocolVersion()); buf.put(request.getCommandCode()); buf.put((byte) 0x00); // Reserved buf.put(addressType); if (host == null) { buf.put(request.getIpAddress()); } else { buf.put((byte) host.length); buf.put(host); } buf.put(request.getPort()); return buf; }
/** * Encode a SOCKS4/SOCKS4a request and writes it to the next filter so it can be sent to the proxy * server. * * @param nextFilter the next filter * @param request the request to send. */ protected void writeRequest(final NextFilter nextFilter, final SocksProxyRequest request) { try { boolean isV4ARequest = Arrays.equals(request.getIpAddress(), SocksProxyConstants.FAKE_IP); byte[] userID = request.getUserName().getBytes("ASCII"); byte[] host = isV4ARequest ? request.getHost().getBytes("ASCII") : null; int len = 9 + userID.length; if (isV4ARequest) { len += host.length + 1; } IoBuffer buf = IoBuffer.allocate(len); buf.put(request.getProtocolVersion()); buf.put(request.getCommandCode()); buf.put(request.getPort()); buf.put(request.getIpAddress()); buf.put(userID); buf.put(SocksProxyConstants.TERMINATOR); if (isV4ARequest) { buf.put(host); buf.put(SocksProxyConstants.TERMINATOR); } if (isV4ARequest) { logger.debug(" sending SOCKS4a request"); } else { logger.debug(" sending SOCKS4 request"); } buf.flip(); writeData(nextFilter, buf); } catch (Exception ex) { closeSession("Unable to send Socks request: ", ex); } }
/** * Encodes the authentication packet for supported authentication methods. * * @param request the socks proxy request data * @return the encoded buffer * @throws GSSException when something fails while using GSSAPI */ private IoBuffer encodeGSSAPIAuthenticationPacket(final SocksProxyRequest request) throws GSSException { GSSContext ctx = (GSSContext) getSession().getAttribute(GSS_CONTEXT); if (ctx == null) { // first step in the authentication process GSSManager manager = GSSManager.getInstance(); GSSName serverName = manager.createName(request.getServiceKerberosName(), null); Oid krb5OID = new Oid(SocksProxyConstants.KERBEROS_V5_OID); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Available mechs:"); for (Oid o : manager.getMechs()) { if (o.equals(krb5OID)) { LOGGER.debug("Found Kerberos V OID available"); } LOGGER.debug("{} with oid = {}", manager.getNamesForMech(o), o); } } ctx = manager.createContext(serverName, krb5OID, null, GSSContext.DEFAULT_LIFETIME); ctx.requestMutualAuth(true); // Mutual authentication ctx.requestConf(false); ctx.requestInteg(false); getSession().setAttribute(GSS_CONTEXT, ctx); } byte[] token = (byte[]) getSession().getAttribute(GSS_TOKEN); if (token != null) { LOGGER.debug(" Received Token[{}] = {}", token.length, ByteUtilities.asHex(token)); } IoBuffer buf = null; if (!ctx.isEstablished()) { // token is ignored on the first call if (token == null) { token = new byte[32]; } token = ctx.initSecContext(token, 0, token.length); // Send a token to the server if one was generated by // initSecContext if (token != null) { LOGGER.debug(" Sending Token[{}] = {}", token.length, ByteUtilities.asHex(token)); getSession().setAttribute(GSS_TOKEN, token); buf = IoBuffer.allocate(4 + token.length); buf.put( new byte[] { SocksProxyConstants.GSSAPI_AUTH_SUBNEGOTIATION_VERSION, SocksProxyConstants.GSSAPI_MSG_TYPE }); buf.put(ByteUtilities.intToNetworkByteOrder(token.length, 2)); buf.put(token); } } return buf; }