Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Errors building libdnet for x64 and python 2.7 #3

Open
newlog opened this issue Mar 10, 2015 · 13 comments
Open

Errors building libdnet for x64 and python 2.7 #3

newlog opened this issue Mar 10, 2015 · 13 comments

Comments

@newlog
Copy link

newlog commented Mar 10, 2015

Hello,

First of all, thanks for creating this fork. I've ended here after having to fight with the "WARNING: No match between your pcap and dnet network interfaces found." error without success.

So I've tried to build your fork in my Windows 8.1 x64 machine with Python 2.7. I've had a lot of problems and I'd be really grateful if you could help me.

These are the steps I've followed:

  1. I've cloned you repository and executed the autogen.sh script inside Cygwin, having MinGW also installed.
    This gave me a lot of trouble, basically for using libtool from MinGW instead of the one from Cygwin. So I uninstalled the one from MinGW and installed the one from Cygwin. After this, the autogen.sh worked and the configure file was created.
  2. I executed ./configure and failed when checking for Python, it seemed a MinGW32 issue. So I installed a bunch of MinGW packages of 32 bits such as headers and so. Don't know exactly how, but this solved the problem.
    Nevertheless, the ./configure failed again. Now the problem was because of winpcap developer library not found. So I executed configure as:
    ./configure --with-wpdpack=<path_to_lib>
  3. Then I cd python and executed /c/cygdrive/python2.7/python.exe setup.py build and got this error:
$ /cygdrive/c/Python27/python.exe setup.py build
running build
running build_ext
building 'dnet' extension
error: Unable to find vcvarsall.bat

First real unsolved problem here. So instead of using OS python.exe I've also tried to use cygwin python. I got this error:

$ /usr/bin/python2.7 setup.py build
running build
running build_ext
building 'dnet' extension
gcc -fno-strict-aliasing -ggdb -O2 -pipe -Wimplicit-function-declaration -fdebug-prefix-map=/usr/src/ports/python/python-2.7.8-1.x86_64/build=/usr/src/debug/python-2.7.8-1 -fdebug-prefix-map=/usr/src/ports/python/python-2.7.8-1.x86_64/src/Python-2.7.8=/usr/src/debug/python-2.7.8-1 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I../include -I/usr/include/python2.7 -c ./dnet.c -o build/temp.cygwin-1.7.34-x86_64-2.7/./dnet.o
./dnet.c:4:20: fatal error: Python.h: No such file or directory
 #include "Python.h"
                    ^
compilation terminated.
error: command 'gcc' failed with exit status 1

Seems that Python.h is not found, although it's in the /usr/include/Python2.7 folder. I've added it to PATH with export PATH="$PATH:/usr/include/python2.7" but it gave the same error.

Then I came back to the Unable to find vcvarsall.bat error. Still from cygwin I executed:

$ export DISTUTILS_USE_SDK=1
$ export MSSdk=1
$ /cygdrive/c/Python27/python.exe setup.py build
running build
running build_ext
building 'dnet' extension
cl.exe /c /nologo /Ox /MD /W3 /GS- /DNDEBUG -I../include -I../../WPdpack/Include -IC:\Python27\include -IC:\Python27\PC /Tc./dnet.c /Fobuild\temp.win-amd64-2.7\Release\./dnet.obj
error: command 'cl.exe' failed: No such file or directory

Ok, this problem about not locating 'cl.exe' is because if you use the OS python.exe and you have not built it, the compiler that was used to build it is used to build the python extension. I've tried to add the location of cl.exe folder in path (export PATH="$PATH:/cygwin/c/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin/x86_amd64"), but it didn't work.So...

Next step was to open Visual C++ 2008 64-bits Command Prompt so cl.exe is easily found. I exported the symbols mentioned before and executed:

>C:\Python27\python.exe setup.py build
running build
running build_ext
building 'dnet' extension
C:\Users\windows8\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\cl.exe /c /nologo /Ox /MD /W3 /GS- /DNDEBUG -I../include -I../../WPdpac
k/Include -IC:\Python27\include -IC:\Python27\PC /Tc./dnet.c /Fobuild\temp.win-amd64-2.7\Release\./dnet.obj
dnet.c
../include\dnet/os.h(29) : error C2371: 'ssize_t' : redefinition; different basic types
        c:\python27\include\pyconfig.h(200) : see declaration of 'ssize_t'
../include\dnet/os.h(151) : fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory
error: command 'C:\\Users\\windows8\\AppData\\Local\\Programs\\Common\\Microsoft\\Visual C++ for Python\\9.0\\VC\\Bin\\amd64\\cl.exe' failed with exit status 2

This is the REAL problem. It seems that python already defines the ssize_t type in pyconfig.h. I could remove declarations or make them match. The best approach was to make them match types (modifying __int64 for long) by modifying line 199 of pyconfig.h:

#ifdef MS_WIN64
typedef long ssize_t;
#else
typedef _W64 int ssize_t;
#endif

This solved the problem of redefinitions, but still remained the fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory.

I've tried to comment this includes in os.h and intf.h, but it ended up giving me this error after a large number of warnings:

C:\Users\windows8\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\cl.exe /c /nologo /Ox /MD /W3 /GS- /DNDEBUG -I../include -I../../WPdpac
k/Include -IC:\Python27\include -IC:\Python27\PC /Tc../src/addr-util.c /Fobuild\temp.win-amd64-2.7\Release\../src/addr-util.obj
addr-util.c
c:\users\windows8\appdata\local\programs\common\microsoft\visual c++ for python\9.0\vc\include\codeanalysis\sourceannotations.h(17) : warning C4114: same type qualifier
 used more than once
c:\users\windows8\appdata\local\programs\common\microsoft\visual c++ for python\9.0\vc\include\codeanalysis\sourceannotations.h(17) : error C2632: '__int64' followed by
 'int' is illegal
c:\users\windows8\appdata\local\programs\common\microsoft\visual c++ for python\9.0\vc\include\codeanalysis\sourceannotations.h(17) : warning C4091: 'typedef ' : ignore
d on left of 'unsigned __int64' when no variable is declared
C:\Users\windows8\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Include\string.h(81) : warning C4391: 'unsigned int strlen(char *)' : incorrect r
eturn type for intrinsic function, expected 'unsigned __int64'
C:\Users\windows8\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Include\string.h(254) : warning C4391: 'unsigned int wcslen(wchar_t *)' : incorre
ct return type for intrinsic function, expected 'unsigned __int64'
../src/addr-util.c(223) : warning C4244: 'function' : conversion from '__int64' to 'unsigned int', possible loss of data
error: command 'C:\\Users\\windows8\\AppData\\Local\\Programs\\Common\\Microsoft\\Visual C++ for Python\\9.0\\VC\\Bin\\amd64\\cl.exe' failed with exit status 2

I realised that the lack of stdint.h was because of Microsoft VC 2008 didn't supported some C99 features, so I tried with VC 2013. After removing comments from the stdint.h includes (I also could remove the modification of pyconfig.h) I executed the same command from the Developer Command Prompt for VS 2013 and got the following (complete) output:

>c:\Python27\python.exe setup.py build
running build
running build_ext
building 'dnet' extension
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe /c /nologo /Ox /MD /W3 /GS- /
DNDEBUG -I../include -I../../WPdpack/Include -Ic:\Python27\include -Ic:\Python27\PC /Tc./dnet.c
 /Fobuild\temp.win-amd64-2.7\Release\./dnet.obj
