From 558509e796ef356c287b1c18d24252a0462e4edb Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 27 Sep 2022 14:28:59 +0200 Subject: [PATCH 01/12] Revert "[Android] Port getifaddrs implementation from Xamarin.Android (#71943)" This reverts commit 1de4a5ca073da24211fc4d427b2224da2212f372. --- src/mono/cmake/config.h.in | 3 + src/native/libs/Common/pal_config.h.in | 1 + src/native/libs/System.Native/CMakeLists.txt | 7 - src/native/libs/System.Native/pal_ifaddrs.c | 760 ------------------ src/native/libs/System.Native/pal_ifaddrs.h | 43 - .../System.Native/pal_interfaceaddresses.c | 74 +- src/native/libs/configure.cmake | 12 + 7 files changed, 85 insertions(+), 815 deletions(-) delete mode 100644 src/native/libs/System.Native/pal_ifaddrs.c delete mode 100644 src/native/libs/System.Native/pal_ifaddrs.h diff --git a/src/mono/cmake/config.h.in b/src/mono/cmake/config.h.in index 4ac722c9d928c1..c21ff89a018406 100644 --- a/src/mono/cmake/config.h.in +++ b/src/mono/cmake/config.h.in @@ -517,6 +517,9 @@ /* Have getifaddrs */ #cmakedefine HAVE_GETIFADDRS 1 +/* Have struct ifaddrs */ +#cmakedefine HAVE_IFADDRS 1 + /* Have access */ #cmakedefine HAVE_ACCESS 1 diff --git a/src/native/libs/Common/pal_config.h.in b/src/native/libs/Common/pal_config.h.in index 6243761d8600d0..3f5b8c3627edcd 100644 --- a/src/native/libs/Common/pal_config.h.in +++ b/src/native/libs/Common/pal_config.h.in @@ -11,6 +11,7 @@ #cmakedefine01 HAVE_F_FULLFSYNC #cmakedefine01 HAVE_O_CLOEXEC #cmakedefine01 HAVE_GETIFADDRS +#cmakedefine01 HAVE_IFADDRS #cmakedefine01 HAVE_UTSNAME_DOMAINNAME #cmakedefine01 HAVE_STAT64 #cmakedefine01 HAVE_FORK diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt index b4d97039824319..19466c7572dbd9 100644 --- a/src/native/libs/System.Native/CMakeLists.txt +++ b/src/native/libs/System.Native/CMakeLists.txt @@ -83,13 +83,6 @@ include(${CMAKE_CURRENT_LIST_DIR}/extra_libs.cmake) set(NATIVE_LIBS_EXTRA) append_extra_system_libs(NATIVE_LIBS_EXTRA) -if (CLR_CMAKE_TARGET_ANDROID) - add_compile_options(-Wno-gnu-zero-variadic-macro-arguments) - - list (APPEND NATIVE_LIBS_EXTRA -llog) - list (APPEND NATIVE_SOURCES pal_ifaddrs.c) -endif () - if (GEN_SHARED_LIB) add_library(System.Native SHARED diff --git a/src/native/libs/System.Native/pal_ifaddrs.c b/src/native/libs/System.Native/pal_ifaddrs.c deleted file mode 100644 index 3e885d08114ee7..00000000000000 --- a/src/native/libs/System.Native/pal_ifaddrs.c +++ /dev/null @@ -1,760 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "pal_ifaddrs.h" -#include "pal_safecrt.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include -#define LOG(level, ...) __android_log_print(level, "DOTNET_NETLINK", ## __VA_ARGS__) -#define LOG_INFO(...) LOG(ANDROID_LOG_INFO, ## __VA_ARGS__) -#define LOG_WARN(...) LOG(ANDROID_LOG_WARN, ## __VA_ARGS__) -#ifdef DEBUG -#define LOG_DEBUG(...) LOG(ANDROID_LOG_DEBUG, ## __VA_ARGS__) -#else -#define LOG_DEBUG(...) do {} while (0) -#endif - -/* Maximum interface address label size, should be more than enough */ -#define MAX_IFA_LABEL_SIZE 1024 - -/* This is the message we send to the kernel */ -struct netlink_request { - struct nlmsghdr header; - struct rtgenmsg message; -}; - -struct netlink_session { - int sock_fd; - int seq; - struct sockaddr_nl them; /* kernel end */ - struct sockaddr_nl us; /* our end */ - struct msghdr message_header; /* for use with sendmsg */ - struct iovec payload_vector; /* Used to send netlink_request */ -}; - -struct sockaddr_ll_extended { - unsigned short int sll_family; - unsigned short int sll_protocol; - int sll_ifindex; - unsigned short int sll_hatype; - unsigned char sll_pkttype; - unsigned char sll_halen; - unsigned char sll_addr[24]; -}; - -static void free_single_ifaddrs(struct ifaddrs **ifap) -{ - struct ifaddrs *ifa = ifap ? *ifap : NULL; - if (!ifa) - return; - - if (ifa->ifa_name) - free(ifa->ifa_name); - - if (ifa->ifa_addr) - free(ifa->ifa_addr); - - if (ifa->ifa_netmask) - free(ifa->ifa_netmask); - - if (ifa->ifa_broadaddr) - free(ifa->ifa_broadaddr); - - if (ifa->ifa_data) - free(ifa->ifa_data); - - free(ifa); - *ifap = NULL; -} - -static int open_netlink_session(struct netlink_session *session) -{ - abort_if_invalid_pointer_argument(session); - - memset(session, 0, sizeof(*session)); - session->sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (session->sock_fd == -1) { - LOG_WARN("Failed to create a netlink socket. %s\n", strerror(errno)); - return -1; - } - - /* Fill out addresses */ - session->us.nl_family = AF_NETLINK; - - /* We have previously used `getpid()` here but it turns out that WebView/Chromium does the same - and there can only be one session with the same PID. Setting it to 0 will cause the kernel to - assign some PID that's unique and valid instead. - See: https://bugzilla.xamarin.com/show_bug.cgi?id=41860 - */ - session->us.nl_pid = 0; - session->us.nl_groups = 0; - - session->them.nl_family = AF_NETLINK; - - if (bind (session->sock_fd, (struct sockaddr *)&session->us, sizeof(session->us)) < 0) { - LOG_WARN("Failed to bind to the netlink socket. %s\n", strerror(errno)); - return -1; - } - - return 0; -} - -static int send_netlink_dump_request(struct netlink_session *session, int type) -{ - struct netlink_request request; - - memset(&request, 0, sizeof(request)); - request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - /* Flags (from netlink.h): - NLM_F_REQUEST - it's a request message - NLM_F_DUMP - gives us the root of the link tree and returns all links matching our requested - AF, which in our case means all of them (AF_PACKET) - */ - request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH; - request.header.nlmsg_seq = (uint32_t)++session->seq; - request.header.nlmsg_pid = session->us.nl_pid; - request.header.nlmsg_type = (uint16_t)type; - - /* AF_PACKET means we want to see everything */ - request.message.rtgen_family = AF_PACKET; - - memset(&session->payload_vector, 0, sizeof(session->payload_vector)); - session->payload_vector.iov_len = request.header.nlmsg_len; - session->payload_vector.iov_base = &request; - - memset(&session->message_header, 0, sizeof(session->message_header)); - session->message_header.msg_namelen = sizeof(session->them); - session->message_header.msg_name = &session->them; - session->message_header.msg_iovlen = 1; - session->message_header.msg_iov = &session->payload_vector; - - if (sendmsg(session->sock_fd, (const struct msghdr*)&session->message_header, 0) < 0) { - LOG_WARN("Failed to send netlink message. %s\n", strerror(errno)); - return -1; - } - - return 0; -} - -static int append_ifaddr(struct ifaddrs *addr, struct ifaddrs **ifaddrs_head, struct ifaddrs **last_ifaddr) -{ - abort_if_invalid_pointer_argument(addr); - abort_if_invalid_pointer_argument(ifaddrs_head); - abort_if_invalid_pointer_argument(last_ifaddr); - - if (addr->ifa_name == NULL) { - LOG_WARN("ifa_name is NULL -- skipping"); - return 0; // skip this addr - } - - if (!*ifaddrs_head) { - *ifaddrs_head = *last_ifaddr = addr; - if (!*ifaddrs_head) - return -1; - } else if (!*last_ifaddr) { - struct ifaddrs *last = *ifaddrs_head; - - while (last->ifa_next) - last = last->ifa_next; - *last_ifaddr = last; - } - - addr->ifa_next = NULL; - if (addr == *last_ifaddr) - return 0; - - (*last_ifaddr)->ifa_next = addr; - *last_ifaddr = addr; - - return 0; -} - -static int fill_sa_address(struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_data, size_t rta_payload_length) -{ - abort_if_invalid_pointer_argument(sa); - abort_if_invalid_pointer_argument(net_address); - abort_if_invalid_pointer_argument(rta_data); - - switch (net_address->ifa_family) { - case AF_INET: { - struct sockaddr_in *sa4; - if (rta_payload_length != 4) /* IPv4 address length */ { - LOG_WARN("Unexpected IPv4 address payload length %zu", rta_payload_length); - return -1; - } - sa4 = (struct sockaddr_in*)calloc(1, sizeof(*sa4)); - if (sa4 == NULL) - return -1; - - sa4->sin_family = AF_INET; - memcpy(&sa4->sin_addr, rta_data, rta_payload_length); - *sa = (struct sockaddr*)sa4; - break; - } - - case AF_INET6: { - struct sockaddr_in6 *sa6; - if (rta_payload_length != 16) /* IPv6 address length */ { - LOG_WARN("Unexpected IPv6 address payload length %zu", rta_payload_length); - return -1; - } - sa6 = (struct sockaddr_in6*)calloc(1, sizeof(*sa6)); - if (sa6 == NULL) - return -1; - - sa6->sin6_family = AF_INET6; - memcpy(&sa6->sin6_addr, rta_data, rta_payload_length); - if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL (&sa6->sin6_addr)) - sa6->sin6_scope_id = net_address->ifa_index; - *sa = (struct sockaddr*)sa6; - break; - } - - default: { - struct sockaddr *sagen; - if (rta_payload_length > sizeof(sagen->sa_data)) { - LOG_WARN("Unexpected RTA payload length %zu (wanted at most %zu)", rta_payload_length, sizeof(sagen->sa_data)); - return -1; - } - - *sa = sagen = (struct sockaddr*)calloc(1, sizeof(*sagen)); - if (!sagen) - return -1; - - sagen->sa_family = net_address->ifa_family; - memcpy(&sagen->sa_data, rta_data, rta_payload_length); - break; - } - } - - return 0; -} - -static int fill_ll_address(struct sockaddr_ll_extended **sa, struct ifinfomsg *net_interface, void *rta_data, size_t rta_payload_length) -{ - abort_if_invalid_pointer_argument(sa); - abort_if_invalid_pointer_argument(net_interface); - - /* Always allocate, do not free - caller may reuse the same variable */ - *sa = (struct sockaddr_ll_extended*)calloc(1, sizeof(**sa)); - if (!*sa) - return -1; - - (*sa)->sll_family = AF_PACKET; /* Always for physical links */ - - /* The assert can only fail for Iniband links, which are quite unlikely to be found - * in any mobile devices - */ - LOG_DEBUG("rta_payload_length == %zu; sizeof sll_addr == %zu; hw type == 0x%X\n", rta_payload_length, sizeof((*sa)->sll_addr), net_interface->ifi_type); - if ((size_t)(rta_payload_length) > sizeof((*sa)->sll_addr)) { - LOG_INFO("Address is too long to place in sockaddr_ll (%zu > %zu)", rta_payload_length, sizeof((*sa)->sll_addr)); - free(*sa); - *sa = NULL; - return -1; - } - - if (rta_payload_length > UCHAR_MAX) { - LOG_INFO("Payload length too big to fit in the address structure"); - free(*sa); - *sa = NULL; - return -1; - } - - (*sa)->sll_ifindex = net_interface->ifi_index; - (*sa)->sll_hatype = net_interface->ifi_type; - (*sa)->sll_halen = (unsigned char)(rta_payload_length); - memcpy((*sa)->sll_addr, rta_data, rta_payload_length); - - return 0; -} - - -static struct ifaddrs *get_link_info(struct nlmsghdr *message) -{ - ssize_t length; - struct rtattr *attribute; - struct ifinfomsg *net_interface; - struct ifaddrs *ifa = NULL; - struct sockaddr_ll_extended *sa = NULL; - - abort_if_invalid_pointer_argument(message); - net_interface = (struct ifinfomsg*)(NLMSG_DATA(message)); - length = (ssize_t)(message->nlmsg_len - NLMSG_LENGTH(sizeof(*net_interface))); - if (length <= 0) { - goto error; - } - - ifa = (struct ifaddrs*)calloc(1, sizeof(*ifa)); - if (!ifa) { - goto error; - } - - ifa->ifa_flags = net_interface->ifi_flags; - attribute = IFLA_RTA(net_interface); - while (RTA_OK(attribute, length)) { - switch (attribute->rta_type) { - case IFLA_IFNAME: - ifa->ifa_name = strdup((const char*)(RTA_DATA(attribute))); - if (!ifa->ifa_name) { - goto error; - } - LOG_DEBUG(" interface name (payload length: %zu; string length: %zu)\n", RTA_PAYLOAD(attribute), strlen(ifa->ifa_name)); - LOG_DEBUG(" %s\n", ifa->ifa_name); - break; - - case IFLA_BROADCAST: - LOG_DEBUG(" interface broadcast (%zu bytes)\n", RTA_PAYLOAD(attribute)); - if (fill_ll_address(&sa, net_interface, RTA_DATA(attribute), RTA_PAYLOAD(attribute)) < 0) { - goto error; - } - ifa->ifa_broadaddr = (struct sockaddr*)sa; - break; - - case IFLA_ADDRESS: - LOG_DEBUG(" interface address (%zu bytes)\n", RTA_PAYLOAD(attribute)); - if (fill_ll_address(&sa, net_interface, RTA_DATA(attribute), RTA_PAYLOAD(attribute)) < 0) { - goto error; - } - ifa->ifa_addr = (struct sockaddr*)sa; - break; - - default: - break; - } - - attribute = RTA_NEXT (attribute, length); - } - - LOG_DEBUG("link flags: 0x%X", ifa->ifa_flags); - return ifa; - - error: - if (sa) - free(sa); - free_single_ifaddrs(&ifa); - - return NULL; -} - -static struct ifaddrs *find_interface_by_index(int index, struct ifaddrs **ifaddrs_head) -{ - struct ifaddrs *cur; - if (!ifaddrs_head || !*ifaddrs_head) - return NULL; - - /* Normally expensive, but with the small amount of links in the chain we'll deal with it's not - * worth the extra housekeeping and memory overhead - */ - cur = *ifaddrs_head; - while (cur) { - if (cur->ifa_addr && cur->ifa_addr->sa_family == AF_PACKET && ((struct sockaddr_ll_extended*)cur->ifa_addr)->sll_ifindex == index) - return cur; - if (cur == cur->ifa_next) - break; - cur = cur->ifa_next; - } - - return NULL; -} - -static char *get_interface_name_by_index(int index, struct ifaddrs **ifaddrs_head) -{ - struct ifaddrs *iface = find_interface_by_index(index, ifaddrs_head); - if (!iface || !iface->ifa_name) - return NULL; - - return iface->ifa_name; -} - -static int get_interface_flags_by_index(int index, struct ifaddrs **ifaddrs_head) -{ - struct ifaddrs *iface = find_interface_by_index(index, ifaddrs_head); - if (!iface) - return 0; - - return (int)(iface->ifa_flags); -} - -static int calculate_address_netmask(struct ifaddrs *ifa, struct ifaddrmsg *net_address) -{ - if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_UNSPEC && ifa->ifa_addr->sa_family != AF_PACKET) { - uint32_t prefix_length = 0; - uint32_t data_length = 0; - unsigned char *netmask_data = NULL; - - switch (ifa->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sa = (struct sockaddr_in*)calloc(1, sizeof(struct sockaddr_in)); - if (!sa) - return -1; - - ifa->ifa_netmask = (struct sockaddr*)sa; - prefix_length = net_address->ifa_prefixlen; - if (prefix_length > 32) - prefix_length = 32; - data_length = sizeof(sa->sin_addr); - netmask_data = (unsigned char*)&sa->sin_addr; - break; - } - - case AF_INET6: { - struct sockaddr_in6 *sa = (struct sockaddr_in6*)calloc(1, sizeof(struct sockaddr_in6)); - if (!sa) - return -1; - - ifa->ifa_netmask = (struct sockaddr*)sa; - prefix_length = net_address->ifa_prefixlen; - if (prefix_length > 128) - prefix_length = 128; - data_length = sizeof(sa->sin6_addr); - netmask_data = (unsigned char*)&sa->sin6_addr; - break; - } - } - - if (ifa->ifa_netmask && netmask_data) { - /* Fill the first X bytes with 255 */ - uint32_t prefix_bytes = prefix_length / 8; - uint32_t postfix_bytes; - - if (prefix_bytes > data_length) { - errno = EINVAL; - return -1; - } - postfix_bytes = data_length - prefix_bytes; - memset(netmask_data, 0xFF, prefix_bytes); - if (postfix_bytes > 0) - memset(netmask_data + prefix_bytes + 1, 0x00, postfix_bytes); - LOG_DEBUG(" calculating netmask, prefix length is %u bits (%u bytes), data length is %u bytes\n", prefix_length, prefix_bytes, data_length); - if (prefix_bytes + 2 < data_length) - /* Set the rest of the mask bits in the byte following the last 0xFF value */ - netmask_data[prefix_bytes + 1] = (unsigned char)(0xff << (8 - (prefix_length % 8))); - } - } - - return 0; -} - - -static struct ifaddrs *get_link_address(struct nlmsghdr *message, struct ifaddrs **ifaddrs_head) -{ - ssize_t length = 0; - struct rtattr *attribute; - struct ifaddrmsg *net_address; - struct ifaddrs *ifa = NULL; - struct sockaddr **sa; - size_t payload_size; - - abort_if_invalid_pointer_argument(message); - net_address = (struct ifaddrmsg*)(NLMSG_DATA(message)); - length = (ssize_t)(IFA_PAYLOAD(message)); - LOG_DEBUG(" address data length: %zu", length); - if (length <= 0) { - goto error; - } - - ifa = (struct ifaddrs*)(calloc(1, sizeof(*ifa))); - if (!ifa) { - goto error; - } - - // values < 0 are never returned, the cast is safe - ifa->ifa_flags = (unsigned int)(get_interface_flags_by_index((int)(net_address->ifa_index), ifaddrs_head)); - - attribute = IFA_RTA(net_address); - LOG_DEBUG(" reading attributes"); - while (RTA_OK(attribute, length)) { - payload_size = RTA_PAYLOAD(attribute); - LOG_DEBUG(" attribute payload_size == %zu\n", payload_size); - sa = NULL; - - switch (attribute->rta_type) { - case IFA_LABEL: { - size_t room_for_trailing_null = 0; - - LOG_DEBUG(" attribute type: LABEL"); - if (payload_size > MAX_IFA_LABEL_SIZE) { - payload_size = MAX_IFA_LABEL_SIZE; - room_for_trailing_null = 1; - } - - if (payload_size > 0) { - size_t alloc_size; - if (!multiply_s(payload_size, room_for_trailing_null, &alloc_size)) { - goto error; - } - - ifa->ifa_name = (char*)malloc(alloc_size); - if (!ifa->ifa_name) { - goto error; - } - - memcpy(ifa->ifa_name, RTA_DATA (attribute), payload_size); - if (room_for_trailing_null) - ifa->ifa_name[payload_size] = '\0'; - } - break; - } - - case IFA_LOCAL: - LOG_DEBUG(" attribute type: LOCAL"); - if (ifa->ifa_addr) { - /* P2P protocol, set the dst/broadcast address union from the original address. - * Since ifa_addr is set it means IFA_ADDRESS occurred earlier and that address - * is indeed the P2P destination one. - */ - ifa->ifa_dstaddr = ifa->ifa_addr; - ifa->ifa_addr = 0; - } - sa = &ifa->ifa_addr; - break; - - case IFA_BROADCAST: - LOG_DEBUG(" attribute type: BROADCAST"); - if (ifa->ifa_dstaddr) { - /* IFA_LOCAL happened earlier, undo its effect here */ - free(ifa->ifa_dstaddr); - ifa->ifa_dstaddr = NULL; - } - sa = &ifa->ifa_broadaddr; - break; - - case IFA_ADDRESS: - LOG_DEBUG(" attribute type: ADDRESS"); - if (ifa->ifa_addr) { - /* Apparently IFA_LOCAL occurred earlier and we have a P2P connection - * here. IFA_LOCAL carries the destination address, move it there - */ - ifa->ifa_dstaddr = ifa->ifa_addr; - ifa->ifa_addr = NULL; - } - sa = &ifa->ifa_addr; - break; - - case IFA_UNSPEC: - LOG_DEBUG(" attribute type: UNSPEC"); - break; - - case IFA_ANYCAST: - LOG_DEBUG(" attribute type: ANYCAST"); - break; - - case IFA_CACHEINFO: - LOG_DEBUG(" attribute type: CACHEINFO"); - break; - - case IFA_MULTICAST: - LOG_DEBUG(" attribute type: MULTICAST"); - break; - - default: - LOG_DEBUG(" attribute type: %u", attribute->rta_type); - break; - } - - if (sa) { - if (fill_sa_address(sa, net_address, RTA_DATA(attribute), RTA_PAYLOAD(attribute)) < 0) { - goto error; - } - } - - attribute = RTA_NEXT(attribute, length); - } - - /* glibc stores the associated interface name in the address if IFA_LABEL never occurred */ - if (!ifa->ifa_name) { - char *name = get_interface_name_by_index((int)(net_address->ifa_index), ifaddrs_head); - LOG_DEBUG(" address has no name/label, getting one from interface\n"); - ifa->ifa_name = name ? strdup(name) : NULL; - } - LOG_DEBUG(" address label: %s\n", ifa->ifa_name); - - if (calculate_address_netmask(ifa, net_address) < 0) { - goto error; - } - - return ifa; - - error: - { - /* errno may be modified by free, or any other call inside the free_single_xamarin_ifaddrs - * function. We don't care about errors in there since it is more important to know how we - * failed to obtain the link address and not that we went OOM. Save and restore the value - * after the resources are freed. - */ - int errno_save = errno; - free_single_ifaddrs (&ifa); - errno = errno_save; - return NULL; - } - -} - -static int parse_netlink_reply(struct netlink_session *session, struct ifaddrs **ifaddrs_head, struct ifaddrs **last_ifaddr) -{ - struct msghdr netlink_reply; - struct iovec reply_vector; - struct nlmsghdr *current_message; - struct ifaddrs *addr; - int ret = -1; - unsigned char *response = NULL; - - abort_if_invalid_pointer_argument(session); - abort_if_invalid_pointer_argument(ifaddrs_head); - abort_if_invalid_pointer_argument(last_ifaddr); - - size_t buf_size = (size_t)(getpagesize()); - LOG_DEBUG("receive buffer size == %zu", buf_size); - - size_t alloc_size; - if (!multiply_s(sizeof(*response), buf_size, &alloc_size)) { - goto cleanup; - } - - response = (unsigned char*)malloc(alloc_size); - ssize_t length = 0; - if (!response) { - goto cleanup; - } - - while (1) { - memset(response, 0, buf_size); - memset(&reply_vector, 0, sizeof(reply_vector)); - reply_vector.iov_len = buf_size; - reply_vector.iov_base = response; - - memset(&netlink_reply, 0, sizeof(netlink_reply)); - netlink_reply.msg_namelen = sizeof(&session->them); - netlink_reply.msg_name = &session->them; - netlink_reply.msg_iovlen = 1; - netlink_reply.msg_iov = &reply_vector; - - length = recvmsg(session->sock_fd, &netlink_reply, 0); - LOG_DEBUG(" length == %d\n", (int)length); - - if (length < 0) { - LOG_DEBUG("Failed to receive reply from netlink. %s\n", strerror(errno)); - goto cleanup; - } - -#ifdef DEBUG - LOG_DEBUG("response flags:"); - if (netlink_reply.msg_flags == 0) - LOG_DEBUG(" [NONE]"); - else { - if (netlink_reply.msg_flags & MSG_EOR) - LOG_DEBUG(" MSG_EOR"); - if (netlink_reply.msg_flags & MSG_TRUNC) - LOG_DEBUG(" MSG_TRUNC"); - if (netlink_reply.msg_flags & MSG_CTRUNC) - LOG_DEBUG(" MSG_CTRUNC"); - if (netlink_reply.msg_flags & MSG_OOB) - LOG_DEBUG(" MSG_OOB"); - if (netlink_reply.msg_flags & MSG_ERRQUEUE) - LOG_DEBUG(" MSG_ERRQUEUE"); - } -#endif - - if (length == 0) - break; - - for (current_message = (struct nlmsghdr*)response; current_message && NLMSG_OK(current_message, (size_t)length); current_message = NLMSG_NEXT(current_message, length)) { - LOG_DEBUG("next message... (type: %u)\n", current_message->nlmsg_type); - switch (current_message->nlmsg_type) { - /* See rtnetlink.h */ - case RTM_NEWLINK: - LOG_DEBUG(" dumping link...\n"); - addr = get_link_info(current_message); - if (!addr || append_ifaddr(addr, ifaddrs_head, last_ifaddr) < 0) { - ret = -1; - goto cleanup; - } - LOG_DEBUG(" done\n"); - break; - - case RTM_NEWADDR: - LOG_DEBUG(" got an address\n"); - addr = get_link_address(current_message, ifaddrs_head); - if (!addr || append_ifaddr(addr, ifaddrs_head, last_ifaddr) < 0) { - ret = -1; - goto cleanup; - } - break; - - case NLMSG_DONE: - LOG_DEBUG(" message done\n"); - ret = 0; - goto cleanup; - - default: - LOG_DEBUG(" message type: %u", current_message->nlmsg_type); - break; - } - } - } - - cleanup: - if (response) - free(response); - return ret; -} - -int getifaddrs(struct ifaddrs **ifap) -{ - int ret = -1; - - *ifap = NULL; - struct ifaddrs *ifaddrs_head = 0; - struct ifaddrs *last_ifaddr = 0; - struct netlink_session session; - - if (open_netlink_session(&session) < 0) { - goto cleanup; - } - - /* Request information about the specified link. In our case it will be all of them since we - request the root of the link tree below - */ - if ((send_netlink_dump_request(&session, RTM_GETLINK) < 0) || - (parse_netlink_reply(&session, &ifaddrs_head, &last_ifaddr) < 0) || - (send_netlink_dump_request(&session, RTM_GETADDR) < 0) || - (parse_netlink_reply(&session, &ifaddrs_head, &last_ifaddr) < 0)) { - freeifaddrs (ifaddrs_head); - goto cleanup; - } - - ret = 0; - *ifap = ifaddrs_head; - -cleanup: - if (session.sock_fd >= 0) { - close(session.sock_fd); - session.sock_fd = -1; - } - - return ret; -} - -void freeifaddrs(struct ifaddrs *ifa) -{ - struct ifaddrs *cur, *next; - - if (!ifa) - return; - - cur = ifa; - while (cur) { - next = cur->ifa_next; - free_single_ifaddrs (&cur); - cur = next; - } -} diff --git a/src/native/libs/System.Native/pal_ifaddrs.h b/src/native/libs/System.Native/pal_ifaddrs.h deleted file mode 100644 index e52a392b13d9d4..00000000000000 --- a/src/native/libs/System.Native/pal_ifaddrs.h +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#pragma once - -#ifndef TARGET_ANDROID -#error The pal_ifaddrs.h shim is intended only for Android -#endif - -// Android doesn't include the getifaddrs and freeifaddrs functions in older Bionic libc (pre API 24). -// In recent Android versions (Android 11+) the data returned by the getifaddrs function is not valid. -// This shim is a port of Xamarin Android's implementation of getifaddrs using Netlink. - -#include "pal_compiler.h" -#include "pal_config.h" -#include "pal_types.h" - -#include -#include -#include - -struct ifaddrs -{ - struct ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - struct sockaddr *ifa_addr; - struct sockaddr *ifa_netmask; - union - { - struct sockaddr *ifu_broadaddr; - struct sockaddr *ifu_dstaddr; - } ifa_ifu; - void *ifa_data; -}; - -// Synonym for `ifa_ifu.ifu_broadaddr` in `struct ifaddrs`. -#define ifa_broadaddr ifa_ifu.ifu_broadaddr -// Synonym for `ifa_ifu.ifu_dstaddr` in `struct ifaddrs`. -#define ifa_dstaddr ifa_ifu.ifu_dstaddr - -int getifaddrs (struct ifaddrs **ifap); -void freeifaddrs (struct ifaddrs *ifap); diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index fa05d575ef7ad8..a876e7f1728435 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -11,11 +11,12 @@ #include #include #include -#if HAVE_GETIFADDRS && !defined(TARGET_ANDROID) +#if HAVE_IFADDRS || HAVE_GETIFADDRS #include #endif -#ifdef TARGET_ANDROID -#include "pal_ifaddrs.h" +#if !HAVE_GETIFADDRS && TARGET_ANDROID +#include +#include #endif #include #include @@ -100,12 +101,66 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length) return len; } +#if !HAVE_IFADDRS && TARGET_ANDROID +// This structure is exactly the same as struct ifaddrs defined in ifaddrs.h but since the header +// might not be available (e.g., in bionics used in Android before API 24) we need to mirror it here +// so that we can dynamically load the getifaddrs function and use it. +struct ifaddrs +{ + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + union + { + struct sockaddr *ifu_broadaddr; + struct sockaddr *ifu_dstaddr; + } ifa_ifu; + void *ifa_data; +}; +#endif + +#if !HAVE_GETIFADDRS && TARGET_ANDROID +// Try to load the getifaddrs and freeifaddrs functions manually. +// This workaround is necessary on Android prior to API 24 and it can be removed once +// we drop support for earlier Android versions. +static int (*getifaddrs)(struct ifaddrs**) = NULL; +static void (*freeifaddrs)(struct ifaddrs*) = NULL; + +static void try_loading_getifaddrs() +{ + void *libc = dlopen("libc.so", RTLD_NOW); + if (libc) + { + getifaddrs = (int (*)(struct ifaddrs**)) dlsym(libc, "getifaddrs"); + freeifaddrs = (void (*)(struct ifaddrs*)) dlsym(libc, "freeifaddrs"); + } +} + +static bool ensure_getifaddrs_is_loaded() +{ + static pthread_once_t getifaddrs_is_loaded = PTHREAD_ONCE_INIT; + pthread_once(&getifaddrs_is_loaded, try_loading_getifaddrs); + return getifaddrs != NULL && freeifaddrs != NULL; +} +#endif + int32_t SystemNative_EnumerateInterfaceAddresses(void* context, IPv4AddressFound onIpv4Found, IPv6AddressFound onIpv6Found, LinkLayerAddressFound onLinkLayerFound) { -#if HAVE_GETIFADDRS || defined(TARGET_ANDROID) +#if !HAVE_GETIFADDRS && TARGET_ANDROID + // Workaround for Android API < 24 + if (!ensure_getifaddrs_is_loaded()) + { + errno = ENOTSUP; + return -1; + } +#endif + +#if HAVE_GETIFADDRS || TARGET_ANDROID struct ifaddrs* headAddr; if (getifaddrs(&headAddr) == -1) { @@ -250,7 +305,16 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context, int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInterfaceInfo **interfaceList, int32_t * addressCount, IpAddressInfo **addressList ) { -#if HAVE_GETIFADDRS || defined(TARGET_ANDROID) +#if !HAVE_GETIFADDRS && TARGET_ANDROID + // Workaround for Android API < 24 + if (!ensure_getifaddrs_is_loaded()) + { + errno = ENOTSUP; + return -1; + } +#endif + +#if HAVE_GETIFADDRS || TARGET_ANDROID struct ifaddrs* head; // Pointer to block allocated by getifaddrs(). struct ifaddrs* ifaddrsEntry; IpAddressInfo *ai; diff --git a/src/native/libs/configure.cmake b/src/native/libs/configure.cmake index bc6c133fe89212..eb3af8c73aafd1 100644 --- a/src/native/libs/configure.cmake +++ b/src/native/libs/configure.cmake @@ -121,6 +121,18 @@ check_c_source_compiles( " HAVE_FLOCK64) +check_c_source_compiles( + " + #include + #include + int main(void) + { + struct ifaddrs ia; + return 0; + } + " + HAVE_IFADDRS) + check_symbol_exists( O_CLOEXEC fcntl.h From e6c7971b9baf793ccf801a6d56da563d5d470888 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 27 Sep 2022 17:53:44 +0200 Subject: [PATCH 02/12] Fix allocating memory block for interfaces and addresses on recent Android SDKs --- src/native/libs/System.Native/pal_interfaceaddresses.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index a876e7f1728435..dd9392b918dfad 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -353,7 +353,13 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter // To save allocation need for separate free() we will allocate one memory chunk // where we first write out NetworkInterfaceInfo entries immediately followed by // IpAddressInfo list. - void * memoryBlock = calloc((size_t)count, sizeof(NetworkInterfaceInfo)); +#if TARGET_ANDROID + int interfacesCount = count; +#else + int interfacesCount = count - ip4count - ip6count; +#endif + size_t interfacesAndAddressesCount = (size_t)(interfacesCount + ip4count + ip6count); + void * memoryBlock = calloc(interfacesAndAddressesCount, sizeof(NetworkInterfaceInfo)); if (memoryBlock == NULL) { errno = ENOMEM; @@ -364,7 +370,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter ifaddrsEntry = head; *interfaceList = nii = (NetworkInterfaceInfo*)memoryBlock; // address of first IpAddressInfo after all NetworkInterfaceInfo entries. - *addressList = ai = (IpAddressInfo*)(nii + (count - ip4count - ip6count)); + *addressList = ai = (IpAddressInfo*)(nii + interfacesCount); while (ifaddrsEntry != NULL) { From f7c87fc3ad261d001cfc1d65416d0027820dc26a Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 29 Sep 2022 11:48:05 +0200 Subject: [PATCH 03/12] Detect loopback interface on Android --- src/native/libs/System.Native/pal_interfaceaddresses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index dd9392b918dfad..9c82712feba882 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -394,7 +394,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter memcpy(nii->Name, ifaddrsEntry->ifa_name, sizeof(nii->Name)); nii->InterfaceIndex = if_nametoindex(ifaddrsEntry->ifa_name); nii->Speed = -1; - nii->HardwareType = NetworkInterfaceType_Unknown; + nii->HardwareType = ((ifaddrsEntry->ifa_flags & IFF_LOOPBACK) == IFF_LOOPBACK) ? NetworkInterfaceType_Loopback : NetworkInterfaceType_Unknown; // Get operational state and multicast support. if ((ifaddrsEntry->ifa_flags & (IFF_MULTICAST|IFF_ALLMULTI)) != 0) From 5d63e0380d5402001f98320975fbf5b185b90852 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 29 Sep 2022 12:04:31 +0200 Subject: [PATCH 04/12] Add comment with explanation --- .../libs/System.Native/pal_interfaceaddresses.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index 9c82712feba882..a76f0e8c063747 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -354,12 +354,16 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter // where we first write out NetworkInterfaceInfo entries immediately followed by // IpAddressInfo list. #if TARGET_ANDROID - int interfacesCount = count; + // Since Android API 30, getifaddrs returns only AP_INET and AF_INET6 addresses and + // we do not get any AP_PACKET addresses and so count == ip4count + ip6count. + // We need to make sure that the memoryBlock is large enough to hold all interfaces + // and all addresses without any overlap between interfaceList and addressList. + int interfaceCountUpperLimit = count; #else - int interfacesCount = count - ip4count - ip6count; + int interfaceCountUpperLimit = count - ip4count - ip6count; #endif - size_t interfacesAndAddressesCount = (size_t)(interfacesCount + ip4count + ip6count); - void * memoryBlock = calloc(interfacesAndAddressesCount, sizeof(NetworkInterfaceInfo)); + size_t entriesCount = (size_t)(interfaceCountUpperLimit + ip4count + ip6count); + void * memoryBlock = calloc(entriesCount, sizeof(NetworkInterfaceInfo)); if (memoryBlock == NULL) { errno = ENOMEM; @@ -370,7 +374,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter ifaddrsEntry = head; *interfaceList = nii = (NetworkInterfaceInfo*)memoryBlock; // address of first IpAddressInfo after all NetworkInterfaceInfo entries. - *addressList = ai = (IpAddressInfo*)(nii + interfacesCount); + *addressList = ai = (IpAddressInfo*)(nii + interfaceCountUpperLimit); while (ifaddrsEntry != NULL) { From b89a6158741f8218e01d32470b1610a834e08638 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 29 Sep 2022 12:27:35 +0200 Subject: [PATCH 05/12] Simplify the changes to be closer to the original code --- src/native/libs/System.Native/pal_interfaceaddresses.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index a76f0e8c063747..e8b52d8710df91 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -358,12 +358,11 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter // we do not get any AP_PACKET addresses and so count == ip4count + ip6count. // We need to make sure that the memoryBlock is large enough to hold all interfaces // and all addresses without any overlap between interfaceList and addressList. - int interfaceCountUpperLimit = count; + int entriesCount = count + ip4count + ip6count; #else - int interfaceCountUpperLimit = count - ip4count - ip6count; + int entriesCount = count; #endif - size_t entriesCount = (size_t)(interfaceCountUpperLimit + ip4count + ip6count); - void * memoryBlock = calloc(entriesCount, sizeof(NetworkInterfaceInfo)); + void * memoryBlock = calloc((size_t)entriesCount, sizeof(NetworkInterfaceInfo)); if (memoryBlock == NULL) { errno = ENOMEM; @@ -374,7 +373,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter ifaddrsEntry = head; *interfaceList = nii = (NetworkInterfaceInfo*)memoryBlock; // address of first IpAddressInfo after all NetworkInterfaceInfo entries. - *addressList = ai = (IpAddressInfo*)(nii + interfaceCountUpperLimit); + *addressList = ai = (IpAddressInfo*)(nii + (entriesCount - ip4count - ip6count)); while (ifaddrsEntry != NULL) { From cf263aeedbdb412c453a5c003daac09d1a0985a0 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 29 Sep 2022 14:05:56 +0200 Subject: [PATCH 06/12] Fix build --- src/native/libs/System.Native/pal_interfaceaddresses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index e8b52d8710df91..6d4cb7d0057d3b 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -353,7 +353,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter // To save allocation need for separate free() we will allocate one memory chunk // where we first write out NetworkInterfaceInfo entries immediately followed by // IpAddressInfo list. -#if TARGET_ANDROID +#ifdef TARGET_ANDROID // Since Android API 30, getifaddrs returns only AP_INET and AF_INET6 addresses and // we do not get any AP_PACKET addresses and so count == ip4count + ip6count. // We need to make sure that the memoryBlock is large enough to hold all interfaces From 7e192d4dc062676d13dd6d51c8b77376e09c1bc0 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 29 Sep 2022 14:56:10 +0200 Subject: [PATCH 07/12] Fix typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Köplinger --- src/native/libs/System.Native/pal_interfaceaddresses.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index 6d4cb7d0057d3b..ae38e2dc375579 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -103,7 +103,7 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length) #if !HAVE_IFADDRS && TARGET_ANDROID // This structure is exactly the same as struct ifaddrs defined in ifaddrs.h but since the header -// might not be available (e.g., in bionics used in Android before API 24) we need to mirror it here +// might not be available (e.g., in bionic used in Android before API 24) we need to mirror it here // so that we can dynamically load the getifaddrs function and use it. struct ifaddrs { @@ -354,8 +354,8 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter // where we first write out NetworkInterfaceInfo entries immediately followed by // IpAddressInfo list. #ifdef TARGET_ANDROID - // Since Android API 30, getifaddrs returns only AP_INET and AF_INET6 addresses and - // we do not get any AP_PACKET addresses and so count == ip4count + ip6count. + // Since Android API 30, getifaddrs returns only AF_INET and AF_INET6 addresses and + // we do not get any AF_PACKET addresses and so count == ip4count + ip6count. // We need to make sure that the memoryBlock is large enough to hold all interfaces // and all addresses without any overlap between interfaceList and addressList. int entriesCount = count + ip4count + ip6count; From 4751ee0b3eed23fe8027900fdceed6cd33ca053a Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 29 Sep 2022 15:31:53 +0200 Subject: [PATCH 08/12] Improve comment --- src/native/libs/System.Native/pal_interfaceaddresses.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index ae38e2dc375579..864837b1e78bd6 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -357,7 +357,8 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter // Since Android API 30, getifaddrs returns only AF_INET and AF_INET6 addresses and // we do not get any AF_PACKET addresses and so count == ip4count + ip6count. // We need to make sure that the memoryBlock is large enough to hold all interfaces - // and all addresses without any overlap between interfaceList and addressList. + // and (up to `count` entries) all addresses (ip4count + ip6count) without any overlap + // between interfaceList and addressList. int entriesCount = count + ip4count + ip6count; #else int entriesCount = count; From 9224b932a106f36bda641a4b5ad5e6a65adeab76 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 29 Sep 2022 15:58:09 +0200 Subject: [PATCH 09/12] Indent using spaces instead of tabs --- .../System.Native/pal_interfaceaddresses.c | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index 864837b1e78bd6..30992929e9d83b 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -106,18 +106,18 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length) // might not be available (e.g., in bionic used in Android before API 24) we need to mirror it here // so that we can dynamically load the getifaddrs function and use it. struct ifaddrs -{ - struct ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - struct sockaddr *ifa_addr; - struct sockaddr *ifa_netmask; - union - { - struct sockaddr *ifu_broadaddr; - struct sockaddr *ifu_dstaddr; - } ifa_ifu; - void *ifa_data; + { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + union + { + struct sockaddr *ifu_broadaddr; + struct sockaddr *ifu_dstaddr; + } ifa_ifu; + void *ifa_data; }; #endif From 510dd98a92c3f513f266fd5475af526049a39a9a Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 30 Sep 2022 10:59:05 +0200 Subject: [PATCH 10/12] Remove check for ifaddrs.h --- src/mono/cmake/config.h.in | 3 --- src/native/libs/Common/pal_config.h.in | 1 - .../System.Native/pal_interfaceaddresses.c | 24 ------------------- src/native/libs/configure.cmake | 12 ---------- 4 files changed, 40 deletions(-) diff --git a/src/mono/cmake/config.h.in b/src/mono/cmake/config.h.in index c21ff89a018406..4ac722c9d928c1 100644 --- a/src/mono/cmake/config.h.in +++ b/src/mono/cmake/config.h.in @@ -517,9 +517,6 @@ /* Have getifaddrs */ #cmakedefine HAVE_GETIFADDRS 1 -/* Have struct ifaddrs */ -#cmakedefine HAVE_IFADDRS 1 - /* Have access */ #cmakedefine HAVE_ACCESS 1 diff --git a/src/native/libs/Common/pal_config.h.in b/src/native/libs/Common/pal_config.h.in index 3f5b8c3627edcd..6243761d8600d0 100644 --- a/src/native/libs/Common/pal_config.h.in +++ b/src/native/libs/Common/pal_config.h.in @@ -11,7 +11,6 @@ #cmakedefine01 HAVE_F_FULLFSYNC #cmakedefine01 HAVE_O_CLOEXEC #cmakedefine01 HAVE_GETIFADDRS -#cmakedefine01 HAVE_IFADDRS #cmakedefine01 HAVE_UTSNAME_DOMAINNAME #cmakedefine01 HAVE_STAT64 #cmakedefine01 HAVE_FORK diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index 30992929e9d83b..4ee055827bfea5 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -11,9 +11,7 @@ #include #include #include -#if HAVE_IFADDRS || HAVE_GETIFADDRS #include -#endif #if !HAVE_GETIFADDRS && TARGET_ANDROID #include #include @@ -101,26 +99,6 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length) return len; } -#if !HAVE_IFADDRS && TARGET_ANDROID -// This structure is exactly the same as struct ifaddrs defined in ifaddrs.h but since the header -// might not be available (e.g., in bionic used in Android before API 24) we need to mirror it here -// so that we can dynamically load the getifaddrs function and use it. -struct ifaddrs - { - struct ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - struct sockaddr *ifa_addr; - struct sockaddr *ifa_netmask; - union - { - struct sockaddr *ifu_broadaddr; - struct sockaddr *ifu_dstaddr; - } ifa_ifu; - void *ifa_data; -}; -#endif - #if !HAVE_GETIFADDRS && TARGET_ANDROID // Try to load the getifaddrs and freeifaddrs functions manually. // This workaround is necessary on Android prior to API 24 and it can be removed once @@ -152,7 +130,6 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context, LinkLayerAddressFound onLinkLayerFound) { #if !HAVE_GETIFADDRS && TARGET_ANDROID - // Workaround for Android API < 24 if (!ensure_getifaddrs_is_loaded()) { errno = ENOTSUP; @@ -306,7 +283,6 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context, int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInterfaceInfo **interfaceList, int32_t * addressCount, IpAddressInfo **addressList ) { #if !HAVE_GETIFADDRS && TARGET_ANDROID - // Workaround for Android API < 24 if (!ensure_getifaddrs_is_loaded()) { errno = ENOTSUP; diff --git a/src/native/libs/configure.cmake b/src/native/libs/configure.cmake index eb3af8c73aafd1..bc6c133fe89212 100644 --- a/src/native/libs/configure.cmake +++ b/src/native/libs/configure.cmake @@ -121,18 +121,6 @@ check_c_source_compiles( " HAVE_FLOCK64) -check_c_source_compiles( - " - #include - #include - int main(void) - { - struct ifaddrs ia; - return 0; - } - " - HAVE_IFADDRS) - check_symbol_exists( O_CLOEXEC fcntl.h From 580b2e80573ea6674374cc6837ef442e20d61ae7 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 30 Sep 2022 12:39:48 +0200 Subject: [PATCH 11/12] Add ANDROID_GETIFADDRS_WORKAROUND --- src/native/libs/System.Native/CMakeLists.txt | 4 ++++ .../libs/System.Native/pal_interfaceaddresses.c | 14 ++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt index 19466c7572dbd9..ebc1539d57a9e6 100644 --- a/src/native/libs/System.Native/CMakeLists.txt +++ b/src/native/libs/System.Native/CMakeLists.txt @@ -83,6 +83,10 @@ include(${CMAKE_CURRENT_LIST_DIR}/extra_libs.cmake) set(NATIVE_LIBS_EXTRA) append_extra_system_libs(NATIVE_LIBS_EXTRA) +if (CLR_CMAKE_TARGET_ANDROID AND NOT HAVE_GETIFADDRS) + add_definitions(-DANDROID_GETIFADDRS_WORKAROUND) +endif () + if (GEN_SHARED_LIB) add_library(System.Native SHARED diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index 4ee055827bfea5..fefd9335a5343f 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -11,8 +11,10 @@ #include #include #include +#if HAVE_GETIFADDRS || defined(ANDROID_GETIFADDRS_WORKAROUND) #include -#if !HAVE_GETIFADDRS && TARGET_ANDROID +#endif +#ifdef ANDROID_GETIFADDRS_WORKAROUND #include #include #endif @@ -99,7 +101,7 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length) return len; } -#if !HAVE_GETIFADDRS && TARGET_ANDROID +#ifdef ANDROID_GETIFADDRS_WORKAROUND // Try to load the getifaddrs and freeifaddrs functions manually. // This workaround is necessary on Android prior to API 24 and it can be removed once // we drop support for earlier Android versions. @@ -129,7 +131,7 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context, IPv6AddressFound onIpv6Found, LinkLayerAddressFound onLinkLayerFound) { -#if !HAVE_GETIFADDRS && TARGET_ANDROID +#ifdef ANDROID_GETIFADDRS_WORKAROUND if (!ensure_getifaddrs_is_loaded()) { errno = ENOTSUP; @@ -137,7 +139,7 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context, } #endif -#if HAVE_GETIFADDRS || TARGET_ANDROID +#if HAVE_GETIFADDRS || defined(ANDROID_GETIFADDRS_WORKAROUND) struct ifaddrs* headAddr; if (getifaddrs(&headAddr) == -1) { @@ -282,7 +284,7 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context, int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInterfaceInfo **interfaceList, int32_t * addressCount, IpAddressInfo **addressList ) { -#if !HAVE_GETIFADDRS && TARGET_ANDROID +#ifdef ANDROID_GETIFADDRS_WORKAROUND if (!ensure_getifaddrs_is_loaded()) { errno = ENOTSUP; @@ -290,7 +292,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter } #endif -#if HAVE_GETIFADDRS || TARGET_ANDROID +#if HAVE_GETIFADDRS || defined(ANDROID_GETIFADDRS_WORKAROUND) struct ifaddrs* head; // Pointer to block allocated by getifaddrs(). struct ifaddrs* ifaddrsEntry; IpAddressInfo *ai; From b49f6f57847700f24383d0100a00ad09f422677e Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 30 Sep 2022 12:43:06 +0200 Subject: [PATCH 12/12] Update comment --- src/native/libs/System.Native/pal_interfaceaddresses.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index fefd9335a5343f..876b894fee45b5 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -332,11 +332,10 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter // where we first write out NetworkInterfaceInfo entries immediately followed by // IpAddressInfo list. #ifdef TARGET_ANDROID - // Since Android API 30, getifaddrs returns only AF_INET and AF_INET6 addresses and - // we do not get any AF_PACKET addresses and so count == ip4count + ip6count. - // We need to make sure that the memoryBlock is large enough to hold all interfaces - // and (up to `count` entries) all addresses (ip4count + ip6count) without any overlap - // between interfaceList and addressList. + // Since Android API 30, getifaddrs returns only AF_INET and AF_INET6 addresses and we do not + // get any AF_PACKET addresses and so count == ip4count + ip6count. We need to make sure that + // the memoryBlock is large enough to hold all interfaces (up to `count` entries) and all + // addresses (ip4count + ip6count) without any overlap between interfaceList and addressList. int entriesCount = count + ip4count + ip6count; #else int entriesCount = count;