vouch-opensource / krell

Simple ClojureScript React Native Tooling
Eclipse Public License 1.0
675 stars 37 forks source link

Enhance IP address selection logic #104

Closed mfikes closed 3 years ago

mfikes commented 4 years ago

When running an app on a physical device, the IP address that Krell selects and interpolates into the SERVER_IP value in krell_repl.js becomes important as it is the one that the app will use to connect back upon when establishing the REPL connection.

Currently Krell obtains the set of addresses allocated to the machine and does some filtering (eliminating interfaces that are down, eliminating loopback / link-local addresses, etc.). But if you have virtual machines set up on your dev box, it might be possible for this logic to inadvertently select an address that is associated with a virtual machine (for example, associated with vnic0 instead of en0.)

A consequence of this is that the REPL connection may not be established if this occurs. This can be worked around by manually editing the SERVER_IP value.

For my particular case (vnic interfaces that result from Parallels being run on macOS), inspecting both the network interfaces involved and the IP addresses associated with them shows that they are indistinguisable from "regular" IP addresses, so some other technique is needed.

This SO deals with the same problem: https://stackoverflow.com/questions/9481865/getting-the-ip-address-of-the-current-machine-using-java

The following approach (inspired by that SO) might work (it returns the correct address for me).

$ clj
Clojure 1.10.1
user=> (import '(java.net InetSocketAddress Socket))
java.net.Socket
user=> (with-open [socket (Socket.)] 
     (.connect socket (InetSocketAddress. "google.com" 80)) 
     (.. socket getLocalAddress getHostAddress))
"10.0.1.32"

This is essentially establishing an actual outbound connection in order to learn what the OS assigns as the source address for the TCP connection, and the involvement of this actual connection makes this approach a bit unsavory. (Other approaches are suggested in the SO that are close to the same, without actually making a connection, but they fail on macOS, returning "0.0.0.0".)

Another approach is to simply make the IP address logic overridable and explicitly configurable.

But this also raises the interesting question, does React Native itself encounter this problem and if so, how does it address it?

millettjon commented 3 years ago

Can mDNS be used to get the local IP?

mfikes commented 3 years ago

With respect to @millettjon 's question, I can add that the Ambly REPL uses mDNS, and the JmDNS implementation makes a best effort to select an IP address and can similarly run into issues if the selected address is unsuitable.

FWIW I'm having Ambly do a couple of things:

  1. Surface visibility of the address being used with a message like "Ambly binding to 10.0.1.41 for mDNS."
  2. Allow the user to optionally explicitly configure the address via a custom REPL option.
Gonzih commented 3 years ago

Does it make sense to allow configuration for this to be overwriten in build.edn or via cli argument? I'm totally fine with setting this to localhost and relying on adb reverse for my dev environment, looking at the code it does not seem to be an easy way to achieve that.

Gonzih commented 3 years ago

Update on my last comment:

Took me a while to figure this out but I managed to create file called repl.edn:

{:port 5001
 :host "localhost"}

That can be passed via -ro repl.edn cli option. Unfortunately :host option gets ignored. Fix for that is in #114

swannodette commented 3 years ago

fixed https://github.com/vouch-opensource/krell/commit/8a9d30e4ad61ea54f16dc2bf021c2a3904a80325