日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

前言

Socket代理協議

Socket代理協議有Socket4和Socket5兩個版本,Socket4協議只支持TCP/IP,Socket代理協議只是單純傳遞數據包,不關心具體協議和用法,所以速度快很快。

Socket4代理已經過時了,支持Socket4代理,需要自己編寫協議,這里研究是為了抓一些數據包供分析。

協議:
http://www.openssh.com/txt/socks4.protocol

協議說明

客戶端請求,服務器端綁定。

請求:|VN-1|CD-1|DSTPORT-2|DSTIP-4|NULL...|

響應:|VN-1|CD-1|DSTPORT-2|DSTIP-4|

Socket4代理服務器

一個類可以搞定~

代碼實現

import JAVA.io.*;
import java.NET.*;
import java.util.Arrays;
import java.util.Base64;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Socks4Server {

    // constants
    private static final int MAX_REQUEST_BYTES_NUMBER = 50;
    private static final int MINIMUM_REQUEST_LENGTH = 8;
    private static final int REQUEST_OK = 90;
    private static final int REQUEST_REJECTED_OR_FAILED = 91;
    private static final int MAX_PARALLEL_CONNECTIONS = 20;
    private static final int PROTOCOL_VERSION = 4;
    private static final int CONNECT_REQUEST = 1;
    private static final int TIMEOUT_TIME = 2000;
    private static final int BUF_SIZE = 4096;

    // error message definitions
    private static final String SUCCESSFUL_CONNECTION = "Successful connection from ";
    private static final String PASSword_FOUND = "Password found! ";
    private static final String CLOSING_CONNECTION = "Closing connection from: ";
    private static final String CONNECTER_ERROR = "Unknown Connection Error";
    private static final String UNSUPPOERTED_SOCKS_PROT = "Unsupported SOCKS protocol version ";
    private static final String UNKNOWN_SOCKS_COMMAND_ERROR = "Unknown socks command! currently supports only CONNECT request";
    private static final String ILLEGAL_IP_LENGTH = "IP address is of illegal length";
    private static final String ILLEGAL_REQUEST_LENGTH_ERROR = "The request has an illegal length - under 8 characters";
    private static final String ILLEGAL_PORT_NUMBER_ERROR = "Illegal port number. given port number is 0";
    private static final String CONNECTION_TO_DESTINATION_IP_FAILED = "Connection error: while connecting to destination: connect timed out";
    private static final String TIMOUT_ERROR = "Timeout limit reached closing all connection";
    private static final String CLIENTHOSTIOERROR = "Error during client host communication";
    private static final String NOCONNECT = "No connect message received";

    /**
     * @param args
     */
    public static void main(String[] args) {
        // 服務端口
        int port = 1080;
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            // 線程池
            ThreadPoolExecutor connections = new ThreadPoolExecutor(0, MAX_PARALLEL_CONNECTIONS,
                    1, TimeUnit.HOURS, new ArrayBlockingQueue(1), new RejectedConnection());
            while (true) {
                try {
                    connections.submit(new Handler(serverSocket.accept()));
                } catch (Exception e) {
                    System.err.println("與客戶端的連接過程中出錯");
                }
            }
        } catch (Exception e) {
            System.err.println("代理服務器崩潰");
        }
    }

    /**
     * SOCKS4服務器拒絕
     */
    private static class RejectedConnection implements RejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            executor.remove(r);
            System.err.println("服務器容量已滿,連接請求已被拒絕.");
        }

    }

    /**
     * 處理實際連接
     */
    private static class Handler extends Thread {

        private Socket clientSocket;
        private int destinationPort;
        private InetAddress destinationIP;

        Handler(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }

        @Override
        public void run() {
            try (DataInputStream clientInput = new DataInputStream(clientSocket.getInputStream());
                 DataOutputStream clientOutput = new DataOutputStream(clientSocket.getOutputStream())) {
                // 設置客戶端超時時間
                clientSocket.setSoTimeout(TIMEOUT_TIME);
                // 讀取來自客戶端的請求
                byte[] byteArray = new byte[MAX_REQUEST_BYTES_NUMBER];
                int successFlag = clientInput.read(byteArray);
                if (successFlag == -1) {
                    System.err.println("已到達流的末端");
                    throw new NullPointerException();
                }
                // 處理連接請求并生成響應
                byte[] response = processRequest(byteArray);
                // 錯誤的請求導致連接被拒絕
                if (response[1] == REQUEST_REJECTED_OR_FAILED) {
                    clientOutput.write(response);
                    clientOutput.flush();
                    closingClientConnectionMessage(clientSocket);
                } else if (response[1] == REQUEST_OK) {
                    // 正常連接
                    try (Socket hostSocket = new Socket(destinationIP, destinationPort);
                         BufferedWriter HostOutput = new BufferedWriter(new OutputStreamWriter(hostSocket.getOutputStream()))) {
                        hostSocket.setSoTimeout(TIMEOUT_TIME);
                        clientOutput.write(response);
                        clientOutput.flush();
                        // 連接成功
                        successfulConnectionMessage(clientSocket);
                        try (BufferedReader clientBufReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))) {
                            ExecutorService IOService = Executors.newFixedThreadPool(2);
                            if (destinationPort == 80) {
                                processClientDataHTTP(clientBufReader, HostOutput);
                            }
                            // 數據交換
                            while (true) {
                                ioService.submit(new ProcessData(clientSocket.getOutputStream(), hostSocket.getInputStream()));
                                ioService.submit(new ProcessData(hostSocket.getOutputStream(), clientSocket.getInputStream()));
                                if (!ioService.awaitTermination(TIMEOUT_TIME, TimeUnit.MILLISECONDS)) {
                                    throw new SocketTimeoutException();
                                }
                            }
                        } catch (SocketTimeoutException e) {
                            closingConnectionMessage(clientSocket);
                        } catch (IOException e) {
                            System.err.println(CLIENTHOSTIOERROR);
                        }
                    } catch (Exception e) {
                        response[1] = REQUEST_REJECTED_OR_FAILED;
                        clientOutput.write(response);
                        clientOutput.flush();
                        System.err.println(CONNECTION_TO_DESTINATION_IP_FAILED);
                        closingClientConnectionMessage(clientSocket);
                    }
                }
            } catch (NullPointerException e) {
                System.err.println(NOCONNECT);
            } catch (SocketTimeoutException e) {
                System.err.println(TIMOUT_ERROR);
            } catch (IOException e) {
                System.err.println(CONNECTER_ERROR);
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    System.err.println("關閉過程中出錯");
                }
            }
        }

        /**
         * 主機通信
         */
        private class ProcessData implements Runnable {

            OutputStream out;
            InputStream in;

            private ProcessData(OutputStream out, InputStream in) {
                this.in = in;
                this.out = out;
            }

            @Override
            public void run() {
                try {
                    byte[] buf = new byte[BUF_SIZE];
                    int numOfbytes = 0;
                    int numOfLine = 0;
                    while ((numOfbytes = in.read(buf)) > 0 && numOfbytes < BUF_SIZE) {
                        System.out.print(String.format("%02x", numOfbytes) + " ");
                        if (numOfLine % 16 == 0) {
                            System.out.println();
                        }
                        numOfLine++;
                        out.write(buf, 0, numOfbytes);
                    }
                } catch (Exception e) {
                    return;
                }
            }
        }

        /**
         * @param clientBufReader
         * @param HostOutput
         * @throws Exception
         */
        private void processClientDataHTTP(BufferedReader clientBufReader, BufferedWriter HostOutput) throws Exception {
            String line = "";
            StringBuilder clientData = new StringBuilder();
            line = clientBufReader.readLine();
            // regex definition
            Pattern authorizationPattern = Pattern.compile("^[Aa]uthorization: [Bb]asic (.*)");
            String credentials = "";
            Pattern hostPattern = Pattern.compile("Host: (.*)");
            String hostName = "";
            Base64.Decoder decoder = Base64.getDecoder();
            // 讀取客戶端數據
            while (clientBufReader.ready()) {
                // password/username regex
                Matcher authorizationMatcher = authorizationPattern.matcher(line);
                if (authorizationMatcher.matches()) {
                    credentials = authorizationMatcher.group(1);
                    credentials = new String(decoder.decode(credentials.getBytes("UTF-8")));
                }
                // hostname regex
                Matcher hostMatcher = hostPattern.matcher(line);
                if (hostMatcher.matches()) {
                    hostName = hostMatcher.group(1);
                }
                // parsing request
                clientData.Append(line);
                clientData.append("rn");
                line = clientBufReader.readLine();
            }
            System.out.println(PASSWORD_FOUND + "http//:" + credentials + "@" + hostName);
            clientData.append("rnrn");
            HostOutput.write(clientData.toString());
            HostOutput.flush();
        }

        private void successfulConnectionMessage(Socket clientSocket) {
            System.out.println(SUCCESSFUL_CONNECTION + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort() + " to " + destinationIP.getHostAddress() + ":" + destinationPort);
        }

        private void closingConnectionMessage(Socket clientSocket) {
            System.out.println(CLOSING_CONNECTION + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort() + " to " + destinationIP.getHostAddress() + ":" + destinationPort);
        }

        private void closingClientConnectionMessage(Socket clientSocket) {
            System.out.println(CLOSING_CONNECTION + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
        }

        /**
         * @param request - the client request
         * @return response - the SOCKS4 server response
         */
        private byte[] processRequest(byte[] request) {
            byte[] response = new byte[8];
            byte replyStatus = REQUEST_OK;
            // 檢查請求是否有效
            if (!isRequestLengthLegal(request, response) ||
                    !processProtocolVersionRequest(request[0]) ||
                    !processSOCKScommandCode(request[1]) ||
                    !processDestinationPortNumber(request[2], request[3]) ||
                    !processDestinationIP(request)) {
                System.out.println("請求被拒絕!");
                replyStatus = REQUEST_REJECTED_OR_FAILED;
            }
            response[1] = replyStatus;
            return response;
        }

        // VN - SOCKS protocol version number
        private boolean processProtocolVersionRequest(byte version) {
            if (version != PROTOCOL_VERSION) {
                System.err.println(UNSUPPOERTED_SOCKS_PROT + "(got " + version + ")");
                return false;
            }
            return true;
        }

        // DSPORT
        private boolean processDestinationPortNumber(byte firstByte, byte secondByte) {
            this.destinationPort = (firstByte & 0xff) << 8 | (secondByte & 0xff);
            if (this.destinationPort <= 0) {
                System.err.println(ILLEGAL_PORT_NUMBER_ERROR);
                return false;
            }
            return true;
        }

        // CD - SOCKS command code and should be 1 for CONNECT request
        private boolean processSOCKScommandCode(byte code) {
            if (code != CONNECT_REQUEST) {
                System.err.println(UNKNOWN_SOCKS_COMMAND_ERROR);
                return false;
            }
            return true;
        }

        // DSTIP
        private boolean processDestinationIP(byte[] requestArray) {
            try {
                // SOCKS 4A
                if (requestArray[4] == 0 && requestArray[5] == 0 && requestArray[6] == 0 && requestArray[7] != 0) {
                    int start = 0;
                    int end = 0;
                    int i = 8;
                    while (requestArray[i] != 0) {
                        i++;
                    }
                    start = i + 1;
                    i++;
                    while (requestArray[i] != 0) {
                        i++;
                    }
                    end = i;
                    destinationIP = InetAddress.getByName(new String(Arrays.copyOfRange(requestArray, start, end)));
                }
                // regular SOCKS
                else {
                    destinationIP = InetAddress.getByAddress(Arrays.copyOfRange(requestArray, 4, 8));
                }
            } catch (UnknownHostException e) {
                System.err.println(ILLEGAL_IP_LENGTH);
                return false;
            }
            return true;
        }

        // request length must be minimum of length 8
        private boolean isRequestLengthLegal(byte[] request, byte[] response) {
            if (request.length < MINIMUM_REQUEST_LENGTH) {
                System.err.println(ILLEGAL_REQUEST_LENGTH_ERROR);
                return false;
            }
            // dest port
            response[2] = request[2];
            response[3] = request[3];
            // ip
            response[4] = request[4];
            response[5] = request[5];
            response[6] = request[6];
            response[7] = request[7];
            return true;
        }
    }

}

