Repository: secdev/scapy

Issue:
len(pkt) error for some packet like CDP/VTP
#### Brief description
I tried to test len of packet but found that python3.7+scapy does not work and raise below exception

some special packet that I have tried: CPD, VTP, 

It is ok with python2.7
```
root@trex:/tmp# python
Python 2.7.12 (default, Nov 12 2018, 14:36:49) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.contrib.cdp import *
>>> from scapy.all import *
>>> pkt=CDPv2_HDR(vers=2, ttl=180, msg='123')
>>> len(pkt)
7
>>> 
```

python3.7
```
root@ubuntu:/workspace/_prototype/rtg-avatar# python
Python 3.7.5 (default, Nov  7 2019, 10:50:52) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> from scapy.contrib import *
>>> pkt=CDPv2_HDR(vers=2, ttl=180, msg='123')
>>> len(pkt)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/dist-packages/scapy/packet.py", line 522, in __len__
    return len(self.__bytes__())
  File "/usr/local/lib/python3.7/dist-packages/scapy/packet.py", line 487, in __bytes__
    return self.build()
  File "/usr/local/lib/python3.7/dist-packages/scapy/packet.py", line 607, in build
    p = self.do_build()
  File "/usr/local/lib/python3.7/dist-packages/scapy/packet.py", line 594, in do_build
    return self.post_build(pkt, pay)
  File "/usr/local/lib/python3.7/dist-packages/scapy/contrib/cdp.py", line 371, in post_build
    cksum = checksum(self._check_len(p))
  File "/usr/local/lib/python3.7/dist-packages/scapy/contrib/cdp.py", line 361, in _check_len
    if last_chr <= b'\x80':
TypeError: '<=' not supported between instances of 'int' and 'bytes'
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 63, in apport_excepthook
    from apport.fileutils import likely_packaged, get_recent_crashes
  File "/usr/lib/python3/dist-packages/apport/__init__.py", line 5, in <module>
    from apport.report import Report
  File "/usr/lib/python3/dist-packages/apport/report.py", line 30, in <module>
    import apport.fileutils
  File "/usr/lib/python3/dist-packages/apport/fileutils.py", line 23, in <module>
    from apport.packaging_impl import impl as packaging
  File "/usr/lib/python3/dist-packages/apport/packaging_impl.py", line 24, in <module>
    import apt
  File "/usr/lib/python3/dist-packages/apt/__init__.py", line 23, in <module>
    import apt_pkg
ModuleNotFoundError: No module named 'apt_pkg'

Original exception was:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/dist-packages/scapy/packet.py", line 522, in __len__
    return len(self.__bytes__())
  File "/usr/local/lib/python3.7/dist-packages/scapy/packet.py", line 487, in __bytes__
    return self.build()
  File "/usr/local/lib/python3.7/dist-packages/scapy/packet.py", line 607, in build
    p = self.do_build()
  File "/usr/local/lib/python3.7/dist-packages/scapy/packet.py", line 594, in do_build
    return self.post_build(pkt, pay)
  File "/usr/local/lib/python3.7/dist-packages/scapy/contrib/cdp.py", line 371, in post_build
    cksum = checksum(self._check_len(p))
  File "/usr/local/lib/python3.7/dist-packages/scapy/contrib/cdp.py", line 361, in _check_len
    if last_chr <= b'\x80':
TypeError: '<=' not supported between instances of 'int' and 'bytes'
>>> 
```

#### Environment

-   Scapy version: `2.4.3`
-   Python version: `3.7` and `2.7`
-   Operating System: `Ubuntu18.04`



Discussion:
Thanks reporting the issue. I managed to reproduce the problem and will provide a fix.

