diff --git a/scapy/fields.py b/scapy/fields.py index 91df1adaa4d6927c1e14e8a2bc784fd33454c2b1..fa6cba4d7ad22a90bd80da8fb9bb0c177b7c8280 100644 --- a/scapy/fields.py +++ b/scapy/fields.py @@ -372,7 +372,6 @@ class PacketField(StrField): return remain,i class PacketLenField(PacketField): - holds_packets=1 def __init__(self, name, default, cls, length_from=None): PacketField.__init__(self, name, default, cls) self.length_from = length_from @@ -389,7 +388,6 @@ class PacketLenField(PacketField): class PacketListField(PacketField): islist = 1 - holds_packets=1 def __init__(self, name, default, cls, count_from=None, length_from=None): if default is None: default = [] # Create a new list for each instance diff --git a/scapy/layers/dhcp6.py b/scapy/layers/dhcp6.py index 2bd215d055d3877185c895f2ed83b238a41d3ac2..fba74898b7b61ea1926f6a9425c5620f51461e0d 100644 --- a/scapy/layers/dhcp6.py +++ b/scapy/layers/dhcp6.py @@ -256,7 +256,6 @@ class DHCP6OptUnknown(_DHCP6OptGuessPayload): # A generic DHCPv6 Option length_from = lambda pkt: pkt.optlen)] class _DUIDField(PacketField): - holds_packets=1 def __init__(self, name, default, length_from=None): StrField.__init__(self, name, default) self.length_from = length_from diff --git a/scapy/layers/dns.py b/scapy/layers/dns.py index 533db6c20c2bc4f1bae02e926abf785a9ba6ce1e..9c5f69e86825bb85e99ad4a350b7a0ce52d92d57 100644 --- a/scapy/layers/dns.py +++ b/scapy/layers/dns.py @@ -52,7 +52,6 @@ class DNSStrField(StrField): class DNSRRCountField(ShortField): - holds_packets=1 def __init__(self, name, default, rr): ShortField.__init__(self, name, default) self.rr = rr @@ -158,7 +157,6 @@ class DNSRRField(StrField): class DNSQRField(DNSRRField): - holds_packets=1 def decodeRR(self, name, s, p): ret = s[p:p+4] p += 4 diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py index 5346a1f3235e2931d002d79fcb1640533184d7b7..28978fe49b3a1add3d290773f315be03d2a82586 100644 --- a/scapy/layers/inet6.py +++ b/scapy/layers/inet6.py @@ -741,8 +741,6 @@ _hbhoptcls = { 0x00: Pad1, ######################## Hop-by-Hop Extension Header ######################## class _HopByHopOptionsField(PacketListField): - islist = 1 - holds_packet = 1 def __init__(self, name, default, cls, curpos, count_from=None, length_from=None): self.curpos = curpos PacketListField.__init__(self, name, default, cls, count_from=count_from, length_from=length_from) @@ -2609,9 +2607,6 @@ class MIP6MH_Generic(_MobilityHeader): # Mainly for decoding of unknown msg # TODO: make a generic _OptionsField class _MobilityOptionsField(PacketListField): - islist = 1 - holds_packet = 1 - def __init__(self, name, default, cls, curpos, count_from=None, length_from=None): self.curpos = curpos PacketListField.__init__(self, name, default, cls, count_from=count_from, length_from=length_from) diff --git a/scapy/layers/sctp.py b/scapy/layers/sctp.py index 632becb1bdca08ab5d6ec08170e15db3c8e856c0..299e49c1d3d85926c94b0d7e411097094fb0ab5e 100644 --- a/scapy/layers/sctp.py +++ b/scapy/layers/sctp.py @@ -207,8 +207,6 @@ class SCTP(_SCTPChunkGuessPayload, Packet): ############## SCTP Chunk variable params class ChunkParamField(PacketListField): - islist = 1 - holds_packets=1 def __init__(self, name, default, count_from=None, length_from=None): PacketListField.__init__(self, name, default, conf.raw_layer, count_from=count_from, length_from=length_from) def m2i(self, p, m): diff --git a/scapy/packet.py b/scapy/packet.py index 6c2094f27b2000de5923ffe0ec19e351f79de8da..bab03eef6838ce5203aa68cd62bcca5897a3890f 100644 --- a/scapy/packet.py +++ b/scapy/packet.py @@ -49,6 +49,7 @@ class Packet(BasePacket): show_indent=1 explicit = 0 raw_packet_cache = None + raw_packet_cache_fields = None @classmethod def from_hexcap(cls): @@ -144,15 +145,16 @@ class Packet(BasePacket): def copy(self): """Returns a deep copy of the instance.""" clone = self.__class__() - clone.fields = self.fields.copy() - for k in clone.fields: - clone.fields[k] = self.get_field(k).do_copy(clone.fields[k]) - clone.default_fields = self.default_fields.copy() + clone.fields = self.copy_fields_dict(self.fields) + clone.default_fields = self.copy_fields_dict(self.default_fields) clone.overloaded_fields = self.overloaded_fields.copy() clone.overload_fields = self.overload_fields.copy() clone.underlayer = self.underlayer clone.explicit = self.explicit clone.raw_packet_cache = self.raw_packet_cache + clone.raw_packet_cache_fields = self.copy_fields_dict( + self.raw_packet_cache_fields + ) clone.post_transforms = self.post_transforms[:] clone.__dict__["payload"] = self.payload.copy() clone.payload.add_underlayer(clone) @@ -194,6 +196,7 @@ class Packet(BasePacket): self.fields[attr] = any2i(self, val) self.explicit = 0 self.raw_packet_cache = None + self.raw_packet_cache_fields = None elif attr == "payload": self.remove_payload() self.add_payload(val) @@ -215,6 +218,7 @@ class Packet(BasePacket): del(self.fields[attr]) self.explicit = 0 # in case a default value must be explicited self.raw_packet_cache = None + self.raw_packet_cache_fields = None elif self.default_fields.has_key(attr): pass elif attr == "payload": @@ -295,9 +299,22 @@ class Packet(BasePacket): return True def __len__(self): return len(self.__str__()) + def copy_field_value(self, fieldname, value): + return self.get_field(fieldname).do_copy(value) + def copy_fields_dict(self, fields): + if fields is None: + return None + return dict([fname, self.copy_field_value(fname, fval)] + for fname, fval in fields.iteritems()) def self_build(self, field_pos_list=None): if self.raw_packet_cache is not None: - return self.raw_packet_cache + for fname, fval in self.raw_packet_cache_fields.iteritems(): + if self.getfieldval(fname) != fval: + self.raw_packet_cache = None + self.raw_packet_cache_fields = None + break + if self.raw_packet_cache is not None: + return self.raw_packet_cache p="" for f in self.fields_desc: val = self.getfieldval(f.name) @@ -558,9 +575,14 @@ Creates an EPS file describing a packet. If filename is not provided a temporary flist = self.fields_desc[:] flist.reverse() raw = s + self.raw_packet_cache_fields = {} while s and flist: f = flist.pop() - s,fval = f.getfield(self, s) + s, fval = f.getfield(self, s) + # We need to track fields with mutable values to discard + # .raw_packet_cache when needed. + if f.islist or f.holds_packets: + self.raw_packet_cache_fields[f.name] = f.do_copy(fval) self.fields[f.name] = fval assert(raw.endswith(s)) if s: @@ -630,14 +652,18 @@ Creates an EPS file describing a packet. If filename is not provided a temporary pkt = self.__class__() pkt.explicit = 1 pkt.fields = kargs + pkt.default_fields = self.copy_fields_dict(self.default_fields) pkt.time = self.time pkt.underlayer = self.underlayer pkt.overload_fields = self.overload_fields.copy() pkt.post_transforms = self.post_transforms + pkt.raw_packet_cache = self.raw_packet_cache + pkt.raw_packet_cache_fields = self.copy_fields_dict( + self.raw_packet_cache_fields + ) if payload is not None: pkt.add_payload(payload) return pkt - def __iter__(self): def loop(todo, done, self=self): @@ -666,7 +692,7 @@ Creates an EPS file describing a packet. If filename is not provided a temporary pkt = self.clone_with(payload=payl, **done2) yield pkt - if self.explicit: + if self.explicit or self.raw_packet_cache is not None: todo = [] done = self.fields else: diff --git a/scapy/utils.py b/scapy/utils.py index c5ac2520724de2e893b4cc656e71ec463c9d45aa..07b00ab4e877f86c1693e3de390af24632300510 100644 --- a/scapy/utils.py +++ b/scapy/utils.py @@ -646,8 +646,9 @@ class RawPcapWriter: def write(self, pkt): - """accepts a either a single packet or a list of packets - to be written to the dumpfile + """accepts either a single packet or a list of packets to be + written to the dumpfile + """ if not self.header_present: self._write_header(pkt) @@ -700,7 +701,7 @@ class PcapWriter(RawPcapWriter): self.linktype = 1 RawPcapWriter._write_header(self, pkt) - def _write_packet(self, packet): + def _write_packet(self, packet): sec = int(packet.time) usec = int(round((packet.time-sec)*1000000)) s = str(packet) diff --git a/test/regression.uts b/test/regression.uts index b1bc365ad37705b6e098d3b8f342f334db4f91d5..d8f9277d0d2191c2be75ace8c13b3cc5485d3137 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -693,15 +693,21 @@ s.show() s.show(2) = DNS packet manipulation -~ netaccess DNS -* We have to recalculate IP and UDP length because -* DNS is not able to reassemble correctly +~ netaccess IP UDP DNS dns_ans.show() -del(dns_ans[IP].len) -del(dns_ans[UDP].len) dns_ans.show2() dns_ans[DNS].an.show() -DNS in IP(str(dns_ans)) +dns_ans2 = IP(str(dns_ans)) +DNS in dns_ans2 +assert(str(dns_ans2) == str(dns_ans)) +dns_ans2.qd.qname = "www.secdev.org." +* We need to recalculate these values +del(dns_ans2[IP].len) +del(dns_ans2[IP].chksum) +del(dns_ans2[UDP].len) +del(dns_ans2[UDP].chksum) +assert("\x03www\x06secdev\x03org\x00" in str(dns_ans2)) +assert(DNS in IP(str(dns_ans2))) = Arping ~ netaccess @@ -1053,13 +1059,15 @@ assert(p == q) = IP assembly and dissection with options ~ IP options -IP(src="9.10.11.12",dst="13.14.15.16",options=IPOption_SDBM(addresses=["1.2.3.4","5.6.7.8"]))/TCP() -str(_) +p = IP(src="9.10.11.12",dst="13.14.15.16",options=IPOption_SDBM(addresses=["1.2.3.4","5.6.7.8"]))/TCP() +str(p) assert(_ == 'H\x00\x004\x00\x01\x00\x00@\x06\xa2q\t\n\x0b\x0c\r\x0e\x0f\x10\x95\n\x01\x02\x03\x04\x05\x06\x07\x08\x00\x00\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00_K\x00\x00') q=IP(_) q assert( isinstance(q.options[0],IPOption_SDBM) ) assert( q[IPOption_SDBM].addresses[1] == "5.6.7.8" ) +p.options[0].addresses[0] = '5.6.7.8' +assert( IP(str(p)).options[0].addresses[0] == '5.6.7.8' ) IP(src="9.10.11.12", dst="13.14.15.16", options=[IPOption_NOP(),IPOption_LSRR(routers=["1.2.3.4","5.6.7.8"]),IPOption_Security(transmission_control_code="XYZ")])/TCP() str(_) assert(_ == 'K\x00\x00@\x00\x01\x00\x00@\x06\xf3\x83\t\n\x0b\x0c\r\x0e\x0f\x10\x01\x83\x0b\x04\x01\x02\x03\x04\x05\x06\x07\x08\x82\x0b\x00\x00\x00\x00\x00\x00XYZ\x00\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00_K\x00\x00') diff --git a/test/run_tests b/test/run_tests index 6cb635945f9a31703142d424d8a99a172ae9988c..7df78972b7472d9e5f28168e56851dd29ae1722c 100755 --- a/test/run_tests +++ b/test/run_tests @@ -2,7 +2,7 @@ DIR=$(dirname $0)/.. if [ "$*" == "" ] then -PYTHONPATH=$DIR exec python ${DIR}/scapy/tools/UTscapy.py -t regression.uts -f html -o /tmp/scapy_regression_test_$(date +%Y%M%d-%H%H%S).html +PYTHONPATH=$DIR exec python ${DIR}/scapy/tools/UTscapy.py -t regression.uts -f html -l -o /tmp/scapy_regression_test_$(date +%Y%m%d-%H%M%S).html else PYTHONPATH=$DIR exec python ${DIR}/scapy/tools/UTscapy.py "$@" fi