Search code examples
pythonnetwork-programmingethernetscapyf5

Scapy - How to Dissect an Ethernet Trailer field


I'm using the F5 Networks Big-IP products, which are appending a custom Ethernet II trailer frame for debugging purposes. I'm trying with Scapy to bind a new layer for this trailer, but I'm unable to do so.

I can see the payload of interest in the Padding field but using bind_layers does not perform proper dissection of the required Padding section.

class MyEthTrailer(Packet):
    name = "Ethernet Trailer"
    fields_desc = [ ####Fields Mapping Section ]
    def dissect(self, s):
        self.payl,self.pad = self.extract_padding(s)
        s = self.do_dissect(self.pad)

One solution I was thinking was to create a new Ethernet replacement class (or overloaded), which I can then refers to the typical Ethernet payload and my new trailer. But I'm not a super Python/scapy programmer, and I am not certain if this is the best option.

This is how Scapy currently maps my packet after I apply bind_layers(TCP,MyEthTrailer). The info I should have parse is in the Padding class

<Ether  dst=00:00:00:00:00:00 src=00:00:00:00:00:01 type=0x8100 |<Dot1Q  prio=0L id=0L vlan=01L type=0x800 |<IP  version=4L ihl=5L tos=0x0 len=67 id=1 flags=DF frag=0L ttl=255 proto=tcp chksum=0x01 src=10.0.0.1 dst=10.0.1.1 options=[] |<TCP  sport=1111 dport=https seq=1 ack=1 dataofs=5L reserved=0L flags=PA window=4380 chksum=0xb718 urgptr=0 options=[] |<MyEthTrailer  |<Padding  load='\xPayload of MyEtherTrailer' |>>>>>>

[UPDATE-1]

I can force decoding a TCP SYN packet by calling :

packet[TCP].decode_payload_as(MyEthTrailer)

However, the bind_layers method, does not seem to work automatically, and this does not work with more complex packet because it's mixing up TCP Padding with MyEthTrailer payload.

[UPDATE-2]

I got it partly working, but every packet needs to be casted properly, then I can read the trailer payload and decode it. For example if a packet is TCP/DNS/MyEthTrailer, this will work. If I don't know it's DNS, and it's not set up properly, it's still mixed in in TCP payload and Padding.

Your help is appreciated.


Solution

  • I was able to do it by overloading the pre_dissect function of my new custom class MyEthTrailer. I try to parse the payload of the last layer which has Padding, and verify if it has the correct length.

    This is handle with 2 things :

    PART 1 DISSECT section
    class MyEthTrailer(Packet):
        def pre_dissect(self,s):
            verify_if_payload_is_mine_and_assign_fields()
    
    PART 2 Manual Force payload decode
    _debug=True
    
    if re.match(r'F5\-Pseudo-\pkt.+tcpdump',str(packets[0][Raw])):
            if re.match(r'.+CMD\:.+\-s0.+VER\:.+',str(packets[0][Raw])): has_F5_trailer=True
            if re.match(r'.+CMD\:.+\:nnn.+VER\:.+',str(packets[0][Raw])): F5_trailer_noise_level=3
            elif re.match(r'.+CMD\:.+\:nn.+VER\:.+',str(packets[0][Raw])): F5_trailer_noise_level=2
            elif re.match(r'.+CMD\:.+\:n.+VER\:.+',str(packets[0][Raw])): F5_trailer_noise_level=1
            else:
                if _debug: print "No F5 EthTrailer F5_Noise_level visible from packets[0]"
        if has_F5_trailer:
            #Skip the F5 first packet, which only contains the info. 
            for pk in packets[1:]:
                try:
                    if isinstance(pk.lastlayer(),Padding):
                        pk.lastlayer().underlayer.decode_payload_as(MyEthTrailer)
                except:
                    #Errorhandling
    

    I will post the whole solution to Github and update here if anybody is interested.