package sockslib.server; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sockslib.client.SocksProxy; import sockslib.common.SSLConfiguration; import sockslib.common.methods.NoAuthenticationRequiredMethod; import sockslib.common.methods.SocksMethod; import sockslib.common.methods.UsernamePasswordMethod; import sockslib.server.io.PipeListener; import sockslib.server.listener.PipeInitializer; import sockslib.server.listener.SessionListener; import sockslib.server.manager.MemoryBasedUserManager; import sockslib.server.manager.UserManager; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import static com.google.common.base.Preconditions.checkNotNull; /** * The class <code>SocksServerBuilder</code> is a tool class to build an {@link SocksProxyServer}. * * @author Youchao Feng * @version 1.0 * @date Aug 27, 2015 * @since JDK1.7 */ public class SocksServerBuilder { private static final Logger logger = LoggerFactory.getLogger(SocksServerBuilder.class); private static final int DEFAULT_PORT = 1080; private Class<? extends SocksHandler> socksHandlerClass; private Set<SocksMethod> socksMethods; private UserManager userManager; private SocksProxy proxy; private int timeout; private InetAddress bindAddr; private int bindPort = DEFAULT_PORT; private boolean daemon = false; private ExecutorService executorService; private SessionManager sessionManager = new BasicSessionManager(); private SSLConfiguration sslConfiguration; private Map<String, SessionListener> sessionListeners = new HashMap<>(); private PipeInitializer pipeInitializer; /** * Creates a <code>SocksServerBuilder</code> with a <code>Class<? extends {@link * SocksHandler}</code> * instance. * * @param socksHandlerClass <code>java.lang.Class<? extends {@link SocksHandler}</code> instance. */ private SocksServerBuilder(Class<? extends SocksHandler> socksHandlerClass) { this.socksHandlerClass = checkNotNull(socksHandlerClass, "Argument [socksHandlerClass] may not be null"); userManager = new MemoryBasedUserManager(); } /** * Builds a {@link SocksProxyServer} which support SOCKS5 protocol. * This SOCKS5 server will accept all requests from clients with no authentication. * * @return Instance of {@link SocksProxyServer}. */ public static SocksProxyServer buildAnonymousSocks5Server() { return buildAnonymousSocks5Server(DEFAULT_PORT); } /** * Builds a {@link SocksProxyServer} which support SOCKS5 protocol bind at a specified port. * This SOCKS5 server will accept all requests from clients with no authentication. * * @param bindPort The port that server listened. * @return Instance of {@link SocksProxyServer}. */ public static SocksProxyServer buildAnonymousSocks5Server(int bindPort) { return newSocks5ServerBuilder().setSocksMethods(new NoAuthenticationRequiredMethod()) .setBindPort(bindPort).build(); } /** * Builds a SSL based {@link SocksProxyServer} with no authentication required. * * @param bindPort The port that server listened. * @param configuration SSL configuration * @return Instance of {@link SocksProxyServer} */ public static SocksProxyServer buildAnonymousSSLSocks5Server(int bindPort, SSLConfiguration configuration) { return newSocks5ServerBuilder().setSocksMethods(new NoAuthenticationRequiredMethod()) .setBindPort(bindPort).useSSL(configuration).build(); } public static SocksProxyServer buildAnonymousSSLSocks5Server(SSLConfiguration configuration) { return buildAnonymousSSLSocks5Server(DEFAULT_PORT, configuration); } /** * Creates a <code>SocksServerBuilder</code> instance with specified Class instance of {@link * SocksHandler}. * * @param socksHandlerClass Class instance of {@link SocksHandler}. * @return Instance of {@link SocksServerBuilder}. */ public static SocksServerBuilder newBuilder(Class<? extends SocksHandler> socksHandlerClass) { checkNotNull(socksHandlerClass, "Argument [socksHandlerClass] may not be null"); return new SocksServerBuilder(socksHandlerClass); } /** * Calls {@link #newBuilder(Class)} with an argument <code>Socks5Handler.class</code>; * * @return Instance of {@link SocksServerBuilder}. */ public static SocksServerBuilder newSocks5ServerBuilder() { return new SocksServerBuilder(Socks5Handler.class); } /** * Add {@link SocksMethod}. * * @param methods Instance of {@link SocksMethod}. * @return Instance of {@link SocksServerBuilder}. */ public SocksServerBuilder addSocksMethods(SocksMethod... methods) { if (socksMethods == null) { socksMethods = new HashSet<>(); } Collections.addAll(socksMethods, methods); return this; } /** * Set SOCKS methods that SOCKS server will support. * * @param methods Instance of {@link SocksMethod}. * @return Instance of {@link SocksServerBuilder}. */ public SocksServerBuilder setSocksMethods(SocksMethod... methods) { if (socksMethods == null) { socksMethods = new HashSet<>(); } Collections.addAll(socksMethods, methods); return this; } public SocksServerBuilder setPipeInitializer(PipeInitializer pipeInitializer) { this.pipeInitializer = pipeInitializer; return this; } public SocksServerBuilder setSocksMethods(Set<SocksMethod> methods) { socksMethods = checkNotNull(methods, "Argument [methods] may not be null"); return this; } public SocksServerBuilder setUserManager(UserManager userManager) { this.userManager = checkNotNull(userManager, "Argument [userManager] may not be null"); return this; } public SocksServerBuilder setProxy(SocksProxy proxy) { this.proxy = proxy; return this; } public SocksServerBuilder setTimeout(int timeout) { this.timeout = timeout; return this; } public SocksServerBuilder setTimeout(long timeout, TimeUnit timeUnit) { this.timeout = (int) timeUnit.toMillis(timeout); return this; } public SocksServerBuilder setBindAddr(InetAddress bindAddr) { this.bindAddr = bindAddr; return this; } public SocksServerBuilder setBindPort(int bindPort) { this.bindPort = bindPort; return this; } public SocksServerBuilder setExecutorService(ExecutorService executorService) { this.executorService = checkNotNull(executorService); return this; } public SocksServerBuilder setDaemon(boolean daemon) { this.daemon = daemon; return this; } /** * Sets {@link SessionManager}. * * @param sessionManager instance of {@link SessionManager}. * @return Instance of {@link SocksServerBuilder}. */ public SocksServerBuilder setSessionManager(SessionManager sessionManager) { this.sessionManager = checkNotNull(sessionManager); return this; } /** * Add a {@link SessionListener}. * * @param name name of {@link SessionListener} * @param listener instance of {@link SessionListener}. * @return Instance of {@link SocksServerBuilder}. */ public SocksServerBuilder addSessionListener(String name, SessionListener listener) { sessionListeners.put(name, listener); return this; } /** * Sets server in SSL mode. * * @param sslConfiguration instance of {@link SSLConfiguration}. * @return Instance of {@link SocksServerBuilder}. */ public SocksServerBuilder useSSL(SSLConfiguration sslConfiguration) { this.sslConfiguration = sslConfiguration; return this; } /** * Builds a {@link SocksProxyServer} instance. * * @return instance of {@link SocksProxyServer}. */ public SocksProxyServer build() { SocksProxyServer proxyServer = null; if (sslConfiguration == null) { proxyServer = new BasicSocksProxyServer(socksHandlerClass); } else { proxyServer = new SSLSocksProxyServer(socksHandlerClass, sslConfiguration); } proxyServer.setTimeout(timeout); proxyServer.setBindAddr(bindAddr); proxyServer.setBindPort(bindPort); proxyServer.setDaemon(daemon); proxyServer.setSessionManager(sessionManager); proxyServer.setPipeInitializer(pipeInitializer); if (socksMethods == null) { socksMethods = new HashSet<>(); socksMethods.add(new NoAuthenticationRequiredMethod()); } SocksMethod[] methods = new SocksMethod[socksMethods.size()]; int i = 0; for (SocksMethod method : socksMethods) { if (method instanceof UsernamePasswordMethod) { if (userManager == null) { userManager = new MemoryBasedUserManager(); userManager.addUser("fucksocks", "fucksocks"); } ((UsernamePasswordMethod) method).setAuthenticator(new UsernamePasswordAuthenticator (userManager)); } methods[i] = method; i++; } if (executorService != null) { proxyServer.setExecutorService(executorService); } proxyServer.setSupportMethods(methods); if (proxy != null) { proxyServer.setProxy(proxy); } for (String name : sessionListeners.keySet()) { proxyServer.getSessionManager().addSessionListener(name, sessionListeners.get(name)); } return proxyServer; } }