Repository: secdev/scapy

Issue:
broken fragmenting already fragmented packets
I've found another issue with fragment, but this time it is not a regression:
IP.flags and IP.frag are incorrectly computed when fragment is performed on already fragmented packet.

```python
p = fragment(Ether() / IP() / ("x"*1480*3), 1480)
q = fragment(p, 1400)
assert len(q) == 6
assert q[1][IP].flags == 1  # bug
assert q[2][IP].frag > 0 # bug
```



Discussion:
I think the fix should looks like this:
```diff
-            if i == nb-1:
-                q[IP].flags &= ~1
-            else:
-                q[IP].flags |= 1 
-            q[IP].frag = i*fragsize/8
+            if i != nb-1:
+                q[IP].flags |= 1
+            q[IP].frag += i*fragsize/8
```

Since you provide a fix, could you submit a pull request? BTW, please be PEP-8 compliant in the code you change:
```Python
            if i != nb - 1:
                q[IP].flags |= 1
            q[IP].frag += i * fragsize / 8
```

Also if you create a PR, please add your test to `test/regression.uts` just after the tests introduced in #416.

That would be perfect!
OK, I will create a pull request soon.
Thanks. Don't forget to add `Fixes #418` in the text for your pull request.

Resolving patch:
diff --git a/scapy/layers/inet.py b/scapy/layers/inet.py
--- a/scapy/layers/inet.py
+++ b/scapy/layers/inet.py
@@ -462,13 +462,11 @@ def fragment(self, fragsize=1480):
                 del(q[fnb].payload)
                 del(q[fnb].chksum)
                 del(q[fnb].len)
-                if i == nb-1:
-                    q[IP].flags &= ~1
-                else:
-                    q[IP].flags |= 1 
-                q[IP].frag = i*fragsize/8
+                if i != nb - 1:
+                    q[fnb].flags |= 1
+                q[fnb].frag += i * fragsize / 8
                 r = conf.raw_layer(load=s[i*fragsize:(i+1)*fragsize])
-                r.overload_fields = p[IP].payload.overload_fields.copy()
+                r.overload_fields = p[fnb].payload.overload_fields.copy()
                 q.add_payload(r)
                 lst.append(q)
         return lst
@@ -816,11 +814,9 @@ def fragment(pkt, fragsize=1480):
             del(q[IP].payload)
             del(q[IP].chksum)
             del(q[IP].len)
-            if i == nb-1:
-                q[IP].flags &= ~1
-            else:
-                q[IP].flags |= 1 
-            q[IP].frag = i*fragsize/8
+            if i != nb - 1:
+                q[IP].flags |= 1
+            q[IP].frag += i * fragsize / 8
             r = conf.raw_layer(load=s[i*fragsize:(i+1)*fragsize])
             r.overload_fields = p[IP].payload.overload_fields.copy()
             q.add_payload(r)


Test patch:
diff --git a/test/regression.uts b/test/regression.uts
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -4787,6 +4787,22 @@ pkt2 = fragment(pkt1)[0]
 pkt3 = pkt2.__class__(str(pkt2))
 assert pkt1[IP].proto == pkt2[IP].proto == pkt3[IP].proto
 
+= fragment() already fragmented packets
+payloadlen = 1480 * 3
+ffrags = fragment(IP() / ("X" * payloadlen), 1480)
+ffrags = fragment(ffrags, 1400)
+len(ffrags) == 6
+* each fragment except the last one should have MF set
+assert all(p.flags == 1 for p in ffrags[:-1])
+assert ffrags[-1].flags == 0
+* fragment offset should be well computed
+plen = 0
+for p in ffrags:
+    assert p.frag == plen / 8
+    plen += len(p.payload)
+
+assert plen == payloadlen
+
 = defragment()
 defrags = defragment(frags)
 * we should have one single packet