Android reverse proxy client can not properly proccess requests

Viewed 14

I am trying to make Reverse Proxy for android, that kind of proxy that uses client`s internet. And I have encountered problem doing such. Client speaks with server via SSL and using json messages (IdentificationMessage, ProxyInit, ReverseProxyConnect, ReverseProxyConnectResponse, ReverseProxyData, ReverseProxyDisconnect). Server uses Socks5 proxy and only sends data to client for processing, also server is written on C#. Response from server that are in ReverseProxyClient is present and sent to server that connected via SSL, however no new messages are sent to client for processing. Meanwhile a C# client that makes same thing does it successfully. I have a suspicion that mobile phone can not properly proccess PC requests and so responses are not proper for PC. In android manifest internet is enabled.

ReverseProxyHandler:

public class ReverseProxyHandler {
    static List<ReverseProxyClient> _clients = new LinkedList<ReverseProxyClient>();
    static public TcpClient stream;

    static public ReverseProxyClient GetClientById(int id)
    {
        return _clients.stream().filter(x->x.ConnectionId == id).findAny().get();
    }
    static public void MessageSrvExecuter(IMessage message)
    {
        try {
            stream.sendMessage(message);
        } catch (Exception e) { }
    }
    static public void MessageClnExecuter(IMessage message)
    {

        if(message instanceof ReverseProxyConnect) {
            ReverseProxyConnect i = (ReverseProxyConnect)message;
            ExecuteCln(i);
        } else if(message instanceof ReverseProxyData) {
            ReverseProxyData i = (ReverseProxyData)message;
            ExecuteCln(i);
        } else if(message instanceof ReverseProxyDisconnect) {
            ReverseProxyDisconnect i = (ReverseProxyDisconnect)message;
            ExecuteCln(i);
        }
    }
    static private void ExecuteCln(ReverseProxyConnect message)
    {
        Log.e(TcpClient.TAG,String.valueOf(_clients.size()));
        ReverseProxyClient rpc =new ReverseProxyClient(message);
        new Thread(rpc).start();
        _clients.add(rpc);
    }
    static private void ExecuteCln(ReverseProxyData message)
    {
        ReverseProxyClient proxyClient = GetClientById(message.ConnectionId);
        if(proxyClient!=null)
            proxyClient.SendToTargetServer(message.Data);
    }
    static private void ExecuteCln(ReverseProxyDisconnect message)
    {
        ReverseProxyClient proxyClient = GetClientById(message.ConnectionId);
        if(proxyClient!=null)
            proxyClient.Disconnect();
    }
}

ReverseProxyClient:

public class ReverseProxyClient implements Runnable {

    private InputStream m_ServerInput = null;
    private OutputStream m_ServerOutput = null;

    public static final int BUFFER_SIZE = 1024 * 8;
    public static final int DEFAULT_PROXY_TIMEOUT = 10000;
    boolean isActive = true;

    public int ConnectionId;
    public Socket Handle;
    public String Target;
    public int Port;
    byte[] m_Buffer = new byte[BUFFER_SIZE];
    private boolean _disconnectIsSend;
    private Object m_lock;
    public ReverseProxyClient(ReverseProxyConnect command)
    {
        this.ConnectionId = command.ConnectionId;
        this.Target = command.Target;
        this.Port = command.Port;
        m_lock = this;
    }
    public void connectToServer() throws IOException {
        try
        {
            Log.e(TcpClient.TAG, "connecting to server");
            Handle = new Socket(Target, Port);
            Handle.setSoTimeout(DEFAULT_PROXY_TIMEOUT);
            prepareServer();
            ReverseProxyConnectResponse i = new ReverseProxyConnectResponse();
            i.ConnectionId = ConnectionId;
            i.IsConnected = true;
            i.LocalAddress = Handle.getLocalAddress().getAddress();
            i.LocalPort = Handle.getLocalPort();
            i.HostName = Target;
            ReverseProxyHandler.MessageSrvExecuter(i);
        }
        catch (Exception e)
        {
            Log.e(TcpClient.TAG, e.getMessage());
            ReverseProxyConnectResponse i = new ReverseProxyConnectResponse();
            i.ConnectionId = ConnectionId;
            i.IsConnected = true;
            i.LocalAddress = Handle.getLocalAddress().getAddress();
            i.LocalPort = Handle.getLocalPort();
            i.HostName = Target;
            ReverseProxyHandler.MessageSrvExecuter(i);
        }
    }
    protected void prepareServer() throws IOException {
        synchronized (m_lock) {
            m_ServerInput = Handle.getInputStream();
            m_ServerOutput = Handle.getOutputStream();
            Log.e(TcpClient.TAG, "set streams");
        }
    }
    public void Disconnect() {
        isActive = false;
        Log.e(TcpClient.TAG, "closing");
        if (!_disconnectIsSend)
        {
            _disconnectIsSend = true;
            close();
            //send to the Server we've been disconnected
            ReverseProxyDisconnect i = new ReverseProxyDisconnect();
            i.ConnectionId = ConnectionId;
            ReverseProxyHandler.MessageSrvExecuter(i);
        }
        try
        {
            Handle.close();
        }
        catch(Exception e) {
            Log.e(TcpClient.TAG, e.getMessage());
        }
    }
    public void SendToTargetServer(byte[] data)
    {
        int len = data.length;
        if (m_ServerOutput != null && len > 0 && len <= m_Buffer.length) {
            try {
                m_ServerOutput.write(data, 0, len);
                m_ServerOutput.flush();
            } catch (IOException e) {
                Log.e(TcpClient.TAG, e.getMessage());
            }
        }

        int dlen;
        dlen = checkServerData();
        Log.e(TcpClient.TAG, "sending "+dlen);

        if (dlen > 0) {
            byte[] payload = new byte[dlen];
            System.arraycopy(m_Buffer, 0, payload, 0, dlen);
            ReverseProxyData i = new ReverseProxyData();
            i.ConnectionId = ConnectionId;
            i.Data = payload;
            ReverseProxyHandler.MessageSrvExecuter(i);
        }
    }
    public void setLock(Object lock) {
        this.m_lock = lock;
    }
    public int checkServerData() {
        synchronized (m_lock) {
            if (m_ServerInput == null)
            {
                return -1;
            }

            int dlen;

            try {
                dlen = m_ServerInput.read(m_Buffer, 0, BUFFER_SIZE);
            } catch (InterruptedIOException e) {
                Log.e(TcpClient.TAG, e.getMessage());
                return -1;
            } catch (IOException e) {
                Log.e(TcpClient.TAG, e.getMessage());
                Disconnect();    // Close the server on this exception
                return -1;
            }

            if (dlen < 0) {
                Disconnect();
            }

            return dlen;
        }
    }
    @Override
    public void run() {
        setLock(this);
        try {
            connectToServer();
        } catch (IOException e) {
            Log.e(TcpClient.TAG, e.getMessage());
        }
        relay();
        close();
    }
    public void close() {
        try {
            if (m_ServerOutput != null) {
                m_ServerOutput.flush();
                m_ServerOutput.close();
            }
        } catch (IOException e) {
            // ignore
        }
    }
    public void relay() {
        while (isActive) {
            int dlen;
            Log.d(TcpClient.TAG,"Trying to...");
            dlen = checkServerData();
            Log.e(TcpClient.TAG, "got "+dlen);
            if (dlen < 0) isActive = false;
            if (dlen > 0) {
                byte[] payload = new byte[dlen];
                System.arraycopy(m_Buffer, 0, payload, 0, dlen);
                ReverseProxyData i = new ReverseProxyData();
                i.ConnectionId = ConnectionId;
                i.Data = payload;
                ReverseProxyHandler.MessageSrvExecuter(i);
            }
            Thread.yield();
        }
    }
}

MainActivity:

public class MainActivity extends AppCompatActivity {
    TcpClient mTcpClient;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView v = (TextView)findViewById(R.id.text);
        try {
            Toast.makeText(this, "before", Toast.LENGTH_LONG).show();
            mTcpClient = new TcpClient(message -> {
                if(message.charAt(0)=='1') {
                    ReverseProxyConnect i = new ReverseProxyConnect();
                    i.FromJSON(message.substring(1));
                    ReverseProxyHandler.MessageClnExecuter(i);
                    Log.e(TcpClient.TAG,"connect");
                } else if(message.charAt(0)=='3') {
                    ReverseProxyData i = new ReverseProxyData();
                    i.FromJSON(message.substring(1));
                    ReverseProxyHandler.MessageClnExecuter(i);
                    Log.e(TcpClient.TAG,"data");
                } else if(message.charAt(0)=='4') {
                    ReverseProxyDisconnect i = new ReverseProxyDisconnect();
                    i.FromJSON(message.substring(1));
                    ReverseProxyHandler.MessageClnExecuter(i);
                    Log.e(TcpClient.TAG,"disconnect");
                }
            });
            ReverseProxyHandler.stream = mTcpClient;
            Toast.makeText(this, "created", Toast.LENGTH_LONG).show();
            new Thread(()->{
                try {
                    Log.d(TcpClient.TAG,"before ran");
                    mTcpClient.run();
                } catch (Exception e) {
                    Log.e(TcpClient.TAG,e.getMessage());
                }
            }).start();
            Toast.makeText(this, "started", Toast.LENGTH_LONG).show();
        }
        catch (Exception e)
        {
            v.setText(e.getMessage());
        }
    }
}

TcpClient:

public class TcpClient {

    public static final String TAG = "Kranstein";
    public static final String SERVER_IP = "93.95.224.224"; //server IP address
    public static final int SERVER_PORT = 8001; //server port
    // message to send to the server
    private String mServerMessage;
    // sends message received notifications
    private OnMessageReceived mMessageListener = null;
    // while this is true, the server will continue running
    private boolean mRun = false;
    // used to send messages
    private PrintWriter mBufferOut;
    // used to read messages from the server
    private BufferedReader mBufferIn;
    private Queue<IMessage> msgs;
    private boolean is_sending = false;
    /**
     * Constructor of the class. OnMessagedReceived listens for the messages received from server
     */
    public TcpClient(OnMessageReceived listener) {
        msgs = new LinkedBlockingQueue<>();
        mMessageListener = listener;
    }

    /**
     * Sends the message entered by client to the server
     *
     * @param message text entered by client
     */
    public void sendMessage(final String message) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if (mBufferOut != null) {
                    Log.d(TAG, "Sending: " + message);
                    mBufferOut.print(message);
                    mBufferOut.flush();
                }
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
    public void sendMessage(final IMessage message) {
        msgs.add(message);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if(!is_sending)
                {
                    if (mBufferOut != null) {
                        is_sending = true;
                        while(!msgs.isEmpty())
                        {
                            IMessage message = msgs.remove();
                            Log.d(TAG, "Sending: " + message.GetID()+message.ToJSON());
                            mBufferOut.print(message.GetID()+message.ToJSON());
                            mBufferOut.flush();
                            Log.d(TAG, "Sent");
                        }
                        is_sending = false;
                    }
                }
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }

    /**
     * Close the connection and release the members
     */
    public void stopClient() {

        mRun = false;

        sendMessage("end");
        if (mBufferOut != null) {
            mBufferOut.flush();
            mBufferOut.close();
        }

        mMessageListener = null;
        mBufferIn = null;
        mBufferOut = null;
        mServerMessage = null;
    }

    public void run() throws IOException {
        mRun = true;
        try {
            // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            }
            };
            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL"); // Add in try catch block if you get error.
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
            SSLSocketFactory ssf = sc.getSocketFactory();
            SSLSocket socket = null;
            socket = (SSLSocket) ssf.createSocket(serverAddr, SERVER_PORT);
            socket.setNeedClientAuth(false);
            socket.addHandshakeCompletedListener((HandshakeCompletedEvent handshakeCompletedEvent)-> {
                    try {
                        mBufferOut = new PrintWriter(handshakeCompletedEvent.getSocket().getOutputStream());
                        mBufferIn = new BufferedReader(new InputStreamReader(handshakeCompletedEvent.getSocket().getInputStream(), StandardCharsets.UTF_8));
                        int charsRead = 0; char[] buffer = new char[8096]; //choose your buffer size if you need other than 1024
                        Log.e(TAG,"identifaction");
                        IdentificationMessage mes = new IdentificationMessage();
                        mes.id = 0;
                        mes.mac = "";
                        mes.type = 0;
                        sendMessage(mes);
                        Log.e(TAG,"sent identification");
                        ProxyInit i = new ProxyInit();
                        i.Password = "asd";
                        i.Username = "asd";
                        i.Port = 2005;
                        sendMessage(i);
                        Log.e(TAG,"sent init");
                        while (mRun) {
                            charsRead = mBufferIn.read(buffer);
                            if(charsRead!=-1)
                            {
                                mServerMessage = new String(buffer).substring(0, charsRead);
                                if (mServerMessage != null && mMessageListener != null) {
                                    mMessageListener.messageReceived(mServerMessage);
                                }
                            }
                            mServerMessage = null;
                        }
                        handshakeCompletedEvent.getSocket().close();
                    } catch (IOException e) {
                        Log.e(TAG,e.getMessage());
                    }
            });
            socket.startHandshake();
        } catch (IOException | NoSuchAlgorithmException | KeyManagementException e) {
            Log.e(TAG,""+e.getMessage());
        }
    }
    public interface OnMessageReceived {
        public void messageReceived(String message);
    }

}
0 Answers
Related