Resolving patch:
diff --git a/scapy/contrib/cdp.py b/scapy/contrib/cdp.py
--- a/scapy/contrib/cdp.py
+++ b/scapy/contrib/cdp.py
@@ -371,9 +371,9 @@ def _check_len(self, pkt):
         This padding is only used for checksum computation.  The original
         packet should not be altered."""
         if len(pkt) % 2:
-            last_chr = pkt[-1]
-            if last_chr <= b'\x80':
-                return pkt[:-1] + b'\x00' + last_chr
+            last_chr = orb(pkt[-1])
+            if last_chr <= 0x80:
+                return pkt[:-1] + b'\x00' + chb(last_chr)
             else:
                 return pkt[:-1] + b'\xff' + chb(orb(last_chr) - 1)
         else:
diff --git a/scapy/contrib/vtp.py b/scapy/contrib/vtp.py
--- a/scapy/contrib/vtp.py
+++ b/scapy/contrib/vtp.py
@@ -63,6 +63,7 @@
     FieldLenField, IPField, PacketListField, ShortField, SignedIntField, \
     StrFixedLenField, StrLenField, XIntField
 from scapy.layers.l2 import SNAP
+from scapy.compat import chb
 from scapy.config import conf
 
 _VTP_VLAN_TYPE = {
@@ -125,7 +126,7 @@ def post_build(self, p, pay):
 
         if self.len is None:
             tmp_len = vlannamelen + 12
-            p = chr(tmp_len & 0xff) + p[1:]
+            p = chb(tmp_len & 0xff) + p[1:]
 
         # Pad vlan name with zeros if vlannamelen > len(vlanname)
         tmp_len = vlannamelen - len(self.vlanname)
@@ -189,7 +190,7 @@ class VTP(Packet):
     def post_build(self, p, pay):
         if self.domnamelen is None:
             domnamelen = len(self.domname.strip(b"\x00"))
-            p = p[:3] + chr(domnamelen & 0xff) + p[4:]
+            p = p[:3] + chb(domnamelen & 0xff) + p[4:]
 
         p += pay
 


Test patch:
diff --git a/test/contrib/cdp.uts b/test/contrib/cdp.uts
--- a/test/contrib/cdp.uts
+++ b/test/contrib/cdp.uts
@@ -8,6 +8,7 @@
 = CDPv2 - Dissection (1)
 s = b'\x02\xb4\x8c\xfa\x00\x01\x00\x0cmyswitch\x00\x02\x00\x11\x00\x00\x00\x01\x01\x01\xcc\x00\x04\xc0\xa8\x00\xfd\x00\x03\x00\x13FastEthernet0/1\x00\x04\x00\x08\x00\x00\x00(\x00\x05\x01\x14Cisco Internetwork Operating System Software \nIOS (tm) C2950 Software (C2950-I6K2L2Q4-M), Version 12.1(22)EA14, RELEASE SOFTWARE (fc1)\nTechnical Support: http://www.cisco.com/techsupport\nCopyright (c) 1986-2010 by cisco Systems, Inc.\nCompiled Tue 26-Oct-10 10:35 by nburra\x00\x06\x00\x15cisco WS-C2950-12\x00\x08\x00$\x00\x00\x0c\x01\x12\x00\x00\x00\x00\xff\xff\xff\xff\x01\x02!\xff\x00\x00\x00\x00\x00\x00\x00\x0b\xbe\x18\x9a@\xff\x00\x00\x00\t\x00\x0cMYDOMAIN\x00\n\x00\x06\x00\x01\x00\x0b\x00\x05\x01\x00\x0e\x00\x07\x01\x00\n\x00\x12\x00\x05\x00\x00\x13\x00\x05\x00\x00\x16\x00\x11\x00\x00\x00\x01\x01\x01\xcc\x00\x04\xc0\xa8\x00\xfd'
 cdpv2 = CDPv2_HDR(s)
+assert(len(cdpv2) == 450)
 assert(cdpv2.vers == 2)
 assert(cdpv2.ttl == 180)
 assert(cdpv2.cksum == 0x8cfa)
@@ -75,3 +76,8 @@ assert raw(cdpv2) == s2
 r = b'\x01\x00\x0c\xcc\xcc\xcc\x11"3DUf\x01\x80\xaa\xaa\x03\x00\x00\x0c \x00\x02\xb4uV\x00\x01\x00\nRouter\x00\x05\x00\x04\x00\x06\x00\x04\x00\x02\x00\x11\x00\x00\x00\x02\x01\x01\xcc\x00\x04\xc0\xa8\x01e\x00\x03\x00\x18GigabitEthernet0/0/1\x00\x04\x00\x08\x00\x00\x00A\x00\x07\x00\t\x14\x00\x00\x00\x18\x00\t\x00\x04\x00\x0b\x00\x05\x01\x00\x16\x00\x11\x00\x00\x00\x01\x01\x01\xcc\x00\x04\xc0\xa8\x01e'
 p = Dot3(r)
 assert CDPMsgPortID in p and CDPMsgIPPrefix in p
+
+= CDPChecksum - packet with odd length
+
+pkt = CDPv2_HDR(vers=2, ttl=180, msg='123')
+assert len(pkt) == 7
diff --git a/test/contrib/vtp.uts b/test/contrib/vtp.uts
new file mode 100644
--- /dev/null
+++ b/test/contrib/vtp.uts
@@ -0,0 +1,11 @@
+# VP unit tests
+#
+# Type the following command to launch start the tests:
+# $ test/run_tests -P "load_contrib('vtp')" -t test/contrib/vtp.uts
+
+
++ VTP
+
+= VTP, basic instantiation
+pkt = VTP(vlaninfo=[VTPVlanInfo()])
+assert len(pkt) == 72