博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用java实现的socket代理(支持socket4和socket5)
阅读量:5270 次
发布时间:2019-06-14

本文共 7630 字,大约阅读时间需要 25 分钟。

代码如下:

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;@Overridepublic 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);}}

转载于:https://www.cnblogs.com/jiaoyiping/p/8511962.html

你可能感兴趣的文章
Windows Azure Cloud Service (29) 在Windows Azure发送邮件(下)
查看>>
CS61A Efficiency 笔记
查看>>
ArcGIS Server Javascript 多图对比功能
查看>>
c#实现把异常写入日志示例(异常日志)
查看>>
函数的进阶
查看>>
对百度杀毒软件的评价
查看>>
微信上传素材返回 '{"errcode":41005,"errmsg":"media data missing"}',php5.6返回
查看>>
七七四十九劫,九九八十一难
查看>>
.net 获取CPU频率 内存 磁盘大小,域名 端口 虚拟目录等
查看>>
div或者p标签单行和多行超出显示省略号
查看>>
Elasticsearch 滚动重启 必读
查看>>
mysql explain执行计划详解
查看>>
windows下面安装Python和pip终极教程
查看>>
Hadoop基本概念
查看>>
java.util.zip压缩打包文件总结一:压缩文件及文件下面的文件夹
查看>>
JavaScript高级程序设计(四): 关键字With的使用
查看>>
浅说 apache setenvif_module模块
查看>>
MySQL--数据插入
查看>>
判断一个元素有没有条件
查看>>
[JLOI2011]飞行路线 (分层图,最短路)
查看>>