Repository: secdev/scapy

Issue:
Can't concat str to bytes
#### Brief description

<!-- describe the main issue in one sentence -->
<!-- if possible, describe what components / protocols could be affected by the issue (e.g. wrpcap() + IPv6, it is likely this also affects XXX) -->

Hello everyone,

I have a DHCP listener which uses L2 socket this way.
```python
  self._logger.info("Starting DHCP listener")
  self._socket = scapy.conf.L2listen(type=scapy.ETH_P_ALL, iface=self._interface, filter="udp and (port 67 or 68)")
  scapy.sniff(opened_socket=self._socket, prn=self._proc_packet, store=False, stop_filter=lambda bool: self._stop_event.isSet())
  self._logger.info("DHCP listener stopped")
````

I also have a L2 socket for sending broadcast discover trames. Implementation below.
```python
  result_list, unanswered = self._l2socket.sr(scapy.Ether(dst="ff:ff:ff:ff:ff:ff")/scapy.ARP(pdst=cidr), timeout=20, verbose=True)
```

The problem is that when I receive a DHCP request callback & when a network discovery is running at the same time (they are both threaded), I always (almost certain) get the following error (**see Actual result section**).

After some test, this error also appears even when the DHCP listener is disabled (not instantiated).

#### Environment
-   Scapy version: `Scapy 2.4.4 (pip)`
-   Python version: `Python 3.8.5`
-   Operating System: `Linux Buildroot`
-   Running in dockerized environement & with privileged (root) permissions

#### How to reproduce
I can't seem to reproduce it easily, it seems kind of random so far. I enabled more logging but nothing conclusive yet.

#### Actual result
```python
  File "app/lib/network_discoverer.py", line 87, in _discover_network_devices
    result_list, unanswered = self._l2socket.sr(scapy.Ether(dst="ff:ff:ff:ff:ff:ff")/scapy.ARP(pdst=cidr), timeout=20, verbose=True)
  File "usr/lib/python3.8/site-packages/scapy/supersocket.py", line 95, in sr
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 261, in sndrcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 136, in __init__
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 243, in _sndrcv_rcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 925, in _run
  File "usr/lib/python3.8/site-packages/scapy/sessions.py", line 47, in on_packet_received
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 212, in _process_packet
  File "usr/lib/python3.8/site-packages/scapy/layers/l2.py", line 166, in hashret
TypeError: can't concat str to bytes
```

#### Expected result

No errors

#### Related resources

Nothing so far.



Discussion:
Thanks for the report.

Could your try to sniff packets when running your tool ? We might be able to identify packets triggering the error.

Could you also replace self._l2socket.sr with scapy.srp?




Could you also try with the current master branch?
Still getting the same error using `scapy.srp`. 
```python3
11/03/2021-09:47:48 [INFO] [NetworkDiscoverer] New device '192.168.1.20/HUAWEI_P10_lite-1486fcc07' detected when listening to DHCP request, triggering scan to check if a new device is present.
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
  File "usr/lib/python3.8/site-packages/netguard/loop_thread.py", line 66, in run
  File "app/lib/network_discoverer.py", line 60, in _discover_devices
    self._devices = self._discover_network_devices()
  File "app/lib/network_discoverer.py", line 83, in _discover_network_devices
    result_list, unanswered = scapy.srp(scapy.Ether(dst="ff:ff:ff:ff:ff:ff")/scapy.ARP(pdst=cidr), timeout=20, verbose=True)
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 505, in srp
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 261, in sndrcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 136, in __init__
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 243, in _sndrcv_rcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 925, in _run
  File "usr/lib/python3.8/site-packages/scapy/sessions.py", line 47, in on_packet_received
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 212, in _process_packet
  File "usr/lib/python3.8/site-packages/scapy/layers/l2.py", line 166, in hashret