dnet.c
../include\dnet/os.h(29) : warning C4142: benign redefinition of type
./dnet.c(691) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(916) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(1485) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(1491) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(1810) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(1816) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(1935) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(1941) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(2044) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(2050) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(2464) : warning C4102: '__pyx_L4' : unreferenced label
./dnet.c(2462) : warning C4102: '__pyx_L3' : unreferenced label
./dnet.c(2748) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(2754) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(3118) : warning C4090: 'function' : different 'const' qualifiers
./dnet.c(3118) : warning C4028: formal parameter 1 different from declaration
./dnet.c(3211) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(3567) : warning C4018: '<' : signed/unsigned mismatch
./dnet.c(3591) : warning C4102: '__pyx_L7' : unreferenced label
./dnet.c(3589) : warning C4102: '__pyx_L6' : unreferenced label
./dnet.c(3647) : warning C4013: 'strlcpy' undefined; assuming extern returning int
./dnet.c(3655) : warning C4244: '=' : conversion from 'long' to 'unsigned short', possible loss
 of data
./dnet.c(3730) : warning C4018: '<' : signed/unsigned mismatch
./dnet.c(3745) : warning C4102: '__pyx_L9' : unreferenced label
./dnet.c(3743) : warning C4102: '__pyx_L8' : unreferenced label
./dnet.c(4135) : warning C4090: 'function' : different 'const' qualifiers
./dnet.c(4135) : warning C4028: formal parameter 1 different from declaration
./dnet.c(4225) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(4556) : warning C4090: 'function' : different 'const' qualifiers
./dnet.c(4556) : warning C4028: formal parameter 1 different from declaration
./dnet.c(4646) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(5216) : warning C4090: 'function' : different 'const' qualifiers
./dnet.c(5216) : warning C4028: formal parameter 1 different from declaration
./dnet.c(5306) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(5640) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(5730) : warning C4018: '>' : signed/unsigned mismatch
./dnet.c(5736) : warning C4102: '__pyx_L5' : unreferenced label
./dnet.c(5729) : warning C4102: '__pyx_L4' : unreferenced label
./dnet.c(5798) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(5817) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(5890) : warning C4102: '__pyx_L6' : unreferenced label
./dnet.c(5888) : warning C4102: '__pyx_L5' : unreferenced label
./dnet.c(5854) : warning C4102: '__pyx_L3' : unreferenced label
./dnet.c(6146) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(6180) : warning C4102: '__pyx_L1' : unreferenced label
./dnet.c(6421) : warning C4101: 'e' : unreferenced local variable
./dnet.c(6575) : warning C4101: 'e' : unreferenced local variable
./dnet.c(6718) : warning C4101: 'e' : unreferenced local variable
./dnet.c(6947) : warning C4101: 'e' : unreferenced local variable
./dnet.c(7098) : warning C4101: 'e' : unreferenced local variable
./dnet.c(7253) : warning C4101: 'e' : unreferenced local variable
./dnet.c(7409) : warning C4101: 'e' : unreferenced local variable
./dnet.c(7564) : warning C4101: 'e' : unreferenced local variable
./dnet.c(7718) : warning C4101: 'e' : unreferenced local variable
./dnet.c(7867) : warning C4101: 'e' : unreferenced local variable
./dnet.c(8018) : warning C4101: 'e' : unreferenced local variable
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe /c /nologo /Ox /MD /W3 /GS- /
DNDEBUG -I../include -I../../WPdpack/Include -Ic:\Python27\include -Ic:\Python27\PC /Tc../src/a
ddr-util.c /Fobuild\temp.win-amd64-2.7\Release\../src/addr-util.obj
addr-util.c
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\crtdefs.h(496) : warning C4114:
same type qualifier used more than once
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\crtdefs.h(496) : error C2632: 'i
nt' followed by 'int' is illegal
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\crtdefs.h(496) : warning C4091:
'typedef ' : ignored on left of '__w64 unsigned int' when no variable is declared
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\BIN\\cl.exe' failed
with exit status 2

Seems that the problem is that size_t is already defined as int so the following code in crtdefs.h fails:

#ifndef _SIZE_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64    size_t;
#else  /* _WIN64 */
typedef _W64 unsigned int   size_t;      <--
#endif  /* _WIN64 */
#define _SIZE_T_DEFINED
#endif  /* _SIZE_T_DEFINED */

It seems that there's again a redefinition. I've found it in libdnet source at include/config.h in line 270:

/* Define to `unsigned int' if <sys/types.h> does not define. */
//#define size_t unsigned int

After commenting it, the build process has continued with a lot of warnings until this error:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe /c /nologo /Ox /MD /W3 /GS- /
DNDEBUG -I../include -I../../WPdpack/Include -Ic:\Python27\include -Ic:\Python27\PC /Tc../src/e
th-win32.c /Fobuild\temp.win-amd64-2.7\Release\../src/eth-win32.obj
eth-win32.c
../src/eth-win32.c(20) : fatal error C1083: Cannot open include file: 'pcap.h': No such file or
 directory
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\BIN\\cl.exe' failed
with exit status 2

Given that the libdnet doesn't have any pcap.h file, I guess that this file must refer to the winpcap development library. So I try to add the correct directory to the INCLUDE environment variable with set INCLUDE=%INCLUDE%;<path_to_winpcap_dev>\WpdPack_4_1_2\WpdPack\Include

There are two pcap.h files. One in the Include directory and another in the Include\pcap directory. I've tried to add both of them in the INCLUDE environment, but neither worked. I finally got a long list of new errors:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe /c /nologo /Ox /MD /W3 /GS- /
DNDEBUG -I../include -I../../WPdpack/Include -Ic:\Python27\include -Ic:\Python27\PC /Tc../src/f
w-pktfilter.c /Fobuild\temp.win-amd64-2.7\Release\../src/fw-pktfilter.obj
fw-pktfilter.c
C:\Program Files (x86)\Windows Kits\8.1\include\shared\ipifcons.h(246) : error C2061: syntax er
ror : identifier 'IFTYPE'
C:\Program Files (x86)\Windows Kits\8.1\include\shared\ipifcons.h(246) : error C2059: syntax er
ror : ';'
C:\Program Files (x86)\Windows Kits\8.1\include\shared\iprtrmib.h(145) : error C2016: C require
s that a struct or union has at least one member
C:\Program Files (x86)\Windows Kits\8.1\include\shared\iprtrmib.h(145) : error C2061: syntax er
ror : identifier 'DWORD'
C:\Program Files (x86)\Windows Kits\8.1\include\shared\iprtrmib.h(146) : error C2061: syntax er
ror : identifier 'rgdwVarIndex'
(...)

So I'm stuck here and I don't know what else to do. This is a nightmare, guys. How could you build this? I'm defeated....

Thank you very much for reading until here.

@newlog newlog changed the title Error building libdnet Errors building libdnet for x64 and python 2.7 Mar 10, 2015
@rgom
Copy link

rgom commented May 24, 2015

I've been able to compile this beast in very similar environment.
I'll try to describe the details later, but there are the following key points:

  • code can't be compiled on Microsoft Python Visual Studio 9, as recommened in all places - there's no stdint.h
  • distutils import in setup.py(.in) shall be replaced with setuptools - the same API, much better handling of vcvarsall.bat
  • source has to be fixed - intf-win32.c - added MAX_LEN define and added declarations of some vars in the beginning of some function instead of the middle to make compiler happy

I haven't verified the executable yet.
I'll have to clean up all artifcacts and provide clean instruction. Hopefully they can be turned into valid pull requests.

Robert

@rgom
Copy link

rgom commented May 25, 2015

