Rename get_windows_interface_friendlyname() to
[metze/wireshark/wip.git] / capture_win_ifnames.c
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>
4 *
5 * $Id$
6 *
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
10 *
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.
15 *
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.
20 *
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.
24 */
25
26 #include "config.h"
27
28 #ifdef _WIN32
29
30 #include <winsock2.h>
31 #include <windows.h>
32 #include <iphlpapi.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #include <wtap.h>
37 #include <libpcap.h>
38 #include <glib.h>
39
40 #include <ntddndis.h>
41
42 #ifndef NDIS_IF_MAX_STRING_SIZE
43 #define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE   /* =256 in <ifdef.h> */
44 #endif
45
46 #ifndef NETIO_STATUS
47 #define NETIO_STATUS DWORD
48 #endif
49
50 #include "log.h"
51
52 #include "capture_ifinfo.h"
53 #include "capture_win_ifnames.h"
54 #include "wsutil/file_util.h"
55
56 /**********************************************************************************/
57 gboolean IsWindowsVistaOrLater()
58 {
59     OSVERSIONINFO osvi;
60
61     SecureZeroMemory(&osvi, sizeof(OSVERSIONINFO));
62     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
63
64     if(GetVersionEx(&osvi)){
65         return osvi.dwMajorVersion >= 6;
66     }
67     return FALSE;
68 }
69
70 /**********************************************************************************/
71 /* Get the Connection Name for the given GUID */
72 static char *
73 GetInterfaceFriendlyNameFromDeviceGuid(__in GUID *guid)
74 {
75     HMODULE hIPHlpApi;
76     HRESULT status;
77     WCHAR wName[NDIS_IF_MAX_STRING_SIZE + 1];
78     HRESULT hr;
79     gboolean fallbackToUnpublishedApi=TRUE;
80     gboolean haveInterfaceFriendlyName=FALSE;
81     int size;
82     char *name;
83
84     /* Load the ip helper api DLL */
85     hIPHlpApi = LoadLibrary(TEXT("iphlpapi.dll"));
86     if (hIPHlpApi == NULL) {
87         /* Load failed - DLL should always be available in XP+*/
88         return NULL;
89     }
90
91     /* Need to convert an Interface GUID to the interface friendly name (e.g. "Local Area Connection")
92     * The functions required to do this all reside within iphlpapi.dll
93     * - The preferred approach is to use published API functions (Available since Windows Vista)
94     * - We do however fallback to trying undocumented API if the published API is not available (Windows XP/2k3 scenario)
95     */
96
97     if(IsWindowsVistaOrLater()){
98         /* Published API function prototypes (for Windows Vista/Windows Server 2008+) */
99         typedef NETIO_STATUS (WINAPI *ProcAddr_CIG2L) (__in CONST GUID *InterfaceGuid, __out PNET_LUID InterfaceLuid);
100         typedef NETIO_STATUS (WINAPI *ProcAddr_CIL2A) ( __in CONST NET_LUID *InterfaceLuid,__out_ecount(Length) PWSTR InterfaceAlias, __in SIZE_T Length);
101
102         /* Attempt to do the conversion using Published API functions */
103         ProcAddr_CIG2L proc_ConvertInterfaceGuidToLuid=(ProcAddr_CIG2L) GetProcAddress(hIPHlpApi, "ConvertInterfaceGuidToLuid");
104         if(proc_ConvertInterfaceGuidToLuid!=NULL){
105             ProcAddr_CIL2A Proc_ConvertInterfaceLuidToAlias=(ProcAddr_CIL2A) GetProcAddress(hIPHlpApi, "ConvertInterfaceLuidToAlias");
106             if(Proc_ConvertInterfaceLuidToAlias!=NULL){
107                 /* we have our functions ready to go, attempt to convert interface guid->luid->friendlyname */
108                 NET_LUID InterfaceLuid;
109                 hr = proc_ConvertInterfaceGuidToLuid(guid, &InterfaceLuid);
110                 if(hr==NO_ERROR){
111                     /* guid->luid success */
112                     hr = Proc_ConvertInterfaceLuidToAlias(&InterfaceLuid, wName, NDIS_IF_MAX_STRING_SIZE+1);
113
114                     if(hr==NO_ERROR){
115                         /* luid->friendly name success */
116                         haveInterfaceFriendlyName=TRUE; /* success */
117                     }else{
118                         /* luid->friendly name failed */
119                         fallbackToUnpublishedApi=FALSE;
120                     }
121                 }else{
122                     fallbackToUnpublishedApi=FALSE;
123                 }
124
125             }
126         }
127     }
128
129
130     if(fallbackToUnpublishedApi && !haveInterfaceFriendlyName){
131         /* Didn't manage to get the friendly name using published api functions
132         * (most likely cause wireshark is running on Windows XP/Server 2003)
133         * Retry using nhGetInterfaceNameFromGuid (an older unpublished API function) */
134         typedef HRESULT (WINAPI *ProcAddr_nhGINFG) (__in GUID *InterfaceGuid, __out PCWSTR InterfaceAlias, __inout DWORD *LengthAddress, wchar_t *a4, wchar_t *a5);
135
136         ProcAddr_nhGINFG Proc_nhGetInterfaceNameFromGuid = NULL;
137         Proc_nhGetInterfaceNameFromGuid = (ProcAddr_nhGINFG) GetProcAddress(hIPHlpApi, "NhGetInterfaceNameFromGuid");
138         if (Proc_nhGetInterfaceNameFromGuid!= NULL) {
139             wchar_t *p4=NULL, *p5=NULL;
140             DWORD NameSize;
141
142             /* testing of nhGetInterfaceNameFromGuid indicates the unpublished API function expects the 3rd parameter
143             * to be the available space in bytes (as compared to wchar's) available in the second parameter buffer
144             * to receive the friendly name (in unicode format) including the space for the nul termination.*/
145             NameSize = sizeof(wName);
146
147             /* do the guid->friendlyname lookup */
148             status = Proc_nhGetInterfaceNameFromGuid(guid, wName, &NameSize, p4, p5);
149
150             if(status==0){
151                 haveInterfaceFriendlyName=TRUE; /* success */
152             }
153         }
154     }
155
156     /* we have finished with iphlpapi.dll - release it */
157     FreeLibrary(hIPHlpApi);
158
159     if(!haveInterfaceFriendlyName){
160         /* failed to get the friendly name, nothing further to do */
161         return NULL;
162     }
163
164     /* Get the required buffer size, and then convert the string */
165     size=WideCharToMultiByte(CP_UTF8, 0, wName, -1, NULL, 0, NULL, NULL);
166     name=(char *) g_malloc(size);
167     if (name == NULL){
168         return NULL;
169     }
170     size=WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, size, NULL, NULL);
171     if(size==0){
172         /* bytes written == 0, indicating some form of error*/
173         g_free(name);
174         return NULL;
175     }
176     return name;
177 }
178
179 static int gethexdigit(const char *p)
180 {
181     if(*p >= '0' && *p <= '9'){
182         return *p - '0';
183     }else if(*p >= 'A' && *p <= 'F'){
184         return *p - 'A' + 0xA;
185     }else if(*p >= 'a' && *p <= 'f'){
186         return *p - 'a' + 0xa;
187     }else{
188         return -1; /* Not a hex digit */
189     }
190 }
191
192 static gboolean get8hexdigits(const char *p, DWORD *d)
193 {
194     int digit;
195     DWORD val;
196     int i;
197
198     val = 0;
199     for(i = 0; i < 8; i++){
200         digit = gethexdigit(p++);
201         if(digit == -1){
202             return FALSE; /* Not a hex digit */
203         }
204         val = (val << 4) | digit;
205     }
206     *d = val;
207     return TRUE;
208 }
209
210 static gboolean get4hexdigits(const char *p, WORD *w)
211 {
212     int digit;
213     WORD val;
214     int i;
215
216     val = 0;
217     for(i = 0; i < 4; i++){
218         digit = gethexdigit(p++);
219         if(digit == -1){
220             return FALSE; /* Not a hex digit */
221         }
222         val = (val << 4) | digit;
223     }
224     *w = val;
225     return TRUE;
226 }
227
228 /**********************************************************************************/
229 /* returns the interface friendly name for a device name, if it is unable to
230 * resolve the name, "" is returned */
231 char *
232 get_windows_interface_friendly_name(/* IN */ char *interface_devicename)
233 {
234     const char* guid_text;
235     GUID guid;
236     int i;
237     int digit1, digit2;
238
239     /* ensure we can return a result */
240     if(interface_friendlyname==NULL){
241         return NULL;
242     }
243     /* start on the basis we know nothing */
244     interface_friendlyname=NULL;
245
246     /* Extract the guid text from the interface device name */
247     if(strncmp("\\Device\\NPF_", interface_devicename, 12)==0){
248         guid_text=interface_devicename+12; /* skip over the '\Device\NPF_' prefix, assume the rest is the guid text */
249     }else{
250         guid_text=interface_devicename;
251     }
252
253     /*
254      * If what follows is a GUID in {}, then convert it to a GUID structure
255      * and use that to look up the interface to get its friendly name.
256      */
257     if(*guid_text != '{'){
258         return NULL; /* Nope, not enclosed in {} */
259     }
260     guid_text++;
261     /* There must be 8 hex digits; if so, they go into guid.Data1 */
262     if(!get8hexdigits(guid_text, &guid.Data1)){
263         return NULL; /* nope, not 8 hex digits */
264     }
265     guid_text += 8;
266     /* Now there must be a hyphen */
267     if(*guid_text != '-'){
268         return NULL; /* Nope */
269     }
270     guid_text++;
271     /* There must be 4 hex digits; if so, they go into guid.Data2 */
272     if(!get4hexdigits(guid_text, &guid.Data2)){
273         return NULL; /* nope, not 4 hex digits */
274     }
275     guid_text += 4;
276     /* Now there must be a hyphen */
277     if(*guid_text != '-'){
278         return NULL; /* Nope */
279     }
280     guid_text++;
281     /* There must be 4 hex digits; if so, they go into guid.Data3 */
282     if(!get4hexdigits(guid_text, &guid.Data3)){
283         return NULL; /* nope, not 4 hex digits */
284     }
285     guid_text += 4;
286     /* Now there must be a hyphen */
287     if(*guid_text != '-'){
288         return NULL; /* Nope */
289     }
290     guid_text++;
291     /*
292      * There must be 4 hex digits; if so, they go into the first 2 bytes
293      * of guid.Data4.
294      */
295     for(i = 0; i < 2; i++){
296         digit1 = gethexdigit(guid_text);
297         if(digit1 == -1){
298             return NULL; /* Not a hex digit */
299         }
300         guid_text++;
301         digit2 = gethexdigit(guid_text);
302         if(digit2 == -1){
303             return NULL; /* Not a hex digit */
304         }
305         guid_text++;
306         guid.Data4[i] = (digit1 << 4)|(digit2);
307     }
308     /* Now there must be a hyphen */
309     if(*guid_text != '-'){
310         return NULL; /* Nope */
311     }
312     guid_text++;
313     /*
314      * There must be 12 hex digits; if so,t hey go into the next 6 bytes
315      * of guid.Data4.
316      */
317     for(i = 0; i < 6; i++){
318         digit1 = gethexdigit(guid_text);
319         if(digit1 == -1){
320             return NULL; /* Not a hex digit */
321         }
322         guid_text++;
323         digit2 = gethexdigit(guid_text);
324         if(digit2 == -1){
325             return NULL; /* Not a hex digit */
326         }
327         guid_text++;
328         guid.Data4[i+2] = (digit1 << 4)|(digit2);
329     }
330     /* Now there must be a closing } */
331     if(*guid_text != '}'){
332         return NULL; /* Nope */
333     }
334     guid_text++;
335     /* And that must be the end of the string */
336     if(*guid_text != '\0'){
337         return NULL; /* Nope */
338     }
339
340     /* guid okay, get the interface friendly name associated with the guid */
341     return GetInterfaceFriendlyNameFromDeviceGuid(&guid);
342 }
343
344 /**************************************************************************************/
345 #endif
346