diff --git a/include/stellar/packet.h b/include/stellar/packet.h index d8d94c7..b867b6f 100644 --- a/include/stellar/packet.h +++ b/include/stellar/packet.h @@ -27,22 +27,23 @@ enum layer_type // L3 -- network layer LAYER_TYPE_IPV4 = 1 << 8, LAYER_TYPE_IPV6 = 1 << 9, - LAYER_TYPE_L3 = (LAYER_TYPE_IPV4 | LAYER_TYPE_IPV6), + LAYER_TYPE_IPAH = 1 << 10, + LAYER_TYPE_L3 = (LAYER_TYPE_IPV4 | LAYER_TYPE_IPV6 | LAYER_TYPE_IPAH), // L3 -- tunnel - LAYER_TYPE_GRE = 1 << 10, + LAYER_TYPE_GRE = 1 << 11, LAYER_TYPE_L3_TUN = (LAYER_TYPE_GRE), // L4 -- transport layer - LAYER_TYPE_UDP = 1 << 11, - LAYER_TYPE_TCP = 1 << 12, - LAYER_TYPE_ICMP = 1 << 13, - LAYER_TYPE_ICMP6 = 1 << 14, + LAYER_TYPE_UDP = 1 << 12, + LAYER_TYPE_TCP = 1 << 13, + LAYER_TYPE_ICMP = 1 << 14, + LAYER_TYPE_ICMP6 = 1 << 15, LAYER_TYPE_L4 = (LAYER_TYPE_UDP | LAYER_TYPE_TCP | LAYER_TYPE_ICMP | LAYER_TYPE_ICMP6), // L4 -- tunnel - LAYER_TYPE_VXLAN = 1 << 15, - LAYER_TYPE_GTPV1_U = 1 << 16, + LAYER_TYPE_VXLAN = 1 << 16, + LAYER_TYPE_GTPV1_U = 1 << 17, // ALL LAYER_TYPE_ALL = (LAYER_TYPE_L2 | LAYER_TYPE_L2_TUN | LAYER_TYPE_L3 | LAYER_TYPE_L3_TUN | LAYER_TYPE_L4 | LAYER_TYPE_VXLAN | LAYER_TYPE_GTPV1_U), diff --git a/src/packet/ipv4_utils.h b/src/packet/ipv4_utils.h index a67e7bf..f2dc3a0 100644 --- a/src/packet/ipv4_utils.h +++ b/src/packet/ipv4_utils.h @@ -40,6 +40,7 @@ static inline uint8_t ipv4_hdr_get_version(const struct ip *hdr) return hdr->ip_v; } +// IP Options are included in the hdr_len field static inline uint8_t ipv4_hdr_get_hdr_len(const struct ip *hdr) { return hdr->ip_hl << 2; diff --git a/src/packet/packet.cpp b/src/packet/packet.cpp index 029258a..19c4a51 100644 --- a/src/packet/packet.cpp +++ b/src/packet/packet.cpp @@ -72,6 +72,7 @@ static inline const char *parse_mpls(struct packet *pkt, const char *data, uint1 // 网络层 static inline const char *parse_ipv4(struct packet *pkt, const char *data, uint16_t len); static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint16_t len); +static inline const char *parse_auth(struct packet *pkt, const char *data, uint16_t len); // 网络层 -- 隧道 static inline const char *parse_gre(struct packet *pkt, const char *data, uint16_t len); // 传输层 @@ -133,6 +134,8 @@ static inline const char *layer_type_to_str(enum layer_type type) return "IPV4"; case LAYER_TYPE_IPV6: return "IPV6"; + case LAYER_TYPE_IPAH: + return "IPAH"; case LAYER_TYPE_GRE: return "GRE"; case LAYER_TYPE_UDP: @@ -958,7 +961,21 @@ static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint1 return data; } struct ip6_ext *ext = (struct ip6_ext *)next_hdr_ptr; - uint16_t skip_len = ext->ip6e_len * 8 + 8; + uint16_t skip_len = 0; + if (next_proto == IPPROTO_AH) + { + /* + * https://datatracker.ietf.org/doc/html/rfc4302#section-2 + * For IPv6, the total length of the header must be a multiple of 8-octet units. + * (Note that although IPv6 [DH98] characterizes AH as an extension header, + * its length is measured in 32-bit words, not the 64-bit words used by other IPv6 extension headers.) + */ + skip_len = ext->ip6e_len * 4 + 8; + } + else + { + skip_len = ext->ip6e_len * 8 + 8; + } if (unlikely(skip_len > pld_len)) { PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_TYPE_IPV6); @@ -982,6 +999,59 @@ static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint1 return parse_l4(pkt, next_proto, layer->pld_ptr, layer->pld_len); } +static inline const char *parse_auth(struct packet *pkt, const char *data, uint16_t len) +{ + /* + * https://datatracker.ietf.org/doc/html/rfc4302#section-2 + * For IPv4: AH not IPv4 option, as an single layer + * For IPv6: AH as IPv6 extension header + * + * AH Format + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Next Header | Payload Len | RESERVED | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Security Parameters Index (SPI) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Sequence Number Field | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + Integrity Check Value-ICV (variable) | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + if (unlikely(len < 12)) + { + PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_TYPE_IPAH); + return data; + } + /* + * https://datatracker.ietf.org/doc/html/rfc4302#section-2 + * For IPv4, This 8-bit field specifies the length of AH in 32-bit words (4-byte units), minus "2". + * Thus, for example, if an integrity algorithm yields a 96-bit authentication value, + * this length field will be "4" (3 32-bit word fixed fields plus 3 32-bit words for the ICV, minus 2). + */ + uint8_t next_proto = ((const uint8_t *)data)[0]; + uint16_t hdr_len = ((const uint8_t *)data)[1] * 4 + 8; + if (unlikely(len < hdr_len)) + { + PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_TYPE_IPAH); + return data; + } + + struct packet_layer *layer = get_free_layer(pkt); + if (unlikely(layer == NULL)) + { + return data; + } + SET_LAYER(pkt, layer, LAYER_TYPE_IPAH, hdr_len, data, len, 0); + + return parse_l4(pkt, next_proto, layer->pld_ptr, layer->pld_len); +} + static inline const char *parse_gre(struct packet *pkt, const char *data, uint16_t len) { #define GRE_PRO_IPV4 (0x0800) @@ -1042,10 +1112,19 @@ static inline const char *parse_udp(struct packet *pkt, const char *data, uint16 if (udp_hdr_get_dst_port(hdr) == 2152 || udp_hdr_get_src_port(hdr) == 2152) { + // TODO + // check V1 or V2 + // GTP1U_PORT 2152 return parse_gtpv1_u(pkt, layer->pld_ptr, layer->pld_len); } + if (udp_hdr_get_dst_port(hdr) == 2123 || udp_hdr_get_src_port(hdr) == 2123) + { + // TODO + // GTP-C - GTP control 2123 + } + if (udp_hdr_get_dst_port(hdr) == 1701) { // L2TP_DPORT 1701 @@ -1209,6 +1288,8 @@ static inline const char *parse_l4(struct packet *pkt, uint8_t next_proto, const { switch (next_proto) { + case IPPROTO_AH: + return parse_auth(pkt, data, len); case IPPROTO_TCP: return parse_tcp(pkt, data, len); case IPPROTO_UDP: @@ -1294,6 +1375,8 @@ void packet_print_str(const struct packet *pkt) case LAYER_TYPE_IPV6: used = ipv6_hdr_to_str((const struct ip6_hdr *)layer->hdr_ptr, buffer, sizeof(buffer)); break; + case LAYER_TYPE_IPAH: + break; case LAYER_TYPE_GRE: break; case LAYER_TYPE_UDP: @@ -1320,38 +1403,6 @@ void packet_print_str(const struct packet *pkt) } } -void packet_print_table(const struct packet *pkt) -{ - if (pkt == NULL) - { - return; - } - - printf("packet: %p, data_ptr: %p, data_len: %u, trim_len: %u, layers_used: %u, layers_size: %u\n", - pkt, pkt->data_ptr, pkt->data_len, pkt->trim_len, - pkt->layers_used, pkt->layers_size); - printf("+------------+------------+------------+------------+------------+------------+------------+\n"); - printf("| %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s |\n", - "index", "type", "hdr ptr", "hdr offset", "hdr len", "pld ptr", "pld len"); - printf("+------------+------------+------------+------------+------------+------------+------------+\n"); - - for (uint8_t i = 0; i < pkt->layers_used; i++) - { - const struct packet_layer *layer = &pkt->layers[i]; - printf("| %-10u | %-10s | %-10p | %-10u | %-10u | %-10p | %-10u |\n", - i, layer_type_to_str(layer->type), - layer->hdr_ptr, layer->hdr_offset, layer->hdr_len, - layer->pld_ptr, layer->pld_len); - printf("+------------+------------+------------+------------+------------+------------+------------+\n"); - } - printf("data: "); - for (uint16_t i = 0; i < pkt->data_len; i++) - { - printf("0x%02x, ", (uint8_t)pkt->data_ptr[i]); - } - printf("\n"); -} - // return 0 : found // return -1 : not found int packet_get_innermost_tuple2(const struct packet *pkt, struct tuple2 *tuple) diff --git a/src/packet/packet_priv.h b/src/packet/packet_priv.h index ec60196..a40b049 100644 --- a/src/packet/packet_priv.h +++ b/src/packet/packet_priv.h @@ -55,7 +55,6 @@ struct packet // return innermost payload const char *packet_parse(struct packet *pkt, const char *data, uint16_t len); void packet_print_str(const struct packet *pkt); -void packet_print_table(const struct packet *pkt); // direction 1: E2I // direction 0: I2E diff --git a/test/packet_parser/cmp_layers.sh b/test/packet_parser/cmp_layers.sh index 7d690f7..496961f 100644 --- a/test/packet_parser/cmp_layers.sh +++ b/test/packet_parser/cmp_layers.sh @@ -108,13 +108,10 @@ function preprocess_tshark_ouput() { ":data" "" ":sctp:m3ua" "" ":sctp" "" - ":teredo:ipv6:udp" "" - ":teredo:ipv6:tcp" "" - ":teredo:ipv6:icmpv6" "" - ":teredo:ipv6:gre:ip:udp" "" ":igmp" "" ":icmp:ip:tcp" ":icmp" ":pwethheuristic:pwethnocw" "" + ":ospf" "" ) for ((i = 0; i < ${#kv_array[@]}; i += 2)); do key=${kv_array[i]} diff --git a/test/packet_parser/packet_parser.cpp b/test/packet_parser/packet_parser.cpp index ae6b68c..22f11bc 100644 --- a/test/packet_parser/packet_parser.cpp +++ b/test/packet_parser/packet_parser.cpp @@ -25,7 +25,7 @@ static int ipv6_proto_to_str(const struct packet_layer *ipv6_layer, char *buff, used += snprintf(buff + used, size - used, ":ipv6.routing"); break; case IPPROTO_AH: - used += snprintf(buff + used, size - used, ":ipv6.ah"); + used += snprintf(buff + used, size - used, ":ah"); break; case IPPROTO_DSTOPTS: used += snprintf(buff + used, size - used, ":ipv6.dstopts"); @@ -79,6 +79,9 @@ static int packet_proto_to_str(const struct packet *pkt, char *buff, int size) case LAYER_TYPE_IPV6: used += ipv6_proto_to_str(layer, buff + used, size - used); break; + case LAYER_TYPE_IPAH: + used += snprintf(buff + used, size - used, "ah"); + break; case LAYER_TYPE_GRE: used += snprintf(buff + used, size - used, "gre"); break;