For the time being I'm posting the exact steps. I hope I'll send patches later on.

  1. Build
    • Install cygwin build tools (autoconf, automake, libtool)

    • start cmd

    • run "c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" (VC 10)

    • run c:\cygwin\cygwin.bat

    • run ./autogen.sh

    • run ./configure --with-wpdpack=c:/temp/scapy-new/WpdPack

    • Modify setup.py

      #from distutils.core import setup, Extension
      from setuptools import setup, Extension
      

      and this

        # ROGO - below line modified to contain wpcap
        dnet_libs.extend([ 'advapi32', 'iphlpapi', 'ws2_32', 'packet', 'wpcap' ])
      
    • modify sources

        /* (intf-win32.c) */
      IP_ADAPTER_UNICAST_ADDRESS *addr;
      char friendly_name[MAX_INTERFACE_NAME_LEN];
      const char *name_start;
      /* The total length of the entry may be passed inside entry.
         Remember it and clear the entry. */
      u_int intf_len = entry->intf_len;
      memset(entry, 0, sizeof(*entry));
      entry->intf_len = intf_len;
      
      type = _if_type_canonicalize(a->IfType);
      for (i = 0; i < intf->ifcombo[type].cnt; i++) {
      if (intf->ifcombo[type].idx[i].ipv4 == a->IfIndex &&
          intf->ifcombo[type].idx[i].ipv6 == a->Ipv6IfIndex) {
          break;
      }
      }
      /* XXX - type matches MIB-II ifType. */
      snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu",
      _ifcombo_name(a->IfType), i);
      entry->intf_type = (uint16_t)type;
      strncpy_wchar(friendly_name, a->FriendlyName, MAX_INTERFACE_NAME_LEN);
      snprintf(entry->os_intf_name, MAX_INTERFACE_NAME_LEN, "%s %s", friendly_name,
      a->AdapterName);
      entry->os_intf_name[MAX_INTERFACE_NAME_LEN - 1] = '\0';
      
      name_start = strstr(a->AdapterName, "{");
      if (name_start) {
      snprintf(entry->pcap_intf_name, MAX_INTERFACE_NAME_LEN - 1,
          "\\Device\\NPF_%s", name_start);
      }
      

      and add to the top:

      #define MAX_INTERFACE_NAME_LEN 255
      
    • quit cygwin with exit

    • python setup.py build --compiler=msvc

    • python setup.py bdist_wheel

