2 * mono-route.c: Read the network routing tables using sysctl(3) calls
3 * Required for Unix-like systems that don't have Linux's /proc/net/route
6 * Ben Woods (woodsb02@gmail.com)
9 #if defined(PLATFORM_MACOSX) || defined(PLATFORM_BSD)
11 #include <sys/socket.h>
13 #include <net/if_dl.h>
14 #include <netinet/in.h>
15 #include <sys/param.h>
16 #include <sys/sysctl.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/mono-route.h>
22 extern MonoBoolean
ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo_internal(MonoString
*iface
, MonoArray
**gw_addr_list
)
28 int num_gws
=0, gwnum
=0;
29 unsigned int ifindex
= 0;
30 char *buf
, *next
, *lim
, *ifacename
;
31 struct rt_msghdr
*rtm
;
33 MonoDomain
*domain
= mono_domain_get ();
35 ifacename
= mono_string_to_utf8_checked(iface
, &error
);
36 if (mono_error_set_pending_exception (&error
))
39 if ((ifindex
= if_nametoindex(ifacename
)) == 0)
43 // MIB array defining data to read from sysctl
44 mib
[0] = CTL_NET
; // Networking
45 mib
[1] = PF_ROUTE
; // Routing messages
46 mib
[2] = 0; // Protocol number (always zero)
47 mib
[3] = AF_INET
; // Address family (IPv4)
48 mib
[4] = NET_RT_DUMP
; // Dump routing table
51 // First sysctl call with oldp set to NULL to determine size of available data
52 if (sysctl(mib
, G_N_ELEMENTS(mib
), NULL
, &needed
, NULL
, 0) < 0)
55 // Allocate suffcient memory for available data based on the previous sysctl call
56 if ((buf
= g_malloc (needed
)) == NULL
)
59 // Second sysctl call to retrieve data into appropriately sized buffer
60 if (sysctl(mib
, G_N_ELEMENTS(mib
), buf
, &needed
, NULL
, 0) < 0)
64 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
65 rtm
= (struct rt_msghdr
*)next
;
66 if (rtm
->rtm_version
!= RTM_VERSION
)
68 if (rtm
->rtm_index
!= ifindex
)
70 if((in
= gateway_from_rtm(rtm
)) == 0)
75 *gw_addr_list
= mono_array_new(domain
, mono_get_string_class (), num_gws
);
77 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
78 rtm
= (struct rt_msghdr
*)next
;
79 if (rtm
->rtm_version
!= RTM_VERSION
)
81 if (rtm
->rtm_index
!= ifindex
)
83 if ((in
= gateway_from_rtm(rtm
)) == 0)
86 MonoString
*addr_string
;
91 len
= snprintf(addr
, sizeof(addr
), "%u.%u.%u.%u",
92 (unsigned char) ptr
[0],
93 (unsigned char) ptr
[1],
94 (unsigned char) ptr
[2],
95 (unsigned char) ptr
[3]);
97 if ((len
>= sizeof(addr
)) || (len
< 0))
98 // snprintf output truncated
101 addr_string
= mono_string_new (domain
, addr
);
102 mono_array_setref (*gw_addr_list
, gwnum
, addr_string
);
109 in_addr_t
gateway_from_rtm(struct rt_msghdr
*rtm
)
114 struct sockaddr
*addr
= (struct sockaddr
*)(rtm
+ 1);
115 l
= roundup(addr
->sa_len
, sizeof(long)); \
116 gw
= (struct sockaddr
*)((char *) addr
+ l
); \
118 if (rtm
->rtm_addrs
& RTA_GATEWAY
) {
119 if(gw
->sa_family
== AF_INET
) {
120 struct sockaddr_in
*sockin
= (struct sockaddr_in
*)gw
;
121 return(sockin
->sin_addr
.s_addr
);
128 #endif /* #if defined(PLATFORM_MACOSX) || defined(PLATFORM_BSD) */