in src/filtration/packet.h [170:262]
inline void check_ipv6() __attribute__((always_inline))
{
if(dlen < sizeof(IPv6Header)) return;
auto header = reinterpret_cast<const IPv6Header*>(data);
if(header->version() != 6) return;
data += sizeof(IPv6Header);
dlen -= sizeof(IPv6Header);
const uint32_t payload = header->payload_len();
if(payload == 0) return; // The length is set to zero when a Hop-by-Hop extension header carries a Jumbo Payload option
if(dlen < payload) return; // truncated packet
dlen = payload; // skip padding at the end
// handling optional headers
uint8_t htype = header->nexthdr();
switch_type: // TODO: remove ugly goto
switch(htype)
{
case ip::NextProtocol::TCP:
check_tcp();
break;
case ip::NextProtocol::UDP:
check_udp();
break;
case ip::NextProtocol::HOPOPTS:
{
auto hbh = reinterpret_cast<const ipv6_hbh*>(data);
const unsigned int size{1U + hbh->hbh_len};
if(dlen < size) return; // truncated packet
data += size;
dlen -= size;
htype = hbh->hbh_nexthdr;
goto switch_type;
}
case ip::NextProtocol::DSTOPTS:
{
auto dest = reinterpret_cast<const ipv6_dest*>(data);
const unsigned int size{1U + dest->dest_len};
if(dlen < size) return; // truncated packet
data += size;
dlen -= size;
htype = dest->dest_nexthdr;
goto switch_type;
}
case ip::NextProtocol::ROUTING:
{
auto route = reinterpret_cast<const ipv6_route*>(data);
const unsigned int size{1U + route->route_len};
if(dlen < size) return; // truncated packet
data += size;
dlen -= size;
htype = route->route_nexthdr;
goto switch_type;
}
case ip::NextProtocol::FRAGMENT:
{
auto frag = reinterpret_cast<const ipv6_frag*>(data);
// isn't first fragment (offset != 0)
if((ntohs(frag->frag_offlg) & ipv6_frag::OFFSET) != 0) return;
const unsigned int size{sizeof(ipv6_frag)};
if(dlen < size) return; // truncated packet
data += size;
dlen -= size;
htype = frag->frag_nexthdr;
goto switch_type;
}
case ip::NextProtocol::NONE:
default: // unknown header
return;
}
ipv6 = header;
}