Notes:

  1. Don't use mingw
  2. The following wouldn't work - there's no stdint.h in MSVC9:
    Install Python 2.7 MS visual from http://aka.ms/vcpython27 (http://www.microsoft.com/en-us/download/details.aspx?id=44266)
    (http://blog.ionelmc.ro/2014/12/21/compiling-python-extensions-on-windows/)
    I've used MSVC 10

@rgom
Copy link

rgom commented May 25, 2015

Despite compiling it successfully 1.13 seems to be broken.
There were numerous changes pulled in (e.g. from nmap), at least one of them broke get_dst() (intf-win32), which is now just unsupported (https://github.com/nmap/nmap/tree/master/libdnet-stripped)
Add to the above fact that the code required modifications in order to become compilable, it's status on win32 is poor.

I'll look into fixing things, but that will take several weeks/months.

Regards,
Robert

@rgom
Copy link

rgom commented Jun 1, 2015

Build requirements

Build

  • Apply a patch (not included here)
  • start cmd
  • run: (default installation directory of MSVC 9 for Python)
   c:\Users\rgomulk\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\vcvarsall.bat
  • c:\cygwin\cygwin.bat
  • ./autogen.sh
  • ./configure --with-wpdpack=../WpdPack
  • run pyrex
    (or use provided dnet.c if there are no changes to dnet.pyx in further builds):
   c:\Python27\python.exe c:\Python27\Scripts\pyrexc.py dnet.pyx
  • quit cygwin with exit
  • c:\python27\python setup.py build --compiler=msvc
  • c:\python27\python setup.py bdist_wheel

@rgom
Copy link

rgom commented Jun 1, 2015

diff -r -u libdnet-orig/include/config.h.in libdnet-master/include/config.h.in
--- libdnet-orig/include/config.h.in    2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/include/config.h.in  2015-05-29 11:15:16.832308200 +0200
@@ -220,8 +220,7 @@
 /* Define to 1 if you have the <winsock2.h> header file. */
 #undef HAVE_WINSOCK2_H

-/* Define to the sub-directory in which libtool stores uninstalled libraries.
-   */
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
 #undef LT_OBJDIR

 /* Name of package */
diff -r -u libdnet-orig/include/dnet/intf.h libdnet-master/include/dnet/intf.h
--- libdnet-orig/include/dnet/intf.h    2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/include/dnet/intf.h  2015-05-29 21:47:32.298636100 +0200
@@ -11,8 +11,16 @@
 #ifndef DNET_INTF_H
 #define DNET_INTF_H

-#include <stdint.h>
+#ifdef _MSC_VER
+
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;

+#else
+#include <stdint.h>
+#endif
 /*
  * Interface entry
  */
diff -r -u libdnet-orig/include/dnet/os.h libdnet-master/include/dnet/os.h
--- libdnet-orig/include/dnet/os.h  2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/include/dnet/os.h    2015-05-29 21:53:47.895192000 +0200
@@ -148,7 +148,16 @@
 #define dnet_ntohl(val) (val)
 #define dnet_ntohll(val) (val)
 #else
+#ifdef _MSC_VER
+
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#else
 #include <stdint.h>
+#endif
 #define dnet_htons(val) htons(val)
 #define dnet_htonl(val) htonl(val)
 #define dnet_htonll(val) (((uint64_t)htonl(val) << 32) | htonl((uint64_t)(val) >> 32))
Only in libdnet-master: libdnet.spec.bak
diff -r -u libdnet-orig/python/dnet.pyx libdnet-master/python/dnet.pyx
--- libdnet-orig/python/dnet.pyx    2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/python/dnet.pyx  2015-05-29 17:51:01.451833000 +0200
@@ -16,7 +16,7 @@
 __copyright__ = 'Copyright (c) 2003 Dug Song'
 __license__ = 'BSD'
 __url__ = 'http://libdnet.sourceforge.net/'
-__version__ = '1.12'
+__version__ = '1.12.1rg'

 cdef extern from "dnet.h":
     pass
@@ -37,6 +37,7 @@
     void   *memset(char *b, int c, int len)
     char   *strerror(int errnum)
     int     strlcpy(char *dst, char *src, int size)
+    int     strlen(char *src)
     unsigned long htonl(unsigned long n)
     unsigned long ntohl(unsigned long n)

@@ -160,7 +161,7 @@
     return PyString_FromStringAndSize(ea.data, 6)

 def eth_pack_hdr(dst=ETH_ADDR_BROADCAST, src=ETH_ADDR_BROADCAST,
-                 type=ETH_TYPE_IP):
+                 typee=ETH_TYPE_IP):
     """Return a packed binary string representing an Ethernet header.

     Keyword arguments:
@@ -172,7 +173,7 @@
     cdef eth_addr_t s, d
     __memcpy(s.data, src, 6)
     __memcpy(d.data, dst, 6)
-    __eth_pack_hdr(hdr, d, s, type)
+    __eth_pack_hdr(hdr, d, s, typee)
     return PyString_FromStringAndSize(hdr, 14)

 #
@@ -441,7 +442,7 @@
     """
     cdef addr_t _addr

-    def __init__(self, addrtxt=None, type=ADDR_TYPE_NONE):
+    def __init__(self, addrtxt=None, typee=ADDR_TYPE_NONE):
         if addrtxt != None and addr_aton(addrtxt, &self._addr) < 0:
             if PyString_Size(addrtxt) == 4:
                 self._addr.addr_type = ADDR_TYPE_IP
@@ -785,7 +786,7 @@
 cdef extern from *:
     void __icmp_pack_hdr "icmp_pack_hdr" (char *hdr, int type, int code)

-def icmp_pack_hdr(type, code):
+def icmp_pack_hdr(typee, code):
     """Return a packed binary string representing an ICMP header.

     Keyword arguments:
@@ -793,7 +794,7 @@
     code -- ICMP code      (8-bit integer)
     """
     cdef char buf[4]
-    __icmp_pack_hdr(buf, type, code)
+    __icmp_pack_hdr(buf, typee, code)
     return PyString_FromStringAndSize(buf, sizeof(buf))

 #
@@ -909,6 +910,7 @@
     int     intf_set(intf_t *intf, intf_entry *entry)
     int     intf_loop(intf_t *intf, intf_handler callback, void *arg)
     intf_t *intf_close(intf_t *intf)
+    int     intf_get_pcap_devname(char *intf_name, char *pcapdev, int pcapdevlen)

 INTF_TYPE_OTHER =  1   # /* other */
 INTF_TYPE_ETH =        6   # /* Ethernet */
@@ -958,7 +960,28 @@
         entry.intf_alias_num = len(d['alias_addrs'])
         for i from 0 <= i < entry.intf_alias_num:
             entry.intf_alias_addrs[i] = (<addr>d['alias_addrs'][i])._addr
-
+"""
+int     intf_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen)
+"""
+def get_pcap_devname(intf_name):
+    """ Get pcap device name from our device name.
+    
+    Arguments:
+        intf_name - 'eth0', 'eth1', 'eth2', ...
+        
+    Output:
+        pcap interface name
+    """
+    
+    cdef char pcapdev[128]
+    if intf_name is not None:
+        if (intf_get_pcap_devname(intf_name, pcapdev, sizeof(pcapdev)) != -1):
+            return PyString_FromStringAndSize(pcapdev, strlen(pcapdev))
+        else:
+            raise RuntimeError("Pcap interface for intf_name '%s' not found" % intf_name)
+    else:
+        return None
+    
 cdef int __intf_callback(intf_entry *entry, void *arg) except -1:
     f, a = <object>arg
     ret = f(ifent_to_dict(entry), a)
@@ -1013,7 +1036,7 @@
         if intf_get_dst(self.intf, ifent, &dst._addr) < 0:
             raise OSError, __oserror()
         return ifent_to_dict(ifent)
-    
+
     def set(self, d):
         """Set the configuration for an interface from a dict.

diff -r -u libdnet-orig/python/setup.py.in libdnet-master/python/setup.py.in
--- libdnet-orig/python/setup.py.in 2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/python/setup.py.in   2015-05-28 21:33:45.242841200 +0200
@@ -1,7 +1,7 @@
 #!/usr/bin/env python

 import glob, os, sys
-from distutils.core import setup, Extension
+from setuptools import setup, Extension

 dnet_srcs = [ '@srcdir@/dnet.c' ]
 dnet_incdirs = [ '@top_srcdir@/include' ]
@@ -15,7 +15,7 @@
     dnet_srcs.extend(['../src/addr-util.c', '../src/addr.c', '../src/blob.c', '../src/ip-util.c', '../src/ip6.c', '../src/rand.c', '../src/err.c', '../src/strlcat.c', '../src/strlcpy.c', '../src/err.c', '../src/strlcat.c', '../src/strlcpy.c', '../src/strsep.c', '../src/arp-win32.c', '../src/eth-win32.c', '../src/fw-pktfilter.c', '../src/intf-win32.c', '../src/ip-win32.c', '../src/route-win32.c', '../src/tun-none.c'])
     dnet_incdirs.append(winpcap_dir + '/Include')
     dnet_libdirs.append(winpcap_dir + '/Lib')
-    dnet_libs.extend([ 'advapi32', 'iphlpapi', 'ws2_32', 'packet' ])
+    dnet_libs.extend([ 'advapi32', 'iphlpapi', 'ws2_32', 'packet', 'wpcap' ])
 else:
     # XXX - can't build on Cygwin+MinGW yet.
     #if sys.platform == 'cygwin':
diff -r -u libdnet-orig/src/intf-win32.c libdnet-master/src/intf-win32.c
--- libdnet-orig/src/intf-win32.c   2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/src/intf-win32.c 2015-06-01 09:50:11.468751700 +0200
@@ -89,6 +89,7 @@
    } else if (strncmp(device, "tun", 3) == 0) {
        type = INTF_TYPE_TUN;
    }
+
    return (type);
 }

@@ -131,10 +132,12 @@
    int i;
    int type;
    IP_ADAPTER_UNICAST_ADDRESS *addr;
-
+   char friendly_name[MAX_INTERFACE_NAME_LEN];
+        const char *name_start;
    /* The total length of the entry may be passed inside entry.
            Remember it and clear the entry. */
    u_int intf_len = entry->intf_len;
+    
    memset(entry, 0, sizeof(*entry));
    entry->intf_len = intf_len;

@@ -149,13 +152,12 @@
    snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu",
        _ifcombo_name(a->IfType), i);
    entry->intf_type = (uint16_t)type;
-   char friendly_name[MAX_INTERFACE_NAME_LEN];
    strncpy_wchar(friendly_name, a->FriendlyName, MAX_INTERFACE_NAME_LEN);
    snprintf(entry->os_intf_name, MAX_INTERFACE_NAME_LEN, "%s %s", friendly_name,
        a->AdapterName);
    entry->os_intf_name[MAX_INTERFACE_NAME_LEN - 1] = '\0';

-   const char *name_start = strstr(a->AdapterName, "{");
+   name_start = strstr(a->AdapterName, "{");
    if (name_start) {
        snprintf(entry->pcap_intf_name, MAX_INTERFACE_NAME_LEN - 1,
            "\\Device\\NPF_%s", name_start);
@@ -277,7 +279,17 @@
    char *p = (char *)device;
    int n, type = _ifcombo_type(device);

+    /* only ethernet supported (and as a safeguard for invalid
+       interfaces names, leading to crash */
+    if (type != INTF_TYPE_ETH)
+        return NULL;
+    
    while (isalpha((int) (unsigned char) *p)) p++;
+    
+    /* poor check - first digits only - eth0a will be still treated as eth0*/
+    if (!isdigit((int) (unsigned char) *p))
+        return NULL;
+    
    n = atoi(p);

    for (a = intf->iftable; a != NULL; a = a->Next) {
@@ -377,9 +389,28 @@
 int
 intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst)
 {
-   errno = ENOSYS;
-   SetLastError(ERROR_NOT_SUPPORTED);
+    IP_ADAPTER_ADDRESSES *a;
+    DWORD intfIdx;
+
+    if (dst->addr_type != ADDR_TYPE_IP) {
+   errno = EINVAL;
+   return (-1);
+    }
+
+    if (_refresh_tables(intf) < 0)
    return (-1);
+
+    if (GetBestInterface(dst->addr_ip, &intfIdx) != NO_ERROR)
+        return (-1);
+
+    for (a = intf->iftable; a != NULL; a = a->Next) {
+        if (a->IfIndex == intfIdx) {
+            _adapter_address_to_entry(intf, a, entry);
+            return (0);
+        }
+    }
+    
+    return (-1);
 }

 int
@@ -447,10 +478,12 @@

    if ((intf = intf_open()) == NULL)
        return (-1);
+    
    if (_refresh_tables(intf) < 0) {
        intf_close(intf);
        return (-1);
    }
+    
    a = _find_adapter_address(intf, intf_name);

    if (a == NULL) {

@rgom
Copy link

rgom commented Jun 1, 2015

After the above dnet can be compiled successfully, but will have some issues interacting with scapy+pcap. The following scapy patch should address scapy issues:

diff -r -u scapy-2.3.1-orig/scapy/arch/pcapdnet.py scapy-2.3.1/scapy/arch/pcapdnet.py
--- scapy-2.3.1-orig/scapy/arch/pcapdnet.py 2014-12-23 11:24:06.000000000 +0100
+++ scapy-2.3.1/scapy/arch/pcapdnet.py  2015-06-01 10:05:29.426547700 +0200
@@ -43,6 +43,10 @@
         if hasattr(pcap,"pcap"): # python-pypcap
             class _PcapWrapper_pypcap:
                 def __init__(self, device, snaplen, promisc, to_ms):
+                    # avoid interfaces mapping in pcap
+                    # there's a lot of guessing going on there
+                    # give pcap its own name
+                    # and the interfaces can easily be incorrectly mapped
                     try:
                         self.pcap = pcap.pcap(device, snaplen, promisc, immediate=1, timeout_ms=to_ms)
                     except TypeError:
diff -r -u scapy-2.3.1-orig/scapy/arch/windows/__init__.py scapy-2.3.1/scapy/arch/windows/__init__.py
--- scapy-2.3.1-orig/scapy/arch/windows/__init__.py 2014-12-23 11:24:06.000000000 +0100
+++ scapy-2.3.1/scapy/arch/windows/__init__.py  2015-06-01 10:06:20.396644200 +0200
@@ -109,48 +109,16 @@
     def _update_pcapdata(self):
         """Supplement more info from pypcap and the Windows registry"""

-        # XXX: We try eth0 - eth29 by bruteforce and match by IP address, 
-        # because only the IP is available in both pypcap and dnet.
-        # This may not work with unorthodox network configurations and is
-        # slow because we have to walk through the Windows registry.
-        for n in range(30):
-            guess = "eth%s" % n
-            win_name = pcapdnet.pcap.ex_name(guess)
-            if win_name.endswith("}"):
-                try:
-                    uuid = win_name[win_name.index("{"):win_name.index("}")+1]
-                    keyname = r"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\%s" % uuid
-                    try:
-                        key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyname)
-                    except WindowsError:
-                        log_loading.debug("Couldn't open 'HKEY_LOCAL_MACHINE\\%s' (for guessed pcap iface name '%s')." % (keyname, guess))
-                        continue
-                    try:    
-                        fixed_ip = _winreg.QueryValueEx(key, "IPAddress")[0][0].encode("utf-8")
-                    except (WindowsError, UnicodeDecodeError, IndexError):
-                        fixed_ip = None
-                    try:
-                        dhcp_ip = _winreg.QueryValueEx(key, "DhcpIPAddress")[0].encode("utf-8")
-                    except (WindowsError, UnicodeDecodeError, IndexError):
-                        dhcp_ip = None
-                    # "0.0.0.0" or None means the value is not set (at least not correctly).
-                    # If both fixed_ip and dhcp_ip are set, fixed_ip takes precedence 
-                    if fixed_ip is not None and fixed_ip != "0.0.0.0":
-                        ip = fixed_ip
-                    elif dhcp_ip is not None and dhcp_ip != "0.0.0.0":
-                        ip = dhcp_ip
-                    else:
-                        continue
-                except IOError:
-                    continue
-                else:
-                    if ip == self.ip:
-                        self.pcap_name = guess
-                        self.win_name = win_name
-                        self.uuid = uuid
-                        break
-        else:
+        win_name = pcapdnet.dnet.get_pcap_devname(self.name)
+        if win_name is None:
             raise PcapNameNotFoundError
+        
+        uuid = win_name[win_name.index("{"):win_name.index("}")+1]
+        
+        self.win_name = win_name
+        self.uuid = uuid
+        # use win_name as pcap_name to avoid names mismatch
+        self.pcap_name = self.win_name

     def __repr__(self):
         return "<%s: %s %s %s pcap_name=%s win_name=%s>" % (self.__class__.__name__,
@@ -166,10 +134,7 @@
         for i in pcapdnet.dnet.intf():
             try:
                 # XXX: Only Ethernet for the moment: localhost is not supported by dnet and pcap
-                # We only take interfaces that have an IP address, because the IP
-                # is used for the mapping between dnet and pcap interface names
-                # and this significantly improves Scapy's startup performance
-                if i["name"].startswith("eth") and "addr" in i:
+                if i["name"].startswith("eth"):
                     self.data[i["name"]] = NetworkInterface(i)
             except (KeyError, PcapNameNotFoundError):
                 pass
@@ -183,12 +148,10 @@

         This mapping is necessary because pypcap numbers the devices differently."""

-        try:
-            pcap_name = self.data[devname].pcap_name
-        except KeyError:
-            raise ValueError("Unknown network interface %r" % devname)
+        if devname is not None:
+            return self.data[devname].pcap_name
         else:
-            return pcap_name
+            return None

     def devname(self, pcap_name):
         """Return libdnet/Scapy device name for given pypcap device name
@@ -254,7 +217,7 @@
             netif  = match.group(4)
             metric = match.group(5)
             try:
-                intf = pcapdnet.dnet.intf().get_dst(pcapdnet.dnet.addr(type=2, addrtxt=dest))
+                intf = pcapdnet.dnet.intf().get_dst(pcapdnet.dnet.addr(typee=2, addrtxt=dest))
             except OSError:
                 log_loading.warning("Building Scapy's routing table: Couldn't get outgoing interface for destination %s" % dest)
                 continue               
Only in scapy-2.3.1/scapy/arch/windows: __init__.py.bak
diff -r -u scapy-2.3.1-orig/scapy/layers/inet6.py scapy-2.3.1/scapy/layers/inet6.py
--- scapy-2.3.1-orig/scapy/layers/inet6.py  2014-12-23 11:24:06.000000000 +0100
+++ scapy-2.3.1/scapy/layers/inet6.py   2015-05-28 21:45:48.729841200 +0200
@@ -3003,4 +3003,5 @@
 bind_layers(IPv6,      UDP,      nh = socket.IPPROTO_UDP )
 bind_layers(IP,        IPv6,     proto = socket.IPPROTO_IPV6 )
 bind_layers(IPv6,      IPv6,     nh = socket.IPPROTO_IPV6 )
-bind_layers(IPv6,      IP,       nh = socket.IPPROTO_IPIP )
+# bind_layers(IPv6,      IP,       nh = socket.IPPROTO_IPIP )
+bind_layers(IPv6, IP, nh = 4 )
diff -r -u scapy-2.3.1-orig/setup.py scapy-2.3.1/setup.py
--- scapy-2.3.1-orig/setup.py   2014-12-23 11:35:20.000000000 +0100
+++ scapy-2.3.1/setup.py    2015-05-28 21:49:25.098496700 +0200
@@ -6,9 +6,7 @@


 from distutils import archive_util
-from distutils import sysconfig
-from distutils.core import setup
-from distutils.command.sdist import sdist
+from setuptools import setup
 import os


@dloss
Copy link

dloss commented Jun 6, 2015

I have successfully built libdnet using the instructions and patches given by @rgom above. The patched Scapy can send and receive packets (e.g. its traceroute command works).

  • If configure tells you no acceptable ld found in $PATH, install the binutils package via Cygwin
  • The patch command is part of the patch package in Cygwin
  • I had to pass the --ignore-whitespace option to the patch command to make the patches apply
  • On my 32bit system I got a misleading configure error: need MingW32 package to build under Cygwin. This went away after I added || test "$MINGW" = no to the if condition on line 85 of configure.ac and ran autogen.sh again.
  • For pyrex I used the binary installer from http://brl.thefreecat.org/python-pyrex/Pyrex-0.9.9.win32.exe
  • Binary Windows installers can be created by using python setup.py build bdist_wininst.

@rgom
Copy link

rgom commented Jun 7, 2015

Ah, that makes sense now.
I must have kept some cygwin packages installed in the past (mingw*).
And yes, I've forgotten about some other build dependencies in the description above for the same reason.
You're right that configure/autogen additional modifications are necessary.

Best regards,
Robert

@rgom
Copy link

rgom commented Jun 7, 2015

Ok, forked the repo and created first of pull requests.
Let's see how well it goes - this is the easiest one, some of later patches will cause API incompatibility (some function arguments in pyx were named after Python reserved words).
That might require further discussion and even version change.
I'll see how responsive is upstream.

Robert

@rgom
Copy link

rgom commented Jun 9, 2015

There's a possibility to simplify the patches a bit:

  • type -> typee change seems unnecessary (can be done another way)
  • distutils -> setuptools in scapy is needed only when trying to create wheels (as I want) - otherwise (even for bdist_wininst) distutils is fine (no setup.py changes required)

I'll try to update the patches next days.
(Pull requests already submitted for scapy and dnet still require merging - they are fine by themselves)

Robert

@rgom
Copy link

rgom commented Jun 10, 2015

Ok, here it comes.
I'll post updated dnet and scapy patches here with added comments.
Patches will be split.

  1. Dnet:

Update revision to indicate local changes:

diff -u -r libdnet-master-orig/configure.ac libdnet-master/configure.ac
--- libdnet-master-orig/configure.ac    2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/configure.ac 2015-06-10 09:05:04.140602600 +0200
@@ -5,7 +5,7 @@
 dnl
 dnl $Id: configure.in 638 2007-01-20 11:39:21Z dugsong $

-AC_INIT([libdnet], [1.12])
+AC_INIT([libdnet], [1.12.1+rg])
 AC_CONFIG_SRCDIR([include/dnet.h])
 AC_CONFIG_AUX_DIR(config)
 AC_SUBST(ac_aux_dir)

uint32_t not available on MSVC9

diff -u -r libdnet-master-orig/include/dnet/intf.h libdnet-master/include/dnet/intf.h
--- libdnet-master-orig/include/dnet/intf.h 2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/include/dnet/intf.h  2015-05-29 21:47:32.298636100 +0200
@@ -11,8 +11,16 @@
 #ifndef DNET_INTF_H
 #define DNET_INTF_H

-#include <stdint.h>
+#ifdef _MSC_VER
+
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;

+#else
+#include <stdint.h>
+#endif
 /*
  * Interface entry
  */
diff -u -r libdnet-master-orig/include/dnet/os.h libdnet-master/include/dnet/os.h
--- libdnet-master-orig/include/dnet/os.h   2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/include/dnet/os.h    2015-05-29 21:53:47.895192000 +0200
@@ -148,7 +148,16 @@
 #define dnet_ntohl(val) (val)
 #define dnet_ntohll(val) (val)
 #else
+#ifdef _MSC_VER
+
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#else
 #include <stdint.h>
+#endif
 #define dnet_htons(val) htons(val)
 #define dnet_htonl(val) htonl(val)
 #define dnet_htonll(val) (((uint64_t)htonl(val) << 32) | htonl((uint64_t)(val) >> 32))

Make pyrex 0.9.9 happy about "type" argument name, without API change. Additionally provide already introduced get_pcap_devname to Python.

diff -u -r libdnet-master-orig/python/dnet.pyx libdnet-master/python/dnet.pyx
--- libdnet-master-orig/python/dnet.pyx 2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/python/dnet.pyx  2015-06-09 22:24:27.695205800 +0200
@@ -16,7 +16,7 @@
 __copyright__ = 'Copyright (c) 2003 Dug Song'
 __license__ = 'BSD'
 __url__ = 'http://libdnet.sourceforge.net/'
-__version__ = '1.12'
+__version__ = '1.12.1rg'

 cdef extern from "dnet.h":
     pass
@@ -37,6 +37,7 @@
     void   *memset(char *b, int c, int len)
     char   *strerror(int errnum)
     int     strlcpy(char *dst, char *src, int size)
+    int     strlen(char *src)
     unsigned long htonl(unsigned long n)
     unsigned long ntohl(unsigned long n)

@@ -160,7 +161,7 @@
     return PyString_FromStringAndSize(ea.data, 6)

 def eth_pack_hdr(dst=ETH_ADDR_BROADCAST, src=ETH_ADDR_BROADCAST,
-                 type=ETH_TYPE_IP):
+                 object type=ETH_TYPE_IP):
     """Return a packed binary string representing an Ethernet header.

     Keyword arguments:
@@ -441,7 +442,7 @@
     """
     cdef addr_t _addr

-    def __init__(self, addrtxt=None, type=ADDR_TYPE_NONE):
+    def __init__(self, addrtxt=None, object type=ADDR_TYPE_NONE):
         if addrtxt != None and addr_aton(addrtxt, &self._addr) < 0:
             if PyString_Size(addrtxt) == 4:
                 self._addr.addr_type = ADDR_TYPE_IP
@@ -785,7 +786,7 @@
 cdef extern from *:
     void __icmp_pack_hdr "icmp_pack_hdr" (char *hdr, int type, int code)

-def icmp_pack_hdr(type, code):
+def icmp_pack_hdr(object type, code):
     """Return a packed binary string representing an ICMP header.

     Keyword arguments:
@@ -909,6 +910,7 @@
     int     intf_set(intf_t *intf, intf_entry *entry)
     int     intf_loop(intf_t *intf, intf_handler callback, void *arg)
     intf_t *intf_close(intf_t *intf)
+    int     intf_get_pcap_devname(char *intf_name, char *pcapdev, int pcapdevlen)

 INTF_TYPE_OTHER =  1   # /* other */
 INTF_TYPE_ETH =        6   # /* Ethernet */
@@ -958,7 +960,28 @@
         entry.intf_alias_num = len(d['alias_addrs'])
         for i from 0 <= i < entry.intf_alias_num:
             entry.intf_alias_addrs[i] = (<addr>d['alias_addrs'][i])._addr
-
+"""
+int     intf_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen)
+"""
+def get_pcap_devname(intf_name):
+    """ Get pcap device name from our device name.
+    
+    Arguments:
+        intf_name - 'eth0', 'eth1', 'eth2', ...
+        
+    Output:
+        pcap interface name
+    """
+    
+    cdef char pcapdev[128]
+    if intf_name is not None:
+        if (intf_get_pcap_devname(intf_name, pcapdev, sizeof(pcapdev)) != -1):
+            return PyString_FromStringAndSize(pcapdev, strlen(pcapdev))
+        else:
+            raise RuntimeError("Pcap interface for intf_name '%s' not found" % intf_name)
+    else:
+        return None
+    
 cdef int __intf_callback(intf_entry *entry, void *arg) except -1:
     f, a = <object>arg
     ret = f(ifent_to_dict(entry), a)
@@ -1013,7 +1036,7 @@
         if intf_get_dst(self.intf, ifent, &dst._addr) < 0:
             raise OSError, __oserror()
         return ifent_to_dict(ifent)
-    
+
     def set(self, d):
         """Set the configuration for an interface from a dict.

Use setuptools instead of distutils to allow creating wheels. Add missing wpcap library.

diff -u -r libdnet-master-orig/python/setup.py.in libdnet-master/python/setup.py.in
--- libdnet-master-orig/python/setup.py.in  2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/python/setup.py.in   2015-05-28 21:33:45.242841200 +0200
@@ -1,7 +1,7 @@
 #!/usr/bin/env python

 import glob, os, sys
-from distutils.core import setup, Extension
+from setuptools import setup, Extension

 dnet_srcs = [ '@srcdir@/dnet.c' ]
 dnet_incdirs = [ '@top_srcdir@/include' ]
@@ -15,7 +15,7 @@
     dnet_srcs.extend(['../src/addr-util.c', '../src/addr.c', '../src/blob.c', '../src/ip-util.c', '../src/ip6.c', '../src/rand.c', '../src/err.c', '../src/strlcat.c', '../src/strlcpy.c', '../src/err.c', '../src/strlcat.c', '../src/strlcpy.c', '../src/strsep.c', '../src/arp-win32.c', '../src/eth-win32.c', '../src/fw-pktfilter.c', '../src/intf-win32.c', '../src/ip-win32.c', '../src/route-win32.c', '../src/tun-none.c'])
     dnet_incdirs.append(winpcap_dir + '/Include')
     dnet_libdirs.append(winpcap_dir + '/Lib')
-    dnet_libs.extend([ 'advapi32', 'iphlpapi', 'ws2_32', 'packet' ])
+    dnet_libs.extend([ 'advapi32', 'iphlpapi', 'ws2_32', 'packet', 'wpcap' ])
 else:
     # XXX - can't build on Cygwin+MinGW yet.
     #if sys.platform == 'cygwin':

Implement get_dst(), fix compilation problems (move declarations earlier):

diff -u -r libdnet-master-orig/src/intf-win32.c libdnet-master/src/intf-win32.c
--- libdnet-master-orig/src/intf-win32.c    2014-03-18 07:39:14.000000000 +0100
+++ libdnet-master/src/intf-win32.c 2015-06-01 09:50:11.468751700 +0200
@@ -89,6 +89,7 @@
    } else if (strncmp(device, "tun", 3) == 0) {
        type = INTF_TYPE_TUN;
    }
+
    return (type);
 }

@@ -131,10 +132,12 @@
    int i;
    int type;
    IP_ADAPTER_UNICAST_ADDRESS *addr;
-
+   char friendly_name[MAX_INTERFACE_NAME_LEN];
+        const char *name_start;
    /* The total length of the entry may be passed inside entry.
            Remember it and clear the entry. */
    u_int intf_len = entry->intf_len;
+    
    memset(entry, 0, sizeof(*entry));
    entry->intf_len = intf_len;

@@ -149,13 +152,12 @@
    snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu",
        _ifcombo_name(a->IfType), i);
    entry->intf_type = (uint16_t)type;
-   char friendly_name[MAX_INTERFACE_NAME_LEN];
    strncpy_wchar(friendly_name, a->FriendlyName, MAX_INTERFACE_NAME_LEN);
    snprintf(entry->os_intf_name, MAX_INTERFACE_NAME_LEN, "%s %s", friendly_name,
        a->AdapterName);
    entry->os_intf_name[MAX_INTERFACE_NAME_LEN - 1] = '\0';

-   const char *name_start = strstr(a->AdapterName, "{");
+   name_start = strstr(a->AdapterName, "{");
    if (name_start) {
        snprintf(entry->pcap_intf_name, MAX_INTERFACE_NAME_LEN - 1,
            "\\Device\\NPF_%s", name_start);
@@ -277,7 +279,17 @@
    char *p = (char *)device;
    int n, type = _ifcombo_type(device);

+    /* only ethernet supported (and as a safeguard for invalid
+       interfaces names, leading to crash */
+    if (type != INTF_TYPE_ETH)
+        return NULL;
+    
    while (isalpha((int) (unsigned char) *p)) p++;
+    
+    /* poor check - first digits only - eth0a will be still treated as eth0*/
+    if (!isdigit((int) (unsigned char) *p))
+        return NULL;
+    
    n = atoi(p);

    for (a = intf->iftable; a != NULL; a = a->Next) {
@@ -377,9 +389,28 @@
 int
 intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst)
 {
-   errno = ENOSYS;
-   SetLastError(ERROR_NOT_SUPPORTED);
+    IP_ADAPTER_ADDRESSES *a;
+    DWORD intfIdx;
+
+    if (dst->addr_type != ADDR_TYPE_IP) {
+   errno = EINVAL;
+   return (-1);
+    }
+
+    if (_refresh_tables(intf) < 0)
    return (-1);
+
+    if (GetBestInterface(dst->addr_ip, &intfIdx) != NO_ERROR)
+        return (-1);
+
+    for (a = intf->iftable; a != NULL; a = a->Next) {
+        if (a->IfIndex == intfIdx) {
+            _adapter_address_to_entry(intf, a, entry);
+            return (0);
+        }
+    }
+    
+    return (-1);
 }

 int
@@ -447,10 +478,12 @@

    if ((intf = intf_open()) == NULL)
        return (-1);
+    
    if (_refresh_tables(intf) < 0) {
        intf_close(intf);
        return (-1);
    }
+    
    a = _find_adapter_address(intf, intf_name);

    if (a == NULL) {

So far, there's a pull request for get_dst().

@rgom
Copy link

rgom commented Jun 10, 2015

And now corresponding scapy part:

(This is big, sorry for that).
windows/init.py changes:

  • fix getting pcap device name (avoid names mismatch between pcap and dnet)
  • raise exceptions when giving invalid interfaces names (instead of using default names in such cases)
  • (unrelated, but I needed this) use readline only in interactive mode. When using non-interactively it caused problems e.g. with Pydev
  • (unrelated, but I needed this) merge and enhance stop_filter from non-win32 sniff() implementation to allow conditional sniff stop
diff -u -r scapy-2.3.1-orig/scapy/arch/windows/__init__.py scapy-2.3.1/scapy/arch/windows/__init__.py
--- scapy-2.3.1-orig/scapy/arch/windows/__init__.py 2014-12-23 11:24:06.000000000 +0100
+++ scapy-2.3.1/scapy/arch/windows/__init__.py  2015-06-10 10:16:31.945455700 +0200
@@ -109,48 +109,16 @@
     def _update_pcapdata(self):
         """Supplement more info from pypcap and the Windows registry"""

-        # XXX: We try eth0 - eth29 by bruteforce and match by IP address, 
-        # because only the IP is available in both pypcap and dnet.
-        # This may not work with unorthodox network configurations and is
-        # slow because we have to walk through the Windows registry.
-        for n in range(30):
-            guess = "eth%s" % n
-            win_name = pcapdnet.pcap.ex_name(guess)
-            if win_name.endswith("}"):
-                try:
-                    uuid = win_name[win_name.index("{"):win_name.index("}")+1]
-                    keyname = r"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\%s" % uuid
-                    try:
-                        key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyname)
-                    except WindowsError:
-                        log_loading.debug("Couldn't open 'HKEY_LOCAL_MACHINE\\%s' (for guessed pcap iface name '%s')." % (keyname, guess))
-                        continue
-                    try:    
-                        fixed_ip = _winreg.QueryValueEx(key, "IPAddress")[0][0].encode("utf-8")
-                    except (WindowsError, UnicodeDecodeError, IndexError):
-                        fixed_ip = None
-                    try:
-                        dhcp_ip = _winreg.QueryValueEx(key, "DhcpIPAddress")[0].encode("utf-8")
-                    except (WindowsError, UnicodeDecodeError, IndexError):
-                        dhcp_ip = None
-                    # "0.0.0.0" or None means the value is not set (at least not correctly).
-                    # If both fixed_ip and dhcp_ip are set, fixed_ip takes precedence 
-                    if fixed_ip is not None and fixed_ip != "0.0.0.0":
-                        ip = fixed_ip
-                    elif dhcp_ip is not None and dhcp_ip != "0.0.0.0":
-                        ip = dhcp_ip
-                    else:
-                        continue
-                except IOError:
-                    continue
-                else:
-                    if ip == self.ip:
-                        self.pcap_name = guess
-                        self.win_name = win_name
-                        self.uuid = uuid
-                        break
-        else:
+        win_name = pcapdnet.dnet.get_pcap_devname(self.name)
+        if win_name is None:
             raise PcapNameNotFoundError
+        
+        uuid = win_name[win_name.index("{"):win_name.index("}")+1]
+        
+        self.win_name = win_name
+        self.uuid = uuid
+        # use win_name as pcap_name to avoid names mismatch
+        self.pcap_name = self.win_name

     def __repr__(self):
         return "<%s: %s %s %s pcap_name=%s win_name=%s>" % (self.__class__.__name__,
@@ -166,10 +134,7 @@
         for i in pcapdnet.dnet.intf():
             try:
                 # XXX: Only Ethernet for the moment: localhost is not supported by dnet and pcap
-                # We only take interfaces that have an IP address, because the IP
-                # is used for the mapping between dnet and pcap interface names
-                # and this significantly improves Scapy's startup performance
-                if i["name"].startswith("eth") and "addr" in i:
+                if i["name"].startswith("eth"):
                     self.data[i["name"]] = NetworkInterface(i)
             except (KeyError, PcapNameNotFoundError):
                 pass
@@ -183,12 +148,10 @@

         This mapping is necessary because pypcap numbers the devices differently."""

-        try:
-            pcap_name = self.data[devname].pcap_name
-        except KeyError:
-            raise ValueError("Unknown network interface %r" % devname)
+        if devname is not None:
+            return self.data[devname].pcap_name
         else:
-            return pcap_name
+            return None

     def devname(self, pcap_name):
         """Return libdnet/Scapy device name for given pypcap device name
@@ -313,15 +276,17 @@
 import scapy.layers.l2
 scapy.layers.l2.getmacbyip = getmacbyip

-try:
-    import readline
-    console = readline.GetOutputFile()
-except (ImportError, AttributeError):
-    log_loading.info("Could not get readline console. Will not interpret ANSI color codes.") 
-else:
-    conf.readfunc = readline.rl.readline
-    orig_stdout = sys.stdout
-    sys.stdout = console
+# don't use readline when using scapy non-interactively
+if conf.interactive:
+    try:
+        import readline
+        console = readline.GetOutputFile()
+    except (ImportError, AttributeError):
+        log_loading.info("Could not get readline console. Will not interpret ANSI color codes.") 
+    else:
+        conf.readfunc = readline.rl.readline
+        orig_stdout = sys.stdout
+        sys.stdout = console



@@ -472,7 +437,7 @@
 import scapy.sendrecv
 scapy.sendrecv.sndrcv = sndrcv

-def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, *arg, **karg):
+def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, stop_filter=None, *arg, **karg):
     """Sniff packets
 sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets

@@ -487,6 +452,11 @@
 offline: pcap file to read packets from, instead of sniffing them
 timeout: stop sniffing after a given time (default: None)
 L2socket: use the provided L2socket
+stop_filter: python function applied to each packet to determine
+             if we have to stop the capture after this packet
+             (is executed on each loop with None as well
+             to allow stopping sniffing even in case of no packets)
+             ex: stop_filter = lambda x: x.haslayer(TCP) if x else False
     """
     c = 0

@@ -501,7 +471,7 @@
     if timeout is not None:
         stoptime = time.time()+timeout
     remain = None
-    while 1:
+    while not (stop_filter and stop_filter(None)):
         try:
             if timeout is not None:
                 remain = stoptime-time.time()
@@ -523,6 +493,8 @@
                 r = prn(p)
                 if r is not None:
                     print r
+            if stop_filter and stop_filter(p):
+                break
             if count > 0 and c >= count:
                 break
         except KeyboardInterrupt:

Pull request submitted for this one (IPPROTO_IPIP unavailable on some platforms) (https://bitbucket.org/secdev/scapy/pull-request/117/add-missing-socketipproto_ipip)

diff -u -r scapy-2.3.1-orig/scapy/layers/inet6.py scapy-2.3.1/scapy/layers/inet6.py
--- scapy-2.3.1-orig/scapy/layers/inet6.py  2014-12-23 11:24:06.000000000 +0100
+++ scapy-2.3.1/scapy/layers/inet6.py   2015-06-10 09:59:52.908562000 +0200
@@ -30,7 +30,10 @@
 if not hasattr(socket, "IPPROTO_IPV6"):
     # Workaround for http://bugs.python.org/issue6926
     socket.IPPROTO_IPV6 = 41
-
+if not hasattr(socket, "IPPROTO_IPIP"):
+    # Workaround for https://bitbucket.org/secdev/scapy/issue/5119
+    socket.IPPROTO_IPIP = 4
+    
 from scapy.config import conf
 from scapy.layers.l2 import *
 from scapy.layers.inet import *

Bump up scapy revision, use setuptools instead of distutils to allow wheels creation:

diff -u -r scapy-2.3.1-orig/setup.py scapy-2.3.1/setup.py
--- scapy-2.3.1-orig/setup.py   2014-12-23 11:35:20.000000000 +0100
+++ scapy-2.3.1/setup.py    2015-06-10 09:16:02.039482600 +0200
@@ -6,9 +6,7 @@


 from distutils import archive_util
-from distutils import sysconfig
-from distutils.core import setup
-from distutils.command.sdist import sdist
+from setuptools import setup
 import os


@@ -46,7 +44,7 @@

 setup(
     name = 'scapy',
-    version = '2.3.1',
+    version = '2.3.1+rg1',
     packages=['scapy','scapy/arch', 'scapy/arch/windows', 'scapy/layers','scapy/asn1','scapy/tools','scapy/modules', 'scapy/crypto', 'scapy/contrib'],
     scripts = SCRIPTS,
     data_files = [('share/man/man1', ["doc/scapy.1.gz"])],

@pbiswajit4u
Copy link

Thanks for the steps to build libdnet library for Windows 64bit. Currently stuck at below error.
Could you share this prebuilt libdnet library.

C:\Users\Admin\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:../../WPdpack/Lib /LIBPATH:c:\python27\libs /LIBPATH:c:\python27\PCbuild\amd64 /LIBPATH:c:\python27\PC\VS9.0\amd64 advapi32.lib iphlpapi.lib ws2_32.lib packet.lib wpcap.lib /EXPORT:initdnet build\temp.win-amd64-2.7\Release./dnet.obj build\temp.win-amd64-2.7\Release../src/addr-util.obj build\temp.win-amd64-2.7\Release../src/addr.obj build\temp.win-amd64-2.7\Release../src/blob.obj build\temp.win-amd64-2.7\Release../src/ip-util.obj build\temp.win-amd64-2.7\Release../src/ip6.obj build\temp.win-amd64-2.7\Release../src/rand.obj build\temp.win-amd64-2.7\Release../src/err.obj build\temp.win-amd64-2.7\Release../src/strlcat.obj build\temp.win-amd64-2.7\Release../src/strlcpy.obj build\temp.win-amd64-2.7\Release../src/err.obj build\temp.win-amd64-2.7\Release../src/strlcat.obj build\temp.win-amd64-2.7\Release../src/strlcpy.obj build\temp.win-amd64-2.7\Release../src/strsep.obj build\temp.win-amd64-2.7\Release../src/arp-win32.obj build\temp.win-amd64-2.7\Release../src/eth-win32.obj build\temp.win-amd64-2.7\Release../src/fw-pktfilter.obj build\temp.win-amd64-2.7\Release../src/intf-win32.obj build\temp.win-amd64-2.7\Release../src/ip-win32.obj build\temp.win-amd64-2.7\Release../src/route-win32.obj build\temp.win-amd64-2.7\Release../src/tun-none.obj /OUT:build\lib.win-amd64-2.7\dnet.pyd /IMPLIB:build\temp.win-amd64-2.7\Release.\dnet.lib /MANIFESTFILE:build\temp.win-amd64-2.7\Release.\dnet.pyd.manifest
build\temp.win-amd64-2.7\Release../src/err.obj : warning LNK4042: object specified more than once; extras ignored
build\temp.win-amd64-2.7\Release../src/strlcat.obj : warning LNK4042: object specified more than once; extras ignored
build\temp.win-amd64-2.7\Release../src/strlcpy.obj : warning LNK4042: object specified more than once; extras ignored
dnet.obj : warning LNK4197: export 'initdnet' specified multiple times; using first specification
Creating library build\temp.win-amd64-2.7\Release.\dnet.lib and object build\temp.win-amd64-2.7\Release.\dnet.exp
eth-win32.obj : error LNK2019: unresolved external symbol PacketSendPacket referenced in function eth_send
eth-win32.obj : error LNK2019: unresolved external symbol PacketInitPacket referenced in function eth_send
eth-win32.obj : error LNK2019: unresolved external symbol PacketCloseAdapter referenced in function eth_close
eth-win32.obj : error LNK2019: unresolved external symbol PacketFreePacket referenced in function eth_close
eth-win32.obj : error LNK2019: unresolved external symbol PacketRequest referenced in function eth_get
eth-win32.obj : error LNK2019: unresolved external symbol PacketAllocatePacket referenced in function eth_open
eth-win32.obj : error LNK2019: unresolved external symbol PacketSetBuff referenced in function eth_open
eth-win32.obj : error LNK2019: unresolved external symbol PacketOpenAdapter referenced in function eth_open
intf-win32.obj : error LNK2019: unresolved external symbol pcap_freealldevs referenced in function intf_get_pcap_devname
intf-win32.obj : error LNK2019: unresolved external symbol pcap_findalldevs referenced in function intf_get_pcap_devname
build\lib.win-amd64-2.7\dnet.pyd : fatal error LNK1120: 10 unresolved externals
error: command 'C:\Users\Admin\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\link.exe' failed with exit status 1120

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants