Search code examples
csocketsfilteripv6icmp

How to differentiate between extension and upper-layer header


I'm trying to parse IPv6 packet received through raw socket and decide if it is ICMPv6 or not. I can process the Ethernet and IPv6 header, but then there are optional extension headers. If the Next Header field of IPv6 header is not ICMPv6, I have to iterate through any extensions that might precede.

The iteration itself is not a problem as each extension header carry its length. However, I can't find a good way to differentiate between extension header that might follow and other upper-level protocols such as TCP and UDP. I can either check if the Next Header is one of known extension headers (in which case I can iterate) or if the Next Header is upper-layer protocol (in which case I have to stop, there won't be any ICMP..).

In both approaches I'm relying on some self-built list of constants against which I'm checking Next Header and that list might change in future. Isn't there a better way to tell when I'm at the end of extension headers and upper-layer header (or nothing) follows?


Solution

  • Each extension header has its own Next Header field as its first octet, with the same meaning as (but different relative location from) the corresponding field of the fixed IPv6 header. You can use these together with the extension headers' length fields to step through the extension headers until you find the transport layer header. Wikipedia covers this in some detail.


    Update:

    With respect to your revised question, no, there is no standard function or algorithm for distinguishing between header codes designating extension headers and those designating protocol headers, except simply to know which are which. They are assigned from the same code space, with no special internal structure.

    There are only 256 possible values, however, so knowing which are which is feasible. Do be careful, however: nearly half of the available codes are currently unassigned, but may be assigned to either extension header types or protocol types in the future. Until and unless the codes are exhausted, your software will need to recognize three categories:

    • extension header,
    • protocol header, and
    • unknown.

    Additionally, as for implementing such a test, I would recommend creating and using a lookup table instead of building a complicated conditional expression. Something along these lines:

    enum header_type { HDR_PROTOCOL, HDR_EXTENSION, HDR_UNKNOWN };
    
    const enum header_type header_types[256] = {
        [0x00] = HDR_EXTENSION,  // IPv6 hop-by-hop option
        [0x01] = HDR_PROTOCOL,   // ICMP
        // ... both extension and protocol headers in this range ...
        [0x8e] = HDR_PROTOCOL,   // robust header compression
        [0x8f] = HDR_UNKNOWN,    // unassigned
        // ... more unassigned ...
        [0xfd] = HDR_UNKNOWN,    // for experimentation
        [0xfe] = HDR_UNKNOWN,    // for experimentation
        [0xff] = HDR_UNKNOWN,    // reserved
    };
    

    You can use that to answer several kinds of questions, and very efficiently, too. The explicit designators in the initializer are not strictly necessary, but I think they're a good idea: they will help you verify and maintain the table.