Merge pull request #1067 from gpotter2/win-static-py3

Static access to LOOPBACK_INTERFACE
diff --git a/.coveragerc b/.coveragerc
index cec0a08..e279ef3 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,5 +1,7 @@
 [run]
 omit =
+    # Travis specific path
+    /home/travis/virtualenv/python*
     # Python specific path
     /usr/local/lib/python2.7/*
     # Scapy specific paths
@@ -8,6 +10,4 @@
     scapy/tools/*
     # Libraries
     scapy/modules/six.py
-	scapy/modules/winpcapy.py
-    # Python 3: not tested yet
-    scapy/compat.py
+    scapy/modules/winpcapy.py
diff --git a/.travis/test.sh b/.travis/test.sh
index 9e239cf..46c1ef4 100644
--- a/.travis/test.sh
+++ b/.travis/test.sh
@@ -71,7 +71,7 @@
 then
   echo '#!/bin/bash' > test/python
   echo "[ \"\$*\" = \"--version\" ] && echo \"`python --version`\" && exit 0" >> test/python
-  echo "`which coverage` run --concurrency=multiprocessing -a \$*" >> test/python
+  echo "`which coverage` run --rcfile=../.coveragerc --concurrency=multiprocessing -a \$*" >> test/python
   chmod +x test/python
 
   # Copy the fake Python interpreter to bypass /etc/sudoers rules on Ubuntu
diff --git a/README.md b/README.md
index 557b0f3..8f4963c 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@
 using default values that work.
 
 It can easily handle most classical tasks like scanning, tracerouting, probing,
-unit tests, attacks or network discovery (it can replace `hping`, 85% of `nmap̀`,
+unit tests, attacks or network discovery (it can replace `hping`, 85% of `nmap`,
 `arpspoof`, `arp-sk`, `arping`, `tcpdump`, `wireshark`, `p0f`, etc.). It also
 performs very well at a lot of other specific tasks that most other tools can't
 handle, like sending invalid frames, injecting your own 802.11 frames, combining
@@ -66,7 +66,7 @@
 
 p = IP(dst="github.com")/TCP()
 r = sr1(p)
-print r.summary()
+print(r.summary())
 ```
 
 Then, launch the script with:
diff --git a/scapy/arch/bpf/core.py b/scapy/arch/bpf/core.py
index 0340fa6..040067b 100644
--- a/scapy/arch/bpf/core.py
+++ b/scapy/arch/bpf/core.py
@@ -173,7 +173,7 @@
 
             # Check if the interface can be used
             try:
-                fcntl.ioctl(fd, BIOCSETIF, struct.pack("16s16x", ifname))
+                fcntl.ioctl(fd, BIOCSETIF, struct.pack("16s16x", ifname.encode()))
                 interfaces.append((ifname, int(ifname[-1])))
             except IOError as err:
                 pass
diff --git a/scapy/arch/bpf/supersocket.py b/scapy/arch/bpf/supersocket.py
index 34c8f15..7d04e18 100644
--- a/scapy/arch/bpf/supersocket.py
+++ b/scapy/arch/bpf/supersocket.py
@@ -66,7 +66,7 @@
 
         # Assign the network interface to the BPF handle
         try:
-            fcntl.ioctl(self.ins, BIOCSETIF, struct.pack("16s16x", self.iface))
+            fcntl.ioctl(self.ins, BIOCSETIF, struct.pack("16s16x", self.iface.encode()))
         except IOError:
             raise Scapy_Exception("BIOCSETIF failed on %s" % self.iface)
         self.assigned_interface = self.iface
@@ -324,7 +324,7 @@
         # Assign the network interface to the BPF handle
         if self.assigned_interface != iff:
             try:
-                fcntl.ioctl(self.outs, BIOCSETIF, struct.pack("16s16x", iff))
+                fcntl.ioctl(self.outs, BIOCSETIF, struct.pack("16s16x", iff.encode()))
             except IOError:
                 raise Scapy_Exception("BIOCSETIF failed on %s" % iff)
             self.assigned_interface = iff
diff --git a/scapy/arch/windows/__init__.py b/scapy/arch/windows/__init__.py
index 6641970..abb1ea7 100755
--- a/scapy/arch/windows/__init__.py
+++ b/scapy/arch/windows/__init__.py
@@ -521,7 +521,8 @@
         Only available with Npcap."""
         # According to https://nmap.org/npcap/guide/npcap-devguide.html#npcap-feature-dot11
         self._check_npcap_requirement()
-        return sp.Popen([_WlanHelper, self.guid[1:-1], "channel"], stdout=sp.PIPE).communicate()[0].strip().strip()
+        return sp.Popen([_WlanHelper, self.guid[1:-1], "channel"],
+                        stdout=sp.PIPE).communicate()[0].strip()
 
     def setchannel(self, channel):
         """Set the channel of the interface (1-14):
@@ -853,14 +854,13 @@
     _buffer = []
     _pattern = re.compile(".*:\s+(\d+)")
     for _line in stdout:
-        if not _line.strip():
-            continue
-        _buffer.append(_line)
-        if len(_buffer) == 32:  # An interface, with all its parameters, is 32 lines long
+        if not _line.strip() and len(_buffer) > 0:
             if_index = re.search(_pattern, _buffer[3]).group(1)
             if_metric = int(re.search(_pattern, _buffer[5]).group(1))
             res[if_index] = if_metric
             _buffer = []
+        else:
+            _buffer.append(_line)
     return res
 
 def _read_routes_post2008():
diff --git a/scapy/base_classes.py b/scapy/base_classes.py
index a269796..85c47f5 100644
--- a/scapy/base_classes.py
+++ b/scapy/base_classes.py
@@ -166,7 +166,7 @@
                         resolved_fld.append(f2)
                 else:
                     resolved_fld.append(f)
-        else: # look for a field_desc in parent classes
+        else: # look for a fields_desc in parent classes
             resolved_fld = None
             for b in bases:
                 if hasattr(b,"fields_desc"):
diff --git a/scapy/compat.py b/scapy/compat.py
index 1737c04..d00029a 100644
--- a/scapy/compat.py
+++ b/scapy/compat.py
@@ -77,7 +77,7 @@
 
     def plain_str(x):
         """Convert basic byte objects to str"""
-        return x
+        return x if isinstance(x, basestring) else str(x)
 
     def chb(x):
         """Same than chr() but encode as bytes.
@@ -101,7 +101,7 @@
         """Convert basic byte objects to str"""
         if isinstance(x, bytes):
             return x.decode('utf8')
-        return x
+        return x if isinstance(x, str) else str(x)
 
     def chb(x):
         """Same than chr() but encode as bytes.
diff --git a/scapy/data.py b/scapy/data.py
index ff06438..71dda32 100644
--- a/scapy/data.py
+++ b/scapy/data.py
@@ -87,6 +87,7 @@
 DLT_IEEE802_11_RADIO = 127
 DLT_LINUX_IRDA  = 144
 DLT_PPI   = 192
+DLT_CAN_SOCKETCAN = 227
 DLT_IPV4 = 228
 DLT_IPV6 = 229
 
diff --git a/scapy/layers/can.py b/scapy/layers/can.py
new file mode 100644
index 0000000..7dc2d33
--- /dev/null
+++ b/scapy/layers/can.py
@@ -0,0 +1,36 @@
+# This file is part of Scapy
+# See http://www.secdev.org/projects/scapy for more informations
+# Copyright (C) Philippe Biondi <phil@secdev.org>
+# This program is published under a GPLv2 license
+
+
+"""A minimal implementation of the CANopen protocol, based on
+Wireshark dissectors. See https://wiki.wireshark.org/CANopen
+
+"""
+
+
+from scapy.config import conf
+from scapy.data import DLT_CAN_SOCKETCAN
+from scapy.fields import BitField, FieldLenField, FlagsField, StrLenField, \
+    ThreeBytesField, XBitField
+from scapy.packet import Packet
+
+
+class CAN(Packet):
+    """A minimal implementation of the CANopen protocol, based on
+    Wireshark dissectors. See https://wiki.wireshark.org/CANopen
+
+    """
+    fields_desc = [
+        FlagsField("flags", 0, 3, ["extended", "remote_transmission_request",
+                                   "error"]),
+        BitField("unknown", 0, 18),
+        XBitField("identifier", 0, 11),
+        FieldLenField("length", None, length_of="data", fmt="B"),
+        ThreeBytesField("reserved", 0),
+        StrLenField("data", "", length_from=lambda pkt: pkt.length),
+    ]
+
+
+conf.l2types.register(DLT_CAN_SOCKETCAN, CAN)
diff --git a/scapy/layers/radius.py b/scapy/layers/radius.py
index ada1cb4..be7b549 100644
--- a/scapy/layers/radius.py
+++ b/scapy/layers/radius.py
@@ -10,6 +10,8 @@
 
 import struct
 import logging
+import hashlib
+import hmac
 from scapy.compat import *
 from scapy.packet import Packet, bind_layers
 from scapy.fields import ByteField, ByteEnumField, IntField, StrLenField,\
@@ -21,20 +23,6 @@
 from scapy.error import Scapy_Exception
 
 
-g_log_loading = logging.getLogger("scapy.logging")
-
-_crypto_loading_failure_message = \
-    "Could not import python-cryptography."\
-    "Computations for the \"authenticator\" field (RADIUS packets) and"\
-    "\"Message-Authenticator\" attribute value field are disabled."
-
-if conf.crypto_valid:
-    from cryptography.hazmat.backends import default_backend
-    from cryptography.hazmat.primitives import hashes, hmac
-else:
-    g_log_loading.info(_crypto_loading_failure_message)
-
-
 # https://www.iana.org/assignments/radius-types/radius-types.xhtml
 _radius_attribute_types = {
     1: "User-Name",
@@ -540,6 +528,23 @@
     val = 24
 
 
+
+def prepare_packed_data(radius_packet, packed_req_authenticator):
+    """
+    Pack RADIUS data prior computing the authentication MAC
+    """
+
+    packed_hdr = struct.pack("!B", radius_packet.code)
+    packed_hdr += struct.pack("!B", radius_packet.id)
+    packed_hdr += struct.pack("!H", radius_packet.len)
+
+    packed_attrs = b''
+    for attr in radius_packet.attributes:
+        packed_attrs += raw(attr)
+
+    return packed_hdr + packed_req_authenticator + packed_attrs
+
+
 class RadiusAttr_Message_Authenticator(_RadiusAttrHexStringVal):
     """RFC 2869"""
     val = 80
@@ -556,35 +561,16 @@
     ]
 
     @staticmethod
-    def compute_message_authenticator(
-            radius_packet,
-            packed_req_authenticator,
-            shared_secret
-    ):
+    def compute_message_authenticator(radius_packet, packed_req_authenticator,
+                                      shared_secret):
         """
         Computes the "Message-Authenticator" of a given RADIUS packet.
         """
 
-        if not conf.crypto_valid:
-            g_log_loading.info(_crypto_loading_failure_message)
-            return None
+        data = prepare_packed_data(radius_packet, packed_req_authenticator)
+        radius_hmac = hmac.new(shared_secret, data, hashlib.md5)
 
-        packed_hdr = struct.pack("!B", radius_packet.code)
-        packed_hdr += struct.pack("!B", radius_packet.id)
-        packed_hdr += struct.pack("!H", radius_packet.len)
-        packed_attrs = ''
-        for index in range(0, len(radius_packet.attributes)):
-            packed_attrs = packed_attrs + str(radius_packet.attributes[index])
-
-        hmac_ = hmac.HMAC(
-            shared_secret,
-            hashes.MD5(),
-            backend=default_backend()
-        )
-        packed_data = packed_hdr + packed_req_authenticator + packed_attrs
-        hmac_.update(packed_data)
-        return hmac_.finalize()
-
+        return radius_hmac.digest()
 
 #
 # RADIUS attributes which values are IPv4 prefixes
@@ -1171,23 +1157,9 @@
         Computes the authenticator field (RFC 2865 - Section 3)
         """
 
-        if not conf.crypto_valid:
-            g_log_loading.info(_crypto_loading_failure_message)
-            return None
-
-        packed_hdr = struct.pack("!B", self.code)
-        packed_hdr += struct.pack("!B", self.id)
-        packed_hdr += struct.pack("!H", self.len)
-        packed_attrs = b''
-        for attr in self.attributes:
-            packed_attrs = packed_attrs + raw(attr)
-        packed_data = packed_hdr + packed_request_auth + packed_attrs +\
-            shared_secret
-
-        digest = hashes.Hash(hashes.MD5(), backend=default_backend())
-        digest.update(packed_data)
-        return digest.finalize()
-
+        data = prepare_packed_data(self, packed_request_auth)
+        radius_mac = hashlib.md5(data + shared_secret)
+        return radius_mac.digest()
 
     def post_build(self, p, pay):
         p += pay
diff --git a/scapy/layers/tls/automaton.py b/scapy/layers/tls/automaton.py
index c9f2329..886b1b2 100644
--- a/scapy/layers/tls/automaton.py
+++ b/scapy/layers/tls/automaton.py
@@ -130,6 +130,7 @@
                 else:
                     self.remain_in += tmp
             except:
+                self.vprint("Could not join host ! Retrying...")
                 retry -= 1
 
         if len(self.remain_in) < 2 or len(self.remain_in) != grablen:
diff --git a/scapy/layers/tls/automaton_cli.py b/scapy/layers/tls/automaton_cli.py
index d58a6b2..bda49df 100644
--- a/scapy/layers/tls/automaton_cli.py
+++ b/scapy/layers/tls/automaton_cli.py
@@ -20,6 +20,7 @@
 from __future__ import print_function
 import socket
 
+from scapy.pton_ntop import inet_pton
 from scapy.utils import randstring
 from scapy.automaton import ATMT
 from scapy.layers.tls.automaton import _TLSAutomaton
@@ -70,9 +71,9 @@
         self.remote_name = None
         try:
             if ':' in server:
-                socket.inet_pton(socket.AF_INET6, server)
+                inet_pton(socket.AF_INET6, server)
             else:
-                socket.inet_pton(socket.AF_INET, server)
+                inet_pton(socket.AF_INET, server)
         except:
             self.remote_name = socket.getfqdn(server)
             if self.remote_name != server:
diff --git a/scapy/layers/tls/automaton_srv.py b/scapy/layers/tls/automaton_srv.py
index 9f76df4..1d37aa4 100644
--- a/scapy/layers/tls/automaton_srv.py
+++ b/scapy/layers/tls/automaton_srv.py
@@ -19,6 +19,7 @@
 from __future__ import print_function
 import socket
 
+from scapy.pton_ntop import inet_pton
 from scapy.utils import randstring, repr_hex
 from scapy.automaton import ATMT
 from scapy.layers.tls.automaton import _TLSAutomaton
@@ -69,9 +70,9 @@
                                                    **kargs)
         try:
             if ':' in server:
-                socket.inet_pton(socket.AF_INET6, server)
+                inet_pton(socket.AF_INET6, server)
             else:
-                socket.inet_pton(socket.AF_INET, server)
+                inet_pton(socket.AF_INET, server)
             tmp = socket.getaddrinfo(server, sport)
         except:
             tmp = socket.getaddrinfo(socket.getfqdn(server), sport)
diff --git a/scapy/layers/tls/cert.py b/scapy/layers/tls/cert.py
index 735e63a..acd771a 100644
--- a/scapy/layers/tls/cert.py
+++ b/scapy/layers/tls/cert.py
@@ -279,9 +279,9 @@
     def import_from_tuple(self, tup):
         # this is rarely used
         e, m, mLen = tup
-        if isinstance(m, str):
+        if isinstance(m, bytes):
             m = pkcs_os2ip(m)
-        if isinstance(e, str):
+        if isinstance(e, bytes):
             e = pkcs_os2ip(e)
         self.fill_and_store(modulus=m, pubExp=e)
         self.pem = self.pubkey.public_bytes(
@@ -512,7 +512,6 @@
 
     @crypto_validator
     def import_from_asn1pkt(self, privkey):
-        print(privkey)
         self.key = serialization.load_der_private_key(raw(privkey), None,
                                                   backend=default_backend())
         self.pubkey = self.key.public_key()
diff --git a/scapy/layers/tls/crypto/cipher_block.py b/scapy/layers/tls/crypto/cipher_block.py
index bd2b04f..ab463cc 100644
--- a/scapy/layers/tls/crypto/cipher_block.py
+++ b/scapy/layers/tls/crypto/cipher_block.py
@@ -51,7 +51,7 @@
             else:
                 l = self.key_len
             key = b"\0" * l
-        if iv is None or iv == "":
+        if not iv:
             self.ready["iv"] = False
             iv = b"\0" * self.block_size
 
diff --git a/scapy/layers/tls/crypto/groups.py b/scapy/layers/tls/crypto/groups.py
index 9cef2a3..f0a9ca3 100644
--- a/scapy/layers/tls/crypto/groups.py
+++ b/scapy/layers/tls/crypto/groups.py
@@ -68,8 +68,8 @@
         return the_class
 
 
-class _FFDHParams(object):
-    __metaclass__ = _FFDHParamsMetaclass
+class _FFDHParams(six.with_metaclass(_FFDHParamsMetaclass)):
+    pass
 
 
 class modp768(_FFDHParams):
diff --git a/scapy/layers/tls/handshake.py b/scapy/layers/tls/handshake.py
index 4a4226a..95cd914 100644
--- a/scapy/layers/tls/handshake.py
+++ b/scapy/layers/tls/handshake.py
@@ -608,7 +608,7 @@
     def dispatch_hook(cls, _pkt=None, *args, **kargs):
         if _pkt:
             tls_session = kargs.get("tls_session", None)
-            if tls_session and tls_session.tls_version >= 0x0304:
+            if tls_session and (tls_session.tls_version or 0) >= 0x0304:
                 return TLS13Certificate
         return TLSCertificate
 
diff --git a/scapy/layers/tls/keyexchange.py b/scapy/layers/tls/keyexchange.py
index 386a9bb..64ed6be 100644
--- a/scapy/layers/tls/keyexchange.py
+++ b/scapy/layers/tls/keyexchange.py
@@ -120,7 +120,7 @@
         s = pkt.tls_session
         if s.tls_version and s.tls_version < 0x0300:
             if len(s.client_certs) > 0:
-                sig_len = s.client_certs[0].pubKey.pubkey.key_size / 8
+                sig_len = s.client_certs[0].pubKey.pubkey.key_size // 8
             else:
                 warning("No client certificate provided. "
                         "We're making a wild guess about the signature size.")
@@ -219,7 +219,7 @@
         i = self.m2i(pkt, s)
         if i is None:
             return s, None
-        remain = ""
+        remain = b""
         if conf.padding_layer in i:
             r = i[conf.padding_layer]
             del(r.underlayer.payload)
@@ -307,12 +307,12 @@
         default_params = _ffdh_groups['modp2048'][0].parameter_numbers()
         default_mLen = _ffdh_groups['modp2048'][1]
 
-        if self.dh_p is "":
-            self.dh_p = pkcs_i2osp(default_params.p, default_mLen/8)
+        if not self.dh_p:
+            self.dh_p = pkcs_i2osp(default_params.p, default_mLen//8)
         if self.dh_plen is None:
             self.dh_plen = len(self.dh_p)
 
-        if self.dh_g is "":
+        if not self.dh_g:
             self.dh_g = pkcs_i2osp(default_params.g, 1)
         if self.dh_glen is None:
             self.dh_glen = 1
@@ -321,11 +321,11 @@
         g = pkcs_os2ip(self.dh_g)
         real_params = dh.DHParameterNumbers(p, g).parameters(default_backend())
 
-        if self.dh_Ys is "":
+        if not self.dh_Ys:
             s.server_kx_privkey = real_params.generate_private_key()
             pubkey = s.server_kx_privkey.public_key()
             y = pubkey.public_numbers().y
-            self.dh_Ys = pkcs_i2osp(y, pubkey.key_size/8)
+            self.dh_Ys = pkcs_i2osp(y, pubkey.key_size//8)
         # else, we assume that the user wrote the server_kx_privkey by himself
         if self.dh_Yslen is None:
             self.dh_Yslen = len(self.dh_Ys)
@@ -642,13 +642,13 @@
         self.tls_session.server_tmp_rsa_key = k
         pubNum = k.pubkey.public_numbers()
 
-        if self.rsamod is "":
-            self.rsamod = pkcs_i2osp(pubNum.n, k.pubkey.key_size/8)
+        if not self.rsamod:
+            self.rsamod = pkcs_i2osp(pubNum.n, k.pubkey.key_size//8)
         if self.rsamodlen is None:
             self.rsamodlen = len(self.rsamod)
 
         rsaexplen = math.ceil(math.log(pubNum.e)/math.log(2)/8.)
-        if self.rsaexp is "":
+        if not self.rsaexp:
             self.rsaexp = pkcs_i2osp(pubNum.e, rsaexplen)
         if self.rsaexplen is None:
             self.rsaexplen = len(self.rsaexp)
@@ -722,7 +722,7 @@
         s.client_kx_privkey = params.generate_private_key()
         pubkey = s.client_kx_privkey.public_key()
         y = pubkey.public_numbers().y
-        self.dh_Yc = pkcs_i2osp(y, pubkey.key_size/8)
+        self.dh_Yc = pkcs_i2osp(y, pubkey.key_size//8)
 
         if s.client_kx_privkey and s.server_kx_pubkey:
             pms = s.client_kx_privkey.exchange(s.server_kx_pubkey)
@@ -730,7 +730,7 @@
             s.compute_ms_and_derive_keys()
 
     def post_build(self, pkt, pay):
-        if self.dh_Yc == "":
+        if not self.dh_Yc:
             try:
                 self.fill_missing()
             except ImportError:
@@ -782,8 +782,8 @@
         x = pubkey.public_numbers().x
         y = pubkey.public_numbers().y
         self.ecdh_Yc = (b"\x04" +
-                        pkcs_i2osp(x, params.key_size/8) +
-                        pkcs_i2osp(y, params.key_size/8))
+                        pkcs_i2osp(x, params.key_size//8) +
+                        pkcs_i2osp(y, params.key_size//8))
 
         if s.client_kx_privkey and s.server_kx_pubkey:
             pms = s.client_kx_privkey.exchange(ec.ECDH(), s.server_kx_pubkey)
@@ -791,7 +791,7 @@
             s.compute_ms_and_derive_keys()
 
     def post_build(self, pkt, pay):
-        if self.ecdh_Yc == "":
+        if not self.ecdh_Yc:
             try:
                 self.fill_missing()
             except ImportError:
diff --git a/scapy/layers/tls/keyexchange_tls13.py b/scapy/layers/tls/keyexchange_tls13.py
index 2bbdc51..09af443 100644
--- a/scapy/layers/tls/keyexchange_tls13.py
+++ b/scapy/layers/tls/keyexchange_tls13.py
@@ -84,7 +84,7 @@
         if self.group is None:
             self.group = 23     # secp256r1
 
-        if self.key_exchange == "":
+        if not self.key_exchange:
             try:
                 self.create_privkey()
             except ImportError:
diff --git a/scapy/layers/tls/record.py b/scapy/layers/tls/record.py
index 55a3c08..f2d5024 100644
--- a/scapy/layers/tls/record.py
+++ b/scapy/layers/tls/record.py
@@ -99,7 +99,7 @@
                 return cls(m, tls_session=pkt.tls_session)
             except:
                 if conf.debug_dissector:
-                    traceback.print_exc()
+                    raise
                 return Raw(m)
 
     def getfield(self, pkt, s):
@@ -288,6 +288,11 @@
                     if s.rcs and not isinstance(s.rcs.cipher, Cipher_NULL):
                         from scapy.layers.tls.record_tls13 import TLS13
                         return TLS13
+        if _pkt and len(_pkt) < 5:
+                # Layer detected as TLS but too small to be a real packet (len<5).
+                # Those packets appear when sessions are interrupted or to flush buffers.
+                # Scapy should not try to decode them
+            return conf.raw_layer
         return TLS
 
     ### Parsing methods
@@ -352,7 +357,7 @@
             if version > 0x300:
                 h = alg.digest(read_seq_num + hdr + msg)
             elif version == 0x300:
-                h = alg.digest_sslv3(read_seq_num + hdr[0] + hdr[3:5] + msg)
+                h = alg.digest_sslv3(read_seq_num + hdr[:1] + hdr[3:5] + msg)
             else:
                 raise Exception("Unrecognized version.")
         except HMACError:
diff --git a/scapy/modules/p0f.py b/scapy/modules/p0f.py
index bc312a1..aa1f2e9 100644
--- a/scapy/modules/p0f.py
+++ b/scapy/modules/p0f.py
@@ -22,6 +22,7 @@
 from scapy.error import warning, Scapy_Exception, log_runtime
 from scapy.volatile import RandInt, RandByte, RandChoice, RandNum, RandShort, RandString
 from scapy.sendrecv import sniff
+from scapy.modules import six
 from scapy.modules.six.moves import map, range
 if conf.route is None:
     # unused import, only to initialize conf.route
@@ -359,10 +360,7 @@
     
     if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP):
         raise TypeError("Not a TCP/IP packet")
-    
-    if uptime is None:
-        uptime = random.randint(120,100*60*60*24*365)
-    
+
     db = p0f_selectdb(pkt.payload.flags)
     if osgenre:
         pb = db.get_base()
@@ -386,7 +384,15 @@
     pers = pb[random.randint(0, len(pb) - 1)]
     
     # options (we start with options because of MSS)
-    ## TODO: let the options already set if they are valid
+    # Take the options already set as "hints" to use in the new packet if we
+    # can. MSS, WScale and Timestamp can all be wildcarded in a signature, so
+    # we'll use the already-set values if they're valid integers.
+    orig_opts = dict(pkt.payload.options)
+    int_only = lambda val: val if isinstance(val, six.integer_types) else None
+    mss_hint = int_only(orig_opts.get('MSS'))
+    wscale_hint = int_only(orig_opts.get('WScale'))
+    ts_hint = [int_only(o) for o in orig_opts.get('Timestamp', (None, None))]
+
     options = []
     if pers[4] != '.':
         for opt in pers[4].split(','):
@@ -394,42 +400,73 @@
                 # MSS might have a maximum size because of window size
                 # specification
                 if pers[0][0] == 'S':
-                    maxmss = (2**16-1) / int(pers[0][1:])
+                    maxmss = (2**16-1) // int(pers[0][1:])
                 else:
                     maxmss = (2**16-1)
+                # disregard hint if out of range
+                if mss_hint and not 0 <= mss_hint <= maxmss:
+                    mss_hint = None
                 # If we have to randomly pick up a value, we cannot use
                 # scapy RandXXX() functions, because the value has to be
                 # set in case we need it for the window size value. That's
                 # why we use random.randint()
                 if opt[1:] == '*':
-                    options.append(('MSS', random.randint(1,maxmss)))
+                    if mss_hint is not None:
+                        options.append(('MSS', mss_hint))
+                    else:
+                        options.append(('MSS', random.randint(1, maxmss)))
                 elif opt[1] == '%':
                     coef = int(opt[2:])
-                    options.append(('MSS', coef*random.randint(1,maxmss/coef)))
+                    if mss_hint is not None and mss_hint % coef == 0:
+                        options.append(('MSS', mss_hint))
+                    else:
+                        options.append((
+                            'MSS', coef*random.randint(1, maxmss//coef)))
                 else:
                     options.append(('MSS', int(opt[1:])))
             elif opt[0] == 'W':
+                if wscale_hint and not 0 <= wscale_hint < 2**8:
+                    wscale_hint = None
                 if opt[1:] == '*':
-                    options.append(('WScale', RandByte()))
+                    if wscale_hint is not None:
+                        options.append(('WScale', wscale_hint))
+                    else:
+                        options.append(('WScale', RandByte()))
                 elif opt[1] == '%':
                     coef = int(opt[2:])
-                    options.append(('WScale', coef*RandNum(min=1,
-                                                           max=(2**8-1)/coef)))
+                    if wscale_hint is not None and wscale_hint % coef == 0:
+                        options.append(('WScale', wscale_hint))
+                    else:
+                        options.append((
+                            'WScale', coef*RandNum(min=1, max=(2**8-1)//coef)))
                 else:
                     options.append(('WScale', int(opt[1:])))
             elif opt == 'T0':
                 options.append(('Timestamp', (0, 0)))
             elif opt == 'T':
-                if 'T' in pers[5]:
+                # Determine first timestamp.
+                if uptime is not None:
+                    ts_a = uptime
+                elif ts_hint[0] and 0 < ts_hint[0] < 2**32:
+                    # Note: if first ts is 0, p0f registers it as "T0" not "T",
+                    # hence we don't want to use the hint if it was 0.
+                    ts_a = ts_hint[0]
+                else:
+                    ts_a = random.randint(120, 100*60*60*24*365)
+                # Determine second timestamp.
+                if 'T' not in pers[5]:
+                    ts_b = 0
+                elif ts_hint[1] and 0 < ts_hint[1] < 2**32:
+                    ts_b = ts_hint[1]
+                else:
                     # FIXME: RandInt() here does not work (bug (?) in
                     # TCPOptionsField.m2i often raises "OverflowError:
                     # long int too large to convert to int" in:
                     #    oval = struct.pack(ofmt, *oval)"
                     # Actually, this is enough to often raise the error:
                     #    struct.pack('I', RandInt())
-                    options.append(('Timestamp', (uptime, random.randint(1,2**32-1))))
-                else:
-                    options.append(('Timestamp', (uptime, 0)))
+                    ts_b = random.randint(1, 2**32-1)
+                options.append(('Timestamp', (ts_a, ts_b)))
             elif opt == 'S':
                 options.append(('SAckOK', ''))
             elif opt == 'N':
@@ -457,7 +494,7 @@
         pkt.payload.window = int(pers[0])
     elif pers[0][0] == '%':
         coef = int(pers[0][1:])
-        pkt.payload.window = coef * RandNum(min=1,max=(2**16-1)/coef)
+        pkt.payload.window = coef * RandNum(min=1, max=(2**16-1)//coef)
     elif pers[0][0] == 'T':
         pkt.payload.window = mtu * int(pers[0][1:])
     elif pers[0][0] == 'S':
@@ -465,7 +502,7 @@
         mss = [x for x in options if x[0] == 'MSS']
         if not mss:
             raise Scapy_Exception("TCP window value requires MSS, and MSS option not set")
-        pkt.payload.window = filter(lambda x: x[0] == 'MSS', options)[0][1] * int(pers[0][1:])
+        pkt.payload.window = mss[0][1] * int(pers[0][1:])
     else:
         raise Scapy_Exception('Unhandled window size specification')
     
@@ -487,7 +524,7 @@
                 if db == p0fo_kdb:
                     pkt.payload.flags |= 0x20 # U
                 else:
-                    pkt.payload.flags |= RandChoice(8, 32, 40) #P / U / PU
+                    pkt.payload.flags |= random.choice([8, 32, 40])  # P/U/PU
             elif qq == 'D' and db != p0fo_kdb:
                 pkt /= conf.raw_layer(load=RandString(random.randint(1, 10))) # XXX p0fo.fp
             elif qq == 'Q': pkt.payload.seq = pkt.payload.ack
diff --git a/scapy/packet.py b/scapy/packet.py
index 50f0901..9c17050 100644
--- a/scapy/packet.py
+++ b/scapy/packet.py
@@ -497,7 +497,7 @@
         if filename is None:
             fname = get_temp_file(autoext=".eps")
             canvas.writeEPSfile(fname)
-            with ContextManagerSubprocess("psdump()"):
+            with ContextManagerSubprocess("psdump()", conf.prog.psreader):
                 subprocess.Popen([conf.prog.psreader, fname])
         else:
             canvas.writeEPSfile(filename)
@@ -515,7 +515,7 @@
         if filename is None:
             fname = get_temp_file(autoext=".pdf")
             canvas.writePDFfile(fname)
-            with ContextManagerSubprocess("pdfdump()"):
+            with ContextManagerSubprocess("pdfdump()", conf.prog.pdfreader):
                 subprocess.Popen([conf.prog.pdfreader, fname])
         else:
             canvas.writePDFfile(filename)
diff --git a/scapy/pton_ntop.py b/scapy/pton_ntop.py
index 0779336..b54a62c 100644
--- a/scapy/pton_ntop.py
+++ b/scapy/pton_ntop.py
@@ -80,10 +80,8 @@
 def inet_pton(af, addr):
     """Convert an IP address from text representation into binary form."""
     # Will replace Net/Net6 objects
-    if not isinstance(addr, str):
-        addr = str(addr)
-    # Use inet_pton if available
     addr = plain_str(addr)
+    # Use inet_pton if available
     try:
         return socket.inet_pton(af, addr)
     except AttributeError:
diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py
index b5c1380..d67e010 100644
--- a/scapy/sendrecv.py
+++ b/scapy/sendrecv.py
@@ -853,7 +853,11 @@
 
 @conf.commands.register
 def tshark(*args,**kargs):
-    """Sniff packets and print them calling pkt.show(), a bit like text wireshark"""
-    sniff(prn=lambda x: x.display(),*args,**kargs)
-
-
+    """Sniff packets and print them calling pkt.summary(), a bit like text wireshark"""
+    print("Capturing on '" + str(kargs.get('iface') if 'iface' in kargs else conf.iface) + "'")
+    i = [0]  # This should be a nonlocal variable, using a mutable object for Python 2 compatibility
+    def _cb(pkt):
+        print("%5d\t%s" % (i[0], pkt.summary()))
+        i[0] += 1
+    sniff(prn=_cb, store=False, *args, **kargs)
+    print("\n%d packet%s captured" % (i[0], 's' if i[0] > 1 else ''))
diff --git a/scapy/utils.py b/scapy/utils.py
index b6d481b..8822e01 100644
--- a/scapy/utils.py
+++ b/scapy/utils.py
@@ -429,17 +429,21 @@
     >>>     subprocess.Popen(["unknown_command"])
 
     """
-    def __init__(self, name):
+    def __init__(self, name, prog):
         self.name = name
+        self.prog = prog
 
     def __enter__(self):
         pass
 
     def __exit__(self, exc_type, exc_value, traceback):
-        if exc_type == OSError:
-            msg = "%s: executing %r failed"
-            log_runtime.error(msg, self.name, conf.prog.wireshark, exc_info=1)
-            return True  # Suppress the exception
+        if isinstance(exc_value, (OSError, TypeError)):
+            msg = "%s: executing %r failed" % (self.name, self.prog) if self.prog else "Could not execute %s, is it installed ?" % self.name
+            if not conf.interactive:
+                raise OSError(msg)
+            else:
+                log_runtime.error(msg, exc_info=True)
+                return True  # Suppress the exception
 
 class ContextManagerCaptureOutput(object):
     """
@@ -500,7 +504,7 @@
             target = get_temp_file(autoext="."+format)
             start_viewer = True
         else:
-            with ContextManagerSubprocess("do_graph()"):
+            with ContextManagerSubprocess("do_graph()", conf.prog.display):
                 target = subprocess.Popen([conf.prog.display],
                                           stdin=subprocess.PIPE).stdin
     if format is not None:
@@ -532,7 +536,7 @@
             if conf.prog.display == conf.prog._default:
                 os.startfile(target.name)
             else:
-                with ContextManagerSubprocess("do_graph()"):
+                with ContextManagerSubprocess("do_graph()", conf.prog.display):
                     subprocess.Popen([conf.prog.display, target.name])
 
 _TEX_TR = {
@@ -1214,7 +1218,7 @@
     """Run wireshark on a list of packets"""
     f = get_temp_file()
     wrpcap(f, pktlist)
-    with ContextManagerSubprocess("wireshark()"):
+    with ContextManagerSubprocess("wireshark()", conf.prog.wireshark):
         subprocess.Popen([conf.prog.wireshark, "-r", f])
 
 @conf.commands.register
@@ -1275,15 +1279,16 @@
         prog = [conf.prog.tcpdump]
     elif isinstance(prog, six.string_types):
         prog = [prog]
+    _prog_name = "windump()" if WINDOWS else "tcpdump()"
     if pktlist is None:
-        with ContextManagerSubprocess("tcpdump()"):
+        with ContextManagerSubprocess(_prog_name, prog[0]):
             proc = subprocess.Popen(
                 prog + (args if args is not None else []),
                 stdout=subprocess.PIPE if dump or getfd else None,
                 stderr=open(os.devnull) if quiet else None,
             )
     elif isinstance(pktlist, six.string_types):
-        with ContextManagerSubprocess("tcpdump()"):
+        with ContextManagerSubprocess(_prog_name, prog[0]):
             proc = subprocess.Popen(
                 prog + ["-r", pktlist] + (args if args is not None else []),
                 stdout=subprocess.PIPE if dump or getfd else None,
@@ -1299,7 +1304,7 @@
             wrpcap(tmpfile, pktlist)
         else:
             tmpfile.close()
-        with ContextManagerSubprocess("tcpdump()"):
+        with ContextManagerSubprocess(_prog_name, prog[0]):
             proc = subprocess.Popen(
                 prog + ["-r", tmpfile.name] + (args if args is not None else []),
                 stdout=subprocess.PIPE if dump or getfd else None,
@@ -1307,7 +1312,7 @@
             )
         conf.temp_files.append(tmpfile.name)
     else:
-        with ContextManagerSubprocess("tcpdump()"):
+        with ContextManagerSubprocess(_prog_name, prog[0]):
             proc = subprocess.Popen(
                 prog + ["-r", "-"] + (args if args is not None else []),
                 stdin=subprocess.PIPE,
@@ -1333,7 +1338,7 @@
     x = str(x)
     f = get_temp_file()
     open(f,"wb").write(x)
-    with ContextManagerSubprocess("hexedit()"):
+    with ContextManagerSubprocess("hexedit()", conf.prog.hexedit):
         subprocess.call([conf.prog.hexedit, f])
     x = open(f).read()
     os.unlink(f)
diff --git a/scapy/volatile.py b/scapy/volatile.py
index 8b86213..0e963db 100644
--- a/scapy/volatile.py
+++ b/scapy/volatile.py
@@ -121,6 +121,8 @@
         return other - self._fix()
     def __mul__(self, other):
         return self._fix() * other
+    def __rmul__(self, other):
+        return other * self._fix()
     def __floordiv__(self, other):
         return self._fix() / other
     __div__ = __floordiv__
diff --git a/test/can.uts b/test/can.uts
new file mode 100644
index 0000000..ed55dd9
--- /dev/null
+++ b/test/can.uts
@@ -0,0 +1,55 @@
+% Regression tests for the CAN layer
+
+# More informations at http://www.secdev.org/projects/UTscapy/
+
+
+############
+############
+
++ Basic operations
+
+= Load module
+
+load_layer("can")
+
+= Build a packet
+
+pkt = CAN(flags="error", identifier=1234, data="test")
+
+= Dissect & parse
+
+pkt = CAN(raw(pkt))
+pkt.flags == "error" and pkt.identifier == 1234 and pkt.length == 4 and pkt.data == b"test"
+
+
+############
+############
+
++ Example PCAP file
+
+= Read PCAP file
+* From https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=CANopen.pca
+
+from io import BytesIO
+pcap_fd = BytesIO(b'\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\xe3\x00\x00\x00\xe2\xf3mT\x93\x8c\x03\x00\t\x00\x00\x00\t\x00\x00\x00\x00\x00\x073\x01\x00\x00\x00\x00\xe2\xf3mT\xae\x8c\x03\x00\n\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x02\x7f\x00\x00\x81\x00\xe2\xf3mTI\x8f\x03\x00\t\x00\x00\x00\t\x00\x00\x00\x00\x00\x07B\x01\x00\x00\x00\x00\xe2\xf3mTM\x8f\x03\x00\t\x00\x00\x00\t\x00\x00\x00\x00\x00\x07c\x01\x00\x00\x00\x00\xe2\xf3mTN\x8f\x03\x00\t\x00\x00\x00\t\x00\x00\x00\x00\x00\x07!\x01\x00\x00\x00\x00\xf8\xf3mTv\x98\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x7f\x00\x00@\x08\x10\x00\x00\x00\x00\x00\xf8\xf3mT\x96\x98\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x05\xc2\x08\x7f\x00\x00A\x08\x10\x00\x15\x00\x00\x00\xf8\xf3mT\xd4\x98\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\xf8\xf3mT\x12\x99\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x00\x00\x00\x80\x00\x00\x00!\x00\x00\x08\xf8\xf3mTC\x99\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x05\xc2\x08\x7f\x00\x00\x00UltraHi\xf8\xf3mTx\x99\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x00\x00\x00\x80\x00\x00\x00!\x00\x00\x08\xf8\xf3mT\xce\x99\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x00\x00\x00p\x00\x00\x00\x00\x00\x00\x00\xf8\xf3mT\xe0\x99\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x00\x00\x00\x80\x00\x00\x00!\x00\x00\x08\xf8\xf3mT \x9a\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x00\x00\x00\x80\x00\x00\x00!\x00\x00\x08\xf8\xf3mTo\x9a\x04\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x05\xc2\x08\x00\x00\x00\x80\x00\x00\x00!\x00\x00\x083\xf4mTw\xbe\t\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x7f\x00\x00@\x08\x10*\x00\x00\x00\x003\xf4mT4\xc0\t\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x05\xc2\x08\x00\x00\x00\x80\x08\x10*\x11\x00\t\x06i\xf4mT\xb0\x88\x0c\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x07\xe5\x08\x7f\x00\x00L\x00\x00\x00\x00\x00\x00\x00i\xf4mT+\x89\x0c\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x07\xe4\x08\x7f\x00\x00P\x00\x00\x00\x00\x00\x00\x00i\xf4mT-\x89\x0c\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x07\xe4\x08\x7f\x00\x00P\x00\x00\x00\x00\x00\x00\x00i\xf4mTS\x89\x0c\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x07\xe4\x08\x7f\x00\x00P\x00\x00\x00\x00\x00\x00\x00i\xf4mT\x99\x89\x0c\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x07\xe4\x08\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x8e\xf4mT\x86\xc4\x04\x00\n\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01B\x92\xf4mT\xae\xf0\x07\x00\n\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\xba\xf4mT%\xaa\x0b\x00\n\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02c\xe8\xf4mT\xbc\x0f\x06\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x7f\x00\x00#\x00b\x01asdf\xe8\xf4mT\x07\x10\x06\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x05\xc2\x08\x00\x00\x00\x80\x00b\x01\x00\x00\x02\x06\x0f\xf5mT\x1c\x81\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x7f\x00\x00@\x00b\x01\x00\x00\x00\x00\x0f\xf5mT\xfe\x81\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x05\xc2\x08\x00\x00\x00\x80\x00b\x01\x00\x00\x02\x068\xf5mT\x19\xc3\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x7f\x00\x00\xa0\x08\x10\x00\x10\x00\x00\x008\xf5mTg\xc3\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x05\xc2\x08\x7f\x00\x00\xc2\x08\x10\x00\x15\x00\x00\x008\xf5mT\xd8\xc3\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x00\x00\x00\x80\x00\x00\x00!\x00\x00\x088\xf5mT\x17\xc4\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x06B\x08\x7f\x00\x00\xa3\x00\x00\x00\x00\x00\x00\x008\xf5mT\xca\xc4\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x00\x00\x05\xc2\x08\x00\x00\x00\x80\x00\x00\x00!\x00\x00\x08')
+packets = rdpcap(pcap_fd)
+
+= Check if parsing worked: each packet has a CAN layer
+
+all(CAN in pkt for pkt in packets)
+
+= Check if parsing worked: no packet has a Raw or Padding layer
+
+not any(Raw in pkt or Padding in pkt for pkt in packets)
+
+= Identifiers
+
+set(pkt.identifier for pkt in packets) == {0, 1474, 1602, 1825, 1843, 1858, 1891, 2020, 2021}
+
+= Flags
+
+set(pkt.flags for pkt in packets) == {0}
+
+= Data length
+
+set(pkt.length for pkt in packets) == {1, 2, 8}
diff --git a/test/dnssecRR.uts b/test/dnssecRR.uts
index ab165bd..63599ad 100644
--- a/test/dnssecRR.uts
+++ b/test/dnssecRR.uts
@@ -117,6 +117,11 @@
 = DNSRR(type="TXT") instanciation
 t = DNSRR(type="TXT", rdata="test")
 
+= Build DNSRR
+an = DNSRR(type='AAAA', rdata='2001::1')
+an = DNSRR(raw(an))
+assert an.rdata == '2001::1'
+
 = DNSRRR(), check parameters
 t = DNSRR(b'\x04test\x00\x00\x10\x00\x01\x00\x00\x00\x00\x018\xffScapy is an interactive packet manipulation program that enables you to sniff, mangle, send network packets ; test equipments ; probe and discover networks ; quickly develop new protocols. It can easily handle most classical tasks like scanning, tracerout7ing, probing, unit tests, attacks or network discovery.')
 t.type == 16 and t.rdlen == 312 and t.rdata[:5] == b"Scapy" and t.rdata[-10:] == b"discovery."
diff --git a/test/mock_windows.uts b/test/mock_windows.uts
index b016294..1cb1b56 100644
--- a/test/mock_windows.uts
+++ b/test/mock_windows.uts
@@ -193,6 +193,81 @@
 
 test_missing_ifacemetric()
 
+= Test _get_metrics with weird netsh length
+
+from scapy.arch.windows import _get_metrics
+
+@mock.patch("scapy.arch.windows.POWERSHELL_PROCESS.query")
+def test_get_metrics(mock_exec_query):
+    exc_query_output = """Interface Loopback Pseudo-Interface 1 Parameters
+-------------------------------
+IfLuid : loopback_0
+IfIndex : 1
+State : connected
+Metric : 75
+Link MTU : 4294967295 byt
+Reachable Time : 40500 ms
+Base Reachable Time : 30000 ms
+Retransmission Interval : 1000 ms
+DAD Transmits : 0
+Site Prefix Length : 64
+Site Id : 1
+Forwarding : disabled
+Advertising : disabled
+Neighbor Discovery : disabled
+Neighbor Unreachability Detection : disabled
+Router Discovery : dhcp
+Managed Address Configuration : enabled
+Other Stateful Configuration : enabled
+Weak Host Sends : disabled
+Weak Host Receives : disabled
+Use Automatic Metric : enabled
+Ignore Default Routes : disabled
+Advertised Router Lifetime : 1800 seconds
+Advertise Default Route : disabled
+Current Hop Limit : 0
+Force ARPND Wake up patterns : disabled
+Directed MAC Wake up patterns : disabled
+ECN capability : application
+
+Interface Wi-Fi Parameters
+-------------------------------
+IfLuid : wireless_32768
+IfIndex : 7
+State : connected
+Metric : 55
+Link MTU : 1500 bytes
+Reachable Time : 43500 ms
+Base Reachable Time : 30000 ms
+Retransmission Interval : 1000 ms
+DAD Transmits : 3
+Site Prefix Length : 64
+Site Id : 1
+Forwarding : disabled
+Advertising : disabled
+Neighbor Discovery : enabled
+Neighbor Unreachability Detection : enabled
+Router Discovery : dhcp
+Managed Address Configuration : enabled
+Other Stateful Configuration : enabled
+Weak Host Sends : disabled
+Weak Host Receives : disabled
+Use Automatic Metric : enabled
+Ignore Default Routes : disabled
+Advertised Router Lifetime : 1800 seconds
+Advertise Default Route : disabled
+Current Hop Limit : 0
+Force ARPND Wake up patterns : disabled
+Directed MAC Wake up patterns : disabled
+ECN capability : application
+"""
+    mock_exec_query.side_effect = lambda *args, **kargs: exc_query_output.split("\n")
+    metrics = _get_metrics()
+    print(metrics)
+    assert metrics == {'1': 75, '7': 55}
+
+test_get_metrics()
+
 ############
 ############
 + Windows arch unit tests
@@ -206,21 +281,23 @@
 from scapy.config import conf
 
 ps_ip = get_ip_from_name(conf.iface.name)
-ps_ip
 ps_if_list = get_windows_if_list()
-ps_if_list
 ps_read_routes = read_routes()
-ps_read_routes
 
 # Turn on VBS mode
 conf.prog.powershell = None
 
 = Test get_ip_from_name with VBS
+ps_ip
+
 assert get_ip_from_name(conf.iface.name) == ps_ip
 
 = Test get_windows_if_list with VBS
+ps_if_list
 
 def is_in_if_list(i, list):
+    if not i["mac"]:
+        return True
     for j in list:
         if j["guid"] == i["guid"] and j["name"] == i["name"]:
             return True
@@ -229,20 +306,23 @@
 vbs_if_list = get_windows_if_list()
 vbs_if_list
 _correct = True
-for i in ps_if_list:
-    if not is_in_if_list(i, vbs_if_list):
+for i in vbs_if_list:
+    if not is_in_if_list(i, ps_if_list):
         _correct = False
         break
 
 assert _correct
 
 = Test read_routes with VBS
+ps_read_routes
 
 def is_in_route_list(i, list):
+    # Ignore all empty IP or macs
+    if i[4] == '':
+        return True
+    if i[3].mac == '' or i[3].guid == '' or i[3].ip == '':
+        return True
     for j in list:
-        #Ignore all empty IP
-        if j[4] == '' or i[4] == '':
-            return True
         if j[2] == i[2] and j[4] == i[4] and j[3].guid == i[3].guid:
             return True
     return False
@@ -250,8 +330,8 @@
 vbs_read_routes = read_routes()
 vbs_if_list
 _correct = True
-for i in ps_read_routes:
-    if not is_in_route_list(i, vbs_read_routes):
+for i in vbs_read_routes:
+    if not is_in_route_list(i, ps_read_routes):
         _correct = False
         break
 
diff --git a/test/nmap.uts b/test/nmap.uts
index 3c64e74..2c3d508 100644
--- a/test/nmap.uts
+++ b/test/nmap.uts
@@ -9,6 +9,14 @@
 = Module loading
 load_module('nmap')
 
+= Test functions
+
+d = nmap_udppacket_sig(IP()/UDP(), IP(raw(IP()/ICMP(type=3, code=2)/IPerror()/UDPerror())))
+assert len(d) == 9
+
+d = nmap_tcppacket_sig(IP()/TCP())
+assert len(d) == 5
+
 = Fetch database
 from __future__ import print_function
 try:
diff --git a/test/p0f.uts b/test/p0f.uts
new file mode 100644
index 0000000..04f415b
--- /dev/null
+++ b/test/p0f.uts
@@ -0,0 +1,62 @@
+% Tests for Scapy's p0f module.
+
+~ p0f
+
+
+############
+############
++ Basic p0f module tests
+
+= Module loading
+load_module('p0f')
+
+
+############
+############
++ Tests for p0f_impersonate
+
+# XXX: a lot of pieces of p0f_impersonate don't have tests yet.
+
+= Impersonate when window size must be multiple of some integer
+sig = ('%467', 64, 1, 60, 'M*,W*', '.', 'Phony Sys', '1.0')
+pkt = p0f_impersonate(IP()/TCP(), signature=sig)
+assert pkt.payload.window % 467 == 0
+
+= Handle unusual flags ("F") quirk
+sig = ('1024', 64, 0, 60, 'W*', 'F', 'Phony Sys', '1.0')
+pkt = p0f_impersonate(IP()/TCP(), signature=sig)
+assert (pkt.payload.flags & 40) in (8, 32, 40)
+
+= Use valid option values from original packet
+sig = ('S4', 64, 1, 60, 'M*,W*,T', '.', 'Phony Sys', '1.0')
+opts = [('MSS', 1400), ('WScale', 3), ('Timestamp', (97256, 0))]
+pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig)
+assert pkt.payload.options == opts
+
+= Use valid option values when multiples required
+sig = ('S4', 64, 1, 60, 'M%37,W%19', '.', 'Phony Sys', '1.0')
+opts = [('MSS', 37*15), ('WScale', 19*12)]
+pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig)
+assert pkt.payload.options == opts
+
+= Discard non-multiple option values when multiples required
+sig = ('S4', 64, 1, 60, 'M%37,W%19', '.', 'Phony Sys', '1.0')
+opts = [('MSS', 37*15 + 1), ('WScale', 19*12 + 1)]
+pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig)
+assert pkt.payload.options[0][1] % 37 == 0
+assert pkt.payload.options[1][1] % 19 == 0
+
+= Discard bad timestamp values
+sig = ('S4', 64, 1, 60, 'M*,T', '.', 'Phony Sys', '1.0')
+opts = [('Timestamp', (0, 1000))]
+pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig)
+# since option is "T" and not "T0":
+assert pkt.payload.options[1][1][0] > 0
+# since T quirk is not present:
+assert pkt.payload.options[1][1][1] == 0
+
+= Discard 2nd timestamp of 0 if "T" quirk is present
+sig = ('S4', 64, 1, 60, 'M*,T', 'T', 'Phony Sys', '1.0')
+opts = [('Timestamp', (54321, 0))]
+pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig)
+assert pkt.payload.options[1][1][1] > 0
diff --git a/test/regression.uts b/test/regression.uts
index 64f8226..3569724 100644
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -5550,6 +5550,10 @@
 values = [tuple(int(val) for val in line[:-1].split(b'\t')) for line in tcpdump(pcapfile, prog=conf.prog.tshark, getfd=True, args=['-T', 'fields', '-e', 'ip.ttl', '-e', 'ip.proto'])]
 assert values == [(64, 6), (64, 17), (64, 1)]
 
+= Run scapy's tshark command
+~ netaccess
+tshark(count=1, timeout=3)
+
 = Check Raw IP pcap files
 
 import tempfile
@@ -8134,6 +8138,10 @@
 assert(radius_packet.attributes[16].len == 6)
 assert(radius_packet.attributes[16].value == 50118)
 
+= RADIUS - compute_message_authenticator()
+ram = radius_packet[RadiusAttr_Message_Authenticator]
+assert ram.compute_message_authenticator(radius_packet, b"dummy bytes", b"scapy") == b'\x19\xa4\x0e*Y4\xe0l?,\x94\x9f \xb8Jb'
+
 = RADIUS - Access-Challenge - Dissection (2)
 s = b'\x0b\xae\x00[\xc7\xae\xfc6\xa1=\xb5\x99&^\xdf=\xe9\x00\xa6\xe8\x12\rHello, leapO\x16\x01\x02\x00\x14\x11\x01\x00\x08\xb8\xc4\x1a4\x97x\xd3\x82leapP\x12\xd3\x12\x17\xa6\x0c.\x94\x85\x03]t\xd1\xdb\xd0\x13\x8c\x18\x12iQs\xf7iSb@k\x9d,\xa0\x99\x8ehO'
 radius_packet = Radius(s)
@@ -8235,7 +8243,6 @@
 assert(radius_packet.attributes[3].value == b'iQs\xf7hRb@k\x9d,\xa0\x99\x8ehO')
 
 = RADIUS - Response Authenticator computation
-~ crypto
 s = b'\x01\xae\x01\x17>k\xd4\xc4\x19V\x0b*1\x99\xc8D\xea\xc2\x94Z\x01\x06leap\x06\x06\x00\x00\x00\x02\x1a\x1b\x00\x00\x00\t\x01\x15service-type=Framed\x0c\x06\x00\x00#\xee\x1e\x13AC-7E-8A-4E-E2-92\x1f\x1300-26-73-9E-0F-D3O\x0b\x02\x01\x00\t\x01leapP\x12U\xbc\x12\xcdM\x00\xf8\xdb4\xf1\x18r\xca_\x8c\xf6f\x02\x1a1\x00\x00\x00\t\x01+audit-session-id=0AC8090E0000001A0354CA00\x1a\x14\x00\x00\x00\t\x01\x0emethod=dot1x\x08\x06\xc0\xa8\n\xb9\x04\x06\xc0\xa8\n\x80\x1a\x1d\x00\x00\x00\t\x02\x17GigabitEthernet1/0/18W\x17GigabitEthernet1/0/18=\x06\x00\x00\x00\x0f\x05\x06\x00\x00\xc3\xc6'
 access_request = Radius(s)
 s = b'\x0b\xae\x00[\xc7\xae\xfc6\xa1=\xb5\x99&^\xdf=\xe9\x00\xa6\xe8\x12\rHello, leapO\x16\x01\x02\x00\x14\x11\x01\x00\x08\xb8\xc4\x1a4\x97x\xd3\x82leapP\x12\xd3\x12\x17\xa6\x0c.\x94\x85\x03]t\xd1\xdb\xd0\x13\x8c\x18\x12iQs\xf7iSb@k\x9d,\xa0\x99\x8ehO'
diff --git a/test/tls.uts b/test/tls.uts
index 84ce41b..ffaf690 100644
--- a/test/tls.uts
+++ b/test/tls.uts
@@ -968,6 +968,9 @@
 assert(isinstance(t7.msg[0], _TLSEncryptedContent))
 len(t7.msg[0].load) == 478
 
+= Reading TLS msg dissect - Packet too small
+assert isinstance(TLS(b"\x00"), Raw)
+
 = Reading TLS msg dissect - Wrong data
 from scapy.layers.tls.record import _TLSMsgListField
 assert isinstance(_TLSMsgListField.m2i(_TLSMsgListField("", []), TLS(type=0), '\x00\x03\x03\x00\x03abc'), Raw)
diff --git a/test/tls/tests_tls_netaccess.uts b/test/tls/tests_tls_netaccess.uts
index 63424ca..30ea346 100644
--- a/test/tls/tests_tls_netaccess.uts
+++ b/test/tls/tests_tls_netaccess.uts
@@ -9,7 +9,7 @@
 ### DISCLAIMER: Those tests are slow ###
 
 = Load server util functions
-~ open_ssl_client
+~ open_ssl_client crypto
 
 from __future__ import print_function
 
@@ -64,28 +64,29 @@
 
 
 = Testing TLS server with TLS 1.0 and TLS_RSA_WITH_RC4_128_SHA
-~ open_ssl_client FIXME_py3
+~ open_ssl_client crypto
 
 test_tls_server("RC4-SHA", "-tls1")
 
 = Testing TLS server with TLS 1.1 and TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
-~ open_ssl_client FIXME_py3
+~ open_ssl_client crypto
 
 test_tls_server("EDH-RSA-DES-CBC3-SHA", "-tls1_1")
 
 = Testing TLS server with TLS 1.2 and TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
-~ open_ssl_client FIXME_py3
+~ open_ssl_client crypto
 
 test_tls_server("DHE-RSA-AES128-SHA256", "-tls1_2")
 
 = Testing TLS server with TLS 1.2 and TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
-~ open_ssl_client FIXME_py3
+~ open_ssl_client crypto
 
 test_tls_server("ECDHE-RSA-AES256-GCM-SHA384", "-tls1_2")
 
 + TLS client automaton tests
 
 = Load client utils functions
+~ crypto
 
 import sys, os, threading
 
@@ -112,32 +113,32 @@
         assert False
 
 = Testing TLS server and client with SSLv2 and SSL_CK_DES_192_EDE3_CBC_WITH_MD5
-~ FIXME_py3
+~ crypto
 
 perform_tls_client_test("0700c0", "0002")
 
 = Testing TLS client with SSLv3 and TLS_RSA_EXPORT_WITH_RC4_40_MD5
-~ FIXME_py3
+~ crypto
 
 perform_tls_client_test("0003", "0300")
 
 = Testing TLS client with TLS 1.0 and TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
-~ FIXME_py3
+~ crypto
 
 perform_tls_client_test("0088", "0301")
 
 = Testing TLS client with TLS 1.1 and TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
-~ FIXME_py3
+~ crypto
 
 perform_tls_client_test("c013", "0302")
 
 = Testing TLS client with TLS 1.2 and TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
-~ FIXME_py3
+~ crypto
 
 perform_tls_client_test("009e", "0303")
 
 = Testing TLS client with TLS 1.2 and TLS_ECDH_anon_WITH_RC4_128_SHA
-~ FIXME_py3
+~ crypto
 
 perform_tls_client_test("c016", "0303")