Ip Address shown on android device differs from the one shown in my router

Hi, i’m currently working on a simple server to client communication in the local network, the “server” app shows the Ip address given by the router and the client use it to connect, then i can broadcast messages from my server to the clients:

SERVER START

        MDriver = NetworkDriver.Create();
        var endpoint = NetworkEndpoint.AnyIpv4;
        endpoint.Port = this.Port;
        if (MDriver.Bind(endpoint) != 0)
        {
            Debug.Log($"Failed to bind to port {Port}");
        }
        else
        {
            MDriver.Listen();

CLIENT CONNECTING

        this.ip = _ip;
        this.port = _port;

        if (_isConnected) {
            this.Disconnect();
        }

        var endpoint = NetworkEndpoint.Parse(ip, port);
        Debug.Log($"CONNECTING TO {endpoint.Address}:{endpoint.Port}");
        try
        {
            _isConnected = true;
            statusTextContainer.GetComponent<TMP_Text>().text = $"Connesso a {ip}:{port}";
            sfxStereo.GetComponent<AudioSource>().resource = this.pingConnection;
            sfxStereo.GetComponent<AudioSource>().Play();
            m_Connection = m_Driver.Connect(endpoint);
        }

to make things easier i show the ip address on the server app with:
SHOW IP CODE

        try
        {
            var host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (var ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    return {ip}:{this.Port};
                }
            }
            return "Ip not found";
        }

I tried this with my phone and pc in my wifi and it works without a problem, the ip is shown correctly and the client connects to the server which sends messages which arrive…
I then tried it with my girlfriend’s phone which has 4/5 years, and the shown ip is wrong!
it’s not the router ip and i’m certain of it because i checked it in the router interface AND if i connect using the one shown in the router ui the flow shown earlier works, but i dont understand why the ip shown is wrong…

SUMMARY AND CONTEXT:
-using Unity 6000
-on local network, home wifi
-it works on my phone and pc
-doesnt work on another phone
-both phones have the latest android OS
-the ip shown is wrong but if use the real ip it works, so the phone is connected to the wifi
-the phone data network is turned off, so it’s only connected to the wifi
-if i try to print all the addresses in the loop in debug mode it shows only one

is it a code problem? does the device need some settings i didn’t find?

thanks for the help!

WELP i just thought that the phone may have more then one private ip, using the loop it gets just the first one… how can i be sure that it’s the router one?

If it’s on a local network you can usually tell via the subnet mask. Almost all commercial routers will have a subnet mask of 255.255.255.25x and you’ll probably be fine with just the first 3 digits.

If you do a little digging on that “find IP” code you’ll learn that it’s far from trivial to reliably get the device’s correct IP address used to communicate with the Internet from the device itself.

I don’t know what network interfaces mobile devices may use but more than one is not uncommon. On a desktop you typically find one or two Wifi interfaces, up to four LAN interfaces, and sometimes virtual interfaces such as VPN or hooks from packet monitoring software.

So … which one do you pick? It’s a challenging task and the solutions finding the correct one with a high degree of certainty encompassing both IPv4 and IPv6 are rather complex.

Also consider that some devices may be using IPv6, and this will be increasingly likely going forward the next ten years. The part where you return (ip):(port) is only valid for IPv4. You cannot ignore IPv6 if you intend to publish.

At this point i’d say tthe best thing would be to show the an ip list related to the source of it?
im thinking something like

  • x.x.x.x router A
  • x.x.x.x device 4g
    ecc…

i have to search if it’s doable

so as @CodeSmile said this is not a simple problem, after searching for a bit i can understand why.

  • Devices (mostly pc) can have more then 1 internal ip address.
  • You have to take in account that there’s ipV6 too, but for the internal private ip going with ipV4 is still ok for what i’ve read.
  • Some apps or programs could create some ips, like in my pc i had 3 internal ip, 1 correct for me and 2 coming from virtual machines, obv they where really similiar to the correct one.

