Skip to content

Commit

Permalink
Merge pull request #61 from finsor/feat/windows-luid-to-guid
Browse files Browse the repository at this point in the history
added guid/luid translations for windows
  • Loading branch information
BobbyAtCore authored Jul 2, 2019
2 parents 44ada26 + 7783fa7 commit 0c58209
Show file tree
Hide file tree
Showing 2 changed files with 289 additions and 0 deletions.
287 changes: 287 additions & 0 deletions pcapy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

#include <pcap.h>
#include <Python.h>
#ifdef WIN32
#include <Iphlpapi.h> // IPHelper API for luid/guid conversions
#endif

#include "pcapy.h"
#include "pcapobj.h"
Expand Down Expand Up @@ -62,7 +65,16 @@ findalldevs(PyObject *self, PyObject *args)
PyObject* list = PyList_New(0);
while(cursor)
{
#ifdef WIN32
/* If we are on windows, then display LUID's like "Local Area Connection"
* instead of GUID's like "\Device\NPF_{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}".
*/
char *luid = get_windows_interface_friendly_name(cursor->name);
PyList_Append(list, Py_BuildValue("s", luid));
free(luid);
#else
PyList_Append(list, Py_BuildValue("s", cursor->name));
#endif
cursor = cursor->next;
}

Expand All @@ -86,6 +98,12 @@ open_live(PyObject *self, PyObject *args)
if(!PyArg_ParseTuple(args,"siii:open_live",&device,&snaplen,&promisc,&to_ms))
return NULL;

#ifdef WIN32
/* If we are on windows, then device is an LUID like "Local Area Connection".
* pcap on Windows needs a GUID like "\Device\NPF_{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}".
*/
device = luid_to_guid(device);
#endif
int status = pcap_lookupnet(device, &net, &mask, errbuff);
if(status)
{
Expand All @@ -96,6 +114,10 @@ open_live(PyObject *self, PyObject *args)
pcap_t* pt;

pt = pcap_open_live(device, snaplen, promisc!=0, to_ms, errbuff);
#ifdef WIN32
free(device);
#endif

if(!pt)
{
PyErr_SetString(PcapError, errbuff);
Expand Down Expand Up @@ -319,3 +341,268 @@ initpcapy(void)
#endif //PY_MAJOR_VERSION >= 3
}
/* vim: set tabstop=2 shiftwidth=2 expandtab: */

#ifdef WIN32
/* All of the following code takes care of LUID/GUID conversions.
* Copied from Wireshark.
*/

static BOOL 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 BOOL 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 BOOL 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;
}

static BOOL
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;
}


static char* luid_to_guid(char *luid)
{
char errbuff[PCAP_ERRBUF_SIZE];
pcap_if_t *devs;

int status = pcap_findalldevs(&devs, errbuff);
if(status)
{
PyErr_SetString(PcapError, errbuff);
return NULL;
}

if(devs==NULL)
{
PyErr_SetString(PcapError, "No valid interfaces to open");
return NULL;
}

pcap_if_t *cursor = devs;

char* cursor_luid;
char *ret_guid = NULL;
while(cursor)
{
cursor_luid = get_windows_interface_friendly_name(cursor->name);


if (!strcmp(cursor_luid, luid))
{
ret_guid = strdup(cursor->name);
goto done;
}

free(cursor_luid);

cursor = cursor->next;
}

done:

pcap_freealldevs(devs);

return ret_guid;
}

static char* guid_to_luid(GUID *guid)
{
BOOL status;
int size;
char *name;

WCHAR wName[128 + 1];
HMODULE hIPHlpApi = LoadLibrary(TEXT("iphlpapi.dll"));

typedef HRESULT (WINAPI *ProcAddr_nhGINFG) ( GUID *InterfaceGuid, PCWSTR InterfaceAlias, 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 = ( 0 == Proc_nhGetInterfaceNameFromGuid(guid, wName, &NameSize, p4, p5) );
}

/* we have finished with iphlpapi.dll - release it */
FreeLibrary(hIPHlpApi);

if(FALSE == status){
/* 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 *) 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*/
free(name);
return NULL;
}
return name;
}

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 strdup(interface_devicename); /* not a GUID, so no friendly name */
}

/* guid okay, get the interface friendly name associated with the guid */
return guid_to_luid(&guid);
}
#endif
2 changes: 2 additions & 0 deletions pcapy.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
extern "C" {
#ifdef WIN32
__declspec(dllexport)
char *get_windows_interface_friendly_name(const char *interface_devicename);
static char* luid_to_guid(char *luid);
#endif

#if PY_MAJOR_VERSION >= 3
Expand Down

0 comments on commit 0c58209

Please sign in to comment.