dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.26k stars 4.73k forks source link

NetworkInterface.GetAllNetworkInterfaces on Android Throws Null Exception #58374

Closed SteveBush closed 2 years ago

SteveBush commented 3 years ago

Steps To Reproduce:

1) Dotnet new android 2) Add to csproj so LaunchProfiles start up

  <PropertyGroup>
    <_KeepLaunchProfiles>true</_KeepLaunchProfiles>
  </PropertyGroup>

3) Modify MainActivity.cs by adding the following code. 4) Build and Run in Visual Studio 17.0.0 Preview 3.1

Result:

An exception is thrown and is null

Expected:

Related to System.Net.NetworkInformation needs Android PAL #51303 The System.Net.NetworkInformation APIs stopped working on Android. I have provided a simple repo. This is related to issue System.Net.NetworkInformation needs Android PAL #51303.

In the code below, a null exception is thrown. I have also seen the following exception in another project: NetworkInformation.NetworkInformationException : No such file or directory

Suggestions:

I'm writing a mobile and desktop networking application so it would be helpful for the System.NetworkInterface APIs to work cross platform. Android stopped providing direct access to the system files in API level 24.

However, Android includes the ip and ifconfig commands which essentially read the contents of these protected system files and could be used to create a NetworkInterface on Android. See output below.

Alternately, the Android.Net Xamarin code could be used to construct a NetworkInterface.

$ ifconfig
radio0    Link encap:UNSPEC
          inet addr:192.168.200.2  Bcast:192.168.200.255  Mask:255.255.255.0
          inet6 addr: fec0::34ad:3156:e44c:7fd2/64 Scope: Site
          inet6 addr: fe80::f4dd:7cff:fe8a:7164/64 Scope: Link
          inet6 addr: fec0::f4dd:7cff:fe8a:7164/64 Scope: Site
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:200 errors:0 dropped:0 overruns:0 frame:0
          TX packets:364 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:26233 TX bytes:52801

lo        Link encap:UNSPEC
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope: Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:13 errors:0 dropped:0 overruns:0 frame:0
          TX packets:13 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:852 TX bytes:852

wlan0     Link encap:UNSPEC    Driver mac80211_hwsim
          inet addr:192.168.232.2  Bcast:192.168.239.255  Mask:255.255.248.0
          inet6 addr: fe80::15:b2ff:fe00:0/64 Scope: Link
          inet6 addr: fec0::b5b6:cf7:753e:c210/64 Scope: Site
          inet6 addr: fec0::15:b2ff:fe00:0/64 Scope: Site
          UP BROADCAST RUNNING MULTICAST  MTU:1400  Metric:1
          RX packets:168266 errors:0 dropped:0 overruns:0 frame:0
          TX packets:63578 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:106642482 TX bytes:8605743

$ ip route list match 0 table all scope global
default via 192.168.232.1 dev wlan0 table 1003 proto static
default via 192.168.200.1 dev radio0 table 1011 proto static

$ ip route show
192.168.200.0/24 dev radio0 proto kernel scope link src 192.168.200.2
192.168.232.0/21 dev wlan0 proto kernel scope link src 192.168.232.2

$ ip neigh
192.168.200.1 dev radio0 lladdr 9a:79:ee:05:4e:22 STALE
192.168.232.1 dev wlan0 lladdr 02:15:b2:00:01:00 REACHABLE
fe80::15:b2ff:fe00:100 dev wlan0 lladdr 02:15:b2:00:01:00 router STALE
fe80::9879:eeff:fe05:4e22 dev radio0 lladdr 9a:79:ee:05:4e:22 router STALE

Code in MainActivity.cs

using System;
using System.Net.NetworkInformation;
using Android.App;
using Android.OS;
using Android.Runtime;
using Android.Widget;
using Debug = System.Diagnostics.Debug;

namespace Android.GetAllActiveNetworkInterfaces
{
    [Activity(Label = "@string/app_name", MainLauncher = true)]
    public class MainActivity : Activity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            try
            {
                foreach (var networkInterface in NetworkInterface.GetAllNetworkInterfaces())
                {
                    var name = networkInterface.Name;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("GetAllNetworkInterfaces threw exception: ", ex);
            }

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);
        }
    }
}

Configuration Information:

DotNet Versions: 6.0.100-preview.7.21379.14 Android: targeting SDK version 30 Microsoft Visual Studio Enterprise 2022 Preview Version 17.0.0 Preview 3.1 VisualStudio.17.Preview/17.0.0-pre.3.1+31612.314 Microsoft .NET Framework Version 4.8.04084

Android Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
          android:versionCode="1" 
          android:versionName="1.0" 
          package="com.companyname.Android.GetAllActiveNetworkInterfaces">
  <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
  <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true">
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
  </application>
</manifest>
dotnet-issue-labeler[bot] commented 3 years ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

ghost commented 3 years ago

Tagging subscribers to this area: @dotnet/ncl See info in area-owners.md if you want to be subscribed.

Issue Details
### Steps To Reproduce: 1) Dotnet new android 2) Add to csproj so LaunchProfiles start up ``` <_KeepLaunchProfiles>true ``` 3) Modify MainActivity.cs by adding the following code. 4) Build and Run in Visual Studio 17.0.0 Preview 3.1 ### Result: An exception is thrown and is null ### Expected: - No exception and results of NetworkInterface.GetAllNetworkInterfaces to be returned. Related to System.Net.NetworkInformation needs Android PAL #51303 The System.Net.NetworkInformation APIs stopped working on Android. I have provided a simple repo. This is related to issue System.Net.NetworkInformation needs Android PAL #51303. In the code below, a null exception is thrown. I have also seen the following exception in another project: `NetworkInformation.NetworkInformationException : No such file or directory` ### Suggestions: I'm writing a mobile and desktop networking application so it would be helpful for the System.NetworkInterface APIs to work cross platform. Android stopped providing direct access to the system files in API level 24. However, Android includes the ip and ifconfig commands which essentially read the contents of these protected system files and could be used to create a NetworkInterface on Android. See output below. Alternately, the Android.Net Xamarin code could be used to construct a NetworkInterface. ``` $ ifconfig radio0 Link encap:UNSPEC inet addr:192.168.200.2 Bcast:192.168.200.255 Mask:255.255.255.0 inet6 addr: fec0::34ad:3156:e44c:7fd2/64 Scope: Site inet6 addr: fe80::f4dd:7cff:fe8a:7164/64 Scope: Link inet6 addr: fec0::f4dd:7cff:fe8a:7164/64 Scope: Site UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:200 errors:0 dropped:0 overruns:0 frame:0 TX packets:364 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:26233 TX bytes:52801 lo Link encap:UNSPEC inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope: Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:13 errors:0 dropped:0 overruns:0 frame:0 TX packets:13 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:852 TX bytes:852 wlan0 Link encap:UNSPEC Driver mac80211_hwsim inet addr:192.168.232.2 Bcast:192.168.239.255 Mask:255.255.248.0 inet6 addr: fe80::15:b2ff:fe00:0/64 Scope: Link inet6 addr: fec0::b5b6:cf7:753e:c210/64 Scope: Site inet6 addr: fec0::15:b2ff:fe00:0/64 Scope: Site UP BROADCAST RUNNING MULTICAST MTU:1400 Metric:1 RX packets:168266 errors:0 dropped:0 overruns:0 frame:0 TX packets:63578 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:106642482 TX bytes:8605743 $ ip route list match 0 table all scope global default via 192.168.232.1 dev wlan0 table 1003 proto static default via 192.168.200.1 dev radio0 table 1011 proto static $ ip route show 192.168.200.0/24 dev radio0 proto kernel scope link src 192.168.200.2 192.168.232.0/21 dev wlan0 proto kernel scope link src 192.168.232.2 $ ip neigh 192.168.200.1 dev radio0 lladdr 9a:79:ee:05:4e:22 STALE 192.168.232.1 dev wlan0 lladdr 02:15:b2:00:01:00 REACHABLE fe80::15:b2ff:fe00:100 dev wlan0 lladdr 02:15:b2:00:01:00 router STALE fe80::9879:eeff:fe05:4e22 dev radio0 lladdr 9a:79:ee:05:4e:22 router STALE ``` ### Code in MainActivity.cs ``` using System; using System.Net.NetworkInformation; using Android.App; using Android.OS; using Android.Runtime; using Android.Widget; using Debug = System.Diagnostics.Debug; namespace Android.GetAllActiveNetworkInterfaces { [Activity(Label = "@string/app_name", MainLauncher = true)] public class MainActivity : Activity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); try { foreach (var networkInterface in NetworkInterface.GetAllNetworkInterfaces()) { var name = networkInterface.Name; } } catch (Exception ex) { Debug.WriteLine("GetAllNetworkInterfaces threw exception: ", ex); } // Set our view from the "main" layout resource SetContentView(Resource.Layout.activity_main); } } } ``` ### Configuration Information: DotNet Versions: 6.0.100-preview.7.21379.14 Android: targeting SDK version 30 Microsoft Visual Studio Enterprise 2022 Preview Version 17.0.0 Preview 3.1 VisualStudio.17.Preview/17.0.0-pre.3.1+31612.314 Microsoft .NET Framework Version 4.8.04084 Android Manifest: ``` ```
Author: SteveBush
Assignees: -
Labels: `area-System.Net`, `os-android`, `untriaged`
Milestone: -
marek-safar commented 3 years ago

