使用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: [email protected]
 * 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);
}

}

原文地址:https://www.cnblogs.com/jiaoyiping/p/8511962.html

时间: 2024-10-20 04:39:55

使用java实现的socket代理(支持socket4和socket5)的相关文章

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

java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅 1 TCP的开销 a  连接协商三次握手,c->syn->s,s->syn ack->c, c->ack->s b  关闭协商四次握手,c->fin->s, s->ack-c,s->fin->c,c->ack->s c  保持数据有序,响应确认等计算开销 d

读懂Java中的Socket编程(转)

Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的Socket编程,并且如何写一个客户端/服务器程序. 餐前甜点 Unix的输入输出(IO)系统遵循Open-Read-Write-Close这样的操作范本.当一个用户进程进行IO操作之前,它需要调用Open来指定并获取待操作文件或设备读取或写入的权限.一旦IO操作对象被打开,那么这个用户进程可以对这个

java网络编程socket解析

转载:http://www.blogjava.net/landon/archive/2013/07/02/401137.html Java网络编程精解笔记2:Socket详解 Socket用法详解 在C/S通信模式中,client需要主动创建于server连接的Socket(套接字).服务器端收到了客户端的连接请求,也会创建与客户连接的Socket.Socket可看做是通信两端的收发器.server与client都通过Socket来收发数据. 1.构造Socket 1.Socket() 2.So

Java开发之Socket编程详解

本文从3个方面对Socket编程进行详解: 一,网络编程中两个主要的问题 二,两类传输协议:TCP:UDP 三,基于Socket的java网络编程 一,网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机.而TCP层则提供面向应用的可靠(tcp)的或非可靠(UDP)的数据传输机制,这是网络编程的主要对象,一般不需要

ubuntu 16.04利用docker搭建java+tomcat+nginx反向代理/动静分离

ubuntu 16.04利用docker搭建java+tomcat+nginx反向代理 新建两个docker容器 docker run -it --name Tomcat-mysql -v /mnt:/mnt -p 8866:80 -p 33006:3306 ubuntu /bin/bash docker run -itd --name webserver -p 8888:80 -v /mnt/:/mnt/ ubuntu /bin/bash [email protected]:~# docker

读懂Java中的Socket编程

Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的Socket编程,并且如何写一个客户端/服务器程序. 餐前甜点 Unix的输入输出(IO)系统遵循Open-Read-Write-Close这样的操作范本.当一个用户进程进行IO操作之前,它需要调用Open来指定并获取待操作文件或设备读取或写入的权限.一旦IO操作对象被打开,那么这个用户进程可以对这个

Java基础:静态代理和动态代理

转载请注明出处:jiq?钦's technical Blog 一.静态代理: 假设原来有一个实现了指定接口/抽象类的子类: class RealSubject implements Subject{ public void request(){ System.out.print("real request handling\n"); } } 现在有两种情况会发生: 1新的代码需要调用Subject接口,但是需要给每个接口加入新代码(比如日志记录.权限控制等): 2旧的代码已经使用了Su

java进阶 ------ 基于Socket低层次网络编程

[本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020] Socket通讯: 网络上的两个程序通过一个双向的通讯连接实现数据的交互,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定. 在传统的UNIX环境下可以操作TCP/IP协议的接口不止Socket一个,Socket所支持的协议种类不光

java中的socket编程

Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的Socket编程,并且如何写一个客户端/服务器程序. Unix的输入输出(IO)系统遵循Open-Read-Write-Close这样的操作范本.当一个用户进程进行IO操作之前,它需要调用Open来指定并获取待操作文件或设备读取或写入的权限.一旦IO操作对象被打开,那么这个用户进程可以对这个对象进行一