代码如下:

    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)的更多相关文章

  1. java网络编程socket\server\TCP笔记(转)

    java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅     1 TCP的开销 a ...

  2. java网络编程socket解析

    转载:http://www.blogjava.net/landon/archive/2013/07/02/401137.html Java网络编程精解笔记2:Socket详解 Socket用法详解 在 ...

  3. 读懂Java中的Socket编程

    Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...

  4. 读懂Java中的Socket编程(转)

    Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...

  5. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  6. Java学习笔记--动态代理

    动态代理 1.JDK动态代理 JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy ...

  7. Confluence 6 配置 Web 代理支持

    这个页面中的相关平台中的内容是不被支持的.因此,Atlassian 支持不能保证能够为你提供任何支持.请注意,这个页面下面提供的信息仅为你提供参考同时也不能保证所有的的配置能正常工作.如果你按照本页面 ...

  8. 杨晓峰-Java核心技术-6 动态代理 反射 MD

    目录 第6讲 | 动态代理是基于什么原理? 典型回答 考点分析 知识扩展 反射机制及其演进 动态代理 精选留言 Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAnd ...

  9. java中的socket编程

    Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...

随机推荐

  1. dpkg: error processing package libraspberrypi-doc (--configure): package is in a very bad inconsistent state;

    dpkg: error processing package libraspberrypi-doc (--configure): package is in a very bad inconsiste ...

  2. Android 监听屏幕唤醒和关闭的广播

    今天希望应用程序的服务运行时,可以监听到屏幕的唤醒.继续百度学习法,连同监听闭幕关闭也一同学习了. 此种情况需要动态注册系统广播.在AndroidManifest.xml中静态注册的实际运行中无效. ...

  3. mongoose实现批量删除和多id查询的api/方法

    删除一条数据:传入id Model.remove({ _id: 传入的id }); 删除多条数据,传入id数组,使用$in方法 Model.remove({ _id: { $in: ['aID', ' ...

  4. 最新Java面试题及答案整理

    基础篇 一.基本功 面向对象特征 封装,继承,多态和抽象 1. 封装 封装给对象提供了隐藏内部特性和行为的能力.对象提供一些能被其他对象访问的方法来改变它内部的数据.在 Java 当中,有 3 种修饰 ...

  5. Global.asax的Application_BeginRequest实现url重写无后缀的代码

    本文为大家详细介绍下利用Global.asax的Application_BeginRequest 实现url重写其无后缀,具体核心代码如下,有需求的朋友可以参考下,希望对大家有所帮助 利用Global ...

  6. [转]Android:Layout_weight的深刻理解

    http://mobile.51cto.com/abased-375428.htm 最近写Demo,突然发现了Layout_weight这个属性,发现网上有很多关于这个属性的有意思的讨论,可是找了好多 ...

  7. AndroidManifest详解

    一,重要性AndroidManifest.xml是Android应用程序中最重要的文件之一.它是Android程序的全局配置文件,是每个 android程序中必须的文件.它位于我们开发的应用程序的根目 ...

  8. Nginx Session Sticky

    nginx的粘性session主要通过nginx-sticky-module实现 1 下载 nginx-sticky-module 下载地址:https://code.google.com/p/ngi ...

  9. 设置js同源

    1)设置 document.domain 成一样的就行了(前提是都是同一个顶级域名) 2)例如,域名1:news.xxx.com ,域名2:member.xxx.com,这时可以设置它们的 docum ...

  10. 【代码审计】QYKCMS_v4.3.2 任意文件上传漏洞分析

      0x00 环境准备 QYKCMS官网:http://www.qykcms.com/ 网站源码版本:QYKCMS_v4.3.2(企业站主题) 程序源码下载:http://bbs.qingyunke. ...