From 58fdc06cd17385337d38f2273157efbf65b22cea Mon Sep 17 00:00:00 2001
From: Guillaume Valadon <guillaume.valadon@ssi.gouv.fr>
Date: Wed, 14 Dec 2016 17:26:38 +0100
Subject: [PATCH] AppVeyor support

---
 appveyor.yml                   | 36 ++++++++++++++++++++++++++++++++++
 scapy/arch/pcapdnet.py         |  2 +-
 scapy/arch/windows/__init__.py | 22 ++++++++++++++++++++-
 scapy/pton_ntop.py             | 14 +++++++++----
 scapy/tools/UTscapy.py         |  5 +++++
 test/regression.uts            |  8 ++++++++
 6 files changed, 81 insertions(+), 6 deletions(-)
 create mode 100644 appveyor.yml
 mode change 100755 => 100644 scapy/arch/pcapdnet.py

diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 00000000..a15aacaa
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,36 @@
+environment:
+
+  # Python versions that will be tested
+  # Note: it defines variables that can be used later
+  matrix:
+    - PYTHON: "C:\\Python27-x64"
+      PYTHON_VERSION: "2.7.x"
+      PYTHON_ARCH: "64"
+
+# There is no build phase for Scapy
+build: off
+
+install:
+  # Installing WinPcap directly does not work,
+  # see http://help.appveyor.com/discussions/problems/2280-winpcap-installation-issue
+  - choco install -y nmap
+  - refreshenv
+
+  # Install Python modules
+  - "%PYTHON%\\python -m pip install ecdsa pycrypto"
+
+test_script:
+  # Set environment variables
+  - set PYTHONPATH=%APPVEYOR_BUILD_FOLDER%
+  - set PATH=%APPVEYOR_BUILD_FOLDER%;C:\Windows\System32\Npcap\;%PATH%
+  
+  # Main unit tests
+  - "%PYTHON%\\python bin\\UTscapy -f text -t test\\regression.uts -F -K automaton -K mock_read_routes6_bsd || exit /b 42"
+  - 'del test\regression.uts'
+
+  # Secondary unit tests
+  - 'del test\bpf.uts' # Don't bother with BPF regression tests
+  - "for %%t in (test\\*.uts) do (%PYTHON%\\python bin\\UTscapy -f text -t %%t -F -K combined_modes || exit /b 42)"
+  
+  # Contrib unit tests
+  - "for %%t in (scapy\\contrib\\*.uts) do (%PYTHON%\\python bin\\UTscapy -f text -t %%t -F -P \"load_contrib(\'%%~nt\')\"  || exit /b 42)"
diff --git a/scapy/arch/pcapdnet.py b/scapy/arch/pcapdnet.py
old mode 100755
new mode 100644
index 09bbe8de..a51128ff
--- a/scapy/arch/pcapdnet.py
+++ b/scapy/arch/pcapdnet.py
@@ -85,7 +85,7 @@ if conf.use_winpcapy:
     try:
       p = devs
       while p:
-        if p.contents.name.endswith(iff):
+        if p.contents.name.endswith(iff.guid):
           a = p.contents.addresses
           while a:
             if a.contents.addr.contents.sa_family == socket.AF_INET:
diff --git a/scapy/arch/windows/__init__.py b/scapy/arch/windows/__init__.py
index 2c1a2aab..1d6a4028 100755
--- a/scapy/arch/windows/__init__.py
+++ b/scapy/arch/windows/__init__.py
@@ -236,7 +236,7 @@ class NetworkInterface(object):
         self._update_pcapdata()
 
         try:
-            self.ip = socket.inet_ntoa(get_if_raw_addr(data['guid']))
+            self.ip = socket.inet_ntoa(get_if_raw_addr(data))
         except (KeyError, AttributeError, NameError):
             pass
 
@@ -461,3 +461,23 @@ def get_working_if():
         return LOOPBACK_NAME
 
 conf.iface = get_working_if()
+
+
+def route_add_loopback():
+    """Add a route to 127.0.0.1 to simplify unit tests on Windows"""
+
+    # Build the packed network addresses
+    loop_net = struct.unpack("!I", socket.inet_aton("127.0.0.0"))[0]
+    loop_mask = struct.unpack("!I", socket.inet_aton("255.0.0.0"))[0]
+
+    # Get the adapter from an existing route
+    if len(conf.route.routes) == 0:
+        return
+    adapter = conf.route.routes[0][3]
+
+    # Build and inject the fake route
+    loopback_route = (loop_net, loop_mask, "0.0.0.0", adapter, "127.0.0.1")
+    conf.route.routes.append(loopback_route)
+
+    # Flush the cache
+    conf.route.invalidate_cache()
diff --git a/scapy/pton_ntop.py b/scapy/pton_ntop.py
index 366a1337..25f7ef98 100644
--- a/scapy/pton_ntop.py
+++ b/scapy/pton_ntop.py
@@ -87,9 +87,15 @@ def inet_ntop(af, addr):
                 hexstr = hex(value)[2:]
             except TypeError:
                 raise Exception("Illegal syntax for IP address")
