// Path: dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/exception/SOCKS5Exception.java
// public class SOCKS5Exception extends Exception {
// 
//     public SOCKS5Exception(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-utils/src/main/java/com/vecsight/dragonite/utils/binary/BinaryWriter.java
// public class BinaryWriter {
// 
//     private final ByteBuffer byteBuffer;
// 
//     public BinaryWriter(final int capacity) {
//         byteBuffer = ByteBuffer.allocate(capacity);
//     }
// 
//     public BinaryWriter putSignedByte(final byte sb) {
//         byteBuffer.put(sb);
//         return this;
//     }
// 
//     public BinaryWriter putUnsignedByte(final short ub) {
//         byteBuffer.put((byte) (ub & 0xff));
//         return this;
//     }
// 
//     public BinaryWriter putSignedShort(final short ss) {
//         byteBuffer.putShort(ss);
//         return this;
//     }
// 
//     public BinaryWriter putUnsignedShort(final int us) {
//         byteBuffer.putShort((short) (us & 0xffff));
//         return this;
//     }
// 
//     public BinaryWriter putSignedInt(final int si) {
//         byteBuffer.putInt(si);
//         return this;
//     }
// 
//     public BinaryWriter putUnsignedInt(final long ui) {
//         byteBuffer.putInt((int) (ui & 0xffffffffL));
//         return this;
//     }
// 
//     public BinaryWriter putBytes(final byte[] bytes) {
//         byteBuffer.put(bytes);
//         return this;
//     }
// 
//     public BinaryWriter putBytesGroupWithByteLength(final byte[] bytes) {
//         putUnsignedByte((short) bytes.length);
//         putBytes(bytes);
//         return this;
//     }
// 
//     public BinaryWriter putBytesGroupWithShortLength(final byte[] bytes) {
//         putUnsignedShort(bytes.length);
//         putBytes(bytes);
//         return this;
//     }
// 
//     public BinaryWriter putBoolean(final boolean b) {
//         byteBuffer.put((byte) (b ? 1 : 0));
//         return this;
//     }
// 
//     public byte[] toBytes() {
//         return byteBuffer.array();
//     }
// 
// }


import com.vecsight.dragonite.proxy.exception.SOCKS5Exception;
import com.vecsight.dragonite.utils.binary.BinaryWriter;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
            inputStream.readFully(addr);
        } else if (atyp == 0x04) {
            //IPv6
            addr = new byte[16];
            inputStream.readFully(addr);
        } else {
            throw new SOCKS5Exception("Unknown address type");
        }
        port = inputStream.readUnsignedShort();
        if (cmd == 0x01 || cmd == 0x03) {
            //CONNECT & UDP ASSOCIATE
            if (atyp == 0x03)
                return new SOCKS5Header(true, addr, port, cmd == 0x03);
            else
                return new SOCKS5Header(false, addr, port, cmd == 0x03);
            //No response frame yet
        } else {
            //Not supported, yet
            outputStream.write(SOCKS5_NOT_SUPPORTED);
            throw new SOCKS5Exception("Command " + cmd + " is not supported.");
        }
    }

    public static void sendSucceed(final Socket socket) throws IOException {
        socket.getOutputStream().write(SOCKS5_SUCCEED);
    }

    public static void sendSucceedUDP(final Socket socket, final int port) throws IOException {
        final byte[] localAddress = socket.getLocalAddress().getAddress();

// Path: dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/exception/SOCKS5Exception.java
// public class SOCKS5Exception extends Exception {
// 
//     public SOCKS5Exception(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-utils/src/main/java/com/vecsight/dragonite/utils/binary/BinaryWriter.java
// public class BinaryWriter {
// 
//     private final ByteBuffer byteBuffer;
// 
//     public BinaryWriter(final int capacity) {
//         byteBuffer = ByteBuffer.allocate(capacity);
//     }
// 
//     public BinaryWriter putSignedByte(final byte sb) {
//         byteBuffer.put(sb);
//         return this;
//     }
// 
//     public BinaryWriter putUnsignedByte(final short ub) {
//         byteBuffer.put((byte) (ub & 0xff));
//         return this;
//     }
// 
//     public BinaryWriter putSignedShort(final short ss) {
//         byteBuffer.putShort(ss);
//         return this;
//     }
// 
//     public BinaryWriter putUnsignedShort(final int us) {
//         byteBuffer.putShort((short) (us & 0xffff));
//         return this;
//     }
// 
//     public BinaryWriter putSignedInt(final int si) {
//         byteBuffer.putInt(si);
//         return this;
//     }
// 
//     public BinaryWriter putUnsignedInt(final long ui) {
//         byteBuffer.putInt((int) (ui & 0xffffffffL));
//         return this;
//     }
// 
//     public BinaryWriter putBytes(final byte[] bytes) {
//         byteBuffer.put(bytes);
//         return this;
//     }
// 
//     public BinaryWriter putBytesGroupWithByteLength(final byte[] bytes) {
//         putUnsignedByte((short) bytes.length);
//         putBytes(bytes);
//         return this;
//     }
// 
//     public BinaryWriter putBytesGroupWithShortLength(final byte[] bytes) {
//         putUnsignedShort(bytes.length);
//         putBytes(bytes);
//         return this;
//     }
// 
//     public BinaryWriter putBoolean(final boolean b) {
//         byteBuffer.put((byte) (b ? 1 : 0));
//         return this;
//     }
// 
//     public byte[] toBytes() {
//         return byteBuffer.array();
//     }
// 
// }


// Path: dragonite-proxy/src/main/java/com/vecsight/dragonite/proxy/network/socks5/SOCKS5SocketHelper.java
import com.vecsight.dragonite.proxy.exception.SOCKS5Exception;
import com.vecsight.dragonite.utils.binary.BinaryWriter;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

            inputStream.readFully(addr);
        } else if (atyp == 0x04) {
            //IPv6
            addr = new byte[16];
            inputStream.readFully(addr);
        } else {
            throw new SOCKS5Exception("Unknown address type");
        }
        port = inputStream.readUnsignedShort();
        if (cmd == 0x01 || cmd == 0x03) {
            //CONNECT & UDP ASSOCIATE
            if (atyp == 0x03)
                return new SOCKS5Header(true, addr, port, cmd == 0x03);
            else
                return new SOCKS5Header(false, addr, port, cmd == 0x03);
            //No response frame yet
        } else {
            //Not supported, yet
            outputStream.write(SOCKS5_NOT_SUPPORTED);
            throw new SOCKS5Exception("Command " + cmd + " is not supported.");
        }
    }

    public static void sendSucceed(final Socket socket) throws IOException {
        socket.getOutputStream().write(SOCKS5_SUCCEED);
    }

    public static void sendSucceedUDP(final Socket socket, final int port) throws IOException {
        final byte[] localAddress = socket.getLocalAddress().getAddress();

        final BinaryWriter writer = new BinaryWriter(6 + localAddress.length);