Repository: secdev/scapy

Issue:
Subpackage doesn't get newly initialised after previous initialisation
**\[edited: please remember to format code using triple \`\]**
I have written an example class and example unit test class to demonstrate the problem.

**class implementation:**
```python
from scapy.packet import *
from scapy.fields import *


class _INNER_CLASS(Packet):
    name = "InnerClass"
    fields_desc = [
        ShortField("id", 0),
        StrField("pkg_name", 'Xaver')
    ]

    def extract_padding(self, s):
        return "", s


class TESTCLASS(Packet):

    name = "testclass"

    fields_desc = [
        PacketField("innerclass", _INNER_CLASS(),_INNER_CLASS)
    ]
```

**unit test implementation:**
```
+ Testing

= load module

load_contrib("automotive.test")


= test1

p = TESTCLASS().innerclass
p.id = 5
p.pkg_name = "Peter"

p.show()

assert (p.id == 5)

= test2




p = TESTCLASS()
print(p.innerclass.id)
print(p.innerclass.pkg_name)

p.show()

assert(p.innerclass.pkg_name == "Xaver")
```


**output:**
```
###(000)=[passed] load module

>>> load_contrib("automotive.test")



###(001)=[passed] test1

>>> p = TESTCLASS().innerclass
>>> p.id = 5
>>> p.pkg_name = "Peter"
>>> 
>>> p.show()
###[ InnerClass ]### 
  id= 5
  pkg_name= 'Peter'

>>> 
>>> assert (p.id == 5)


###(002)=[failed] test2

>>> p = TESTCLASS()
>>> print(p.innerclass.id)
5
>>> print(p.innerclass.pkg_name)
Peter
>>> 
>>> p.show()
###[ testclass ]### 
  \innerclass\
   |###[ InnerClass ]### 
   |  id= 5
   |  pkg_name= 'Peter'

>>> 
>>> assert(p.innerclass.pkg_name == "Xaver")
Traceback (most recent call last):
  File "<input>", line 2, in <module>
AssertionError
```


As can be seen in the above output, the innerclass doesn't get newly initialised and still keeps the values it got before. Did I do something wrong here or  is this the default and wanted behaviour?


Discussion:
I've looked into it a little bit more and it seems like the innerclass object only gets created the first time the testclass class is defined. This seems to be a python specific thing, so not necessarily a scapy problem. Other layers also seem to have this problem, like for example the NTP layer. Therefor the question still stands, if this should be the default behaviour or if it should be changed.
This works fine with v2.4.0. According to `git bisect`, this is a regression introduce by de079743169414141b24026c656eace4d33e7d78

Resolving patch:
diff --git a/scapy/packet.py b/scapy/packet.py
--- a/scapy/packet.py
+++ b/scapy/packet.py
@@ -239,8 +239,7 @@ def prepare_cached_fields(self, flist):
                 Packet.class_packetfields[cls_name].append(f)
 
             # Remember references
-            if isinstance(f.default, (list, dict, set)) or \
-                    isinstance(f.default, RandField):
+            if isinstance(f.default, (list, dict, set, RandField, Packet)):
                 Packet.class_default_fields_ref[cls_name].append(f.name)
 
     def dissection_done(self, pkt):


Test patch:
diff --git a/test/regression.uts b/test/regression.uts
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -10577,6 +10577,25 @@ assert(len(a.list) == 1)
 b = TestPacket()
 assert(len(b.list) == 0)
 
+= PacketField
+
+class InnerPacket(Packet):
+    fields_desc = [ StrField("f_name", "test") ]
+
+class TestPacket(Packet):
+    fields_desc = [ PacketField("inner", InnerPacket(), InnerPacket) ]
+
+p = TestPacket()
+print(p.inner.f_name)
+assert p.inner.f_name == b"test"
+
+p = TestPacket()
+p.inner.f_name = b"scapy"
+assert p.inner.f_name == b"scapy"
+
+p = TestPacket()
+assert p.inner.f_name == b"test"
+
 ############
 ############
 + MPLS tests