as of now i’ve come to 2 solutions:


Dynamic native code

If we use DIRECTIVES to differentiate the code between the platforms we can adoperate native code to ask for the wifi they are connected to and get the data (we need the platofrm api, so there's no ace of all trade method in c#, even there you need to have the permission from the user). At that point getting the private ip is not hard...but native code for 3/4 platforms?
ouch i don't even want to think maintining tnative code for the various OS versions and all of the cases for each of them.

In my case i know i'm only targetting android (probably) so i could try but i didn't want to waste time as this is just a POC for now, i'll see how to do it later maybe.

EX:

        #if UNITY_STANDALONE_WIN
        
          ...windows api
        
        #elif UNITY_ANDROID
        
        ...android api
        
        #endif

Filter plus RFC Standard prefix

The "hard coded" solution, knowing i'm going to use the app on windows and trying it on android devices too i'm looping all the networkInterfaces and filter them with:
  • Type of connection:
    The connection from computer wifi is of enum type Wireless80211, the one from android always gave wlan0 (i’ve tried on 4 different device as of now).

  • Private Ip Standard RFC1918
    It seems that there’s a standard for private interal ip which is a prefix based on the size of the network:

    • small network (like home’s router) 192.168.-.-
    • medium network (usually offices, but even there they often use the small one too) 172.16.-.-
    • big network 10.-.-.-
  • Network family
    The AddressFamily field of an private IpV4 is InterNetwork in C# .NET

those filters together formed:

public string GetLocalIp()
{
    //Get all network interfaces
    foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
    {
        if (netInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || netInterface.Name.ToLower() == "wlan0")
            //Get IpS from network
            foreach (UnicastIPAddressInformation ipInfo in netInterface.GetIPProperties().UnicastAddresses)
            {
                if (ipInfo.Address.AddressFamily == AddressFamily.InterNetwork &&
                    PrivateIpV4Handler.IpV4IsPrivateLocal(PrivateIpV4Handler.SmallIp, ipInfo.Address.ToString()))
                {
                    IPAddress ipAddress = ipInfo.Address;
                    return ipAddress.ToString();
                }
            }
    }
    return "ND";
}
//Standard RFC 1918 for private local ipv4 
static class PrivateIpV4Handler
{
    public const string SmallIp = "192.168";
    public const string MediumIp = "172.16";
    public const string LargeIp = "10";

    public static bool IpV4IsPrivateLocal(string localNetPrefixStandard, string IpAddress)
    {
        try
        {
            string[] localNetPrefixPieces = localNetPrefixStandard.Split('.');
            string[] addressPieces = IpAddress.Split('.');

            /**
                if localNetPrefixPieces ordered pieces 
                are equal 
                to the number of ordered pieces of the incoming ipAddress 
                then it's a private ipV4
             */
            int equalPiecesInOrder = 0;
            for (int i = 0; i < localNetPrefixPieces.Length; i++)
            {
                if (localNetPrefixPieces[i] == addressPieces[i])
                    equalPiecesInOrder++;
            }

            return equalPiecesInOrder == localNetPrefixPieces.Length;
        }
        catch (Exception ex)
        {
            Debug.LogError(ex.Message);
            return false;
        }
    }
}

So is it good?
No, as a developer i don’t like this solution, I don’t think it’s 100% reliable, and if something weird happens then this routine won’t work, BUT I had to do this thing for a POC/alpha and it’s working so it’s not a problem and even on “production” we’ll choose the used devices, if they have Android os i know that they will use one wifi and we can still implement the A route which get less complex knowing we will update the native code only for one platform.

This is one of those problem where you can’t find an ace of all trades solution which is reliable without some drawbacks in a cross platform engine, but if you know the “domain” of your app deployment you can still work on it.

Working app on Windows and Android



I'm marking this a solution, if future me or someone else get's a better one i'll update the marked solution.