From 9e6487f24751d1c1a047ee82e158077ac67c9c68 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Fri, 4 Jul 2014 00:24:02 -0700 Subject: Move utility routines for capturing into a libcaputils static library. Some of those routines are used only in dumpcap; others are used in TShark and Wireshark as well. Change-Id: I9d92483f2fcff57a7d8b6bf6bdf2870505d19fb7 Reviewed-on: https://code.wireshark.org/review/2841 Reviewed-by: Guy Harris --- caputils/capture_win_ifnames.c | 369 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 caputils/capture_win_ifnames.c (limited to 'caputils/capture_win_ifnames.c') diff --git a/caputils/capture_win_ifnames.c b/caputils/capture_win_ifnames.c new file mode 100644 index 0000000000..b18250f57d --- /dev/null +++ b/caputils/capture_win_ifnames.c @@ -0,0 +1,369 @@ +/* capture_win_ifnames.c +* Routines supporting the use of Windows friendly interface names within Wireshark +* Copyright 2011-2012, Mike Garratt +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "config.h" + +#ifdef _WIN32 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#ifndef NDIS_IF_MAX_STRING_SIZE +#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE /* =256 in */ +#endif + +#ifndef NETIO_STATUS +#define NETIO_STATUS DWORD +#endif + +#include "log.h" + +#include +#include "caputils/capture_win_ifnames.h" +#include "wsutil/file_util.h" + +static int gethexdigit(const char *p) +{ + if(*p >= '0' && *p <= '9'){ + return *p - '0'; + }else if(*p >= 'A' && *p <= 'F'){ + return *p - 'A' + 0xA; + }else if(*p >= 'a' && *p <= 'f'){ + return *p - 'a' + 0xa; + }else{ + return -1; /* Not a hex digit */ + } +} + +static gboolean get8hexdigits(const char *p, DWORD *d) +{ + int digit; + DWORD val; + int i; + + val = 0; + for(i = 0; i < 8; i++){ + digit = gethexdigit(p++); + if(digit == -1){ + return FALSE; /* Not a hex digit */ + } + val = (val << 4) | digit; + } + *d = val; + return TRUE; +} + +static gboolean get4hexdigits(const char *p, WORD *w) +{ + int digit; + WORD val; + int i; + + val = 0; + for(i = 0; i < 4; i++){ + digit = gethexdigit(p++); + if(digit == -1){ + return FALSE; /* Not a hex digit */ + } + val = (val << 4) | digit; + } + *w = val; + return TRUE; +} + +/* + * If a string is a GUID in {}, fill in a GUID structure with the GUID + * value and return TRUE; otherwise, if the string is not a valid GUID + * in {}, return FALSE. + */ +gboolean +parse_as_guid(const char *guid_text, GUID *guid) +{ + int i; + int digit1, digit2; + + if(*guid_text != '{'){ + return FALSE; /* Nope, not enclosed in {} */ + } + guid_text++; + /* There must be 8 hex digits; if so, they go into guid->Data1 */ + if(!get8hexdigits(guid_text, &guid->Data1)){ + return FALSE; /* nope, not 8 hex digits */ + } + guid_text += 8; + /* Now there must be a hyphen */ + if(*guid_text != '-'){ + return FALSE; /* Nope */ + } + guid_text++; + /* There must be 4 hex digits; if so, they go into guid->Data2 */ + if(!get4hexdigits(guid_text, &guid->Data2)){ + return FALSE; /* nope, not 4 hex digits */ + } + guid_text += 4; + /* Now there must be a hyphen */ + if(*guid_text != '-'){ + return FALSE; /* Nope */ + } + guid_text++; + /* There must be 4 hex digits; if so, they go into guid->Data3 */ + if(!get4hexdigits(guid_text, &guid->Data3)){ + return FALSE; /* nope, not 4 hex digits */ + } + guid_text += 4; + /* Now there must be a hyphen */ + if(*guid_text != '-'){ + return FALSE; /* Nope */ + } + guid_text++; + /* + * There must be 4 hex digits; if so, they go into the first 2 bytes + * of guid->Data4. + */ + for(i = 0; i < 2; i++){ + digit1 = gethexdigit(guid_text); + if(digit1 == -1){ + return FALSE; /* Not a hex digit */ + } + guid_text++; + digit2 = gethexdigit(guid_text); + if(digit2 == -1){ + return FALSE; /* Not a hex digit */ + } + guid_text++; + guid->Data4[i] = (digit1 << 4)|(digit2); + } + /* Now there must be a hyphen */ + if(*guid_text != '-'){ + return FALSE; /* Nope */ + } + guid_text++; + /* + * There must be 12 hex digits; if so,t hey go into the next 6 bytes + * of guid->Data4. + */ + for(i = 0; i < 6; i++){ + digit1 = gethexdigit(guid_text); + if(digit1 == -1){ + return FALSE; /* Not a hex digit */ + } + guid_text++; + digit2 = gethexdigit(guid_text); + if(digit2 == -1){ + return FALSE; /* Not a hex digit */ + } + guid_text++; + guid->Data4[i+2] = (digit1 << 4)|(digit2); + } + /* Now there must be a closing } */ + if(*guid_text != '}'){ + return FALSE; /* Nope */ + } + guid_text++; + /* And that must be the end of the string */ + if(*guid_text != '\0'){ + return FALSE; /* Nope */ + } + return TRUE; +} + +/**********************************************************************************/ +gboolean IsWindowsVistaOrLater() +{ +#if (_MSC_VER >= 1800) + /* + * On VS2103, GetVersionEx is deprecated. Microsoft recommend to + * use VerifyVersionInfo instead + */ + OSVERSIONINFOEX osvi; + DWORDLONG dwlConditionMask = 0; + int op = VER_GREATER_EQUAL; + + SecureZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwMajorVersion = 6; + VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op); + return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask); +#else + OSVERSIONINFO osvi; + + SecureZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + if(GetVersionEx(&osvi)){ + return osvi.dwMajorVersion >= 6; + } + return FALSE; +#endif +} + +/**********************************************************************************/ +/* Get the friendly name for the given GUID */ +char * +get_interface_friendly_name_from_device_guid(__in GUID *guid) +{ + HMODULE hIPHlpApi; + HRESULT status; + WCHAR wName[NDIS_IF_MAX_STRING_SIZE + 1]; + HRESULT hr; + gboolean fallbackToUnpublishedApi=TRUE; + gboolean haveInterfaceFriendlyName=FALSE; + int size; + char *name; + + /* Load the ip helper api DLL */ + hIPHlpApi = LoadLibrary(TEXT("iphlpapi.dll")); + if (hIPHlpApi == NULL) { + /* Load failed - DLL should always be available in XP+*/ + return NULL; + } + + /* Need to convert an Interface GUID to the interface friendly name (e.g. "Local Area Connection") + * The functions required to do this all reside within iphlpapi.dll + * - The preferred approach is to use published API functions (Available since Windows Vista) + * - We do however fallback to trying undocumented API if the published API is not available (Windows XP/2k3 scenario) + */ + + if(IsWindowsVistaOrLater()){ + /* Published API function prototypes (for Windows Vista/Windows Server 2008+) */ + typedef NETIO_STATUS (WINAPI *ProcAddr_CIG2L) (__in CONST GUID *InterfaceGuid, __out PNET_LUID InterfaceLuid); + typedef NETIO_STATUS (WINAPI *ProcAddr_CIL2A) ( __in CONST NET_LUID *InterfaceLuid,__out_ecount(Length) PWSTR InterfaceAlias, __in SIZE_T Length); + + /* Attempt to do the conversion using Published API functions */ + ProcAddr_CIG2L proc_ConvertInterfaceGuidToLuid=(ProcAddr_CIG2L) GetProcAddress(hIPHlpApi, "ConvertInterfaceGuidToLuid"); + if(proc_ConvertInterfaceGuidToLuid!=NULL){ + ProcAddr_CIL2A Proc_ConvertInterfaceLuidToAlias=(ProcAddr_CIL2A) GetProcAddress(hIPHlpApi, "ConvertInterfaceLuidToAlias"); + if(Proc_ConvertInterfaceLuidToAlias!=NULL){ + /* we have our functions ready to go, attempt to convert interface guid->luid->friendlyname */ + NET_LUID InterfaceLuid; + hr = proc_ConvertInterfaceGuidToLuid(guid, &InterfaceLuid); + if(hr==NO_ERROR){ + /* guid->luid success */ + hr = Proc_ConvertInterfaceLuidToAlias(&InterfaceLuid, wName, NDIS_IF_MAX_STRING_SIZE+1); + + if(hr==NO_ERROR){ + /* luid->friendly name success */ + haveInterfaceFriendlyName=TRUE; /* success */ + }else{ + /* luid->friendly name failed */ + fallbackToUnpublishedApi=FALSE; + } + }else{ + fallbackToUnpublishedApi=FALSE; + } + + } + } + } + + + if(fallbackToUnpublishedApi && !haveInterfaceFriendlyName){ + /* Didn't manage to get the friendly name using published api functions + * (most likely cause wireshark is running on Windows XP/Server 2003) + * Retry using nhGetInterfaceNameFromGuid (an older unpublished API function) */ + typedef HRESULT (WINAPI *ProcAddr_nhGINFG) (__in GUID *InterfaceGuid, __out PCWSTR InterfaceAlias, __inout DWORD *LengthAddress, wchar_t *a4, wchar_t *a5); + + ProcAddr_nhGINFG Proc_nhGetInterfaceNameFromGuid = NULL; + Proc_nhGetInterfaceNameFromGuid = (ProcAddr_nhGINFG) GetProcAddress(hIPHlpApi, "NhGetInterfaceNameFromGuid"); + if (Proc_nhGetInterfaceNameFromGuid!= NULL) { + wchar_t *p4=NULL, *p5=NULL; + DWORD NameSize; + + /* testing of nhGetInterfaceNameFromGuid indicates the unpublished API function expects the 3rd parameter + * to be the available space in bytes (as compared to wchar's) available in the second parameter buffer + * to receive the friendly name (in unicode format) including the space for the nul termination.*/ + NameSize = sizeof(wName); + + /* do the guid->friendlyname lookup */ + status = Proc_nhGetInterfaceNameFromGuid(guid, wName, &NameSize, p4, p5); + + if(status==0){ + haveInterfaceFriendlyName=TRUE; /* success */ + } + } + } + + /* we have finished with iphlpapi.dll - release it */ + FreeLibrary(hIPHlpApi); + + if(!haveInterfaceFriendlyName){ + /* failed to get the friendly name, nothing further to do */ + return NULL; + } + + /* Get the required buffer size, and then convert the string + * from UTF-16 to UTF-8. */ + size=WideCharToMultiByte(CP_UTF8, 0, wName, -1, NULL, 0, NULL, NULL); + name=(char *) g_malloc(size); + if (name == NULL){ + return NULL; + } + size=WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, size, NULL, NULL); + if(size==0){ + /* bytes written == 0, indicating some form of error*/ + g_free(name); + return NULL; + } + return name; +} + +/* + * Given an interface name, try to extract the GUID from it and parse it. + * If that fails, return NULL; if that succeeds, attempt to get the + * friendly name for the interface in question. If that fails, return + * NULL, otherwise return the friendly name, allocated with g_malloc() + * (so that it must be freed with g_free()). + */ +char * +get_windows_interface_friendly_name(const char *interface_devicename) +{ + const char* guid_text; + GUID guid; + + /* Extract the guid text from the interface device name */ + if(strncmp("\\Device\\NPF_", interface_devicename, 12)==0){ + guid_text=interface_devicename+12; /* skip over the '\Device\NPF_' prefix, assume the rest is the guid text */ + }else{ + guid_text=interface_devicename; + } + + if (!parse_as_guid(guid_text, &guid)){ + return NULL; /* not a GUID, so no friendly name */ + } + + /* guid okay, get the interface friendly name associated with the guid */ + return get_interface_friendly_name_from_device_guid(&guid); +} + +/**************************************************************************************/ +#endif + -- cgit v1.2.1