`
liyixing1
  • 浏览: 958753 次
  • 性别: 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 ...

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

    在给定的标题“使用Java基于Netty+Socks5+TLS实现的代理服务.zip”中,我们可以看到三个核心概念:Netty、Socks5和TLS,这些都是构建高效、安全网络服务的关键组件。 Netty是一个高性能、异步事件驱动的网络应用...

    jargyle:Java SOCKS5服务器

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

    基于Java实现的代理服务器

    6. **安全性**:如果实现SOCKS5的认证功能,需要考虑用户凭证的安全存储和传输。此外,还可以考虑使用SSL/TLS加密来保护数据的传输安全。 7. **日志和调试**:为了便于问题定位和服务器维护,通常会添加日志记录...

    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: :

    socks5-proxy:socks5代理

    在Netty中实现Socks5代理,我们需要理解以下关键组件和步骤: 1. **协议解析**:首先,我们需要解析Socks5的协议报文。Socks5协议的握手过程包括版本识别、认证阶段、命令请求和响应。Netty中的...

    JAVA代理服务器

    JAVA,代理服务器,JAVA代理服务器 本小工具是使用JAVA开发的代理服务器,只要设置好代理端口(端口在100~65000之内的任意没被占用的端口都可以),点击启动,局域网内用户就可以设置通过代理联网

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

    Java提供了一些库来支持FTP操作,例如Apache Commons Net库,它提供了一个FTPClient类,使得在Java中实现FTP文件上传和下载变得简单。 以下是一个Java利用Apache Commons Net库实现FTP文件下载的示例代码: ```...

    socks_purose.rar_socks

    1. **mh5GameMain.java**:这可能是游戏的主入口点或者游戏主循环的实现,负责初始化游戏环境、处理用户输入、管理游戏状态等。 2. **m13Bullets.java**:这个名字暗示了游戏中存在13种类型的子弹或者与子弹相关的...

    java开源包5

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

    java操作IE代理

    这个"java操作IE代理"的主题涉及到如何在Java程序中控制IE的网络代理设置,这通常需要利用特定的库和方法来实现。下面将详细介绍这个知识点。 首先,"registry.jar"可能是一个包含了对Windows注册表操作功能的Java...

    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开源包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 ...

    wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 负载均衡, 静态文件服务器

    用Rust实现仿nginx,力争实现一个可替代方案,http/https代理, socks5代理, 负载均衡, 反向代理, 静态文件服务器,四层TCP/UDP转发,websocket转发, 内网穿透nat

    java开源包8

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

    Java网络开发相关源码

    `SOCKS.java`可能是一个实现SOCKS协议的类。SOCKS是一种代理协议,允许客户端通过代理服务器与任意TCP服务通信。它分为版本4和5,其中SOCKS5支持更多认证机制和协议类型。 `socks.properties`可能包含了配置SOCKS...

    java开源包10

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

Global site tag (gtag.js) - Google Analytics