package sockslib.quickstart; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sockslib.client.SSLSocks5; import sockslib.client.Socks5; import sockslib.client.SocksProxy; import sockslib.common.Credentials; import sockslib.common.SSLConfiguration; import sockslib.common.SSLConfigurationBuilder; import sockslib.common.UsernamePasswordCredentials; import sockslib.common.methods.NoAuthenticationRequiredMethod; import sockslib.common.methods.UsernamePasswordMethod; import sockslib.server.SocksProxyServer; import sockslib.server.SocksServerBuilder; import sockslib.server.listener.LoggingListener; import sockslib.server.manager.MemoryBasedUserManager; import sockslib.server.manager.User; import sockslib.server.manager.UserManager; import sockslib.utils.Arguments; import sockslib.utils.Timer; import javax.annotation.Nullable; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Arrays; /** * The class <code>Socks5Server</code> can create a simple Socks5 server. * * @author Youchao Feng * @version 1.0 * @date Sep 24, 2015 11:25 AM */ public class Socks5Server { private static final Logger logger = LoggerFactory.getLogger(Socks5Server.class); private final String KEY_STORE_TYPE = "JKS"; private SocksProxyServer server; /** * Run a SOCKS5 server. Same as @{@link #start(String[])}. * * @param args Some arguments. * @throws IOException If any I/O error occurred */ public static void main(@Nullable String[] args) throws IOException { Timer.open(); Socks5Server socks5Server = new Socks5Server(); socks5Server.start(args); } /** * Start a SOCKS5 server with some options. * * @param args Arguments.Support "--h --help --port --auth" * @throws IOException If any I/O error occurred */ public void start(@Nullable String[] args) throws IOException { Arguments arguments = new Arguments(args); SocksServerBuilder builder = null; if (arguments.hasArgsIn("-h", "--help")) { showHelp(); return; } builder = SocksServerBuilder.newSocks5ServerBuilder(); try { initPort(arguments, builder); initAuth(arguments, builder); initSSL(arguments, builder); initProxy(arguments, builder); } catch (IllegalArgumentException e) { return; } server = builder.build(); final SocksProxyServer finalServer = server; Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { finalServer.shutdown(); logger.info("SOCKS5 sever shutdown"); } })); server.getSessionManager().addSessionListener("logger", new LoggingListener()); server.start(); } /** * Print help information. */ public void showHelp() { System.out.println("Usage: [Options]"); System.out.println(" -p, --port <val> Server bind port"); System.out.println(" -a, --auth <val> Use username/password authentication"); System.out.println(" Example: --auth=admin:1234"); System.out.println(" --auth=admin:1234,root:1234"); System.out.println(" -s, --ssl <val> SSL configuration file path"); System.out.println(" -l, --sslClientAuth Authenticate client's certificate"); System.out.println(" -P, --proxy <val> Set server SOCKS5 proxy, <val> should be:"); System.out.println(" host:port:username:password or host:port"); System.out.println(" -S, --proxySsl <val> Proxy SSL configuration file path"); System.out.println(" -k, --keystore <val> Keystore location"); System.out.println(" -w --keystorePassword <val>"); System.out.println(" Password of keystore"); System.out.println(" -t --keystoreType <val>"); System.out.println(" Keystore type, default \"JKS\""); System.out.println( " -K, --trustStore <val> Trust keystore location. default same as " + "[--keystore]"); System.out.println(" -W, --trustStorePassword <val>"); System.out.println(" Password of trusted keystore"); System.out.println(" -T, --trustStoreType <val>"); System.out.println(" Trust keystore type, default \"JKS\""); System.out.println(" -pk <val> Proxy keystore path"); System.out.println(" -pw <val> Password for keystore"); System.out.println(" -pt <val> Proxy keystore type"); System.out.println(" -h, --help Show help"); } /** * Shutdown SOCKS5 server. */ public void shutdown() { if (server != null) { server.shutdown(); } } private void initPort(Arguments arguments, SocksServerBuilder builder) throws IllegalArgumentException { int port = arguments.getIntValue(Arrays.asList("-p", "--port"), 1080); builder.setBindPort(port); } private void initAuth(Arguments arguments, SocksServerBuilder builder) throws IllegalArgumentException { String authValue = arguments.getValue(Arrays.asList("-a", "--auth"), null); if (authValue != null) { UserManager userManager = new MemoryBasedUserManager(); for (String user : authValue.split(",")) { String[] userPassword = user.split(":"); String username = userPassword[0]; String password = userPassword[1]; userManager.create(new User(username, password)); } builder.setSocksMethods(new UsernamePasswordMethod()).setUserManager(userManager); } else { builder.setSocksMethods(new NoAuthenticationRequiredMethod()); } } private void initSSL(Arguments arguments, SocksServerBuilder builder) throws IllegalArgumentException { String sslConfigValue = arguments.getValue(Arrays.asList("-s", "--ssl"), null); boolean clientAuth = arguments.hasArgsIn("-l", "--sslClientAuth"); if (sslConfigValue != null) { try { builder.useSSL(SSLConfiguration.load(sslConfigValue)); } catch (IOException e) { throw new IllegalArgumentException(e.getMessage()); } } String keyStorePath = arguments.getValue(Arrays.asList("-k", "--keystore"), null); String keyStorePassword = arguments.getValue(Arrays.asList("-w", "--keystorePassword"), null); String keyStoreType = arguments.getValue(Arrays.asList("-t", "--keystoreType"), KEY_STORE_TYPE); String trustKeyStorePath = arguments.getValue(Arrays.asList("-K", "--trustStore"), null); String trustKeyStorePassword = arguments.getValue(Arrays.asList("-W", "--trustStorePassword"), null); String trustKeyStoreType = arguments.getValue(Arrays.asList("-T", "--trustStoreType"), KEY_STORE_TYPE); if (keyStorePath != null) { if (keyStorePassword == null) { logger.error("Need password for keystore:{}", keyStorePath); throw new IllegalArgumentException(); } SSLConfigurationBuilder sslConfigBuilder = SSLConfigurationBuilder.newBuilder(); sslConfigBuilder.setKeyStorePath(keyStorePath).setKeyStorePassword(keyStorePassword) .setKeyStoreType(keyStoreType).setClientAuth(clientAuth); if (clientAuth) { if (trustKeyStorePath != null) { if (trustKeyStorePassword == null) { logger.error("Need password for keystore:{}", trustKeyStorePath); throw new IllegalArgumentException(); } sslConfigBuilder.setTrustKeyStorePath(trustKeyStorePath).setTrustKeyStorePassword (trustKeyStorePassword).setTrustKeyStoreType(trustKeyStoreType).setClientAuth(true); } else {// if trust keystore is null, use keystore as trust keystore sslConfigBuilder.useKeystoreAsTrustKeyStore(); } } builder.useSSL(sslConfigBuilder.build()); } } private void initProxy(Arguments arguments, SocksServerBuilder builder) throws IllegalArgumentException, IOException { String proxyValue = arguments.getValue(Arrays.asList("-P", "--proxy"), null); String regex = "((\\w+):(\\w+)@)?([.\\w]+):(\\d+)"; if (proxyValue != null) { if (proxyValue.matches(regex)) { SocksProxy proxy = null; String host = null; int port = 1080; Credentials credentials = null; String[] values = proxyValue.split("@"); String[] address = null; String[] user = null; if (values.length == 1) { address = values[0].split(":"); } else { user = values[0].split(":"); address = values[1].split(":"); credentials = new UsernamePasswordCredentials(user[0], user[1]); } host = address[0]; port = Integer.parseInt(address[1]); String proxySslValue = arguments.getValue(Arrays.asList("-S", "--proxySsl"), null); if (proxySslValue != null) { proxy = new SSLSocks5(new InetSocketAddress(host, port), SSLConfiguration.load (proxySslValue)); } SocksProxy tempProxy = initProxySSL(arguments, builder, new InetSocketAddress(host, port)); if (tempProxy != null) { proxy = tempProxy; } if (proxy == null) { proxy = new Socks5(new InetSocketAddress(host, port)); } if (credentials != null) { proxy.setCredentials(credentials); } builder.setProxy(proxy); } else { logger.error("[-P] or [--proxy] value: [username:password@]host:port"); throw new IllegalArgumentException(); } } } private SocksProxy initProxySSL(Arguments arguments, SocksServerBuilder builder, SocketAddress address) throws IllegalArgumentException { String keystorePath = arguments.getValue("-pk", null); String keystorePassword = arguments.getValue("-pw", null); String keystoreType = arguments.getValue("-pt", KEY_STORE_TYPE); if (keystorePath != null) { if (keystorePassword == null) { logger.info("Need password for keystore:{}", keystorePath); throw new IllegalArgumentException(); } SSLConfigurationBuilder sslConfigurationBuilder = SSLConfigurationBuilder.newBuilder(); sslConfigurationBuilder.setKeyStorePath(keystorePath).setKeyStorePassword(keystorePassword) .setKeyStoreType(keystoreType).useKeystoreAsTrustKeyStore(); return new SSLSocks5(address, sslConfigurationBuilder.build()); } return null; } }