Welcome to mirror list, hosted at ThFree Co, Russian Federation.

mono-route.c « metadata « mono - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: ba7e38ebf077d27591940d4947cbdbaae28ead39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/**
 * \file
 * 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)
 */

#include "config.h"

#if HOST_DARWIN || HOST_BSD

#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <stdlib.h>
#include <string.h>

#if HOST_IOS || HOST_WATCHOS || HOST_TVOS
// The iOS SDK does not provide the net/route.h header but using the Darwin version works fine.
#include "../../support/ios/net/route.h"
#else
#include <net/route.h>
#endif

static in_addr_t
gateway_from_rtm (struct rt_msghdr *rtm);

#include "object.h"
#include "icall-decl.h"

MonoBoolean
ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo (MonoStringHandle iface_handle, MonoArrayHandleOut gw_addr_list_handle, MonoError *error)
{
	MonoString *iface = MONO_HANDLE_RAW (iface_handle);
	MONO_HANDLE_ASSIGN_RAW (gw_addr_list_handle, NULL);

	size_t needed;
	in_addr_t in;
	int mib [6];
	int num_gws = 0, gwnum = 0;
	unsigned int ifindex = 0;
	char *buf = NULL;
	char *next, *lim;
	char *ifacename = NULL;
	struct rt_msghdr *rtm;
	MonoArray *gw_addr_list = NULL;
	MonoStringHandle addr_string_handle = NULL_HANDLE_INIT; // FIXME probably overkill
	MonoDomain *domain = mono_domain_get ();
	MonoBoolean result = FALSE;

	ifacename = mono_string_to_utf8_checked_internal (iface, error);
	goto_if_nok (error, fail);

	if ((ifindex = if_nametoindex (ifacename)) == 0)
		goto fail;

	// 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)
		goto fail;

	// Allocate suffcient memory for available data based on the previous sysctl call
	if ((buf = g_malloc (needed)) == NULL)
		goto fail;

	// Second sysctl call to retrieve data into appropriately sized buffer
	if (sysctl (mib, G_N_ELEMENTS (mib), buf, &needed, NULL, 0) < 0)
		goto fail;

	lim = buf + needed;
	for (next = buf; next < lim; next += rtm->rtm_msglen) {
		rtm = (struct rt_msghdr *)next;
		if (rtm->rtm_version != RTM_VERSION
			|| rtm->rtm_index != ifindex
			|| (in = gateway_from_rtm (rtm)) == 0)
			continue;
		num_gws++;
	}

	gw_addr_list = mono_array_new_checked (domain, mono_get_string_class (), num_gws, error);
	goto_if_nok (error, leave);

	MONO_HANDLE_ASSIGN_RAW (gw_addr_list_handle, gw_addr_list);

	addr_string_handle = MONO_HANDLE_NEW (MonoString, NULL); // FIXME probably overkill

	for (next = buf; next < lim; next += rtm->rtm_msglen) {
		rtm = (struct rt_msghdr *)next;
		if (rtm->rtm_version != RTM_VERSION
			|| rtm->rtm_index != ifindex
			|| (in = gateway_from_rtm (rtm)) == 0)
			continue;

		MonoString *addr_string;
		char addr [16], *ptr;
		int len;

		ptr = (char *) &in;
		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_checked (domain, addr, error);
		goto_if_nok (error, leave);
		MONO_HANDLE_ASSIGN_RAW (addr_string_handle, addr_string); // FIXME probably overkill
		mono_array_setref_internal (gw_addr_list, gwnum, addr_string);
		gwnum++;
	}
leave:
	result = is_ok (error);
fail:
	g_free (ifacename);
	g_free (buf);
	return result;
}

static 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;
}

#else

#include "object.h"
#include "icall-decl.h"

MonoBoolean
ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo (MonoStringHandle iface_handle, MonoArrayHandleOut gw_addr_list_handle, MonoError *error)
{
	mono_error_set_not_implemented (error, "");
	return FALSE;
}

#endif


extern const char mono_route_empty_file_no_warning;
const char mono_route_empty_file_no_warning = 0;