#pragma once #ifdef __cplusplus extern "C" { #endif #define __FAVOR_BSD 1 #include #include #include #include #include #include #include #include enum layer_proto { LAYER_PROTO_NONE = 0, // L2 -- data link layer LAYER_PROTO_ETHER = 1, LAYER_PROTO_PWETH = 2, LAYER_PROTO_PPP = 3, LAYER_PROTO_L2TP = 4, // L2 -- tunnel LAYER_PROTO_VLAN = 21, LAYER_PROTO_PPPOE = 22, LAYER_PROTO_MPLS = 23, // L3 -- network layer LAYER_PROTO_IPV4 = 31, LAYER_PROTO_IPV6 = 32, LAYER_PROTO_IPAH = 33, // L3 -- tunnel LAYER_PROTO_GRE = 41, // L4 -- transport layer LAYER_PROTO_UDP = 51, LAYER_PROTO_TCP = 52, LAYER_PROTO_ICMP = 53, LAYER_PROTO_ICMP6 = 54, // L4 -- tunnel LAYER_PROTO_VXLAN = 61, LAYER_PROTO_GTP_U = 62, LAYER_PROTO_GTP_C = 63, }; struct layer { enum layer_proto proto; uint16_t hdr_len; union { // all hdr ptr refer to raw packet, read-only const struct ethhdr *eth; const struct ip *ip4; const struct ip6_hdr *ip6; const struct tcphdr *tcp; const struct udphdr *udp; const struct icmphdr *icmp4; const struct icmp6_hdr *icmp6; const struct mpls_label *mpls; const char *raw; // e.g. pppoe, l2tp, gre, gtp, etc. } hdr; }; int packet_get_layer_count(const struct packet *pkt); // return 0: success  // return -1: failed int packet_get_layer_by_idx(const struct packet *pkt, int idx, struct layer *out); #define PACKET_FOREACH_LAYER_INORDER(pkt, layer) \ for (int i = 0; i < packet_get_layer_count(pkt) && packet_get_layer_by_idx(pkt, i, &layer) == 0; i++) #define PACKET_FOREACH_LAYER_REVERSE(pkt, layer) \ for (int i = packet_get_layer_count(pkt) - 1; i >= 0 && packet_get_layer_by_idx(pkt, i, &layer) == 0; i--) #define PACKET_GETALL_LAYERS(pkt, layers) \ ({ \ memset(layers, 0, sizeof(layers)); \ int size = sizeof(layers) / sizeof(layers[0]); \ int count = packet_get_layer_count(pkt); \ int num = count > size ? size : count; \ for (int i = 0; i < num && packet_get_layer_by_idx(pkt, i, &layers[i]) == 0; i++) \ /* void */; \ num; \ }) #ifdef __cplusplus } #endif