java 实现socks代理,包含sock4 sock5代理

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

说明

使用方法,直接编译后
USing port openSock4 openSock5 user pwd 
端口号
是否开通sock4
是否开通sock5
user 不为空时表示 sock5需要使用账号登录 。
示例  java SocksServerOneThread 1080

代码如下


import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.CountDownLatch;

/**
 * 标准的socks代理服务器,支持sock4与sock4代理
 * 
 * @author Administrator
 * 
 */
public class SocksServerOneThread implements Runnable {

	/**
	 * 来源的代理socket
	 */
	private final Socket socket;
	/**
	 * 是否开启socks4代理
	 */
	private final boolean openSock4;
	/**
	 * 是否开启socks5代理
	 */
	private final boolean openSock5;
	/**
	 * socks5代理的登录用户名,如果 不为空表示需要登录验证
	 */
	private final String user;
	/**
	 * socks5代理的登录密码,
	 */
	private final String pwd;
	/**
	 * socks是否需要进行登录验证
	 */
	private final boolean socksNeekLogin;

	/**
	 * @param socket
	 *            来源的代理socket
	 * @param openSock4
	 *            是否开启socks4代理
	 * @param openSock5
	 *            是否开启socks5代理
	 * @param user
	 *            socks5代理的登录用户名,如果 不为空表示需要登录验证
	 * @param pwd
	 *            socks5代理的登录密码,
	 */
	protected SocksServerOneThread(Socket socket, boolean openSock4, boolean openSock5, String user, String pwd) {
		this.socket = socket;
		this.openSock4 = openSock4;
		this.openSock5 = openSock5;
		this.user = user;
		this.pwd = pwd;
		this.socksNeekLogin = null != user;
	}

	public void run() {
		// 获取来源的地址用于日志打印使用
		String addr = socket.getRemoteSocketAddress().toString();
		log("process one socket : %s", addr);
		// 声明流
		InputStream a_in = null, b_in = null;
		OutputStream a_out = null, b_out = null;
		Socket proxy_socket = null;
		ByteArrayOutputStream cache = null;
		try {
			a_in = socket.getInputStream();
			a_out = socket.getOutputStream();

			// 获取协议头。取代理的类型,只有 4,5。
			byte[] tmp = new byte[1];
			int n = a_in.read(tmp);
			if (n == 1) {
				byte protocol = tmp[0];
				if ((openSock4 && 0x04 == protocol)) {// 如果开启代理4,并以socks4协议请求
					proxy_socket = sock4_check(a_in, a_out);
				} else if ((openSock5 && 0x05 == protocol)) {// 如果开启代理5,并以socks5协议请求
					proxy_socket = sock5_check(a_in, a_out);
				} else {// 非socks 4 ,5 协议的请求
					log("not socks proxy : %s  openSock4[] openSock5[]", tmp[0], openSock4, openSock5);
				}
				if (null != proxy_socket) {
					CountDownLatch latch = new CountDownLatch(1);
					b_in = proxy_socket.getInputStream();
					b_out = proxy_socket.getOutputStream();
					// 交换流数据
					if (80 == proxy_socket.getPort()) {
						cache = new ByteArrayOutputStream();
					}
					transfer(latch, a_in, b_out, cache);
					transfer(latch, b_in, a_out, cache);
					try {
						latch.await();
					} catch (Exception e) {
					}
				}
			} else {
				log("socks error : %s", Arrays.toString(tmp));
			}
		} catch (Exception e) {
			log("exception : %s %s", e.getClass(), e.getLocalizedMessage());
			e.printStackTrace();
		} finally {
			log("close socket, system cleanning ...  %s ", addr);
			closeIo(a_in);
			closeIo(b_in);
			closeIo(b_out);
			closeIo(a_out);
			closeIo(socket);
			closeIo(proxy_socket);
			if (null != cache) {
				cache2Local(cache);
			}
		}
	}

	private void cache2Local(ByteArrayOutputStream cache) {
		// OutputStream result = null;
		// try {
		// String fileName = System.currentTimeMillis() + "_"
		// + Thread.currentThread().getId();
		// result = new FileOutputStream("E:/cache/" + fileName + ".info");
		// result.write(cache.toByteArray());
		// } catch (Exception e) {
		// e.printStackTrace();
		// } finally {
		// closeIo(result);
		// }
	}

