/* * mono-route.c: Read the network routing tables using sysctl(3) calls * Required for Unix-like systems that don't have Linux's /proc/net/route * * Author: * Ben Woods (woodsb02@gmail.com) */ #if defined(PLATFORM_MACOSX) || defined(PLATFORM_BSD) #include #include #include #include #include #include #include #include #include #include extern MonoBoolean ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo_internal(MonoString *iface, MonoArray **gw_addr_list) { MonoError error; size_t needed; in_addr_t in; int mib[6]; int num_gws=0, gwnum=0; unsigned int ifindex = 0; char *buf, *next, *lim, *ifacename; struct rt_msghdr *rtm; MonoDomain *domain = mono_domain_get (); ifacename = mono_string_to_utf8_checked(iface, &error); if (mono_error_set_pending_exception (&error)) return FALSE; if ((ifindex = if_nametoindex(ifacename)) == 0) return FALSE; g_free(ifacename); // MIB array defining data to read from sysctl mib[0] = CTL_NET; // Networking mib[1] = PF_ROUTE; // Routing messages mib[2] = 0; // Protocol number (always zero) mib[3] = AF_INET; // Address family (IPv4) mib[4] = NET_RT_DUMP; // Dump routing table mib[5] = 0; // // First sysctl call with oldp set to NULL to determine size of available data if (sysctl(mib, G_N_ELEMENTS(mib), NULL, &needed, NULL, 0) < 0) return FALSE; // Allocate suffcient memory for available data based on the previous sysctl call if ((buf = malloc(needed)) == NULL) return FALSE; // Second sysctl call to retrieve data into appropriately sized buffer if (sysctl(mib, G_N_ELEMENTS(mib), buf, &needed, NULL, 0) < 0) return FALSE; lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; if (rtm->rtm_index != ifindex) continue; if((in = gateway_from_rtm(rtm)) == 0) continue; num_gws++; } *gw_addr_list = mono_array_new(domain, mono_get_string_class (), num_gws); for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; if (rtm->rtm_index != ifindex) continue; if ((in = gateway_from_rtm(rtm)) == 0) continue; MonoString *addr_string; char addr [16], *ptr; int len; ptr = (char *) ∈ len = snprintf(addr, sizeof(addr), "%u.%u.%u.%u", (unsigned char) ptr [0], (unsigned char) ptr [1], (unsigned char) ptr [2], (unsigned char) ptr [3]); if ((len >= sizeof(addr)) || (len < 0)) // snprintf output truncated continue; addr_string = mono_string_new (domain, addr); mono_array_setref (*gw_addr_list, gwnum, addr_string); gwnum++; } free(buf); return TRUE; } in_addr_t gateway_from_rtm(struct rt_msghdr *rtm) { struct sockaddr *gw; unsigned int l; struct sockaddr *addr = (struct sockaddr *)(rtm + 1); l = roundup(addr->sa_len, sizeof(long)); \ gw = (struct sockaddr *)((char *) addr + l); \ if (rtm->rtm_addrs & RTA_GATEWAY) { if(gw->sa_family == AF_INET) { struct sockaddr_in *sockin = (struct sockaddr_in *)gw; return(sockin->sin_addr.s_addr); } } return 0; } #endif /* #if defined(PLATFORM_MACOSX) || defined(PLATFORM_BSD) */