Evan Sonnemans | 8 Jun 23:24 2016

Missing fields in CDP packets.

Hey folks,

I'm busy writing a tool with scapy3k and I'm hitting a wall.
When I process CDP packets i do not receive all fields of the packet.
I include my proof of concept code, can any one help me with this ?

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
"""Dissecting the fields of cdp packets.

The CDP class will not extract every field from the packet.
In my case i especially need the VLAN fields, E.G. Native VLAN.

The packet capture source is:

in this capture you will find CDP packets with Native VLAN fields:
"[..]0000   00 0a 00 06 00 f7[..]"

Only the following fields will be dissected on my system:
['Device ID', 'Addresses']
['Device ID', 'Addresses']
['Device ID', 'Addresses']
['Device ID', 'Addresses']

Why do i miss the Native VLAN and VOIP VLAN fields and how can i fix it?

from scapy.utils import PcapReader
from scapy.main import load_contrib
(Continue reading)

Marcus Poller | 22 Apr 13:44 2016

parse fragmented response

Hey guys,

I am looking for a hint. Scapy does not recognize a response if it is fragmented. Here is a minimal working example:

# running in scapy-2.3.2 shell on chronos
Begin emission:
Finished to send 1 packets.
Received 476 packets, got 0 answers, remaining 1 packets

# tcpdump on host "chronos"
19:53:09.653158 IP6 chronos > 2001:1410:200:ee7::: ICMP6, echo request, seq 0, length 1460
19:53:09.668681 IP6 2001:1410:200:ee7:: > chronos: ICMP6, echo reply, seq 0, length 1460
19:53:26.282904 IP6 chronos > 2001:1410:200:ee7::: ICMP6, packet too big, mtu 1452, length 1452
19:53:51.117112 IP6 chronos > 2001:1410:200:ee7::: ICMP6, packet too big, mtu 1452, length 1452
19:54:12.206479 IP6 chronos > 2001:1410:200:ee7::: ICMP6, packet too big, mtu 1452, length 1452
19:54:24.069219 IP6 chronos > 2001:1410:200:ee7::: ICMP6, echo request, seq 0, length 1460
19:54:24.084790 IP6 2001:1410:200:ee7:: > chronos: frag (0|1400) ICMP6, echo reply, seq 0, length 1400
19:54:24.084900 IP6 2001:1410:200:ee7:: > chronos: frag (1400|60)

How can I make scapy parse the response?

Thanks in advance,
(Continue reading)

Conrad | 5 Apr 01:23 2016

Sending MDNS question type

I am using scapy to send a MDNS discover packet.  However, I do not see
support for setting the question type.  I would like to set QU question to
True but as I cannot set it, scapy sets the question type to QM.

I can set qname, qclass and qtype.

Anyone have any ideas here?

To unsubscribe, send a mail to scapy.ml-unsubscribe <at> secdev.org

Runa Barik | 27 Mar 19:47 2016

TCP checksum calculation

     I am looking at checksum calculations for different headers and then I was checking the codes in scapy. Specific to TCP checksum calculation, scapy does the following:
     if self.underlayer.len is not None:
          ln = self.underlayer.len - 20
          ln= len(p)
    This is mentioned in https://github.com/phaethon/scapy/blob/master/scapy/layers/inet.py and ln represents the TCP segment length. I think this
   is correct so far there is no IP  options. When there is IP options, then the correct way of computing ln is self.underlayer.len - 4*self.underlayer.ihl
       ln = self.underlayer.len - 4*self.underlayer.ihl
          ln= len(p)

- Runa

Swaroop Thool | 16 Mar 20:57 2016

How to connect veth interfaces of different s/w switches for packet transfer‏

Hi everyone,

I have not done great experimentation in Scapy as I am new to it.  I am
using scapy snippets in my SDN project to send traffic from veth1 to veth 6
interface through software switch as follows:

At sender (s1):     
a = Ether(dst="aa:bb:cc:dd:ee:ff")  /IP(dst="") / TCP() /"aaaaaaaa"
sendp(a, iface = "veth1")

At receiver side (s1):
sniff(iface = "veth6", prn = lambda x: hexdump(x))

Here, at sender side I can see manipulated packets got transfered.
This is the case with s1 software switch where everything works fine for me.

Now, I want to send the packets from veth6(port 3) of switch s1 to another
switch s2 at some other veth like veth10 (port 5). Here, veth1to 6 are for
s1 and veth8 to 12 are for s2. So I tried doing:

At sender side (s1): 
a = Ether(dst="aa:bb:cc:dd:ee:ff")  /IP(dst="") / TCP() /"aaaaaaaa"
sendp(a, iface = "veth1")

At receiver side (s1):
y=sniff(iface = "veth6", prn = lambda x: hexdump(x))
sendp(y, iface = "veth8") //or any other

At receiver side (s2):
sniff(iface = "veth10", prn = lambda x: hexdump(x))

I didnt get packet manipulated by switch s2. I can see packet manipulated by
switch s1 only. This means both s1 and s2 are not connected by veths here
that is, veth6 of s1 is not connected to other veth of s2 and I can see
output at veth10 as output of veth6. My packets are not going inside switch
s2. I get same packets as s1 output on s2 output.

How can I connect veths interfaces in scapy as diagrammatically:

Thank you for your time


To unsubscribe, send a mail to scapy.ml-unsubscribe <at> secdev.org

Nathan Raffenne | 16 Mar 17:54 2016

Virtual PacketField: how to handle a polymorphic protocole ?

Hello everyone,

I'm a new scapy user and today I'm asking for your help.

I'm trying to add a new protocole in scapy. This protocole is a little bit special because he is extremely polymorph. By polymorph, i mean his structure and his length is dependent of some fields. Typically, there is a 'function' ByteField, and changing this value is changing all the next fields.

So, let's look this code ilustrating what i want to do. There is a simple polymorphic packet with a main constant structure //header//parameter//data//. Variations are inside parameter and data structure.

class myPacketParam(Packet):
    name = "Virtual Param Packet"

class myPacketParamOne(myPacketParam):
    name = "Parameter Type One"
    fields_desc = [
        ByteField("paramOne", 0x0),
        ByteField("paramTwo", 0x0)

class myPacketParamTwo(myPacketParam):
    name = "Parameter Type Two"
    fields_desc = [
        FieldLenField("length", None, length_of="stringOpt"),
        StrLenField("stringOpt", "BAGUETTE", # Random default value
                    length_from=lambda pkt: pkt.length)

class myPacketData(Packet):
    name = "Virtual Data Packet"

class myPacketDataOne(myPacketData):
    name = "Data Type One"
    fields_desc = [
        ByteField("length", 2),
        ByteField("dataOne", 0x0),
        ByteField("dataTwo", 0x0)

class myPacketDataTwo(myPacketData):
    name = "Data Type Two"
    fields_desc = [
        FieldLenField("length", None, length_of="data"),
        StrLenField("data", "SAUCISSON", length_from=lambda pkt: pkt.length) # Random default value

class myPacket(Packet):
    name = "myPacket"

    def changeFunction(self, value, data):
        if value == 0x1:
            self.param = myPacketParamOne()
            self.data = myPacketDataOne()
            self.param = myPacketParamTwo()
            self.data = myPacketDataTwo()

    fields_desc = [
        ByteField("version", 0x15),
        ActionField(ByteField("function", 0x1), "changeFunction"),
        FieldLenField("lengthParam", None, length_of="param"),
        FieldLenField("lengthData", None, length_of="data"),
        PacketField("param", myPacketParamOne(), myPacketParam),
        PacketField("data", myPacketDataOne(), myPacketData)

Well, the point is the "param" and "data" fields in the main packet "myPacket". By example, "param" packetfield is asking a myPacketParam packet. But i want this packet virtual: the real packet behind can be myPacketParamOne or myPacketParamTwo. Same thing for Data.

Building this packet looks like ok.
p = myPacket()

# great result

p.function = 2

###[ myPacket ]###
  version   = 21
  function  = 2
  lengthParam= None
  lengthData= None
  \param     \
   |###[ Parameter Type Two ]###
   |  length    = None
   |  stringOpt = 'BAGUETTE'
  \data      \
   |###[ Data Type Two ]###
   |  length    = None
   |  data      = 'SAUCISSON'

But i guess dissecting is not working correctly.

###[ myPacket ]###
  version   = 21
  function  = 2
  lengthParam= 10
  lengthData= 11
  \param     \
   |###[ Virtual Param Packet ]###
   |###[ Raw ]###
   |     load      = 'BAGUETTE\x00\tSAUCISSON'
  \data      \
   |###[ Data Type One ]###
   |  length    = 2
   |  dataOne   = 0
   |  dataTwo   = 0

This is totally wrong.

I found some solutions. By example using conditionalField. But in my real protocole there is a lot of morphology in the same packet. And because fields cant have the same name, there is not a simple param field in the main packet, but a new name for each case. So, a real utilization of my scapy implementation is very boring and not simple.

A second solution is to unlink header, param and data. So you can use the protocole like this: p = myPacket() / myPacketParamOne() / myPacketDataOne(). But it's not a good solution for me because my real protocole got dependencies between every part, and it's still complicated for the user of my scapy implementation.

So if possible, i'm looking for a solution:
- Respecting the main structure (header/parameter/data)
- Simple use of this protocole (myPacket.param.whatyouwant to get param without consideration of what kind of param packet it is (but of course whatyouwant field exists in this kind of param packe))

I feel that the solution can be to redefine do_dissect function in every "virtual packet", or coding a new field especially for virtual packet, but i tried a lot of things without success.

I hope i was comprehensible.

Thank you in advance :)

Nathan Raffenne.
Aaron Wood | 25 Feb 02:44 2016

More on the performance of parsing pcap files

I think I've tracked it down to what makes dissection slow.  And it's clearly the dissection, as the biggest gains are in tuning the bindings to ignore packet layers that aren't needed for the task at hand (2.5x faster for my application if I don't parse anything above say UDP/TCP, and just ignore their payloads).

It's the __getattr__() and __setattr__() overloads.

I've managed to eek out about 2x the performance by focusing on these two methods, what effect they have on the Packet classes internal methods, as well as some miscellaneous other bits of code cleanup.

For my current application, on a latest-gen MacBook Pro (2.5GHz i7), I've gone from ~1100 packets/sec to ~3700 packets/sec by combining:

1) tuning the dissection to the minimal layers (approx 2x at 2000 packets/sec)
2) __getattr__()/__setattr__() changes (approx 1.7x faster)

I can get a _tiny_ bit more out by mucking around with a parallelized reader, but it just doesn't quite work, because the Packet object can't be pickled.

Here's the situation on the __getattr__()/__setattr__() overload:

1) it provides some really nice syntactic sugar
2) it slows down all the internal assignment of member fields

So what I focused on at first was bypassing them by using the self.__dict__ internally, but that's a big headache.  Then I removed the __setattr__ overload, and installed it at the end of the packet init():

    self.__setattr__ = packet__setattr

Dissection doesn't appear to need the __setattr__ overload, and unlike the __getattr__ overload, it's called before checking the __dicts__'s

I have a micro-benchmark that I've been using for profiling.  It dissects 10K of a simple packet:

base_packet = Ether(src="01:02:03:04:05:06", dst="ff:ff:ff:ff:ff:ff")/IP(src="", dst="")/UDP(sport=59, dport=59)

for i in range(10000):


and the profiling results from that show that it's the Packet.__init__(), do_dissect(), and __getattr__ where most of the time is still being spent (my overloads are in scapy_patches.py):

     30003    0.299    0.000    0.866    0.000 scapy_patches.py:135(do_dissect)
30014/10012    0.277    0.000    2.196    0.000 scapy_patches.py:22(packet__init)
   200046    0.183    0.000    0.307    0.000 packet.py:181(__getattr__)
    40004    0.157    0.000    0.180    0.000 fields.py:673(getfield)
    20002    0.155    0.000    0.592    0.000 packet.py:628(guess_payload_class)
   161034    0.138    0.000    0.379    0.000 {hasattr}
   150015    0.131    0.000    0.286    0.000 fields.py:71(getfield)
60035/10015    0.122    0.000    2.238    0.000 base_classes.py:192(__call__)
   200046    0.095    0.000    0.095    0.000 scapy_patches.py:121(getfield_and_val)
30003/10001    0.071    0.000    2.039    0.000 packet.py:615(dissect)

Here's the profile results from the un-modified code for a comparison

    30003    0.424    0.000    1.332    0.000 packet.py:576(do_dissect)
   490313    0.370    0.000    0.676    0.000 packet.py:206(__setattr__)
203929/200155    0.359    0.000    0.711    0.000 copy.py:145(deepcopy)
30018/10015    0.288    0.000    4.377    0.000 packet.py:68(__init__)
    30018    0.281    0.000    1.022    0.000 packet.py:100(do_init_fields)
   202426    0.246    0.000    0.273    0.000 copy.py:267(_keep_alive)
260141/190128    0.227    0.000    0.306    0.000 packet.py:189(setfieldval)
   200046    0.187    0.000    0.424    0.000 packet.py:181(__getattr__)
    40004    0.172    0.000    0.198    0.000 fields.py:673(getfield)
    20002    0.169    0.000    0.720    0.000 packet.py:628(guess_payload_class)
60035/10015    0.161    0.000    4.430    0.000 base_classes.py:192(__call__)
   200046    0.153    0.000    0.208    0.000 packet.py:172(getfield_and_val)
   161034    0.148    0.000    0.474    0.000 {hasattr}
   150015    0.144    0.000    0.313    0.000 fields.py:71(getfield)
30003/10001    0.077    0.000    3.973    0.000 packet.py:615(dissect)

As you can see, the big gains are in the removal of the deepcopy and other do_init_fields-related calls, bypassing __setattr__, and speeding up do_dissect itself with some small modifications.

My next step is to get the codebase forked on GitHub, and my changes up there, so people can see what I'm doing (sorry about that, but I don't have a github acct, yet).


Roberto Bouza | 23 Feb 02:18 2016

Adding a new TCP option


Im trying to add a new option to the TCP stack, it looked easy but somehow I'm getting this:

ERROR: --- Error in child 54516
Traceback (most recent call last):
  File "/Users/rbouza/Development/test/src/scapy/sendrecv.py", line 89, in sndrcv
  File "/Users/rbouza/Development/test/src/scapy/arch/pcapdnet.py", line 244, in send
    sx = str(cls()/x)
  File "/Users/rbouza/Development/test/src/scapy/packet.py", line 261, in __str__
    return self.build()
  File "/Users/rbouza/Development/test/src/scapy/packet.py", line 319, in build
    p = self.do_build()
  File "/Users/rbouza/Development/test/src/scapy/packet.py", line 311, in do_build
    pay = self.do_build_payload()
  File "/Users/rbouza/Development/test/src/scapy/packet.py", line 303, in do_build_payload
    return self.payload.do_build()
  File "/Users/rbouza/Development/test/src/scapy/packet.py", line 311, in do_build
    pay = self.do_build_payload()
  File "/Users/rbouza/Development/test/src/scapy/packet.py", line 303, in do_build_payload
    return self.payload.do_build()
  File "/Users/rbouza/Development/test/src/scapy/packet.py", line 312, in do_build
    p = self.post_build(pkt,pay)
  File "/Users/rbouza/Development/test/src/scapy/layers/inet.py", line 533, in post_build
    dataofs = 5+((self.get_field("options").i2len(self, self.options)+3)/4)
  File "/Users/rbouza/Development/test/src/scapy/fields.py", line 411, in i2len
    return sum( len(p) for p in val )
  File "/Users/rbouza/Development/test/src/scapy/fields.py", line 411, in <genexpr>
    return sum( len(p) for p in val )
TypeError: an integer is required

The option looks like:
class TCPOption_FO(TCPOption):
name = "Fast Open"
kind = 34
fields_desc = [_TCPOption_HDR,
FieldLenField("length", None, length_of="cookie"),
StrLenField("cookie", "",
length_from=lambda pkt:pkt.length-2),]
And the way I'm creating the packet:

options = [TCPOption_FO()]
l4_segment = TCP(sport=sport, dport=port, seq=RandShort(),
It looks like the option needs a __len__ method but looking at all other options that doesn't seem to be case.

Any ideas?

And thanks!

- Roberto
Richard Kinder | 16 Feb 03:52 2016

Full dot11 RadioTap parsing (field alignment/padding issues)

Hi all,


Looking at the newly (couple of months ago) added dot11 RadioTap parsing, it seems that the code handling the conditional fields is a little too primitive to handle the ‘richness’ of the RadioTap headers.


As an example, try the following RadioTap encapsulated frame:


b"\x00\x00\x1c\x00k\x08\x08\x00o\xdbq\x01\x00\x00\x00\x00\x10\x00q\x16 <at> \x01\xe9\x00\x01\x1f\x04\x07\x88\x028\x00\x90r <at> \x82\xd27\x10\xc3{Q\x144\x10\xc3{Q\x140\x00\x00\x00\x00\xaa\xaa\x03\x00\x00\x00\x08\x00E\x00\x01H5\xd2\x00\x00 <at> \x11\xbf\xd2\xc0\xa8\x01\x01\xc0\xa8\x01\xaf\x00C\x00D\x014\xaa\xc7\x02\x01\x06\x00\xff\x97<l\x00\x00\x00\x00\x00\x00\x00\x00\xc0\xa8\x01\xaf\xc0\xa8\x01\x01\x00\x00\x00\x00\x90r <at> \x82\xd27\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00c\x82Sc5\x01\x056\x04\xc0\xa8\x01\x013\x04\x00\x01Q\x80:\x04\x00\x00\xa8\xc0;\x04\x00\x01'P\x01\x04\xff\xff\xff\x00\x1c\x04\xc0\xa8\x01\xff\x06\x04\xc0\xa8\x01\x01\xfc\x01\n\x03\x04\xc0\xa8\x01\x01\xff\x00\x00\x00\x00\x00_\xb5F?"


This is incorrectly parsing the fields after ‘flags’ due to the alignment requirement of the following ‘channel frequency’ field.


From Wireshark, we see the padding byte:



Directly after the flags byte, there is one byte of padding to ensure the channel frequency is properly aligned. This isn’t handled in the ConditionalField entry properly – it’s not design to account for RadioTap header padding and alignment. I’m sure there are hundreds of such permutations where the alignment and padding aren’t handled by scapy.


I can think of how to fix this using something like ‘ConditionalFieldAligned’, I’m just having trouble figuring out how to implement it. In order for such a field to be possible, the field needs to know the current offset of the bytes being decoded. Is such a thing possible without major surgery in the core code? I’m happy to don the mask and gloves, just reaching out for more clued up people to give me their advice first.


Thanks in advance!




This email, including its contents and any attachment(s), may contain confidential information of Quantenna Communications, Inc. and is solely for the intended recipient(s). If you may have received this in error, please contact the sender and permanently delete this email, its contents and any attachment(s).
Aaron Wood | 11 Feb 20:02 2016

Improving speed of reading a pcap file?


I'm using scapy's ease of adding new protocol layers to support a custom protocol, and I greatly appreciate how well that worked.

Unfortunately, I'm wishing that scapy was faster (much faster).  A simple python script that opens and reads all packets from a file (iterating) seems to only be able to run at about 800 packets/sec max, and if I add any logic, it starts to drop to around 400 packets/sec.

In doing some profiling, it seems that the majority of the time is spent in the packet.py(__init__) method, and in particular, in the copying of the default fields.

         1970839595 function calls (1849378727 primitive calls) in 2416.321 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
150467248/150432518  179.062    0.000  382.760    0.000 packet.py:203(__setattr__)
9107553/3305446  152.967    0.000 1908.473    0.001 packet.py:67(__init__)
122796567/59356974  151.297    0.000  203.762    0.000 packet.py:187(setfieldval)
50185310/50179904  150.721    0.000  308.406    0.000 copy.py:145(deepcopy)
7004124/6987389  118.672    0.000  423.453    0.000 packet.py:557(do_dissect)
  9107553  113.256    0.000  436.917    0.000 packet.py:99(do_init_fields)
 50183807  107.838    0.000  120.957    0.000 copy.py:267(_keep_alive)

From my own quick inspection of the code, it looks like the only time the default fields object is modified after construction is when fuzzing.  Have I read this right?

John Daley (johndale | 6 Feb 20:41 2016

rdpcap() corruption


I'm using a test suite (dts for dpdk) that uses scapy and finding that when reading pcap files sometimes
several packets are corrupted once read into the object.

I'm using fedora 23, python 2.7.19, scapy 2.2.0.

# scapy
Welcome to Scapy (2.2.0)
>>> pcap = rdpcap("sniff_enp13s0f0.pcap")
WARNING: wrong value: DNS.qdcount=48940
WARNING: wrong value: DNS.ancount=59371
WARNING: more wrong value: DNS.nscount=39522
WARNING: DNS RR prematured end (ofs=9788, len=1378)
WARNING: DNS RR prematured end (ofs=2799, len=1378)
WARNING: more DNS RR prematured end (ofs=11652, len=422)
>>> p = pcap[233]
>>> hexdump(p)
0000   02 00 00 00 00 02 68 05  CA 31 FA 90 86 DD 60 00   ......h..1....`.
0010   00 00 00 0C 11 40 00 00  00 00 00 00 00 00 00 00   ..... <at> ..........
0020   00 00 00 00 00 01 00 00  00 00 00 00 00 00 00 00   ................
0030   00 00 00 00 00 01 00 E8  00 35 00 0C CB 7B 7D F5   .........5...{}.
0040   B5 46 00 00 00 00 00 00  00 00                     .F........

[ show the same packet with tcpdump]
#  tcpdump -r sniff_enp13s0f0.pcap src port 232 -xxx
reading from file sniff_enp13s0f0.pcap, link-type EN10MB (Ethernet)
11:03:37.196657 IP6 localhost.232 > localhost.domain: [|domain]
        0x0000:  0200 0000 0002 6805 ca31 fa90 86dd 6000
        0x0010:  0000 000c 1140 0000 0000 0000 0000 0000
        0x0020:  0000 0000 0001 0000 0000 0000 0000 0000
        0x0030:  0000 0000 0001 00e8 0035 000c cb7b 7df5
        0x0040:  b546

Note the extra 0's at the end of the packet!

Sometimes a string of 0's is appended.

Sometimes a string with the following pattern is injected into the packet:
01 00 01 00 00 01 00 01 00 00 

Sometimes random 2 byte words are replaced with 0, like this
Section where 'a3 07' and cb 25' are replaced by 0

Sent: ab 92 8e 5c 7c 06 75 ce 3f 78 1c 20 a3 07 d1 96 20 9a cb 26 5f 8c a4 f2
Recv: ab 92 8e 5c 7c 06 00 3f 78 1c 20 00 d1 96 20 9a 00 5f 8c a4 f2

How could this possibly happen?


To unsubscribe, send a mail to scapy.ml-unsubscribe <at> secdev.org