-            parts.append(hexstr.lower())
-
-        # Note: the returned address is never compact
-        return ":".join(parts)
+            parts.append(hexstr.lstrip("0").lower())
+        result = ":".join(parts)
+        while ":::" in result:
+            result = result.replace(":::", "::")
+        # Leaving out leading and trailing zeros is only allowed with ::
+        if result.endswith(":") and not result.endswith("::"):
+            result = result + "0"
+        if result.startswith(":") and not result.startswith("::"):
+            result = "0" + result
+        return result
     else:
         raise Exception("Address family not supported yet")   
diff --git a/scapy/tools/UTscapy.py b/scapy/tools/UTscapy.py
index 04ee0992..ac5dcdd1 100755
--- a/scapy/tools/UTscapy.py
+++ b/scapy/tools/UTscapy.py
@@ -9,6 +9,7 @@ Unit testing infrastructure for Scapy
 
 import sys,getopt,imp
 import bz2, base64, os.path, time, traceback, zlib, sha
+from scapy.arch.consts import WINDOWS
 
 
 #### Import tool ####
@@ -293,6 +294,10 @@ def remove_empty_testsets(test_campaign):
 #### RUN CAMPAIGN #####
 
 def run_campaign(test_campaign, get_interactive_session, verb=2):
+    if WINDOWS:
+        # Add a route to 127.0.0.1
+        from scapy.arch.windows import route_add_loopback
+        route_add_loopback()
     passed=failed=0
     if test_campaign.preexec:
         test_campaign.preexec_output = get_interactive_session(test_campaign.preexec.strip())[0]
diff --git a/test/regression.uts b/test/regression.uts
index eda698d9..65f983cc 100644
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -4562,6 +4562,7 @@ assert isinstance(pkt, DNS) and isinstance(pkt.payload, NoPayload)
 + Mocked read_routes() calls
 
 = Truncated netstat -rn output on OS X
+~ mock_read_routes6_bsd
 
 import mock
 import StringIO
@@ -4618,6 +4619,7 @@ test_osx_netstat_truncated()
 + Mocked read_routes6() calls
 
 = Preliminary definitions
+~ mock_read_routes6_bsd
 
 import mock
 import StringIO
@@ -4647,6 +4649,7 @@ def check_mandatory_ipv6_routes(routes6):
 
 
 = Mac OS X 10.9.5
+~ mock_read_routes6_bsd
 
 @mock.patch("scapy.arch.unix.in6_getifaddr")
 @mock.patch("scapy.arch.unix.os")
@@ -4687,6 +4690,7 @@ test_osx_10_9_5()
 
 
 = Mac OS X 10.9.5 with global IPv6 connectivity
+~ mock_read_routes6_bsd
 @mock.patch("scapy.arch.unix.in6_getifaddr")
 @mock.patch("scapy.arch.unix.os")
 def test_osx_10_9_5_global(mock_os, mock_in6_getifaddr):
@@ -4734,6 +4738,7 @@ test_osx_10_9_5_global()
 
 
 = Mac OS X 10.10.4
+~ mock_read_routes6_bsd
 
 @mock.patch("scapy.arch.unix.in6_getifaddr")
 @mock.patch("scapy.arch.unix.os")
@@ -4773,6 +4778,7 @@ test_osx_10_10_4()
 
 
 = FreeBSD 10.2
+~ mock_read_routes6_bsd
 
 @mock.patch("scapy.arch.unix.in6_getifaddr")
 @mock.patch("scapy.arch.unix.os")
@@ -4811,6 +4817,7 @@ test_freebsd_10_2()
 
 
 = OpenBSD 5.5
+~ mock_read_routes6_bsd
 
 @mock.patch("scapy.arch.unix.OPENBSD")
 @mock.patch("scapy.arch.unix.in6_getifaddr")
@@ -4868,6 +4875,7 @@ test_openbsd_5_5()
 
 
 = NetBSD 7.0
+~ mock_read_routes6_bsd
 
 @mock.patch("scapy.arch.unix.NETBSD")
 @mock.patch("scapy.arch.unix.in6_getifaddr")
-- 
GitLab