@steveisok I think it'd make sense to change the exception to PNSE

SteveBush commented 3 years ago

The NetworkInformation class works in Xamarin.Android. By not supporting it in net6.0-android, all of the NuGet packages which use the NetworkInformation would be unavailable on .net60. While I can create an abstraction layer for my code, I use some Nuget packages which no longer work if I compile for net6.0-android.

From what I can see from the code, it looks like the Android implementation of NetworkInformation uses the Linux PAL to call the native method getifaddrs(). In the Xamarin.Android, project there is a native implementation of getifaddrs() for Android.

https://github.com/xamarin/xamarin-android/blob/main/src/monodroid/jni/xamarin_getifaddrs.cc

For my purposes, I have created an abstraction layer for NetworkInformation that uses the ip link command to generate a list of network interfaces. I parse the output of ip link to implement NetworkInformation.GetAllNetworkInterfaces.

Below is the output from the ip link command.

generic_x86_arm:/ $ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc mq state UP mode DORMANT group default qlen 1000
    link/ether 02:15:b2:00:00:00 brd ff:ff:ff:ff:ff:ff
6: ip_vti0@NONE: <NOARP> mtu 1364 qdisc noop state DOWN mode DEFAULT group default qlen 1
    link/ipip 0.0.0.0 brd 0.0.0.0
7: ip6_vti0@NONE: <NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1
    link/tunnel6 :: brd ::
8: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1
    link/sit 0.0.0.0 brd 0.0.0.0
9: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1
    link/tunnel6 :: brd ::
11: radio0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 42:b4:98:b4:16:71 brd ff:ff:ff:ff:ff:ff link-netnsid 0
generic_x86_arm:/ $
wfurt commented 3 years ago

I was thinking about the Netlink even for Linux and some other parts - like getting routes. I'm not sure about Andrioind user but on Linux GetAllActiveNetworkInterfaces is used quite frequently.

SteveBush commented 3 years ago

Unfortunately, none of the solutions I proposed above work in API, level 31. The ip commands work fine on a simulator but fail on a device starting in API, level 31. Most of the networking APIs were deprecated in API level 29.

https://developer.android.com/reference/android/net/ConnectivityManager#getAllNetworkInfo()

getAllNetworks was deprecated in Level 31.

public Network[] getAllNetworks ()
This method was deprecated in API level 31.
This method does not provide any notification of network state changes, forcing apps to call it repeatedly. This is inefficient and prone to race conditions. Apps should use methods such as registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback) instead. Apps that desire to obtain information about networks that do not apply to them can use NetworkRequest.Builder#setIncludeOtherUidNetworks.

The best option would be to use the Xamarin native implementation of getifaddrs().

I4-PJ commented 3 years ago

Hello, I have (maybe similar issue) with NetworkInterface.GetAllNetworkInterfaces() under Android. When executing the method I am getting "System.Net.NetworkInformation.NetworkInformationException: 'Success'" exception instead of returing expected values.

the exception is thrown within static method at this line: var interf = NetworkInterface.GetAllNetworkInterfaces();

Application min. API is 27, target API 31. / NET6 rc1

PJ.