3 * Read the network routing tables using sysctl(3) calls
4 * Required for Unix-like systems that don't have Linux's /proc/net/route
7 * Ben Woods (woodsb02@gmail.com)
12 #include <mono/metadata/object.h>
13 #include <mono/metadata/mono-route.h>
15 #if defined(HOST_DARWIN) || defined(HOST_BSD)
16 #include <sys/socket.h>
18 #include <net/if_dl.h>
19 #include <netinet/in.h>
20 #include <sys/param.h>
21 #include <sys/sysctl.h>
25 extern MonoBoolean
ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo_internal(MonoString
*iface
, MonoArray
**gw_addr_list
)
31 int num_gws
=0, gwnum
=0;
32 unsigned int ifindex
= 0;
33 char *buf
, *next
, *lim
, *ifacename
;
34 struct rt_msghdr
*rtm
;
36 MonoDomain
*domain
= mono_domain_get ();
38 ifacename
= mono_string_to_utf8_checked_internal (iface
, error
);
39 if (mono_error_set_pending_exception (error
))
42 if ((ifindex
= if_nametoindex(ifacename
)) == 0)
46 // MIB array defining data to read from sysctl
47 mib
[0] = CTL_NET
; // Networking
48 mib
[1] = PF_ROUTE
; // Routing messages
49 mib
[2] = 0; // Protocol number (always zero)
50 mib
[3] = AF_INET
; // Address family (IPv4)
51 mib
[4] = NET_RT_DUMP
; // Dump routing table
54 // First sysctl call with oldp set to NULL to determine size of available data
55 if (sysctl(mib
, G_N_ELEMENTS(mib
), NULL
, &needed
, NULL
, 0) < 0)
58 // Allocate suffcient memory for available data based on the previous sysctl call
59 if ((buf
= g_malloc (needed
)) == NULL
)
62 // Second sysctl call to retrieve data into appropriately sized buffer
63 if (sysctl(mib
, G_N_ELEMENTS(mib
), buf
, &needed
, NULL
, 0) < 0) {
69 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
70 rtm
= (struct rt_msghdr
*)next
;
71 if (rtm
->rtm_version
!= RTM_VERSION
)
73 if (rtm
->rtm_index
!= ifindex
)
75 if((in
= gateway_from_rtm(rtm
)) == 0)
80 *gw_addr_list
= mono_array_new_checked (domain
, mono_get_string_class (), num_gws
, error
);
81 goto_if_nok (error
, leave
);
83 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
84 rtm
= (struct rt_msghdr
*)next
;
85 if (rtm
->rtm_version
!= RTM_VERSION
)
87 if (rtm
->rtm_index
!= ifindex
)
89 if ((in
= gateway_from_rtm(rtm
)) == 0)
92 MonoString
*addr_string
;
97 len
= snprintf(addr
, sizeof(addr
), "%u.%u.%u.%u",
98 (unsigned char) ptr
[0],
99 (unsigned char) ptr
[1],
100 (unsigned char) ptr
[2],
101 (unsigned char) ptr
[3]);
103 if ((len
>= sizeof(addr
)) || (len
< 0))
104 // snprintf output truncated
107 addr_string
= mono_string_new_checked (domain
, addr
, error
);
108 goto_if_nok (error
, leave
);
109 mono_array_setref_internal (*gw_addr_list
, gwnum
, addr_string
);
114 return is_ok (error
);
117 in_addr_t
gateway_from_rtm(struct rt_msghdr
*rtm
)
122 struct sockaddr
*addr
= (struct sockaddr
*)(rtm
+ 1);
123 l
= roundup(addr
->sa_len
, sizeof(long)); \
124 gw
= (struct sockaddr
*)((char *) addr
+ l
); \
126 if (rtm
->rtm_addrs
& RTA_GATEWAY
) {
127 if(gw
->sa_family
== AF_INET
) {
128 struct sockaddr_in
*sockin
= (struct sockaddr_in
*)gw
;
129 return(sockin
->sin_addr
.s_addr
);
139 ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo_internal(MonoString
*iface
, MonoArray
**gw_addr_list
)
141 g_assert_not_reached ();
145 #endif /* #if defined(HOST_DARWIN) || defined(HOST_BSD) */