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 /**********************************************************************************/
57 gboolean IsWindowsVistaOrLater()
61 SecureZeroMemory(&osvi, sizeof(OSVERSIONINFO));
62 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
64 if(GetVersionEx(&osvi)){
65 return osvi.dwMajorVersion >= 6;
69 /**********************************************************************************/
70 /* The wireshark gui doesn't appear at this stage to support having logging messages
71 * returned using g_log() before the interface list.
72 * Below is a generic logging function that can be easily ripped out or configured to
73 * redirect to g_log() if the behaviour changes in the future.
75 static void ifnames_log(const gchar *log_domain, GLogLevelFlags log_level, const gchar *format, ...)
80 if(log_level!=G_LOG_LEVEL_ERROR){
84 va_start(args, format);
85 vsnprintf(buf, 16383, format, args);
88 fprintf(stderr,"%s\r\n",buf);
92 #define g_log ifnames_log
93 /**********************************************************************************/
94 /* Get the Connection Name for the given GUID */
95 static int GetInterfaceFriendlyNameFromDeviceGuid(__in GUID *guid, __out char **Name)
99 WCHAR wName[NDIS_IF_MAX_STRING_SIZE + 1];
101 gboolean fallbackToUnpublishedApi=TRUE;
102 gboolean haveInterfaceFriendlyName=FALSE;
104 /* check we have a parameter */
109 /* Load the ip helper api DLL */
110 hIPHlpApi = LoadLibrary(TEXT("iphlpapi.dll"));
111 if (hIPHlpApi == NULL) {
112 /* Load failed - DLL should always be available in XP+*/
113 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_ERROR,
114 "Failed to load iphlpapi.dll library for interface name lookups, errorcode=0x%08x\n", GetLastError());
118 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Loaded iphlpapi.dll library for interface friendly name lookups");
120 /* Need to convert an Interface GUID to the interface friendly name (e.g. "Local Area Connection")
121 * The functions required to do this all reside within iphlpapi.dll
122 * - The preferred approach is to use published API functions (Available since Windows Vista)
123 * - We do however fallback to trying undocumented API if the published API is not available (Windows XP/2k3 scenario)
126 if(IsWindowsVistaOrLater()){
127 /* Published API function prototypes (for Windows Vista/Windows Server 2008+) */
128 typedef NETIO_STATUS (WINAPI *ProcAddr_CIG2L) (__in CONST GUID *InterfaceGuid, __out PNET_LUID InterfaceLuid);
129 typedef NETIO_STATUS (WINAPI *ProcAddr_CIL2A) ( __in CONST NET_LUID *InterfaceLuid,__out_ecount(Length) PWSTR InterfaceAlias, __in SIZE_T Length);
131 /* Attempt to do the conversion using Published API functions */
132 ProcAddr_CIG2L proc_ConvertInterfaceGuidToLuid=(ProcAddr_CIG2L) GetProcAddress(hIPHlpApi, "ConvertInterfaceGuidToLuid");
133 if(proc_ConvertInterfaceGuidToLuid!=NULL){
134 ProcAddr_CIL2A Proc_ConvertInterfaceLuidToAlias=(ProcAddr_CIL2A) GetProcAddress(hIPHlpApi, "ConvertInterfaceLuidToAlias");
135 if(Proc_ConvertInterfaceLuidToAlias!=NULL){
136 /* we have our functions ready to go, attempt to convert interface guid->luid->friendlyname */
137 NET_LUID InterfaceLuid;
138 hr = proc_ConvertInterfaceGuidToLuid(guid, &InterfaceLuid);
140 /* guid->luid success */
141 hr = Proc_ConvertInterfaceLuidToAlias(&InterfaceLuid, wName, NDIS_IF_MAX_STRING_SIZE+1);
144 /* luid->friendly name success */
145 haveInterfaceFriendlyName=TRUE; /* success */
146 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
147 "converted interface guid to friendly name.");
149 /* luid->friendly name failed */
150 fallbackToUnpublishedApi=FALSE;
151 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE,
152 "ConvertInterfaceLuidToAlias failed to convert interface luid to a friendly name, LastErrorCode=0x%08x.", GetLastError());
155 fallbackToUnpublishedApi=FALSE;
156 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE,
157 "ConvertInterfaceGuidToLuid failed to convert interface guid to a luid, LastErrorCode=0x%08x.", GetLastError());
161 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_ERROR,
162 "Failed to find address of ConvertInterfaceLuidToAlias in iphlpapi.dll, LastErrorCode=0x%08x.", GetLastError());
165 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_ERROR,
166 "Failed to find address of ConvertInterfaceGuidToLuid in iphlpapi.dll, LastErrorCode=0x%08x.", GetLastError());
171 if(fallbackToUnpublishedApi && !haveInterfaceFriendlyName){
172 /* Didn't manage to get the friendly name using published api functions
173 * (most likely cause wireshark is running on Windows XP/Server 2003)
174 * Retry using nhGetInterfaceNameFromGuid (an older unpublished API function) */
175 typedef HRESULT (WINAPI *ProcAddr_nhGINFG) (__in GUID *InterfaceGuid, __out PCWSTR InterfaceAlias, __inout DWORD *LengthAddress, wchar_t *a4, wchar_t *a5);
177 ProcAddr_nhGINFG Proc_nhGetInterfaceNameFromGuid = NULL;
178 Proc_nhGetInterfaceNameFromGuid = (ProcAddr_nhGINFG) GetProcAddress(hIPHlpApi, "NhGetInterfaceNameFromGuid");
179 if (Proc_nhGetInterfaceNameFromGuid!= NULL) {
180 wchar_t *p4=NULL, *p5=NULL;
183 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
184 "Unpublished NhGetInterfaceNameFromGuid function located in iphlpapi.dll, looking up friendly name from guid");
186 /* testing of nhGetInterfaceNameFromGuid indicates the unpublished API function expects the 3rd parameter
187 * to be the available space in bytes (as compared to wchar's) available in the second parameter buffer
188 * to receive the friendly name (in unicode format) including the space for the nul termination.*/
189 NameSize = sizeof(wName);
191 /* do the guid->friendlyname lookup */
192 status = Proc_nhGetInterfaceNameFromGuid(guid, wName, &NameSize, p4, p5);
194 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
195 "nhGetInterfaceNameFromGuidProc status =%d, p4=%d, p5=%d, namesize=%d\n", status, (int)p4, (int)p5, NameSize);
197 haveInterfaceFriendlyName=TRUE; /* success */
198 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
199 "Converted interface guid to friendly name.");
203 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_ERROR,
204 "Failed to locate unpublished NhGetInterfaceNameFromGuid function located in iphlpapi.dll, "
205 "for looking up interface friendly name, LastErrorCode=0x%08x.", GetLastError());
210 /* we have finished with iphlpapi.dll - release it */
211 FreeLibrary(hIPHlpApi);
213 if(!haveInterfaceFriendlyName){
214 /* failed to get the friendly name, nothing further to do */
218 /* Get the required buffer size, and then convert the string */
220 int size = WideCharToMultiByte(CP_UTF8, 0, wName, -1, NULL, 0, NULL, NULL);
221 char *name = (char *) g_malloc(size);
223 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_ERROR,
224 "Failed to allocate memory to convert format of interface friendly name, LastErrorCode=0x%08x.", GetLastError());
227 size=WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, size, NULL, NULL);
229 /* bytes written == 0, indicating some form of error*/
230 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_ERROR,
231 "Error converting format of interface friendly name, LastErrorCode=0x%08x.", GetLastError());
235 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Friendly name is '%s'", name);
242 static int gethexdigit(const char *p)
244 if(*p >= '0' && *p <= '9'){
246 }else if(*p >= 'A' && *p <= 'F'){
247 return *p - 'A' + 0xA;
248 }else if(*p >= 'a' && *p <= 'f'){
249 return *p - 'a' + 0xa;
251 return -1; /* Not a hex digit */
255 static gboolean get8hexdigits(const char *p, DWORD *d)
262 for(i = 0; i < 8; i++){
263 digit = gethexdigit(p++);
265 return FALSE; /* Not a hex digit */
267 val = (val << 4) | digit;
273 static gboolean get4hexdigits(const char *p, WORD *w)
280 for(i = 0; i < 4; i++){
281 digit = gethexdigit(p++);
283 return FALSE; /* Not a hex digit */
285 val = (val << 4) | digit;
291 /**********************************************************************************/
292 /* returns the interface friendly name for a device name, if it is unable to
293 * resolve the name, "" is returned */
294 void get_windows_interface_friendlyname(/* IN */ char *interface_devicename, /* OUT */char **interface_friendlyname)
296 const char* guid_text;
301 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "test, 1,2,3");
303 /* ensure we can return a result */
304 if(interface_friendlyname==NULL){
305 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_ERROR,
306 "invalid interface_friendlyname parameter to get_windows_interface_friendlyname() function.");
309 /* start on the basis we know nothing */
310 *interface_friendlyname=NULL;
312 /* Extract the guid text from the interface device name */
313 if(strncmp("\\Device\\NPF_", interface_devicename, 12)==0){
314 guid_text=interface_devicename+12; /* skip over the '\Device\NPF_' prefix, assume the rest is the guid text */
316 guid_text=interface_devicename;
320 * If what follows is a GUID in {}, then convert it to a GUID structure
321 * and use that to look up the interface to get its friendly name.
323 if(*guid_text != '{'){
324 return; /* Nope, not enclosed in {} */
327 /* There must be 8 hex digits; if so, they go into guid.Data1 */
328 if(!get8hexdigits(guid_text, &guid.Data1)){
329 return; /* nope, not 8 hex digits */
332 /* Now there must be a hyphen */
333 if(*guid_text != '-'){
337 /* There must be 4 hex digits; if so, they go into guid.Data2 */
338 if(!get4hexdigits(guid_text, &guid.Data2)){
339 return; /* nope, not 4 hex digits */
342 /* Now there must be a hyphen */
343 if(*guid_text != '-'){
347 /* There must be 4 hex digits; if so, they go into guid.Data3 */
348 if(!get4hexdigits(guid_text, &guid.Data3)){
349 return; /* nope, not 4 hex digits */
352 /* Now there must be a hyphen */
353 if(*guid_text != '-'){
358 * There must be 4 hex digits; if so, they go into the first 2 bytes
361 for(i = 0; i < 2; i++){
362 digit1 = gethexdigit(guid_text);
364 return; /* Not a hex digit */
367 digit2 = gethexdigit(guid_text);
369 return; /* Not a hex digit */
372 guid.Data4[i] = (digit1 << 4)|(digit2);
374 /* Now there must be a hyphen */
375 if(*guid_text != '-'){
380 * There must be 12 hex digits; if so,t hey go into the next 6 bytes
383 for(i = 0; i < 6; i++){
384 digit1 = gethexdigit(guid_text);
386 return; /* Not a hex digit */
389 digit2 = gethexdigit(guid_text);
391 return; /* Not a hex digit */
394 guid.Data4[i+2] = (digit1 << 4)|(digit2);
396 /* Now there must be a closing } */
397 if(*guid_text != '}'){
401 /* And that must be the end of the string */
402 if(*guid_text != '\0'){
406 /* guid okay, get the interface friendly name associated with the guid */
408 int r=GetInterfaceFriendlyNameFromDeviceGuid(&guid, interface_friendlyname);
410 /* A message has been logged by GetInterfaceFriendlyNameFromDeviceGuid() */
411 *interface_friendlyname=NULL; /* failed to get friendly name, ensure the ultimate result is NULL */
417 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE,
418 "\nInterface %s => '%s'\n\n\n", interface_devicename, *interface_friendlyname);
425 /**************************************************************************************/