1 /*
2  * route-win32.c
3  *
4  * Copyright (c) 2002 Dug Song <dugsong@monkey.org>
5  *
6  * $Id: route-win32.c 589 2005-02-15 07:11:32Z dugsong $
7  */
8 
9 #ifdef _WIN32
10 #include "dnet_winconfig.h"
11 #else
12 #include "config.h"
13 #endif
14 
15 #include <ws2tcpip.h>
16 #include <iphlpapi.h>
17 
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #include "dnet.h"
23 
24 typedef DWORD (WINAPI *GETIPFORWARDTABLE2)(ADDRESS_FAMILY, PMIB_IPFORWARD_TABLE2 *);
25 
26 struct route_handle {
27 	HINSTANCE iphlpapi;
28 	MIB_IPFORWARDTABLE *ipftable;
29 	MIB_IPFORWARD_TABLE2 *ipftable2;
30 };
31 
32 route_t *
route_open(void)33 route_open(void)
34 {
35 	route_t *r;
36 
37 	r = calloc(1, sizeof(route_t));
38 	if (r == NULL)
39 		return NULL;
40 	r->iphlpapi = GetModuleHandle("iphlpapi.dll");
41 
42 	return r;
43 }
44 
45 int
route_add(route_t * route,const struct route_entry * entry)46 route_add(route_t *route, const struct route_entry *entry)
47 {
48 	MIB_IPFORWARDROW ipfrow;
49 	struct addr net;
50 
51 	memset(&ipfrow, 0, sizeof(ipfrow));
52 
53 	if (GetBestInterface(entry->route_gw.addr_ip,
54 	    &ipfrow.dwForwardIfIndex) != NO_ERROR)
55 		return (-1);
56 
57 	if (addr_net(&entry->route_dst, &net) < 0 ||
58 	    net.addr_type != ADDR_TYPE_IP)
59 		return (-1);
60 
61 	ipfrow.dwForwardDest = net.addr_ip;
62 	addr_btom(entry->route_dst.addr_bits,
63 	    &ipfrow.dwForwardMask, IP_ADDR_LEN);
64 	ipfrow.dwForwardNextHop = entry->route_gw.addr_ip;
65 	ipfrow.dwForwardType = 4;	/* XXX - next hop != final dest */
66 	ipfrow.dwForwardProto = 3;	/* XXX - MIB_PROTO_NETMGMT */
67 
68 	if (CreateIpForwardEntry(&ipfrow) != NO_ERROR)
69 		return (-1);
70 
71 	return (0);
72 }
73 
74 int
route_delete(route_t * route,const struct route_entry * entry)75 route_delete(route_t *route, const struct route_entry *entry)
76 {
77 	MIB_IPFORWARDROW ipfrow;
78 	DWORD mask;
79 
80 	if (entry->route_dst.addr_type != ADDR_TYPE_IP ||
81 	    GetBestRoute(entry->route_dst.addr_ip,
82 	    IP_ADDR_ANY, &ipfrow) != NO_ERROR)
83 		return (-1);
84 
85 	addr_btom(entry->route_dst.addr_bits, &mask, IP_ADDR_LEN);
86 
87 	if (ipfrow.dwForwardDest != entry->route_dst.addr_ip ||
88 	    ipfrow.dwForwardMask != mask) {
89 		errno = ENXIO;
90 		SetLastError(ERROR_NO_DATA);
91 		return (-1);
92 	}
93 	if (DeleteIpForwardEntry(&ipfrow) != NO_ERROR)
94 		return (-1);
95 
96 	return (0);
97 }
98 
99 int
route_get(route_t * route,struct route_entry * entry)100 route_get(route_t *route, struct route_entry *entry)
101 {
102 	MIB_IPFORWARDROW ipfrow;
103 	DWORD mask;
104 	intf_t *intf;
105 	struct intf_entry intf_entry;
106 
107 	if (entry->route_dst.addr_type != ADDR_TYPE_IP ||
108 	    GetBestRoute(entry->route_dst.addr_ip,
109 	    IP_ADDR_ANY, &ipfrow) != NO_ERROR)
110 		return (-1);
111 
112 	if (ipfrow.dwForwardProto == 2 &&	/* XXX - MIB_IPPROTO_LOCAL */
113 	    (ipfrow.dwForwardNextHop|IP_CLASSA_NET) !=
114 	    (IP_ADDR_LOOPBACK|IP_CLASSA_NET) &&
115 	    !IP_LOCAL_GROUP(ipfrow.dwForwardNextHop)) {
116 		errno = ENXIO;
117 		SetLastError(ERROR_NO_DATA);
118 		return (-1);
119 	}
120 	addr_btom(entry->route_dst.addr_bits, &mask, IP_ADDR_LEN);
121 
122 	entry->route_gw.addr_type = ADDR_TYPE_IP;
123 	entry->route_gw.addr_bits = IP_ADDR_BITS;
124 	entry->route_gw.addr_ip = ipfrow.dwForwardNextHop;
125 	entry->metric = ipfrow.dwForwardMetric1;
126 
127 	entry->intf_name[0] = '\0';
128 	intf = intf_open();
129 	if (intf_get_index(intf, &intf_entry,
130 	    AF_INET, ipfrow.dwForwardIfIndex) == 0) {
131 		strlcpy(entry->intf_name, intf_entry.intf_name, sizeof(entry->intf_name));
132 	}
133 	intf_close(intf);
134 
135 	return (0);
136 }
137 
138 static int
route_loop_getipforwardtable(route_t * r,route_handler callback,void * arg)139 route_loop_getipforwardtable(route_t *r, route_handler callback, void *arg)
140 {
141  	struct route_entry entry;
142 	intf_t *intf;
143 	ULONG len;
144 	int i, ret;
145 
146 	for (len = sizeof(r->ipftable[0]); ; ) {
147 		if (r->ipftable)
148 			free(r->ipftable);
149 		r->ipftable = malloc(len);
150 		if (r->ipftable == NULL)
151 			return (-1);
152 		ret = GetIpForwardTable(r->ipftable, &len, FALSE);
153 		if (ret == NO_ERROR)
154 			break;
155 		else if (ret != ERROR_INSUFFICIENT_BUFFER)
156 			return (-1);
157 	}
158 
159 	intf = intf_open();
160 
161 	ret = 0;
162 	for (i = 0; i < (int)r->ipftable->dwNumEntries; i++) {
163 		struct intf_entry intf_entry;
164 
165 		entry.route_dst.addr_type = ADDR_TYPE_IP;
166 		entry.route_dst.addr_bits = IP_ADDR_BITS;
167 
168 		entry.route_gw.addr_type = ADDR_TYPE_IP;
169 		entry.route_gw.addr_bits = IP_ADDR_BITS;
170 
171 		entry.route_dst.addr_ip = r->ipftable->table[i].dwForwardDest;
172 		addr_mtob(&r->ipftable->table[i].dwForwardMask, IP_ADDR_LEN,
173 		    &entry.route_dst.addr_bits);
174 		entry.route_gw.addr_ip =
175 		    r->ipftable->table[i].dwForwardNextHop;
176 		entry.metric = r->ipftable->table[i].dwForwardMetric1;
177 
178 		/* Look up the interface name. */
179 		entry.intf_name[0] = '\0';
180 		intf_entry.intf_len = sizeof(intf_entry);
181 		if (intf_get_index(intf, &intf_entry,
182 		    AF_INET, r->ipftable->table[i].dwForwardIfIndex) == 0) {
183 			strlcpy(entry.intf_name, intf_entry.intf_name, sizeof(entry.intf_name));
184 		}
185 
186 		if ((ret = (*callback)(&entry, arg)) != 0)
187 			break;
188 	}
189 
190 	intf_close(intf);
191 
192 	return ret;
193 }
194 
195 static int
route_loop_getipforwardtable2(GETIPFORWARDTABLE2 GetIpForwardTable2,route_t * r,route_handler callback,void * arg)196 route_loop_getipforwardtable2(GETIPFORWARDTABLE2 GetIpForwardTable2,
197 	route_t *r, route_handler callback, void *arg)
198 {
199 	struct route_entry entry;
200 	intf_t *intf;
201 	ULONG i;
202 	int ret;
203 
204 	ret = GetIpForwardTable2(AF_UNSPEC, &r->ipftable2);
205 	if (ret != NO_ERROR)
206 		return (-1);
207 
208 	intf = intf_open();
209 
210 	ret = 0;
211 	for (i = 0; i < r->ipftable2->NumEntries; i++) {
212 		struct intf_entry intf_entry;
213 		MIB_IPFORWARD_ROW2 *row;
214 		MIB_IPINTERFACE_ROW ifrow;
215 		ULONG metric;
216 
217 		row = &r->ipftable2->Table[i];
218 		addr_ston((struct sockaddr *) &row->DestinationPrefix.Prefix, &entry.route_dst);
219 		entry.route_dst.addr_bits = row->DestinationPrefix.PrefixLength;
220 		addr_ston((struct sockaddr *) &row->NextHop, &entry.route_gw);
221 
222 		/* Look up the interface name. */
223 		entry.intf_name[0] = '\0';
224 		intf_entry.intf_len = sizeof(intf_entry);
225 		if (intf_get_index(intf, &intf_entry,
226 		    row->DestinationPrefix.Prefix.si_family,
227 		    row->InterfaceIndex) == 0) {
228 			strlcpy(entry.intf_name, intf_entry.intf_name, sizeof(entry.intf_name));
229 		}
230 
231 		ifrow.Family = row->DestinationPrefix.Prefix.si_family;
232 		ifrow.InterfaceLuid = row->InterfaceLuid;
233 		ifrow.InterfaceIndex = row->InterfaceIndex;
234 		if (GetIpInterfaceEntry(&ifrow) != NO_ERROR) {
235 			return (-1);
236 		}
237 		metric = ifrow.Metric + row->Metric;
238 		if (metric < INT_MAX)
239 			entry.metric = metric;
240 		else
241 			entry.metric = INT_MAX;
242 
243 		if ((ret = (*callback)(&entry, arg)) != 0)
244 			break;
245 	}
246 
247 	intf_close(intf);
248 
249 	return ret;
250 }
251 
252 int
route_loop(route_t * r,route_handler callback,void * arg)253 route_loop(route_t *r, route_handler callback, void *arg)
254 {
255 	GETIPFORWARDTABLE2 GetIpForwardTable2;
256 
257 	/* GetIpForwardTable2 is only available on Vista and later, dynamic load. */
258 	GetIpForwardTable2 = NULL;
259 	if (r->iphlpapi != NULL)
260 		GetIpForwardTable2 = (GETIPFORWARDTABLE2) GetProcAddress(r->iphlpapi, "GetIpForwardTable2");
261 
262 	if (GetIpForwardTable2 == NULL)
263 		return route_loop_getipforwardtable(r, callback, arg);
264 	else
265 		return route_loop_getipforwardtable2(GetIpForwardTable2, r, callback, arg);
266 }
267 
268 route_t *
route_close(route_t * r)269 route_close(route_t *r)
270 {
271 	if (r != NULL) {
272 		if (r->iphlpapi != NULL)
273 			FreeLibrary(r->iphlpapi);
274 		if (r->ipftable != NULL)
275 			free(r->ipftable);
276 		if (r->ipftable2 != NULL)
277 			FreeMibTable(r->ipftable2);
278 		free(r);
279 	}
280 	return (NULL);
281 }
282