	/**
	 * sock5代理头处理
	 * 
	 * @param in
	 * @param out
	 * @return
	 * @throws IOException
	 */
	private Socket sock5_check(InputStream in, OutputStream out) throws IOException {
		byte[] tmp = new byte[2];
		in.read(tmp);
		boolean isLogin = false;
		byte method = tmp[1];
		if (0x02 == tmp[0]) {
			method = 0x00;
			in.read();
		}
		if (socksNeekLogin) {
			method = 0x02;
		}
		tmp = new byte[] { 0x05, method };
		out.write(tmp);
		out.flush();
		// Socket result = null;
		Object resultTmp = null;
		if (0x02 == method) {// 处理登录.
			int b = in.read();
			String user = null;
			String pwd = null;
			if (0x01 == b) {
				b = in.read();
				tmp = new byte[b];
				in.read(tmp);
				user = new String(tmp);
				b = in.read();
				tmp = new byte[b];
				in.read(tmp);
				pwd = new String(tmp);
				if (null != user && user.trim().equals(this.user) && null != pwd && pwd.trim().equals(this.pwd)) {// 权限过滤
					isLogin = true;
					tmp = new byte[] { 0x05, 0x00 };// 登录成功
					out.write(tmp);
					out.flush();
					log("%s login success !", user);
				} else {
					log("%s login faild !", user);
				}
			}
		}
		byte cmd = 0;
		if (!socksNeekLogin || isLogin) {// 验证是否需要登录
			tmp = new byte[4];
			in.read(tmp);
			log("proxy header >>  %s", Arrays.toString(tmp));
			cmd = tmp[1];
			String host = getHost(tmp[3], in);
			tmp = new byte[2];
			in.read(tmp);
			int port = ByteBuffer.wrap(tmp).asShortBuffer().get() & 0xFFFF;
			log("connect %s:%s", host, port);
			ByteBuffer rsv = ByteBuffer.allocate(10);
			rsv.put((byte) 0x05);
			try {
				if (0x01 == cmd) {
					resultTmp = new Socket(host, port);
					rsv.put((byte) 0x00);
				} else if (0x02 == cmd) {
					resultTmp = new ServerSocket(port);
					rsv.put((byte) 0x00);
				} else {
					rsv.put((byte) 0x05);
					resultTmp = null;
				}
			} catch (Exception e) {
				rsv.put((byte) 0x05);
				resultTmp = null;
			}
			rsv.put((byte) 0x00);
			rsv.put((byte) 0x01);
			rsv.put(socket.getLocalAddress().getAddress());
			Short localPort = (short) ((socket.getLocalPort()) & 0xFFFF);
			rsv.putShort(localPort);
			tmp = rsv.array();
		} else {
			tmp = new byte[] { 0x05, 0x01 };// 登录失败
			log("socks server need login,but no login info .");
		}
		out.write(tmp);
		out.flush();
		if (null != resultTmp && 0x02 == cmd) {
			ServerSocket ss = (ServerSocket) resultTmp;
			try {
				resultTmp = ss.accept();
			} catch (Exception e) {
			} finally {
				closeIo(ss);
			}
		}
		return (Socket) resultTmp;
	}

	/**
	 * sock4代理的头处理
	 * 
	 * @param in
	 * @param out
	 * @return
	 * @throws IOException
	 */
	private Socket sock4_check(InputStream in, OutputStream out) throws IOException {
		Socket proxy_socket = null;
		byte[] tmp = new byte[3];
		in.read(tmp);
		// 请求协议|VN1|CD1|DSTPORT2|DSTIP4|NULL1|
		int port = ByteBuffer.wrap(tmp, 1, 2).asShortBuffer().get() & 0xFFFF;
		String host = getHost((byte) 0x01, in);
		in.read();
		byte[] rsv = new byte[8];// 返回一个8位的响应协议
		// |VN1|CD1|DSTPORT2|DSTIP 4|
		try {
			proxy_socket = new Socket(host, port);
			log("connect [%s] %s:%s", tmp[1], host, port);
			rsv[1] = 90;// 代理成功
		} catch (Exception e) {
			log("connect exception  %s:%s", host, port);
			rsv[1] = 91;// 代理失败.
		}
		out.write(rsv);
		out.flush();
		return proxy_socket;
	}