TypeError: can't concat str to bytes
```

After upgrading to latest master commit, errors still happens:
```python3
Begin emission:
11/03/2021-10:11:02 [INFO] [NetworkDiscoverer] New device '192.168.1.20/HUAWEI_P10_lite-1486fcc07' detected when listening to DHCP request, triggering scan to check if a new device is present.
Finished sending 256 packets.
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
  File "usr/lib/python3.8/site-packages/netguard/loop_thread.py", line 66, in run
  File "app/lib/network_discoverer.py", line 60, in _discover_devices
    self._devices = self._discover_network_devices()
  File "app/lib/network_discoverer.py", line 83, in _discover_network_devices
    result_list, unanswered = scapy.srp(scapy.Ether(dst="ff:ff:ff:ff:ff:ff")/scapy.ARP(pdst=cidr), timeout=20, verbose=True)
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 677, in srp
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 313, in sndrcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 188, in __init__
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 294, in _sndrcv_rcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 1215, in _run
  File "usr/lib/python3.8/site-packages/scapy/sessions.py", line 108, in on_packet_received
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 261, in _process_packet
  File "usr/lib/python3.8/site-packages/scapy/layers/l2.py", line 225, in hashret
TypeError: can't concat str to bytes
```

I found a way to always reproduce it so far: 
- Wait for the emissions to begin for the network discovery (`Begin emission` in the log)
- Trigger a DHCP request before the network discovery trames are sent (before `Finished sending 256 packets`)

**NOTE**: 
I should still get **2.4.4** even when on latest commit right ? 
```bash
$> python3 -c "import scapy; print(scapy.__version__)"
$> 2.4.4
```

I managed to get a [pcap](https://github.com/secdev/scapy/files/6121924/sniff.zip). 
The logs associated are exactly the same as the ones above.
Sorry, I did not manage to reproduce or understand the issue. Could you share the values manipulated by the hashret method that causes the error?
Here is what I get after settings some logs in the `hashret` function. 

```python3
  print(self.type)
  print(self.payload.hashret())
  return struct.pack("H", self.type) + self.payload.hashret()
```

```python3
b'\x00\x00\x00:\x06\xe5\xcf'
2048
b'\x00\x00\x00:\x06\xe5\xcf'
2048
b'\x00\x00\x00:\x06\xe5\xcf'
2048
b'\x00\x00\x00:\x06\xe5\xcf'
2048
b'\x00\x00\x00:\x06\xe5\xcf'
35033
(empty string)
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
  File "usr/lib/python3.8/site-packages/netguard/loop_thread.py", line 66, in run
  File "app/lib/network_discoverer.py", line 60, in _discover_devices
    self._devices = self._discover_network_devices()
  File "app/lib/network_discoverer.py", line 83, in _discover_network_devices
    result_list, unanswered = scapy.srp(scapy.Ether(dst="ff:ff:ff:ff:ff:ff")/scapy.ARP(pdst=cidr), timeout=20, verbose=True)
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 677, in srp
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 313, in sndrcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 188, in __init__
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 294, in _sndrcv_rcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 1215, in _run
  File "usr/lib/python3.8/site-packages/scapy/sessions.py", line 108, in on_packet_received
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 261, in _process_packet
  File "/usr/lib/python3.8/site-packages/scapy/layers/l2.py", line 228, in hashret
    return struct.pack("H", self.type) + self.payload.hashret()

```

It explains the error. Now why does this happen though ? 
Thanks! Could you also share the types of self.type and self.payload.hashret() as well as the content of self.raw_packet_cache ?
Here goes.

```python3
  print(type(self.type))
  print(self.type)
  print(type(self.payload.hashret()))
  print(self.payload.hashret())
  print(type(self.raw_packet_cache))
  print(self.raw_packet_cache)
  return struct.pack("H", self.type) + self.payload.hashret()