客戶端使用Socket4代理

客戶端協議實現類

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Sock4Socket extends Socket {

    // 版本
    private static byte VERSION4 = 0X04;
    // 請求
    private static byte CONNECT_REQUEST = 0X01;
    private static byte BIND_REQUEST = 0X02;
    // 結束
    private static byte END = 0X00;

    private String targetHost;

    private int targetPort;

    public Sock4Socket(String proxyHost, int proxyPort, String targetHost, int targetPort) throws UnknownHostException, IOException {
        super(proxyHost, proxyPort);
        this.targetHost = targetHost;
        this.targetPort = targetPort;
        this.connect();
    }

    /**
     * @param host
     * @param port
     * @return
     * @throws UnknownHostException
     */
    private byte[] connByte(String host, int port) throws UnknownHostException {
        String[] subIP = host.split("\.");
        String portStr = Integer.toHexString(port);
        byte subP1B = 0;
        byte subP2B = 0;
        if (portStr.length() <= 2) {
            subP2B = (byte) Byte.valueOf(portStr, 16);
        } else if (portStr.length() == 3) {
            String p1 = portStr.charAt(0) + "";
            subP1B = (byte) Byte.valueOf(p1, 16);
            String p2 = portStr.charAt(1) + "" + portStr.charAt(2);
            subP2B = (byte) Byte.valueOf(p2, 16);
        } else if (portStr.length() == 4) {
            String p1 = portStr.charAt(0) + "" + portStr.charAt(1);
            subP1B = (byte) Byte.valueOf(p1, 16);
            String p2 = portStr.charAt(2) + "" + portStr.charAt(3);
            subP2B = (byte) Byte.valueOf(p2, 16);
        }
        byte[] bt = new byte[9];
        bt[0] = VERSION4;
        bt[1] = CONNECT_REQUEST;
        bt[2] = subP1B;
        bt[3] = subP2B;
        bt[4] = (byte) Integer.parseInt(subIP[0]);
        bt[5] = (byte) Integer.parseInt(subIP[1]);
        bt[6] = (byte) Integer.parseInt(subIP[2]);
        bt[7] = (byte) Integer.parseInt(subIP[3]);
        bt[8] = END;
        return bt;
    }

    /**
     * 連接
     */
    private void connect() throws IOException {
        byte[] data = connByte(this.targetHost, this.targetPort);
        OutputStream os = this.getOutputStream();
        // 握手字節序列
        os.write(data);
        os.flush();
        // 服務端返回的字節 version,command,ip,port,message
        byte[] receive = new byte[8];
        InputStream is = this.getInputStream();
        is.read(receive);
        byte b = receive[1];
        if (b == 0) {
            throw new IOException("");
        } else if (b == 92) {
            throw new IOException("server time out");
        } else if (b == 90) {
            // success
        }
    }

}

