1 /* capture_win_ifnames.c
2 * Routines supporting the use of Windows friendly interface names within Wireshark
3 * Copyright 2011-2012, Mike Garratt <wireshark@evn.co.nz>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
42 #ifndef NDIS_IF_MAX_STRING_SIZE
43 #define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE /* =256 in <ifdef.h> */
47 #define NETIO_STATUS DWORD
52 #include "capture_ifinfo.h"
53 #include "capture_win_ifnames.h"
54 #include "wsutil/file_util.h"
56 static int gethexdigit(const char *p
)
58 if(*p
>= '0' && *p
<= '9'){
60 }else if(*p
>= 'A' && *p
<= 'F'){
61 return *p
- 'A' + 0xA;
62 }else if(*p
>= 'a' && *p
<= 'f'){
63 return *p
- 'a' + 0xa;
65 return -1; /* Not a hex digit */
69 static gboolean
get8hexdigits(const char *p
, DWORD
*d
)
76 for(i
= 0; i
< 8; i
++){
77 digit
= gethexdigit(p
++);
79 return FALSE
; /* Not a hex digit */
81 val
= (val
<< 4) | digit
;
87 static gboolean
get4hexdigits(const char *p
, WORD
*w
)
94 for(i
= 0; i
< 4; i
++){
95 digit
= gethexdigit(p
++);
97 return FALSE
; /* Not a hex digit */
99 val
= (val
<< 4) | digit
;
106 * If a string is a GUID in {}, fill in a GUID structure with the GUID
107 * value and return TRUE; otherwise, if the string is not a valid GUID
108 * in {}, return FALSE.
111 parse_as_guid(const char *guid_text
, GUID
*guid
)
116 if(*guid_text
!= '{'){
117 return FALSE
; /* Nope, not enclosed in {} */
120 /* There must be 8 hex digits; if so, they go into guid->Data1 */
121 if(!get8hexdigits(guid_text
, &guid
->Data1
)){
122 return FALSE
; /* nope, not 8 hex digits */
125 /* Now there must be a hyphen */
126 if(*guid_text
!= '-'){
127 return FALSE
; /* Nope */
130 /* There must be 4 hex digits; if so, they go into guid->Data2 */
131 if(!get4hexdigits(guid_text
, &guid
->Data2
)){
132 return FALSE
; /* nope, not 4 hex digits */
135 /* Now there must be a hyphen */
136 if(*guid_text
!= '-'){
137 return FALSE
; /* Nope */
140 /* There must be 4 hex digits; if so, they go into guid->Data3 */
141 if(!get4hexdigits(guid_text
, &guid
->Data3
)){
142 return FALSE
; /* nope, not 4 hex digits */
145 /* Now there must be a hyphen */
146 if(*guid_text
!= '-'){
147 return FALSE
; /* Nope */
151 * There must be 4 hex digits; if so, they go into the first 2 bytes
154 for(i
= 0; i
< 2; i
++){
155 digit1
= gethexdigit(guid_text
);
157 return FALSE
; /* Not a hex digit */
160 digit2
= gethexdigit(guid_text
);
162 return FALSE
; /* Not a hex digit */
165 guid
->Data4
[i
] = (digit1
<< 4)|(digit2
);
167 /* Now there must be a hyphen */
168 if(*guid_text
!= '-'){
169 return FALSE
; /* Nope */
173 * There must be 12 hex digits; if so,t hey go into the next 6 bytes
176 for(i
= 0; i
< 6; i
++){
177 digit1
= gethexdigit(guid_text
);
179 return FALSE
; /* Not a hex digit */
182 digit2
= gethexdigit(guid_text
);
184 return FALSE
; /* Not a hex digit */
187 guid
->Data4
[i
+2] = (digit1
<< 4)|(digit2
);
189 /* Now there must be a closing } */
190 if(*guid_text
!= '}'){
191 return FALSE
; /* Nope */
194 /* And that must be the end of the string */
195 if(*guid_text
!= '\0'){
196 return FALSE
; /* Nope */
201 /**********************************************************************************/
202 gboolean
IsWindowsVistaOrLater()
204 #if (_MSC_VER >= 1800)
206 * On VS2103, GetVersionEx is deprecated. Microsoft recommend to
207 * use VerifyVersionInfo instead
209 OSVERSIONINFOEX osvi
;
210 DWORDLONG dwlConditionMask
= 0;
211 int op
= VER_GREATER_EQUAL
;
213 SecureZeroMemory(&osvi
, sizeof(OSVERSIONINFOEX
));
214 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
215 osvi
.dwMajorVersion
= 6;
216 VER_SET_CONDITION(dwlConditionMask
, VER_MAJORVERSION
, op
);
217 return VerifyVersionInfo(&osvi
, VER_MAJORVERSION
, dwlConditionMask
);
221 SecureZeroMemory(&osvi
, sizeof(OSVERSIONINFO
));
222 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
224 if(GetVersionEx(&osvi
)){
225 return osvi
.dwMajorVersion
>= 6;
231 /**********************************************************************************/
232 /* Get the friendly name for the given GUID */
234 get_interface_friendly_name_from_device_guid(__in GUID
*guid
)
238 WCHAR wName
[NDIS_IF_MAX_STRING_SIZE
+ 1];
240 gboolean fallbackToUnpublishedApi
=TRUE
;
241 gboolean haveInterfaceFriendlyName
=FALSE
;
245 /* Load the ip helper api DLL */
246 hIPHlpApi
= LoadLibrary(TEXT("iphlpapi.dll"));
247 if (hIPHlpApi
== NULL
) {
248 /* Load failed - DLL should always be available in XP+*/
252 /* Need to convert an Interface GUID to the interface friendly name (e.g. "Local Area Connection")
253 * The functions required to do this all reside within iphlpapi.dll
254 * - The preferred approach is to use published API functions (Available since Windows Vista)
255 * - We do however fallback to trying undocumented API if the published API is not available (Windows XP/2k3 scenario)
258 if(IsWindowsVistaOrLater()){
259 /* Published API function prototypes (for Windows Vista/Windows Server 2008+) */
260 typedef NETIO_STATUS (WINAPI
*ProcAddr_CIG2L
) (__in CONST GUID
*InterfaceGuid
, __out PNET_LUID InterfaceLuid
);
261 typedef NETIO_STATUS (WINAPI
*ProcAddr_CIL2A
) ( __in CONST NET_LUID
*InterfaceLuid
,__out_ecount(Length
) PWSTR InterfaceAlias
, __in SIZE_T Length
);
263 /* Attempt to do the conversion using Published API functions */
264 ProcAddr_CIG2L proc_ConvertInterfaceGuidToLuid
=(ProcAddr_CIG2L
) GetProcAddress(hIPHlpApi
, "ConvertInterfaceGuidToLuid");
265 if(proc_ConvertInterfaceGuidToLuid
!=NULL
){
266 ProcAddr_CIL2A Proc_ConvertInterfaceLuidToAlias
=(ProcAddr_CIL2A
) GetProcAddress(hIPHlpApi
, "ConvertInterfaceLuidToAlias");
267 if(Proc_ConvertInterfaceLuidToAlias
!=NULL
){
268 /* we have our functions ready to go, attempt to convert interface guid->luid->friendlyname */
269 NET_LUID InterfaceLuid
;
270 hr
= proc_ConvertInterfaceGuidToLuid(guid
, &InterfaceLuid
);
272 /* guid->luid success */
273 hr
= Proc_ConvertInterfaceLuidToAlias(&InterfaceLuid
, wName
, NDIS_IF_MAX_STRING_SIZE
+1);
276 /* luid->friendly name success */
277 haveInterfaceFriendlyName
=TRUE
; /* success */
279 /* luid->friendly name failed */
280 fallbackToUnpublishedApi
=FALSE
;
283 fallbackToUnpublishedApi
=FALSE
;
291 if(fallbackToUnpublishedApi
&& !haveInterfaceFriendlyName
){
292 /* Didn't manage to get the friendly name using published api functions
293 * (most likely cause wireshark is running on Windows XP/Server 2003)
294 * Retry using nhGetInterfaceNameFromGuid (an older unpublished API function) */
295 typedef HRESULT (WINAPI
*ProcAddr_nhGINFG
) (__in GUID
*InterfaceGuid
, __out PCWSTR InterfaceAlias
, __inout DWORD
*LengthAddress
, wchar_t *a4
, wchar_t *a5
);
297 ProcAddr_nhGINFG Proc_nhGetInterfaceNameFromGuid
= NULL
;
298 Proc_nhGetInterfaceNameFromGuid
= (ProcAddr_nhGINFG
) GetProcAddress(hIPHlpApi
, "NhGetInterfaceNameFromGuid");
299 if (Proc_nhGetInterfaceNameFromGuid
!= NULL
) {
300 wchar_t *p4
=NULL
, *p5
=NULL
;
303 /* testing of nhGetInterfaceNameFromGuid indicates the unpublished API function expects the 3rd parameter
304 * to be the available space in bytes (as compared to wchar's) available in the second parameter buffer
305 * to receive the friendly name (in unicode format) including the space for the nul termination.*/
306 NameSize
= sizeof(wName
);
308 /* do the guid->friendlyname lookup */
309 status
= Proc_nhGetInterfaceNameFromGuid(guid
, wName
, &NameSize
, p4
, p5
);
312 haveInterfaceFriendlyName
=TRUE
; /* success */
317 /* we have finished with iphlpapi.dll - release it */
318 FreeLibrary(hIPHlpApi
);
320 if(!haveInterfaceFriendlyName
){
321 /* failed to get the friendly name, nothing further to do */
325 /* Get the required buffer size, and then convert the string
326 * from UTF-16 to UTF-8. */
327 size
=WideCharToMultiByte(CP_UTF8
, 0, wName
, -1, NULL
, 0, NULL
, NULL
);
328 name
=(char *) g_malloc(size
);
332 size
=WideCharToMultiByte(CP_UTF8
, 0, wName
, -1, name
, size
, NULL
, NULL
);
334 /* bytes written == 0, indicating some form of error*/
342 * Given an interface name, try to extract the GUID from it and parse it.
343 * If that fails, return NULL; if that succeeds, attempt to get the
344 * friendly name for the interface in question. If that fails, return
345 * NULL, otherwise return the friendly name, allocated with g_malloc()
346 * (so that it must be freed with g_free()).
349 get_windows_interface_friendly_name(const char *interface_devicename
)
351 const char* guid_text
;
354 /* Extract the guid text from the interface device name */
355 if(strncmp("\\Device\\NPF_", interface_devicename
, 12)==0){
356 guid_text
=interface_devicename
+12; /* skip over the '\Device\NPF_' prefix, assume the rest is the guid text */
358 guid_text
=interface_devicename
;
361 if (!parse_as_guid(guid_text
, &guid
)){
362 return NULL
; /* not a GUID, so no friendly name */
365 /* guid okay, get the interface friendly name associated with the guid */
366 return get_interface_friendly_name_from_device_guid(&guid
);
369 /**************************************************************************************/