Repository: secdev/scapy

Issue:
inet defragment() crash with Attribute Error
#### Brief description

Calling the function `defragment(pkts)`  with a list of fragments, that cannot be reassembled,  crash with ```AttributError``` instead of returning a one list of packets.

Has anyone else already encountered this problem (IPv4) ? 

`AttributeError: 'list' object has no attribute '_defrag_pos'`

#### Environment

-   Scapy version: `2.4.3rc4`
-   Python version: `2.7`

<!-- if needed - further information to get a picture of your setup (e.g. a sketch of your network setup) -->

#### How to reproduce
```python
>>> pkts = fragment(IP(dst="10.0.0.5")/ICMP()/("X"*60000))
>>> defragment(pkts[1:])
```
#### Actual result
```python
AttributeError                            Traceback (most recent call last)
<ipython-input-10-4cb9be065ce9> in <module>()
----> 1 defragment(pkts[1:])

/usr/local/lib/python2.7/dist-packages/scapy/layers/inet.pyc in defragment(plist)
   1111 def defragment(plist):
   1112     """defragment(plist) -> plist defragmented as much as possible """
-> 1113     return _defrag_logic(plist, complete=True)
   1114 
   1115 

/usr/local/lib/python2.7/dist-packages/scapy/layers/inet.pyc in _defrag_logic(plist, complete)
   1091         final.extend(defrag2)
   1092         final.extend(missfrag)
-> 1093         final.sort(key=lambda x: x._defrag_pos)
   1094         if hasattr(plist, "listname"):
   1095             name = "Defragmented %s" % plist.listname

/usr/local/lib/python2.7/dist-packages/scapy/layers/inet.pyc in <lambda>(x)
   1091         final.extend(defrag2)
   1092         final.extend(missfrag)
-> 1093         final.sort(key=lambda x: x._defrag_pos)
   1094         if hasattr(plist, "listname"):
   1095             name = "Defragmented %s" % plist.listname

AttributeError: 'list' object has no attribute '_defrag_pos'
```
<!-- dump results that outline the issue, please format your code -->

#### Expected result
One list containing all packets
<!-- describe the expected result and outline the difference to the actual one, could also be a screen shot (e.g. wireshark) -->

#### Related resources
https://github.com/secdev/scapy/blob/3d231b120762b31c65930fd35997e88f69e62ce0/scapy/layers/inet.py#L1042
https://github.com/secdev/scapy/blob/3d231b120762b31c65930fd35997e88f69e62ce0/scapy/layers/inet.py#L1027

#### Possible Fix
replace `missfrag.append(lst)` with `missfrag.extend(lst)`

Regards
Alex


Discussion:
Can I work on this issue?
Hi elijose55,
yes, you can work on it.
Alex

Resolving patch:
diff --git a/scapy/layers/inet.py b/scapy/layers/inet.py
--- a/scapy/layers/inet.py
+++ b/scapy/layers/inet.py
@@ -1024,7 +1024,7 @@ def _defrag_list(lst, defrag, missfrag):
     p = lst[0]
     lastp = lst[-1]
     if p.frag > 0 or lastp.flags.MF:  # first or last fragment missing
-        missfrag.append(lst)
+        missfrag.extend(lst)
         return
     p = p.copy()
     if conf.padding_layer in p:
@@ -1039,7 +1039,7 @@ def _defrag_list(lst, defrag, missfrag):
         if clen != q.frag << 3:  # Wrong fragmentation offset
             if clen > q.frag << 3:
                 warning("Fragment overlap (%i > %i) %r || %r ||  %r" % (clen, q.frag << 3, p, txt, q))  # noqa: E501
-            missfrag.append(lst)
+            missfrag.extend(lst)
             break
         if q[IP].len is None or q[IP].ihl is None:
             clen += len(q[IP].payload)


Test patch:
diff --git a/test/regression.uts b/test/regression.uts
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -7808,8 +7808,8 @@ payloadlen, fragsize = 100, 8
 assert fragsize % 8 == 0
 packet = Ether()/IP()/("X" * payloadlen)
 frags = fragment(packet, fragsize)
-for i,fragment in enumerate(frags):
-    fragment.time -= 100 + i
+for i,frag in enumerate(frags):
+    frag.time -= 100 + i
 
 last_time = max(frag.time for frag in frags)
 defrags = defragment(frags)
@@ -7817,6 +7817,10 @@ assert defrags[0].time == last_time
 nonfrag, defrags, badfrag = defrag(frags)
 assert defrags[0].time == last_time
 
+= defragment() - Missing fragments
+
+pkts = fragment(IP(dst="10.0.0.5")/ICMP()/("X"*1500))
+assert len(defragment(pkts[1:])) == 1
 
 = defrag() / defragment() - Real DNS packets