`
liyixing1
  • 浏览: 939570 次
  • 性别: Icon_minigender_1
  • 来自: 江西上饶
社区版块
存档分类
最新评论

java实现socks5

阅读更多
socks5的基础知识

关于socks5的定义]https://www.ietf.org/rfc/rfc1928.txt

[/b[b]
关于socks5的账号密码验证方式https://www.ietf.org/rfc/rfc1929.txt


socks5交互过程
1.socks5服务器开启端口
2.客户端链接到sockets服务器
3.客户端发送hello信息,结构如下
VERNMETHODSMETHODS
1字节1字节最高255字节
X05表示socks5,也可以是任意的identifier代表第三个字段的数据长度(byte数)客户端支持的验证方式,每种方法占用一个字节


其中X02表示账号密码验证,我们这里只需要实现该方法

ClientHelloInfo clientHelloInfo = new ClientHelloInfo();
		clientHelloInfo.setVer(inputStream.read());
		clientHelloInfo.setNmethods(inputStream.read());
		
		if(clientHelloInfo.getNmethods() > 0) {
			clientHelloInfo.setMethods(read(clientHelloInfo.getNmethods()));
		}



4.服务端需要回复如下信息

VERMETHOD
1字节1字节
X05表示socks5服务端挑选的验证方法


METHODS
o  X'00' NO AUTHENTICATION REQUIRED
o  X'01' GSSAPI
o  X'02' USERNAME/PASSWORD
o  X'03' to X'7F' IANA ASSIGNED
o  X'80' to X'FE' RESERVED FOR PRIVATE METHODS
o  X'FF' NO ACCEPTABLE METHODS

如果服务端最后挑选的是X'FF',则表示没有适配的验证方法,客户端与服务端的验证方案不匹配,这种情况意味着只能被关闭


public void writeDatas(ServerHelloInfo serverHelloInfo) throws IOException {
		outputStream.write(serverHelloInfo.getVer());
		outputStream.write(serverHelloInfo.getMethod());
		outputStream.flush();
	}


5.客户端发送账号密码信息(如果不是账号密码验证则跳过这步)
VERULENUNAMEPLENPASSWD
1字节,注意这里不是SOCKS的版本1字节,指定用户名有多少字节最大255字节指定密码多少字节最大255字节


public ClientUserPasswordInfo readDatas() throws IOException {
		ClientUserPasswordInfo clientUserPasswordInfo = new ClientUserPasswordInfo();
		
		clientUserPasswordInfo.setVer(read());
		clientUserPasswordInfo.setUlen(read());
		clientUserPasswordInfo.setUname(new String(read(clientUserPasswordInfo.getUlen())));
		clientUserPasswordInfo.setPlen(read());
		clientUserPasswordInfo.setPassword(new String(read(clientUserPasswordInfo.getPlen())));
		
		return clientUserPasswordInfo;
	}
	


6.服务端返回(如果不是账号密码验证则跳过这步)
VERSTATUS
1字节,目前只支持1,因为目前SOCKS5的密码验证协议版本是10X00表示正确,其他表示密码错误,关闭连接


public void writeDatas(ServerUserPasswordInfo serverUserPasswordInfo) throws IOException {
		outputStream.write(serverUserPasswordInfo.getVer());
		outputStream.write(serverUserPasswordInfo.getStatus());
		outputStream.flush();
	}


7.客户端请求代理目标
VER CMD   RSV  ATYP DST.ADDR DST.PORT
1字节    1字节  X'00'   2字节   目标ip    目标端口 2字节   


  • o VER协议版本:X'05'
  • o CMD 三个命令模式
  •            o CONNECT模式X'01'
  •            o BIND模式 X'02'(开启端口监听,客户端需要连接到这个端口的流量会直接转发到目标IP端口)
  •            o UDP模式 X'03'
  • o RSV保留
  • o以下地址的ATYP地址类型
  •              o IP V4地址:X'01'
  •              o DOMAINNAME:X'03'(域名模式)
  •              o IP V6地址:X'04'
  • o DST.ADDR所需的目标地址
  • o DST.PORT网络八位字节中所需的目标端口


IP4模式,4字节
IP6模式,16字节
域名模式,地址第一个字段表示 域名长度(255最大)

地址端口的解析
端口2字节
package com.lsiding.nat.util;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.SocketTimeoutException;

import com.lsiding.nat.core.InOutModel;

public class UtilSocks5 {
	/**
	 * byte数组转int类型的对象 4字节
	 * 
	 * @param bytes
	 * @return
	 */
	public int byte2Int(Byte[] bytes) {
		return (bytes[0] & 0xff) << 24 | (bytes[1] & 0xff) << 16
				| (bytes[2] & 0xff) << 8 | (bytes[3] & 0xff);
	}

	/**
	 * 2个字节 转化成int
	 * 
	 * @throws IOException
	 */
	public static final int byte2ToInteger(InOutModel<?> inOutModel)
			throws IOException {
		byte[] bs = inOutModel.read(2);
		return ((bs[0] & 0xff) << 8 | (bs[1] & 0xff));
	}

	/**
	 * 计算地址 一个byte刚好有0-255,但是当byte超过127时自动变成-128,比如说是129,那么当他超过127时自动从-128开始计算,
	 * 也就是说129==--127
	 * 
	 * @return liyixing
	 * @throws IOException
	 * @throws SocketTimeoutException
	 */
	public static final String getAddress(int type, InOutModel<?> inOutModel)
			throws SocketTimeoutException, IOException {
		if (type == 3) {
			// 域名模式
			int len = inOutModel.readLength();
			byte[] bs = inOutModel.read(len);

			return new String(bs);
		} else if (type == 1) {
			// ip 4
			byte[] bs = inOutModel.read(4);
			StringBuffer sb = new StringBuffer();

			for (int i = 0; i < 4; i++) {
				if (i != 0) {
					sb.append(".");
				}
				int a = bs[i];
				if (a < 0) {
					a = 256 + a;
				}
				sb.append(a);
			}

			return sb.toString();
		} else if (type == 4) {
			// ip6 16字节
			StringBuffer sb = new StringBuffer();

			for (int i = 0; i < 8; i++) {
				if (i != 0) {
					sb.append(":");
				}
				int a = byte2ToInteger(inOutModel);
				// a & 0xffff 显示4位16进制,a & 0xff 2位16进制
				String x = String.format("%02x", new Integer(a & 0xffff))
						.toUpperCase();

				while (true) {
					if (x.length() < 4) {
						x = "0" + x;
					} else {
						break;
					}
				}
				sb.append(x);
			}

			return sb.toString();
		}

		return null;
	}

	/**
	 * int转byte数组 4字节
	 * 
	 * @param bytes
	 * @return
	 */
	public byte[] intToByte(int num) {
		byte[] bytes = new byte[4];
		bytes[0] = (byte) ((num >> 24) & 0xff);
		bytes[1] = (byte) ((num >> 16) & 0xff);
		bytes[2] = (byte) ((num >> 8) & 0xff);
		bytes[3] = (byte) (num & 0xff);
		return bytes;
	}

	/**
	 * int 转2位byte
	 * 
	 * @param i
	 * @return liyixing
	 */
	public static byte[] intTo2ByteArray(int i) {
		byte[] result = new byte[2];
		result[0] = (byte) ((i >> 8));
		result[1] = (byte) (i & 0xff);
		return result;
	}

	/**
	 * 地址转byte
	 * 
	 * @param type
	 * @param ip
	 * @return liyixing
	 */
	public static final byte[] getAddressBytes(int type, String ip) {
		if (type == 3) {
			// 域名模式
			byte[] bs = ip.getBytes();
			int len = bs.length + 1;
			byte[] rs = new byte[len];

			rs[0] = (byte) bs.length;

			for (int index = 0; index < bs.length; index++) {
				rs[index + 1] = bs[index];
			}

			return rs;
		} else if (type == 1) {
			// ip 4
			String[] ips = ip.split("\\.");
			byte[] rs = new byte[4];

			for (int index = 0; index < 4; index++) {
				rs[index] = (byte) Integer.valueOf(ips[index]).intValue();
			}

			return rs;
		} else if (type == 4) {
			// ip 4
			String[] ips = ip.split(":");

			byte[] rs = new byte[16];

			for (int index = 0; index < 8; index++) {
				String ipOne = ips[index];
				byte[] tm = intTo2ByteArray(Integer.valueOf(ipOne, 16));
				rs[index * 2] = tm[0];
				rs[index * 2 + 1] = tm[1];
			}

			return rs;
		}

		return null;
	}

	public static void main(String[] args) throws IOException {
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
				intTo2ByteArray(26381));
		InOutModel<String> inOutModel = new InOutModel<String>(
				byteArrayInputStream);
		System.out.println(byte2ToInteger(inOutModel));

		byteArrayInputStream = new ByteArrayInputStream(getAddressBytes(3,
				"www.lsiding.com"));
		inOutModel = new InOutModel<String>(byteArrayInputStream);
		System.out.println(getAddress(3, inOutModel));

		byteArrayInputStream = new ByteArrayInputStream(getAddressBytes(1,
				"192.168.0.103"));
		inOutModel = new InOutModel<String>(byteArrayInputStream);
		System.out.println(getAddress(1, inOutModel));
		System.out.println("2001:0DB8:0000:0023:1008:0800:200C:0001");
		byteArrayInputStream = new ByteArrayInputStream(getAddressBytes(4,
				"2001:0DB8:0000:0023:1008:0800:200C:0001"));
		inOutModel = new InOutModel<String>(byteArrayInputStream);
		System.out.println(getAddress(4, inOutModel));
	}
}





public RequestInfo readDatas() throws IOException {
		RequestInfo requestInfo = new RequestInfo();
		
		requestInfo.setVer(read());
		requestInfo.setCmd(read());
		requestInfo.setRsv(read());
		requestInfo.setAtyp(read());
		String ip = UtilSocks5.getAddress(requestInfo.getAtyp(), this);
		requestInfo.setDstAddr(ip);
		requestInfo.setPort(UtilSocks5.getProt(this));
		
		return requestInfo;
	}


8.服务端回复
VER REP   RSV  ATYP BND.ADDR BND.PORT
1字节    1字节  X'00'   1字节   Variable     2字节    


  • o  VER    protocol version: X'05'
  • o  REP    Reply 状态码:
  • o  X'00' succeeded
  • o  X'01' 一般SOCKS服务器故障
  • o  X'02' 不允许使用cmd 2
  • o  X'03' 网络无法访问
  • o  X'04' 主机无法访问
  • o  X'05' 连接被拒绝
  • o  X'06' TTL已过期
  • o  X'07' 命令不受支持
  • o  X'08' 不支持地址类型
  • o  X'09' X'09'到X'FF'未分配
  • o  RSV   保留字段 必须填0X00
  • o  ATYP   1ip4,3域名模式,4ip6


connect模式
BND.ADDR BND.PORT 与DST.ADDR和DST.PORT 相等

BIND模式,新开启的服务器的端口,ip
UDP 模式,不准备支持,详情查看https://www.ietf.org/rfc/rfc1928.txt
分享到:
评论

相关推荐

    java开源包4

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    jargyle:Java SOCKS5服务器

    它具有以下功能: SOCKS5协议规范的100%实现,包括和尽管Jargyle可以充当独立的SOCKS5服务器,但它可以充当以下两者之间的桥梁: 使用纯文本连接和无SOCKS5身份验证访问SOCKS5服务器的操作系统和应用程序要求SSL /...

    基于Java实现的代理服务器

    基于Java实现的代理服务器,实现socks4,socks5协议

    使用Java基于Netty+Socks5+TLS实现的代理服务.zip

    使用Java基于Netty+Socks5+TLS实现的代理服务

    java-http2socks.zip_http2soc_http2socks r_java socket _java sock

    java实现的socket转http的小工具

    simple-socks5-server:socks5代理协议的简单实现,用于快速简便的私有socks5代理服务器

    描述使用Scala和Netty轻松实现socks5代理协议。 完全使用异步Java NIO来扩展许多并发连接。 打算与docker一起部署在私有vps上以进行快速设置。 Docker Hub: :

    Java实现FTP文件的上传和下载功能的实例代码

    FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。接下来通过本文给大家实例讲解Java实现FTP文件的上传和下载功能,需要的的朋友一起看看吧

    java开源包5

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    JAVA上百实例源码以及开源项目

    百度云盘分享 ... Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText();...

    JAVA上百实例源码以及开源项目源代码

     Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText(); //得到服务器地址  ...

    java开源包3

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    java开源包101

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    java开源包11

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    java开源包6

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    java开源包9

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    java开源包8

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    java开源包10

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    socks5-proxy:socks5代理

    Socks5 ProxyNetty实现简单,只关注正常流程抛弃非功能性的代码(错误,特殊情况处理)

    java开源包1

    ftp4j提供多种方式连接到远程FTP服务器包括:通过 TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。 Java的命令行进度条 JCmdLineProgess JCmdLineProgess 是一个 Java ...

    socks代理服务器

    java语言编写,基于socks v5协议实现socks代理服务器;其中包括一个客户端,一个应用服务器,一个socks服务器。实现无验证模式和用户名/密码验证模式,可以自由选择,使用dom4j开源工具操作xml配置文件,里面包含dom...

Global site tag (gtag.js) - Google Analytics