Skip to content

Commit b47b3d2

Browse files
committed
[Android] Fix NetworkInterface.GetAllNetworkInterfaces on API 21-23 (dotnet#76541)
* Bring back pal_ifaddrs * Update the header file
1 parent 2046cd7 commit b47b3d2

File tree

4 files changed

+36
-47
lines changed

4 files changed

+36
-47
lines changed

src/libraries/Native/Unix/System.Native/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ append_extra_system_libs(NATIVE_LIBS_EXTRA)
8181

8282
if (CLR_CMAKE_TARGET_ANDROID AND NOT HAVE_GETIFADDRS)
8383
add_definitions(-DANDROID_GETIFADDRS_WORKAROUND)
84-
8584
add_compile_options(-Wno-gnu-zero-variadic-macro-arguments)
8685

8786
list (APPEND NATIVE_LIBS_EXTRA -llog)

src/libraries/Native/Unix/System.Native/pal_ifaddrs.c

+9-9
Original file line numberDiff line numberDiff line change
@@ -312,15 +312,15 @@ static struct ifaddrs *get_link_info(struct nlmsghdr *message)
312312
break;
313313

314314
case IFLA_BROADCAST:
315-
LOG_DEBUG(" interface broadcast (%lu bytes)\n", RTA_PAYLOAD(attribute));
315+
LOG_DEBUG(" interface broadcast (%zu bytes)\n", RTA_PAYLOAD(attribute));
316316
if (fill_ll_address(&sa, net_interface, RTA_DATA(attribute), RTA_PAYLOAD(attribute)) < 0) {
317317
goto error;
318318
}
319319
ifa->ifa_broadaddr = (struct sockaddr*)sa;
320320
break;
321321

322322
case IFLA_ADDRESS:
323-
LOG_DEBUG(" interface address (%lu bytes)\n", RTA_PAYLOAD(attribute));
323+
LOG_DEBUG(" interface address (%zu bytes)\n", RTA_PAYLOAD(attribute));
324324
if (fill_ll_address(&sa, net_interface, RTA_DATA(attribute), RTA_PAYLOAD(attribute)) < 0) {
325325
goto error;
326326
}
@@ -352,7 +352,7 @@ static struct ifaddrs *find_interface_by_index(int index, struct ifaddrs **ifadd
352352
return NULL;
353353

354354
/* Normally expensive, but with the small amount of links in the chain we'll deal with it's not
355-
* worth the extra houskeeping and memory overhead
355+
* worth the extra housekeeping and memory overhead
356356
*/
357357
cur = *ifaddrs_head;
358358
while (cur) {
@@ -509,7 +509,7 @@ static struct ifaddrs *get_link_address(struct nlmsghdr *message, struct ifaddrs
509509
LOG_DEBUG(" attribute type: LOCAL");
510510
if (ifa->ifa_addr) {
511511
/* P2P protocol, set the dst/broadcast address union from the original address.
512-
* Since ifa_addr is set it means IFA_ADDRESS occured earlier and that address
512+
* Since ifa_addr is set it means IFA_ADDRESS occurred earlier and that address
513513
* is indeed the P2P destination one.
514514
*/
515515
ifa->ifa_dstaddr = ifa->ifa_addr;
@@ -531,7 +531,7 @@ static struct ifaddrs *get_link_address(struct nlmsghdr *message, struct ifaddrs
531531
case IFA_ADDRESS:
532532
LOG_DEBUG(" attribute type: ADDRESS");
533533
if (ifa->ifa_addr) {
534-
/* Apparently IFA_LOCAL occured earlier and we have a P2P connection
534+
/* Apparently IFA_LOCAL occurred earlier and we have a P2P connection
535535
* here. IFA_LOCAL carries the destination address, move it there
536536
*/
537537
ifa->ifa_dstaddr = ifa->ifa_addr;
@@ -570,7 +570,7 @@ static struct ifaddrs *get_link_address(struct nlmsghdr *message, struct ifaddrs
570570
attribute = RTA_NEXT(attribute, length);
571571
}
572572

573-
/* glibc stores the associated interface name in the address if IFA_LABEL never occured */
573+
/* glibc stores the associated interface name in the address if IFA_LABEL never occurred */
574574
if (!ifa->ifa_name) {
575575
char *name = get_interface_name_by_index((int)(net_address->ifa_index), ifaddrs_head);
576576
LOG_DEBUG(" address has no name/label, getting one from interface\n");
@@ -708,7 +708,7 @@ static int parse_netlink_reply(struct netlink_session *session, struct ifaddrs *
708708
return ret;
709709
}
710710

711-
int getifaddrs(struct ifaddrs **ifap)
711+
int _netlink_getifaddrs(struct ifaddrs **ifap)
712712
{
713713
int ret = -1;
714714

@@ -728,7 +728,7 @@ int getifaddrs(struct ifaddrs **ifap)
728728
(parse_netlink_reply(&session, &ifaddrs_head, &last_ifaddr) < 0) ||
729729
(send_netlink_dump_request(&session, RTM_GETADDR) < 0) ||
730730
(parse_netlink_reply(&session, &ifaddrs_head, &last_ifaddr) < 0)) {
731-
freeifaddrs (ifaddrs_head);
731+
_netlink_freeifaddrs (ifaddrs_head);
732732
goto cleanup;
733733
}
734734

@@ -744,7 +744,7 @@ int getifaddrs(struct ifaddrs **ifap)
744744
return ret;
745745
}
746746

747-
void freeifaddrs(struct ifaddrs *ifa)
747+
void _netlink_freeifaddrs(struct ifaddrs *ifa)
748748
{
749749
struct ifaddrs *cur, *next;
750750

src/libraries/Native/Unix/System.Native/pal_ifaddrs.h

+8-30
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,15 @@
77
#error The pal_ifaddrs.h shim is intended only for Android
88
#endif
99

10+
#if __ANDROID_API__ >= 24
11+
#error The pal_ifaddrs.h shim is only necessary for Android API 21-23 and it should be removed now that the minimum supported API level is 24 or higher
12+
#endif
13+
1014
// Android doesn't include the getifaddrs and freeifaddrs functions in older Bionic libc (pre API 24).
11-
// In recent Android versions (Android 11+) the data returned by the getifaddrs function is not valid.
1215
// This shim is a port of Xamarin Android's implementation of getifaddrs using Netlink.
16+
// https://github.com/xamarin/xamarin-android/blob/681887ebdbd192ce7ce1cd02221d4939599ba762/src/monodroid/jni/xamarin_getifaddrs.h
1317

14-
#include "pal_compiler.h"
15-
#include "pal_config.h"
16-
#include "pal_types.h"
17-
18-
#include <sys/cdefs.h>
19-
#include <netinet/in.h>
20-
#include <sys/socket.h>
21-
22-
struct ifaddrs
23-
{
24-
struct ifaddrs *ifa_next;
25-
char *ifa_name;
26-
unsigned int ifa_flags;
27-
struct sockaddr *ifa_addr;
28-
struct sockaddr *ifa_netmask;
29-
union
30-
{
31-
struct sockaddr *ifu_broadaddr;
32-
struct sockaddr *ifu_dstaddr;
33-
} ifa_ifu;
34-
void *ifa_data;
35-
};
36-
37-
// Synonym for `ifa_ifu.ifu_broadaddr` in `struct ifaddrs`.
38-
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
39-
// Synonym for `ifa_ifu.ifu_dstaddr` in `struct ifaddrs`.
40-
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
18+
#include <ifaddrs.h>
4119

42-
int getifaddrs (struct ifaddrs **ifap);
43-
void freeifaddrs (struct ifaddrs *ifap);
20+
int _netlink_getifaddrs (struct ifaddrs **ifap);
21+
void _netlink_freeifaddrs (struct ifaddrs *ifap);

src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c

+19-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifdef ANDROID_GETIFADDRS_WORKAROUND
1818
#include <dlfcn.h>
1919
#include <pthread.h>
20+
#include "pal_ifaddrs.h" // fallback for Android API 21-23
2021
#endif
2122
#include <net/if.h>
2223
#include <netinet/in.h>
@@ -102,19 +103,30 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length)
102103
}
103104

104105
#ifdef ANDROID_GETIFADDRS_WORKAROUND
105-
// Try to load the getifaddrs and freeifaddrs functions manually.
106-
// This workaround is necessary on Android prior to API 24 and it can be removed once
107-
// we drop support for earlier Android versions.
106+
// This workaround is necessary as long as we support Android API 21-23 and it can be removed once
107+
// we drop support for these old Android versions.
108108
static int (*getifaddrs)(struct ifaddrs**) = NULL;
109109
static void (*freeifaddrs)(struct ifaddrs*) = NULL;
110110

111111
static void try_loading_getifaddrs()
112112
{
113-
void *libc = dlopen("libc.so", RTLD_NOW);
114-
if (libc)
113+
if (android_get_device_api_level() >= 24)
115114
{
116-
getifaddrs = (int (*)(struct ifaddrs**)) dlsym(libc, "getifaddrs");
117-
freeifaddrs = (void (*)(struct ifaddrs*)) dlsym(libc, "freeifaddrs");
115+
// Bionic on API 24+ contains the getifaddrs/freeifaddrs functions but the NDK doesn't expose those functions
116+
// in ifaddrs.h when the minimum supported SDK is lower than 24 and therefore we need to load them manually
117+
void *libc = dlopen("libc.so", RTLD_NOW);
118+
if (libc)
119+
{
120+
getifaddrs = (int (*)(struct ifaddrs**)) dlsym(libc, "getifaddrs");
121+
freeifaddrs = (void (*)(struct ifaddrs*)) dlsym(libc, "freeifaddrs");
122+
}
123+
}
124+
else
125+
{
126+
// Bionic on API 21-23 doesn't contain the implementation of getifaddrs/freeifaddrs at all
127+
// and we need to reimplement it using netlink (see pal_ifaddrs)
128+
getifaddrs = _netlink_getifaddrs;
129+
freeifaddrs = _netlink_freeifaddrs;
118130
}
119131
}
120132

0 commit comments

Comments
 (0)