測試案例

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

public class Sock4SocketClientDemo {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        // Socket4代理服務地址
        String proxyHost = "127.0.0.1";
        int proxyPort = 1080;
        // 訪問的地址
        String targetHost = "124.239.226.238";
        int targetPort = 80;
        // 創建Socket4代理Socket
        Sock4Socket sock4Socket = new Sock4Socket(proxyHost, proxyPort, targetHost, targetPort);
        OutputStream outputStream = sock4Socket.getOutputStream();
        InputStream inputStream = sock4Socket.getInputStream();
        InputStreamReader isr = new InputStreamReader(inputStream, "GBK");
        BufferedReader br = new BufferedReader(isr);
        // 請求內容
        StringBuilder request = new StringBuilder();
        request.append("GET / HTTP/1.1rn");
        request.append("Accept-Language: zh-cnrn");
        request.append("Host: www.toutiao.comrn");
        request.append("rn");
        outputStream.write(request.toString().getBytes());
        outputStream.flush();
        // 響應內容
        StringBuilder sb = new StringBuilder();
        String str = null;
        while ((str = br.readLine()) != null) {
            sb.append(str + "n");
        }
        System.out.println(sb.toString());
        br.close();
        isr.close();
        outputStream.close();
    }

}

分享到:
標簽:代理服務器
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定