androidmacostcpzeromqportforwarding

How do I receive TCP messages on an android Emulator from a physcal device


In my setup I have 2 apps. One running on my local emulator on my macbook. The other on my physical android phone.

In these apps I use ZeroMQ to have a Req/Rep socket, which under the hood uses TCP.

When hosting my server on the emulated device using port 6543, with it's IP at wlan0 I cannot connect to it from my phone. Reversing the roles works fine where the phone hosts the server and emulator connects to it, but in the long run I need emulators to run this server. Eventually iOS developers want to talk to an Android server, so I'd prefer to keep them using emulators for this.

My understanding is that android emulators exist behind a virtual router, so if you want to talk to them you have to use port forwarding.

I've done this for my emulator. Using redir add tcp:7654:6543. If I understand this correctly then port 7654 of my Macbook should have its traffic redirected to port 6543 of my emulator.

Rather than connect directly to the IP of wlan0 on my emulator, I believe I should be using the IP of my Macbook. For this I run ifconfig | grep "inet " and connect to the IP address that comes back here.

Trying to receive packets in my app though I still don't see traffic.

Additionally I installed Wireshark and filter on tcp.port == 7654 on the wifi interface of my Macbook. While I do see some messages I'm not sure if what I'm seeing is my message itself, or just the TCP handshake as I see multiple SYN and [RST, ACK] but not clear if I should actually be able to see the payloads I'm sending?

I'm not sure at this point what to do. How can I actually verify the traffic is getting to my macbook ok? and how can I verify the forwarding is setup correctly?


Solution

  • So it turns out there are quite a few steps to solve this.

    First we have to do the port forwarding as mentioned in the official android docs so we can get messages to the emulator:

    in a terminal run adb devices to get the port of the device

    List of devices attached
    emulator-5554   device
    

    You'll then need to run telnet localhost 5554 using the port that the device is on.

    From here you'll be prompted for an auth key:

     * Android Console: Authentication required
     * Android Console: type 'auth <auth_token>' to authenticate
     * Android Console: you can find your <auth_token> in
     * '/Users/<your_username>/.emulator_console_auth_token'
    

    Do as the prompt says, open a second terminal and look at the file to get your token.

    Back in the first terminal you'll need to execute auth <your_token>

    Then you can setup your port forward redir add tcp:8765:7654

    This redirects from the loopback port of your Macbook "8765" to the android emulator port "7654".

    Now you have to redirect from your Macbook public IP to its internal loopback address.

    First go to System Preference -> Sharing -> enable Remote Login so that we can setup a port forward using SSH.

    While the SSH requires authentication, and with turning on I'm guessing there may be some security concerns as you're opening up your laptop to external traffic. This may be somewhere to research more before you proceed.

    If this is ok you can then run ssh -v -g -L 9876:localhost:8765 localhost which will then run in the terminal and perform the forwarding for you.

    The final result is: macbook_ip:9876 forwards to macbook_loopback_ip:8765 forwards to android_emulator:7654

    On the Emulator side you have to bind to one of its addresses automatically assigned by the OS: 10.0.2.15:7654

    And on the physical device side you connect to the Macbook IP:port. This number you'll need to look up yourself by running ifconfig | grep "inet "

    As an example you may connect to something like this: 10.0.0.253:9876

    At this point you should have your physical Android phone able to send messages to, and receive from the socket you bound in your Emulator.