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>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
40 #ifndef NDIS_IF_MAX_STRING_SIZE
41 #define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE /* =256 in <ifdef.h> */
45 #define NETIO_STATUS DWORD
50 #include <capchild/capture_ifinfo.h>
51 #include "capture_win_ifnames.h"
52 #include "wsutil/file_util.h"
54 static int gethexdigit(const char *p)
56 if(*p >= '0' && *p <= '9'){
58 }else if(*p >= 'A' && *p <= 'F'){
59 return *p - 'A' + 0xA;
60 }else if(*p >= 'a' && *p <= 'f'){
61 return *p - 'a' + 0xa;
63 return -1; /* Not a hex digit */
67 static gboolean get8hexdigits(const char *p, DWORD *d)
74 for(i = 0; i < 8; i++){
75 digit = gethexdigit(p++);
77 return FALSE; /* Not a hex digit */
79 val = (val << 4) | digit;
85 static gboolean get4hexdigits(const char *p, WORD *w)
92 for(i = 0; i < 4; i++){
93 digit = gethexdigit(p++);
95 return FALSE; /* Not a hex digit */
97 val = (val << 4) | digit;
104 * If a string is a GUID in {}, fill in a GUID structure with the GUID
105 * value and return TRUE; otherwise, if the string is not a valid GUID
106 * in {}, return FALSE.
109 parse_as_guid(const char *guid_text, GUID *guid)
114 if(*guid_text != '{'){
115 return FALSE; /* Nope, not enclosed in {} */
118 /* There must be 8 hex digits; if so, they go into guid->Data1 */
119 if(!get8hexdigits(guid_text, &guid->Data1)){
120 return FALSE; /* nope, not 8 hex digits */
123 /* Now there must be a hyphen */
124 if(*guid_text != '-'){
125 return FALSE; /* Nope */
128 /* There must be 4 hex digits; if so, they go into guid->Data2 */
129 if(!get4hexdigits(guid_text, &guid->Data2)){
130 return FALSE; /* nope, not 4 hex digits */
133 /* Now there must be a hyphen */
134 if(*guid_text != '-'){
135 return FALSE; /* Nope */
138 /* There must be 4 hex digits; if so, they go into guid->Data3 */
139 if(!get4hexdigits(guid_text, &guid->Data3)){
140 return FALSE; /* nope, not 4 hex digits */
143 /* Now there must be a hyphen */
144 if(*guid_text != '-'){
145 return FALSE; /* Nope */
149 * There must be 4 hex digits; if so, they go into the first 2 bytes
152 for(i = 0; i < 2; i++){
153 digit1 = gethexdigit(guid_text);
155 return FALSE; /* Not a hex digit */
158 digit2 = gethexdigit(guid_text);
160 return FALSE; /* Not a hex digit */
163 guid->Data4[i] = (digit1 << 4)|(digit2);
165 /* Now there must be a hyphen */
166 if(*guid_text != '-'){
167 return FALSE; /* Nope */
171 * There must be 12 hex digits; if so,t hey go into the next 6 bytes
174 for(i = 0; i < 6; i++){
175 digit1 = gethexdigit(guid_text);
177 return FALSE; /* Not a hex digit */
180 digit2 = gethexdigit(guid_text);
182 return FALSE; /* Not a hex digit */
185 guid->Data4[i+2] = (digit1 << 4)|(digit2);
187 /* Now there must be a closing } */
188 if(*guid_text != '}'){
189 return FALSE; /* Nope */
192 /* And that must be the end of the string */
193 if(*guid_text != '\0'){
194 return FALSE; /* Nope */
199 /**********************************************************************************/
200 gboolean IsWindowsVistaOrLater()
202 #if (_MSC_VER >= 1800)
204 * On VS2103, GetVersionEx is deprecated. Microsoft recommend to
205 * use VerifyVersionInfo instead
207 OSVERSIONINFOEX osvi;
208 DWORDLONG dwlConditionMask = 0;
209 int op = VER_GREATER_EQUAL;
211 SecureZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
212 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
213 osvi.dwMajorVersion = 6;
214 VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op);
215 return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask);
219 SecureZeroMemory(&osvi, sizeof(OSVERSIONINFO));
220 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
222 if(GetVersionEx(&osvi)){
223 return osvi.dwMajorVersion >= 6;
229 /**********************************************************************************/
230 /* Get the friendly name for the given GUID */
232 get_interface_friendly_name_from_device_guid(__in GUID *guid)
236 WCHAR wName[NDIS_IF_MAX_STRING_SIZE + 1];
238 gboolean fallbackToUnpublishedApi=TRUE;
239 gboolean haveInterfaceFriendlyName=FALSE;
243 /* Load the ip helper api DLL */
244 hIPHlpApi = LoadLibrary(TEXT("iphlpapi.dll"));
245 if (hIPHlpApi == NULL) {
246 /* Load failed - DLL should always be available in XP+*/
250 /* Need to convert an Interface GUID to the interface friendly name (e.g. "Local Area Connection")
251 * The functions required to do this all reside within iphlpapi.dll
252 * - The preferred approach is to use published API functions (Available since Windows Vista)
253 * - We do however fallback to trying undocumented API if the published API is not available (Windows XP/2k3 scenario)
256 if(IsWindowsVistaOrLater()){
257 /* Published API function prototypes (for Windows Vista/Windows Server 2008+) */
258 typedef NETIO_STATUS (WINAPI *ProcAddr_CIG2L) (__in CONST GUID *InterfaceGuid, __out PNET_LUID InterfaceLuid);
259 typedef NETIO_STATUS (WINAPI *ProcAddr_CIL2A) ( __in CONST NET_LUID *InterfaceLuid,__out_ecount(Length) PWSTR InterfaceAlias, __in SIZE_T Length);
261 /* Attempt to do the conversion using Published API functions */
262 ProcAddr_CIG2L proc_ConvertInterfaceGuidToLuid=(ProcAddr_CIG2L) GetProcAddress(hIPHlpApi, "ConvertInterfaceGuidToLuid");
263 if(proc_ConvertInterfaceGuidToLuid!=NULL){
264 ProcAddr_CIL2A Proc_ConvertInterfaceLuidToAlias=(ProcAddr_CIL2A) GetProcAddress(hIPHlpApi, "ConvertInterfaceLuidToAlias");
265 if(Proc_ConvertInterfaceLuidToAlias!=NULL){
266 /* we have our functions ready to go, attempt to convert interface guid->luid->friendlyname */
267 NET_LUID InterfaceLuid;
268 hr = proc_ConvertInterfaceGuidToLuid(guid, &InterfaceLuid);
270 /* guid->luid success */
271 hr = Proc_ConvertInterfaceLuidToAlias(&InterfaceLuid, wName, NDIS_IF_MAX_STRING_SIZE+1);
274 /* luid->friendly name success */
275 haveInterfaceFriendlyName=TRUE; /* success */
277 /* luid->friendly name failed */
278 fallbackToUnpublishedApi=FALSE;
281 fallbackToUnpublishedApi=FALSE;
289 if(fallbackToUnpublishedApi && !haveInterfaceFriendlyName){
290 /* Didn't manage to get the friendly name using published api functions
291 * (most likely cause wireshark is running on Windows XP/Server 2003)
292 * Retry using nhGetInterfaceNameFromGuid (an older unpublished API function) */
293 typedef HRESULT (WINAPI *ProcAddr_nhGINFG) (__in GUID *InterfaceGuid, __out PCWSTR InterfaceAlias, __inout DWORD *LengthAddress, wchar_t *a4, wchar_t *a5);
295 ProcAddr_nhGINFG Proc_nhGetInterfaceNameFromGuid = NULL;
296 Proc_nhGetInterfaceNameFromGuid = (ProcAddr_nhGINFG) GetProcAddress(hIPHlpApi, "NhGetInterfaceNameFromGuid");
297 if (Proc_nhGetInterfaceNameFromGuid!= NULL) {
298 wchar_t *p4=NULL, *p5=NULL;
301 /* testing of nhGetInterfaceNameFromGuid indicates the unpublished API function expects the 3rd parameter
302 * to be the available space in bytes (as compared to wchar's) available in the second parameter buffer
303 * to receive the friendly name (in unicode format) including the space for the nul termination.*/
304 NameSize = sizeof(wName);
306 /* do the guid->friendlyname lookup */
307 status = Proc_nhGetInterfaceNameFromGuid(guid, wName, &NameSize, p4, p5);
310 haveInterfaceFriendlyName=TRUE; /* success */
315 /* we have finished with iphlpapi.dll - release it */
316 FreeLibrary(hIPHlpApi);
318 if(!haveInterfaceFriendlyName){
319 /* failed to get the friendly name, nothing further to do */
323 /* Get the required buffer size, and then convert the string
324 * from UTF-16 to UTF-8. */
325 size=WideCharToMultiByte(CP_UTF8, 0, wName, -1, NULL, 0, NULL, NULL);
326 name=(char *) g_malloc(size);
330 size=WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, size, NULL, NULL);
332 /* bytes written == 0, indicating some form of error*/
340 * Given an interface name, try to extract the GUID from it and parse it.
341 * If that fails, return NULL; if that succeeds, attempt to get the
342 * friendly name for the interface in question. If that fails, return
343 * NULL, otherwise return the friendly name, allocated with g_malloc()
344 * (so that it must be freed with g_free()).
347 get_windows_interface_friendly_name(const char *interface_devicename)
349 const char* guid_text;
352 /* Extract the guid text from the interface device name */
353 if(strncmp("\\Device\\NPF_", interface_devicename, 12)==0){
354 guid_text=interface_devicename+12; /* skip over the '\Device\NPF_' prefix, assume the rest is the guid text */
356 guid_text=interface_devicename;
359 if (!parse_as_guid(guid_text, &guid)){
360 return NULL; /* not a GUID, so no friendly name */
363 /* guid okay, get the interface friendly name associated with the guid */
364 return get_interface_friendly_name_from_device_guid(&guid);
367 /**************************************************************************************/