使用java实现的socket代理(支持socket4和socket5)
代码如下:
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
/**
* Created with Intellij IDEA
*
* @author: jiaoyiping
* Mail: jiaoyiping@gmail.com
* Date: 2018/03/01
* Time: 22:08
* To change this template use File | Settings | Editor | File and Code Templates
*/
public class MySocket5Server implements Runnable {
private static final int SOCKS_PROTOCOL_4 = 0X04;
private static final int SOCKS_PROTOCOL_5 = 0X05;
private static final int DEFAULT_BUFFER_SIZE = 1024;
private static final byte TYPE_IPV4 = 0x01;
private static final byte TYPE_IPV6 = 0X02;
private static final byte TYPE_HOST = 0X03;
private static final byte ALLOW_PROXY = 0X5A;
private static final byte DENY_PROXY = 0X5B;
private Socket sourceSocket;
@Override
public void run() {
String remoteAddress = sourceSocket.getRemoteSocketAddress().toString();
log("process socket:" + remoteAddress);
InputStream sourceIn = null, proxyIn = null;
OutputStream sourceOut = null, proxyOut = null;
Socket proxySocket = null;
try {
sourceIn = sourceSocket.getInputStream();
sourceOut = sourceSocket.getOutputStream();
//从协议头中获取socket的类型
byte[] tmp = new byte[1];
int n = sourceIn.read(tmp);
if (n == 1) {
int protocol = tmp[0];
//socket4
if (SOCKS_PROTOCOL_4 == protocol) {
proxySocket = convertToSocket4(sourceIn, sourceOut);
} else if (SOCKS_PROTOCOL_5 == protocol) {
proxySocket = convertToSocket5(sourceIn, sourceOut);
} else {
log("Socket协议错误,不是Socket4或者Socket5");
}
//socket转换
if (null != proxySocket) {
CountDownLatch countDownLatch = new CountDownLatch(1);
proxyIn = proxySocket.getInputStream();
proxyOut = proxySocket.getOutputStream();
transfer(sourceIn, proxyOut, countDownLatch);
transfer(proxyIn, sourceOut, countDownLatch);
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
log("SOCKET ERROR: " + tmp.toString());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
closeIO(sourceIn);
closeIO(proxyIn);
closeIO(proxyOut);
closeIO(proxyIn);
closeIO(proxySocket);
closeIO(sourceSocket);
}
}
public MySocket5Server(Socket sourceSocket) {
this.sourceSocket = sourceSocket;
}
private static final void log(String message) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(dateFormat.format(new Date()) + " - " + message);
}
private static void startServer(int port) {
log("config =>> port=" + port);
try (ServerSocket serverSocket = new ServerSocket(port)) {
Socket socket = null;
while ((socket = serverSocket.accept()) != null) {
new Thread(new MySocket5Server(socket)).start();
}
log("close socket(this never happen)");
} catch (IOException e) {
e.printStackTrace();
}
}
private Socket convertToSocket4(InputStream inputStream, OutputStream outputStream) throws IOException {
Socket proxySocket = null;
byte[] tmp = new byte[3];
inputStream.read(tmp);
// 请求协议|VN1|CD1|DSTPORT2|DSTIP4|NULL1|
int port = ByteBuffer.wrap(tmp, 1, 2).asShortBuffer().get() & 0xFFFF;
String host = getHost((byte) 0x01, inputStream);
inputStream.read();
//返回一个8字节的响应协议: |VN1|CD1|DSTPORT2|DSTIP 4|
byte[] response = new byte[8];
try {
proxySocket = new Socket(host, port);
response[1] = ALLOW_PROXY;
log("connect " + tmp[1] + "host: " + host + " ,port: " + port);
} catch (Exception e) {
response[1] = DENY_PROXY;
log("connect error,host: " + host + " ,port: " + port);
}
outputStream.write(response);
outputStream.flush();
return proxySocket;
}
private Socket convertToSocket5(InputStream inputStream, OutputStream outputStream) throws IOException {
Socket proxySocket = null;
//处理SOCKS5头信息(不支持登录)
byte[] tmp = new byte[2];
inputStream.read(tmp);
byte method = tmp[1];
if (0x02 == tmp[0]) {
method = 0x00;
inputStream.read();
}
tmp = new byte[]{0x05, method};
outputStream.write(tmp);
outputStream.flush();
byte cmd = 0;
tmp = new byte[4];
inputStream.read(tmp);
log("proxy header is:" + Arrays.toString(tmp));
cmd = tmp[1];
String host = getHost(tmp[3], inputStream);
tmp = new byte[2];
inputStream.read(tmp);
int port = ByteBuffer.wrap(tmp).asShortBuffer().get() & 0xFFFF;
log("connect host: " + host + " :port:" + port);
ByteBuffer rsv = ByteBuffer.allocate(10);
rsv.put((byte) 0x05);
Object resultTmp = null;
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(sourceSocket.getLocalAddress().getAddress());
Short localPort = (short) ((sourceSocket.getLocalPort()) & 0xFFFF);
rsv.putShort(localPort);
tmp = rsv.array();
outputStream.write(tmp);
outputStream.flush();
if (null != resultTmp && 0x02 == cmd) {
ServerSocket ss = (ServerSocket) resultTmp;
try {
resultTmp = ss.accept();
} catch (Exception e) {
} finally {
closeIO(ss);
}
}
return (Socket) resultTmp;
}
private void transfer(InputStream in, OutputStream out, CountDownLatch latch) {
new Thread(() -> {
byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];
int count = 0;
try {
while (0 < (count = in.read(bytes))) {
out.write(bytes, 0, count);
out.flush();
}
} catch (IOException e) {
log("转换出现错误");
e.printStackTrace();
}
if (latch != null) {
latch.countDown();
}
}).start();
}
private void closeIO(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private String getHost(byte type, InputStream inputStream) throws IOException {
String host = null;
byte[] tmp = null;
switch (type) {
case TYPE_IPV4:
tmp = new byte[4];
inputStream.read(tmp);
host = InetAddress.getByAddress(tmp).getHostAddress();
break;
case TYPE_IPV6:
tmp = new byte[16];
inputStream.read(tmp);
host = InetAddress.getByAddress(tmp).getHostAddress();
break;
case TYPE_HOST:
int count = inputStream.read();
tmp = new byte[count];
inputStream.read(tmp);
host = new String(tmp);
default:
break;
}
return host;
}
public static void main(String[] args) {
java.security.Security.setProperty("networkaddress.cache.ttl", "86400");
MySocket5Server.startServer(1033);
}
}
使用java实现的socket代理(支持socket4和socket5)的更多相关文章
- java网络编程socket\server\TCP笔记(转)
java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04| 分类: Socket | 标签:java |举报|字号 订阅 1 TCP的开销 a ...
- java网络编程socket解析
转载:http://www.blogjava.net/landon/archive/2013/07/02/401137.html Java网络编程精解笔记2:Socket详解 Socket用法详解 在 ...
- 读懂Java中的Socket编程
Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...
- 读懂Java中的Socket编程(转)
Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
- Java学习笔记--动态代理
动态代理 1.JDK动态代理 JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy ...
- Confluence 6 配置 Web 代理支持
这个页面中的相关平台中的内容是不被支持的.因此,Atlassian 支持不能保证能够为你提供任何支持.请注意,这个页面下面提供的信息仅为你提供参考同时也不能保证所有的的配置能正常工作.如果你按照本页面 ...
- 杨晓峰-Java核心技术-6 动态代理 反射 MD
目录 第6讲 | 动态代理是基于什么原理? 典型回答 考点分析 知识扩展 反射机制及其演进 动态代理 精选留言 Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAnd ...
- java中的socket编程
Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...
随机推荐
- js eventLoop (使用chunk 同步变异步)
https://www.cnblogs.com/xiaohuochai/p/8527618.html 线程 javascript是单线程的语言,也就是说,同一个时间只能做一件事.而这个单线程的特性,与 ...
- js如何获取asp.net服务器端控件的值(label,textbox,dropdownlist,radiobuttonlist等)
js如何获取asp.net服务器端控件的值(label,textbox,dropdownlist,radiobuttonlist等) 欢迎访问原稿:http://hi.baidu.com/2wixia ...
- 【WP8】扩展CM的INavigationService方法
CM支持通过ViewModel进行导航,并通过支持参数传递,但是内部只是通过反射的方式构造Uri的参数进行导航,所以只支持简单类型的参数传递,下面对其进行扩展,在页面导航时支持复杂类型的参数传递,并扩 ...
- 复制js的“准”正确用法
function kobe(id) { var targetText = document.getElementById(id); try ...
- 虚拟机中安装linux系统步骤
参考:http://blog.csdn.net/u013111221/article/details/50856934 后面参考:http://blog.csdn.net/chenweitang123 ...
- Tomcat------启动出错
描述:在cmd中,执行startup.bar时,报错:Using CLASSPATH: "E:\Tomcat\bin\bootstrap.jar;E:\Tomcat\bin\tomcat-j ...
- hibernate4.3 无法获取数据库最新值
在用ssh框架的时候遇到一个问题(hibernate版本号4.3) 问题描写叙述:web端和应用程序都能够读写数据库.当应用程序改动数据库后.hibernate无法读取最新值,读出来的一直都是旧数据. ...
- Docker background
什么是 Docker? Docker 提供了一个可以运行你的应用程序的封套(envelope),或者说容器.它原本是 dotCloud 启动的一个业余项目,并在前些时候开源了.它吸引了大量的关注和讨论 ...
- Burp Post、Get数据包转为上传multipart/form-data格式数据包
方法一: 新建一个网页进行上传,代码代码如下: <html> <head></head> <body> <form method="po ...
- 【RF库XML测试】parse xml
Name:Parse XmlSource:XML <test library>Arguments:[ source | keep_clark_notation=False ]Parses ...