```

```python3
<class 'int'>
2048
<class 'bytes'>
b'\x00\x00\x00:\x06\xe5\xcf'
<class 'bytes'>
b'\xdc\xa62Y\x0f\xc9\xf4\x8cP[\x02k\x08\x00'
<class 'int'>
2048
<class 'bytes'>
b'\x00\x00\x00:\x06\xe5\xcf'
<class 'bytes'>
b'\xdc\xa62Y\x0f\xc9\xf4\x8cP[\x02k\x08\x00'
<class 'int'>
2048
<class 'bytes'>
b'\x00\x00\x00:\x06\xe5\xcf'
<class 'bytes'>
b'\xdc\xa62Y\x0f\xc9\xf4\x8cP[\x02k\x08\x00'
<class 'int'>
2048
<class 'bytes'>
b'\x00\x00\x00:\x06\xe5\xcf'
<class 'bytes'>
b'\xdc\xa62Y\x0f\xc9\xf4\x8cP[\x02k\x08\x00'
<class 'int'>
35033
<class 'str'>

<class 'bytes'>
b'\xff\xff\xff\xff\xff\xff\x8c\xfd\xde\xba\xce\x8c\x88\xd9'
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
  File "usr/lib/python3.8/site-packages/netguard/loop_thread.py", line 66, in run
  File "app/lib/network_discoverer.py", line 60, in _discover_devices
    self._devices = self._discover_network_devices()
  File "app/lib/network_discoverer.py", line 83, in _discover_network_devices
    result_list, unanswered = scapy.srp(scapy.Ether(dst="ff:ff:ff:ff:ff:ff")/scapy.ARP(pdst=cidr), timeout=20, verbose=True)
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 677, in srp
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 313, in sndrcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 188, in __init__
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 294, in _sndrcv_rcv
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 1215, in _run
  File "usr/lib/python3.8/site-packages/scapy/sessions.py", line 108, in on_packet_received
  File "usr/lib/python3.8/site-packages/scapy/sendrecv.py", line 261, in _process_packet
  File "/usr/lib/python3.8/site-packages/scapy/layers/l2.py", line 231, in hashret
    return struct.pack("H", self.type) + self.payload.hashret()
TypeError: can't concat str to bytes
```
Thanks a lot! I finally identified a way to reproduce the issue:
```
p = Ether(raw(Ether()/LLTD()))
p.hashret()
```

Could you confirm that the following patch fixes the issue?
```
diff --git a/scapy/layers/lltd.py b/scapy/layers/lltd.py
index c9ce0c0a..3142a004 100644
--- a/scapy/layers/lltd.py
+++ b/scapy/layers/lltd.py
@@ -111,7 +111,7 @@ class LLTD(Packet):
 
     def hashret(self):
         tos, function = self.tos, self.function
-        return "%c%c" % self.answer_hashret.get((tos, function),
+        return b"%c%c" % self.answer_hashret.get((tos, function),
                                                 (tos, function))
 
     def answers(self, other):
```
Seems good, thanks a lot ! 

Was it because of something on my end ? My network environment ?

Resolving patch:
diff --git a/scapy/layers/lltd.py b/scapy/layers/lltd.py
--- a/scapy/layers/lltd.py
+++ b/scapy/layers/lltd.py
@@ -111,8 +111,8 @@ def mysummary(self):
 
     def hashret(self):
         tos, function = self.tos, self.function
-        return "%c%c" % self.answer_hashret.get((tos, function),
-                                                (tos, function))
+        return b"%c%c" % self.answer_hashret.get((tos, function),
+                                                 (tos, function))
 
     def answers(self, other):
         if not isinstance(other, LLTD):


Test patch:
diff --git a/test/scapy/layers/lltd.uts b/test/scapy/layers/lltd.uts
--- a/test/scapy/layers/lltd.uts
+++ b/test/scapy/layers/lltd.uts
@@ -20,6 +20,7 @@ assert pkt.dst == pkt.real_dst
 assert pkt.src == pkt.real_src
 assert pkt.tos == 0
 assert pkt.function == 0
+assert pkt.hashret() == b'\xd9\x88\x00\x00'
 
 = Attribute build / dissection
 assert isinstance(LLTDAttribute(), LLTDAttribute)