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 #if HOST_DARWIN || HOST_BSD
14 #include <sys/types.h>
15 #include <sys/socket.h>
17 #include <net/if_dl.h>
18 #include <netinet/in.h>
19 #include <sys/param.h>
20 #include <sys/sysctl.h>
24 #if HOST_IOS || HOST_WATCHOS || HOST_TVOS
25 // The iOS SDK does not provide the net/route.h header but using the Darwin version works fine.
26 #include "../../support/ios/net/route.h"
28 #include <net/route.h>
32 gateway_from_rtm (struct rt_msghdr
*rtm
);
35 #include "icall-decl.h"
38 ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo (MonoStringHandle iface_handle
, MonoArrayHandleOut gw_addr_list_handle
, MonoError
*error
)
40 MonoString
*iface
= MONO_HANDLE_RAW (iface_handle
);
41 MONO_HANDLE_ASSIGN_RAW (gw_addr_list_handle
, NULL
);
46 int num_gws
= 0, gwnum
= 0;
47 unsigned int ifindex
= 0;
50 char *ifacename
= NULL
;
51 struct rt_msghdr
*rtm
;
52 MonoArray
*gw_addr_list
= NULL
;
53 MonoStringHandle addr_string_handle
= NULL_HANDLE_INIT
; // FIXME probably overkill
54 MonoDomain
*domain
= mono_domain_get ();
55 MonoBoolean result
= FALSE
;
57 ifacename
= mono_string_to_utf8_checked_internal (iface
, error
);
58 goto_if_nok (error
, fail
);
60 if ((ifindex
= if_nametoindex (ifacename
)) == 0)
63 // MIB array defining data to read from sysctl
64 mib
[0] = CTL_NET
; // Networking
65 mib
[1] = PF_ROUTE
; // Routing messages
66 mib
[2] = 0; // Protocol number (always zero)
67 mib
[3] = AF_INET
; // Address family (IPv4)
68 mib
[4] = NET_RT_DUMP
; // Dump routing table
71 // First sysctl call with oldp set to NULL to determine size of available data
72 if (sysctl(mib
, G_N_ELEMENTS(mib
), NULL
, &needed
, NULL
, 0) < 0)
75 // Allocate suffcient memory for available data based on the previous sysctl call
76 if ((buf
= g_malloc (needed
)) == NULL
)
79 // Second sysctl call to retrieve data into appropriately sized buffer
80 if (sysctl (mib
, G_N_ELEMENTS (mib
), buf
, &needed
, NULL
, 0) < 0)
84 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
85 rtm
= (struct rt_msghdr
*)next
;
86 if (rtm
->rtm_version
!= RTM_VERSION
87 || rtm
->rtm_index
!= ifindex
88 || (in
= gateway_from_rtm (rtm
)) == 0)
93 gw_addr_list
= mono_array_new_checked (domain
, mono_get_string_class (), num_gws
, error
);
94 goto_if_nok (error
, leave
);
96 MONO_HANDLE_ASSIGN_RAW (gw_addr_list_handle
, gw_addr_list
);
98 addr_string_handle
= MONO_HANDLE_NEW (MonoString
, NULL
); // FIXME probably overkill
100 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
101 rtm
= (struct rt_msghdr
*)next
;
102 if (rtm
->rtm_version
!= RTM_VERSION
103 || rtm
->rtm_index
!= ifindex
104 || (in
= gateway_from_rtm (rtm
)) == 0)
107 MonoString
*addr_string
;
108 char addr
[16], *ptr
;
112 len
= snprintf(addr
, sizeof (addr
), "%u.%u.%u.%u",
113 (unsigned char) ptr
[0],
114 (unsigned char) ptr
[1],
115 (unsigned char) ptr
[2],
116 (unsigned char) ptr
[3]);
118 if (len
>= sizeof (addr
) || len
< 0)
119 // snprintf output truncated
122 addr_string
= mono_string_new_checked (domain
, addr
, error
);
123 goto_if_nok (error
, leave
);
124 MONO_HANDLE_ASSIGN_RAW (addr_string_handle
, addr_string
); // FIXME probably overkill
125 mono_array_setref_internal (gw_addr_list
, gwnum
, addr_string
);
129 result
= is_ok (error
);
137 gateway_from_rtm(struct rt_msghdr
*rtm
)
142 struct sockaddr
*addr
= (struct sockaddr
*)(rtm
+ 1);
143 l
= roundup(addr
->sa_len
, sizeof(long)); \
144 gw
= (struct sockaddr
*)((char *) addr
+ l
); \
146 if (rtm
->rtm_addrs
& RTA_GATEWAY
) {
147 if(gw
->sa_family
== AF_INET
) {
148 struct sockaddr_in
*sockin
= (struct sockaddr_in
*)gw
;
149 return(sockin
->sin_addr
.s_addr
);
159 #include "icall-decl.h"
162 ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo (MonoStringHandle iface_handle
, MonoArrayHandleOut gw_addr_list_handle
, MonoError
*error
)
164 mono_error_set_not_implemented (error
, "");
171 extern const char mono_route_empty_file_no_warning
;
172 const char mono_route_empty_file_no_warning
= 0;