	/**
	 * 获取目标的服务器地址
	 * 
	 * @createTime 2014年12月14日 下午8:32:15
	 * @param type
	 * @param in
	 * @return
	 * @throws IOException
	 */
	private String getHost(byte type, InputStream in) throws IOException {
		String host = null;
		byte[] tmp = null;
		switch (type) {
		case 0x01:// IPV4协议
			tmp = new byte[4];
			in.read(tmp);
			host = InetAddress.getByAddress(tmp).getHostAddress();
			break;
		case 0x03:// 使用域名
			int l = in.read();
			tmp = new byte[l];
			in.read(tmp);
			host = new String(tmp);
			break;
		case 0x04:// 使用IPV6
			tmp = new byte[16];
			in.read(tmp);
			host = InetAddress.getByAddress(tmp).getHostAddress();
			break;
		default:
			break;
		}
		return host;
	}

	/**
	 * IO操作中共同的关闭方法
	 * 
	 * @createTime 2014年12月14日 下午7:50:56
	 * @param socket
	 */
	protected static final void closeIo(Socket closeable) {
		if (null != closeable) {
			try {
				closeable.close();
			} catch (IOException e) {
			}
		}
	}

	/**
	 * IO操作中共同的关闭方法
	 * 
	 * @createTime 2014年12月14日 下午7:50:56
	 * @param socket
	 */
	protected static final void closeIo(Closeable closeable) {
		if (null != closeable) {
			try {
				closeable.close();
			} catch (IOException e) {
			}
		}
	}

	/**
	 * 数据交换.主要用于tcp协议的交换
	 * 
	 * @createTime 2014年12月13日 下午11:06:47
	 * @param lock
	 *            锁
	 * @param in
	 *            输入流
	 * @param out
	 *            输出流
	 */
	protected static final void transfer(final CountDownLatch latch, final InputStream in, final OutputStream out,
			final OutputStream cache) {
		new Thread() {
			public void run() {
				byte[] bytes = new byte[1024];
				int n = 0;
				try {
					while ((n = in.read(bytes)) > 0) {
						out.write(bytes, 0, n);
						out.flush();
						if (null != cache) {
							synchronized (cache) {
								cache.write(bytes, 0, n);
							}
						}
					}
				} catch (Exception e) {
				}
				if (null != latch) {
					latch.countDown();
				}
			};
		}.start();
	}

	private final static void log(String message, Object... args) {
		Date dat = new Date();
		String msg = String.format("%1$tF %1$tT %2$-5s %3$s%n", dat, Thread.currentThread().getId(),
				String.format(message, args));
		System.out.print(msg);
	}

	public static void startServer(int port, boolean openSock4, boolean openSock5, String user, String pwd)
			throws IOException {
		log("config >> port[%s] openSock4[%s] openSock5[%s] user[%s] pwd[%s]", port, openSock4, openSock5, user, pwd);
		ServerSocket ss = new ServerSocket(port);
		Socket socket = null;
		log("Socks server port : %s listenning...", port);
		while (null != (socket = ss.accept())) {
			new Thread(new SocksServerOneThread(socket, openSock4, openSock5, user, pwd)).start();
		}
		ss.close();
	}

	public static void main(String[] args) throws IOException {
		java.security.Security.setProperty("networkaddress.cache.ttl", "86400");
		log("\n\tUSing port openSock4 openSock5 user pwd");
		int port = 1080;
		boolean openSock4 = true;
		boolean openSock5 = true;
		String user = null, pwd = null;
		// user = "user";
		pwd = "123456";
		int i = 0;
		if (args.length > i && null != args[i++]) {
			port = Integer.valueOf(args[i].trim());
		}
		if (args.length > i && null != args[i++]) {
			openSock4 = Boolean.valueOf(args[i].trim());
		}
		if (args.length > i && null != args[i++]) {
			openSock5 = Boolean.valueOf(args[i].trim());
		}
		if (args.length > i && null != args[i++]) {
			user = args[i].trim();
		}
		if (args.length > i && null != args[i++]) {
			pwd = args[i].trim();
		}
		SocksServerOneThread.startServer(port, openSock4, openSock5, user, pwd);
	}
}

转载于:https://my.oschina.net/u/727875/blog/1826079

你可能感兴趣的:(java,python,网络)