zoukankan      html  css  js  c++  java
  • 使用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);
    }
    
    
    }
  • 相关阅读:
    接口的经典使用方法
    多态的程序例子
    log4j常用配置过程
    log4j.properties对于web app摆放的位置
    MySQL优化实例
    No sql 相关
    yii直接执行sql
    android NDK JNI设置自己的log输出函数
    android web 网址收集
    WebKit加载网页的流程
  • 原文地址:https://www.cnblogs.com/jiaoyiping/p/8511962.html
Copyright © 2011-2022 走看看