python-3.xipv6scapyicmpv6

How to create an ICMPv6 scapy object from raw bytestring from a socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPv6)?


I want to check/analyse ICMPv6 router advertisements (RAs) in a Python program using Python, where I get the (not so) raw packet data as follows:

import socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6)
p, addr = sock.recvfrom(4096)

When an ICMPv6 packet gets received, the packet p will contain only(!) the ICMPv6 part itself, but not any other outer elements, so there's no IPv6 header, no Ethernet header, ...

How do I create the correct Scapy ICMPv6-derived packet class from my (no so) raw packet data? _ICMPv6 seems to be just a fallback class. Is there some kind of factory to get the correct sub class (such as ICMPv6ND_RA) from?


Solution

  • After reading the source code of Scapy's inet6.py I noticed that there's a more "direct" -- but not necessarily "cleaner" -- way to get the correct Scapy ICMPv6 message object than Cukic0d's fine answer: that's in the sense that there's an alternative way that doesn't need the "fake" outer IPv6 object shell (albeit I really appreciate Cukic0d's answer, as it would be a good place to dump the sender address into!):

    from scapy.layers.inet6 import *
    
    icmpv6_packet = icmp6typescls.get(p[0], ICMPv6Unknown)(p)
    

    This uses the icmp6typescls dictionary mapping the ICMPv6 (message) type, which is in the first octet of the packet returned from the socket), to its corresponding Scapy ICMPv6 message class ... and then calls the constructor, handing the payload over to it.

    The class ICMPv6Unknown is the default class Scapy uses when the ICMPv6 (message) type cannot be mapped onto a known message class. This ensures that there's always a sensible constructor to be called, even if we don't understand the packet received in its full details.