blob: 56d292e420dacc42504c3e4a54415c2a8c49c34b [file] [log] [blame]
Benny Prijonob681a2f2007-03-25 18:44:51 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonob681a2f2007-03-25 18:44:51 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
Benny Prijonoa6bd7582007-03-28 15:49:48 +000020#include <pj/config.h>
Benny Prijonob681a2f2007-03-25 18:44:51 +000021
22#define WIN32_LEAN_AND_MEAN
23#include <windows.h>
24
Benny Prijonoa6bd7582007-03-28 15:49:48 +000025/* PMIB_ICMP_EX is not declared in VC6, causing error.
26 * But EVC4, which also claims to be VC6, does have it!
27 */
28#if defined(_MSC_VER) && _MSC_VER==1200 && !defined(PJ_WIN32_WINCE)
Benny Prijonob681a2f2007-03-25 18:44:51 +000029# define PMIB_ICMP_EX void*
30#endif
Benny Prijono62b86eb2007-12-01 08:52:57 +000031#include <winsock2.h>
32
33/* If you encounter error "Cannot open include file: 'Iphlpapi.h' here,
34 * you need to install newer Platform SDK. Presumably you're using
35 * Microsoft Visual Studio 6?
36 */
Benny Prijonob681a2f2007-03-25 18:44:51 +000037#include <Iphlpapi.h>
38
39#include <pj/ip_helper.h>
40#include <pj/assert.h>
41#include <pj/errno.h>
42#include <pj/string.h>
43
Benny Prijono48ef5a32007-07-28 01:58:36 +000044typedef DWORD (WINAPI *PFN_GetIpAddrTable)(PMIB_IPADDRTABLE pIpAddrTable,
45 PULONG pdwSize,
46 BOOL bOrder);
Benny Prijono62b86eb2007-12-01 08:52:57 +000047typedef DWORD (WINAPI *PFN_GetAdapterAddresses)(ULONG Family,
48 ULONG Flags,
49 PVOID Reserved,
50 PIP_ADAPTER_ADDRESSES AdapterAddresses,
51 PULONG SizePointer);
Benny Prijono48ef5a32007-07-28 01:58:36 +000052typedef DWORD (WINAPI *PFN_GetIpForwardTable)(PMIB_IPFORWARDTABLE pIpForwardTable,
53 PULONG pdwSize,
54 BOOL bOrder);
Benny Prijono2501e132007-09-24 19:46:41 +000055typedef DWORD (WINAPI *PFN_GetIfEntry)(PMIB_IFROW pIfRow);
Benny Prijono48ef5a32007-07-28 01:58:36 +000056
57static HANDLE s_hDLL;
58static PFN_GetIpAddrTable s_pfnGetIpAddrTable;
Benny Prijono49e78b42009-12-08 16:53:29 +000059static PFN_GetAdapterAddresses s_pfnGetAdapterAddresses;
Benny Prijono48ef5a32007-07-28 01:58:36 +000060static PFN_GetIpForwardTable s_pfnGetIpForwardTable;
Benny Prijono2501e132007-09-24 19:46:41 +000061static PFN_GetIfEntry s_pfnGetIfEntry;
Benny Prijono48ef5a32007-07-28 01:58:36 +000062
Benny Prijono62b86eb2007-12-01 08:52:57 +000063
Benny Prijono16f64792007-08-16 14:13:28 +000064static void unload_iphlp_module(void)
Benny Prijono48ef5a32007-07-28 01:58:36 +000065{
66 FreeLibrary(s_hDLL);
67 s_hDLL = NULL;
68 s_pfnGetIpAddrTable = NULL;
69 s_pfnGetIpForwardTable = NULL;
Benny Prijono62b86eb2007-12-01 08:52:57 +000070 s_pfnGetIfEntry = NULL;
Benny Prijono62b86eb2007-12-01 08:52:57 +000071 s_pfnGetAdapterAddresses = NULL;
Benny Prijono48ef5a32007-07-28 01:58:36 +000072}
73
Benny Prijono2ef519f2009-11-10 04:30:46 +000074static FARPROC GetIpHlpApiProc(char *lpProcName)
Benny Prijono48ef5a32007-07-28 01:58:36 +000075{
76 if(NULL == s_hDLL) {
77 s_hDLL = LoadLibrary(PJ_T("IpHlpApi"));
78 if(NULL != s_hDLL) {
79 pj_atexit(&unload_iphlp_module);
80 }
81 }
82
83 if(NULL != s_hDLL)
84 return GetProcAddress(s_hDLL, lpProcName);
85
86 return NULL;
87}
88
89static DWORD MyGetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable,
90 PULONG pdwSize,
91 BOOL bOrder)
92{
93 if(NULL == s_pfnGetIpAddrTable) {
94 s_pfnGetIpAddrTable = (PFN_GetIpAddrTable)
Benny Prijono2ef519f2009-11-10 04:30:46 +000095 GetIpHlpApiProc("GetIpAddrTable");
Benny Prijono48ef5a32007-07-28 01:58:36 +000096 }
97
98 if(NULL != s_pfnGetIpAddrTable) {
99 return s_pfnGetIpAddrTable(pIpAddrTable, pdwSize, bOrder);
100 }
101
102 return ERROR_NOT_SUPPORTED;
103}
104
Benny Prijono62b86eb2007-12-01 08:52:57 +0000105static DWORD MyGetAdapterAddresses(ULONG Family,
106 ULONG Flags,
107 PVOID Reserved,
108 PIP_ADAPTER_ADDRESSES AdapterAddresses,
109 PULONG SizePointer)
110{
111 if(NULL == s_pfnGetAdapterAddresses) {
112 s_pfnGetAdapterAddresses = (PFN_GetAdapterAddresses)
Benny Prijono49e78b42009-12-08 16:53:29 +0000113 GetIpHlpApiProc("GetAdaptersAddresses");
Benny Prijono62b86eb2007-12-01 08:52:57 +0000114 }
115
116 if(NULL != s_pfnGetAdapterAddresses) {
117 return s_pfnGetAdapterAddresses(Family, Flags, Reserved,
118 AdapterAddresses, SizePointer);
119 }
120
121 return ERROR_NOT_SUPPORTED;
122}
Benny Prijono48ef5a32007-07-28 01:58:36 +0000123
Benny Prijono2501e132007-09-24 19:46:41 +0000124#if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
125static DWORD MyGetIfEntry(MIB_IFROW *pIfRow)
126{
127 if(NULL == s_pfnGetIfEntry) {
128 s_pfnGetIfEntry = (PFN_GetIfEntry)
Benny Prijono2ef519f2009-11-10 04:30:46 +0000129 GetIpHlpApiProc("GetIfEntry");
Benny Prijono2501e132007-09-24 19:46:41 +0000130 }
131
132 if(NULL != s_pfnGetIfEntry) {
133 return s_pfnGetIfEntry(pIfRow);
134 }
135
136 return ERROR_NOT_SUPPORTED;
137}
138#endif
139
140
Benny Prijono48ef5a32007-07-28 01:58:36 +0000141static DWORD MyGetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable,
142 PULONG pdwSize,
143 BOOL bOrder)
144{
145 if(NULL == s_pfnGetIpForwardTable) {
146 s_pfnGetIpForwardTable = (PFN_GetIpForwardTable)
Benny Prijono2ef519f2009-11-10 04:30:46 +0000147 GetIpHlpApiProc("GetIpForwardTable");
Benny Prijono48ef5a32007-07-28 01:58:36 +0000148 }
149
150 if(NULL != s_pfnGetIpForwardTable) {
151 return s_pfnGetIpForwardTable(pIpForwardTable, pdwSize, bOrder);
152 }
153
154 return ERROR_NOT_SUPPORTED;
155}
Benny Prijonob681a2f2007-03-25 18:44:51 +0000156
Benny Prijono62b86eb2007-12-01 08:52:57 +0000157/* Enumerate local IP interface using GetIpAddrTable()
158 * for IPv4 addresses only.
Benny Prijonob681a2f2007-03-25 18:44:51 +0000159 */
Benny Prijono62b86eb2007-12-01 08:52:57 +0000160static pj_status_t enum_ipv4_interface(unsigned *p_cnt,
161 pj_sockaddr ifs[])
Benny Prijonob681a2f2007-03-25 18:44:51 +0000162{
163 /* Provide enough buffer or otherwise it will fail with
164 * error 22 ("Not Enough Buffer") error.
165 */
Benny Prijono6b5b6602007-03-30 18:54:46 +0000166 char ipTabBuff[1024];
Benny Prijonob681a2f2007-03-25 18:44:51 +0000167 MIB_IPADDRTABLE *pTab;
168 ULONG tabSize;
169 unsigned i, count;
Benny Prijono48ef5a32007-07-28 01:58:36 +0000170 DWORD rc = NO_ERROR;
Benny Prijonob681a2f2007-03-25 18:44:51 +0000171
172 PJ_ASSERT_RETURN(p_cnt && ifs, PJ_EINVAL);
173
Benny Prijono6b5b6602007-03-30 18:54:46 +0000174 pTab = (MIB_IPADDRTABLE*)ipTabBuff;
Benny Prijonob681a2f2007-03-25 18:44:51 +0000175
176 /* Get IP address table */
177 tabSize = sizeof(ipTabBuff);
Benny Prijono48ef5a32007-07-28 01:58:36 +0000178
179 rc = MyGetIpAddrTable(pTab, &tabSize, FALSE);
Benny Prijonob681a2f2007-03-25 18:44:51 +0000180 if (rc != NO_ERROR)
181 return PJ_RETURN_OS_ERROR(rc);
182
183 /* Reset result */
184 pj_bzero(ifs, sizeof(ifs[0]) * (*p_cnt));
185
186 /* Now fill out the entries */
187 count = (pTab->dwNumEntries < *p_cnt) ? pTab->dwNumEntries : *p_cnt;
Benny Prijonofed1af92007-03-27 23:29:27 +0000188 *p_cnt = 0;
Benny Prijonob681a2f2007-03-25 18:44:51 +0000189 for (i=0; i<count; ++i) {
Benny Prijono2501e132007-09-24 19:46:41 +0000190 MIB_IFROW ifRow;
191
Benny Prijono62b86eb2007-12-01 08:52:57 +0000192 /* Ignore 0.0.0.0 address (interface is down?) */
Benny Prijonofed1af92007-03-27 23:29:27 +0000193 if (pTab->table[i].dwAddr == 0)
194 continue;
Benny Prijono2501e132007-09-24 19:46:41 +0000195
Benny Prijonodd538ed2008-06-07 11:14:32 +0000196 /* Ignore 0.0.0.0/8 address. This is a special address
197 * which doesn't seem to have practical use.
198 */
199 if ((pj_ntohl(pTab->table[i].dwAddr) >> 24) == 0)
200 continue;
201
Benny Prijono2501e132007-09-24 19:46:41 +0000202#if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
203 /* Investigate the type of this interface */
204 pj_bzero(&ifRow, sizeof(ifRow));
205 ifRow.dwIndex = pTab->table[i].dwIndex;
206 if (MyGetIfEntry(&ifRow) != 0)
207 continue;
208
209 if (ifRow.dwType == MIB_IF_TYPE_LOOPBACK)
210 continue;
211#endif
212
Benny Prijono62b86eb2007-12-01 08:52:57 +0000213 ifs[*p_cnt].ipv4.sin_family = PJ_AF_INET;
214 ifs[*p_cnt].ipv4.sin_addr.s_addr = pTab->table[i].dwAddr;
Benny Prijonofed1af92007-03-27 23:29:27 +0000215 (*p_cnt)++;
Benny Prijonob681a2f2007-03-25 18:44:51 +0000216 }
217
Benny Prijono93993562008-01-24 19:54:51 +0000218 return (*p_cnt) ? PJ_SUCCESS : PJ_ENOTFOUND;
Benny Prijonob681a2f2007-03-25 18:44:51 +0000219}
220
221
Benny Prijono62b86eb2007-12-01 08:52:57 +0000222/* Enumerate local IP interface using GetAdapterAddresses(),
223 * which works for both IPv4 and IPv6.
224 */
Benny Prijono62b86eb2007-12-01 08:52:57 +0000225static pj_status_t enum_ipv4_ipv6_interface(int af,
226 unsigned *p_cnt,
227 pj_sockaddr ifs[])
228{
Benny Prijono49e78b42009-12-08 16:53:29 +0000229 pj_uint8_t buffer[1600];
Benny Prijono62b86eb2007-12-01 08:52:57 +0000230 IP_ADAPTER_ADDRESSES *adapter = (IP_ADAPTER_ADDRESSES*)buffer;
231 ULONG size = sizeof(buffer);
232 unsigned i;
233 DWORD rc;
234
235 rc = MyGetAdapterAddresses(af, 0, NULL, adapter, &size);
236 if (rc != ERROR_SUCCESS)
237 return PJ_RETURN_OS_ERROR(rc);
238
239 for (i=0; i<*p_cnt && adapter; ++i, adapter = adapter->Next) {
Benny Prijonofcaf9cf2009-12-10 04:56:26 +0000240 if (adapter->FirstUnicastAddress) {
241 SOCKET_ADDRESS *pAddr = &adapter->FirstUnicastAddress->Address;
242 ifs[i].addr.sa_family = pAddr->lpSockaddr->sa_family;
243 pj_memcpy(&ifs[i], pAddr->lpSockaddr, pAddr->iSockaddrLength);
244 }
Benny Prijono62b86eb2007-12-01 08:52:57 +0000245 }
246
Benny Prijono49e78b42009-12-08 16:53:29 +0000247 *p_cnt = i;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000248 return PJ_SUCCESS;
249}
Benny Prijono62b86eb2007-12-01 08:52:57 +0000250
251
252/*
253 * Enumerate the local IP interface currently active in the host.
254 */
255PJ_DEF(pj_status_t) pj_enum_ip_interface(int af,
256 unsigned *p_cnt,
257 pj_sockaddr ifs[])
258{
259 pj_status_t status = -1;
260
261 PJ_ASSERT_RETURN(p_cnt && ifs, PJ_EINVAL);
262 PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC || af==PJ_AF_INET || af==PJ_AF_INET6,
263 PJ_EAFNOTSUP);
264
Benny Prijono62b86eb2007-12-01 08:52:57 +0000265 status = enum_ipv4_ipv6_interface(af, p_cnt, ifs);
266 if (status != PJ_SUCCESS && (af==PJ_AF_INET || af==PJ_AF_UNSPEC))
267 status = enum_ipv4_interface(p_cnt, ifs);
268 return status;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000269}
270
Benny Prijonob681a2f2007-03-25 18:44:51 +0000271/*
272 * Enumerate the IP routing table for this host.
273 */
274PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt,
275 pj_ip_route_entry routes[])
276{
Benny Prijono6b5b6602007-03-30 18:54:46 +0000277 char ipTabBuff[1024];
Benny Prijonob681a2f2007-03-25 18:44:51 +0000278 MIB_IPADDRTABLE *pIpTab;
Benny Prijono6b5b6602007-03-30 18:54:46 +0000279 char rtabBuff[1024];
Benny Prijonob681a2f2007-03-25 18:44:51 +0000280 MIB_IPFORWARDTABLE *prTab;
281 ULONG tabSize;
282 unsigned i, count;
Benny Prijono48ef5a32007-07-28 01:58:36 +0000283 DWORD rc = NO_ERROR;
Benny Prijonob681a2f2007-03-25 18:44:51 +0000284
285 PJ_ASSERT_RETURN(p_cnt && routes, PJ_EINVAL);
286
Benny Prijono6b5b6602007-03-30 18:54:46 +0000287 pIpTab = (MIB_IPADDRTABLE *)ipTabBuff;
288 prTab = (MIB_IPFORWARDTABLE *)rtabBuff;
Benny Prijonob681a2f2007-03-25 18:44:51 +0000289
290 /* First get IP address table */
291 tabSize = sizeof(ipTabBuff);
Benny Prijono48ef5a32007-07-28 01:58:36 +0000292 rc = MyGetIpAddrTable(pIpTab, &tabSize, FALSE);
Benny Prijonob681a2f2007-03-25 18:44:51 +0000293 if (rc != NO_ERROR)
294 return PJ_RETURN_OS_ERROR(rc);
295
296 /* Next get IP route table */
297 tabSize = sizeof(rtabBuff);
Benny Prijono48ef5a32007-07-28 01:58:36 +0000298
299 rc = MyGetIpForwardTable(prTab, &tabSize, 1);
Benny Prijonob681a2f2007-03-25 18:44:51 +0000300 if (rc != NO_ERROR)
301 return PJ_RETURN_OS_ERROR(rc);
302
303 /* Reset routes */
304 pj_bzero(routes, sizeof(routes[0]) * (*p_cnt));
305
306 /* Now fill out the route entries */
307 count = (prTab->dwNumEntries < *p_cnt) ? prTab->dwNumEntries : *p_cnt;
308 *p_cnt = 0;
309 for (i=0; i<count; ++i) {
310 unsigned j;
311
312 /* Find interface entry */
313 for (j=0; j<pIpTab->dwNumEntries; ++j) {
314 if (pIpTab->table[j].dwIndex == prTab->table[i].dwForwardIfIndex)
315 break;
316 }
317
318 if (j==pIpTab->dwNumEntries)
319 continue; /* Interface not found */
320
321 routes[*p_cnt].ipv4.if_addr.s_addr = pIpTab->table[j].dwAddr;
322 routes[*p_cnt].ipv4.dst_addr.s_addr = prTab->table[i].dwForwardDest;
323 routes[*p_cnt].ipv4.mask.s_addr = prTab->table[i].dwForwardMask;
324
325 (*p_cnt)++;
326 }
327
328 return PJ_SUCCESS;
329}
330