From 1e59ef63c8d647c1557ffebcdc775ccb5a8b70c0 Mon Sep 17 00:00:00 2001
From: Phil <phil@secdev.org>
Date: Wed, 21 Apr 2010 18:21:44 +0200
Subject: [PATCH] Simplified the build mecanism

Packet.build() is called only on the first layer. It will call
Packet.do_build() which will recurse through all layers. For each layer,
it will call Packet.self_build() which will do the job for each layer.
Packet.do_build() will call Packet.post_build() and transform on them,
and concatenate them. Then Packet.build() will call Packet.build_padding()
and Packet.build_done().

Note that this undetermined case will have a different behavior:
Raw("ABC")/Padding("abc")/Raw("DEF")/Padding("def")

It was "ABCabcDEFdef"
Now it is "ABCDEFabcdef"
---
 scapy/asn1packet.py |  2 +-
 scapy/packet.py     | 56 ++++++++++++++++++++++++++-------------------
 test/regression.uts |  2 +-
 3 files changed, 35 insertions(+), 25 deletions(-)

diff --git a/scapy/asn1packet.py b/scapy/asn1packet.py
index dc900b0a..e49942ce 100644
--- a/scapy/asn1packet.py
+++ b/scapy/asn1packet.py
@@ -12,7 +12,7 @@ class ASN1_Packet(Packet):
         flist = self.ASN1_root.get_fields_list()
         self.do_init_fields(flist)
         self.fields_desc = flist    
-    def do_build(self):
+    def self_build(self):
         return self.ASN1_root.build(self)    
     def do_dissect(self, x):
         return self.ASN1_root.dissect(self, x)
diff --git a/scapy/packet.py b/scapy/packet.py
index 1f51f318..3410a925 100644
--- a/scapy/packet.py
+++ b/scapy/packet.py
@@ -281,37 +281,44 @@ class Packet(BasePacket):
         return True
     def __len__(self):
         return len(self.__str__())
-    def do_build(self):
+    def self_build(self, field_pos_list=None):
         p=""
         for f in self.fields_desc:
             val = self.getfieldval(f.name)
             if isinstance(val, RawVal):
-                p += str(val)
+                sval = str(val)
+                p += sval
+                if field_pos_list is not None:
+                    field_pos_list.append( (f.name, sval.encode("string_escape"), len(p), len(sval) ) )
             else:
                 p = f.addfield(self, p, val)
         return p
-    
-    def post_build(self, pkt, pay):
-        """DEV: called right after the current layer is build."""
-        return pkt+pay
 
-    def build_payload(self):
-        return self.payload.build(internal=1)
+    def do_build_payload(self):
+        return self.payload.do_build()
 
-    def build(self,internal=0):
+    def do_build(self):
         if not self.explicit:
             self = self.__iter__().next()
-        pkt = self.do_build()
+        pkt = self.self_build()
         for t in self.post_transforms:
             pkt = t(pkt)
-        pay = self.build_payload()
+        pay = self.do_build_payload()
         p = self.post_build(pkt,pay)
-        if not internal:
-            pad = self.payload.getlayer(Padding) 
-            if pad: 
-                p += pad.build()
-            p = self.build_done(p)
         return p
+    
+    def build_padding(self):
+        return self.payload.build_padding()
+
+    def build(self):
+        p = self.do_build()
+        p += self.build_padding()
+        p = self.build_done(p)
+        return p
+    
+    def post_build(self, pkt, pay):
+        """DEV: called right after the current layer is build."""
+        return pkt+pay
 
     def build_done(self, p):
         return self.payload.build_done(p)
@@ -1029,8 +1036,12 @@ class NoPayload(Packet):
         return ""
     def __nonzero__(self):
         return False
-    def build(self, internal=0):
-        return ""    
+    def do_build(self):
+        return ""
+    def build(self):
+        return ""
+    def build_padding(self):
+        return ""
     def build_done(self, p):
         return p
     def build_ps(self, internal=0):
@@ -1109,11 +1120,10 @@ class Raw(Packet):
         
 class Padding(Raw):
     name = "Padding"
-    def build(self, internal=0):
-        if internal:
-            return ""
-        else:
-            return Raw.build(self)
+    def self_build(self):
+        return ""
+    def build_padding(self):
+        return self.load+self.payload.build_padding()
 
 conf.raw_layer = Raw
 if conf.default_l2 is None:
diff --git a/test/regression.uts b/test/regression.uts
index f5b5f732..069c617d 100644
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -125,7 +125,7 @@ assert( _ == "abcdef" )
 str(Raw("ABC")/Padding("abc")/Padding("def"))
 assert( _ == "ABCabcdef" )
 str(Raw("ABC")/Padding("abc")/Raw("DEF")/Padding("def"))
-assert( _ == "ABCabcDEFdef" )
+assert( _ == "ABCDEFabcdef" )
 
 = Padding and length computation
 IP(str(IP()/Padding("abc")))
-- 
GitLab