Add support for parsing PW Ethernet and Enhanced MPLS parsing

This commit is contained in:
luwenpeng
2024-06-02 00:07:33 +08:00
parent f3b92a8a15
commit 18fe1e2e41
13 changed files with 615 additions and 250 deletions

View File

@@ -1,11 +1,5 @@
#include <string.h>
#include <stdlib.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#define __FAVOR_BSD 1
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ether.h>
#include <netinet/icmp6.h>
#include <netinet/ip_icmp.h>
#include <linux/ppp_defs.h>
@@ -16,6 +10,8 @@
#include "tcp_utils.h"
#include "ipv4_utils.h"
#include "ipv6_utils.h"
#include "mpls_utils.h"
#include "eth_utils.h"
#define likely(expr) __builtin_expect((expr), 1)
#define unlikely(expr) __builtin_expect((expr), 0)
@@ -32,10 +28,10 @@
(tag), (next_proto)); \
}
#define PACKET_LOG_UNSUPPORT_ETHPROTO(tag, next_proto) \
{ \
PACKET_LOG_WARN("%s: unsupport next eth proto %d: %s", \
(tag), (next_proto), ethproto_to_str(next_proto)); \
#define PACKET_LOG_UNSUPPORT_ETHPROTO(tag, next_proto) \
{ \
PACKET_LOG_WARN("%s: unsupport next eth proto %d: %s", \
(tag), (next_proto), eth_proto_to_str(next_proto)); \
}
#define PACKET_LOG_UNSUPPORT_IPPROTO(tag, next_proto) \
@@ -48,7 +44,6 @@
* Static API
******************************************************************************/
static const char *ethproto_to_str(uint16_t proto);
static const char *ipproto_to_str(uint16_t proto);
static inline const char *ldbc_method_to_str(enum ldbc_method method);
static inline const char *layer_type_to_str(enum layer_type type);
@@ -65,6 +60,7 @@ static inline uint16_t get_l2tpv2_hdr_len(const char *data, uint16_t len);
// 数据链路层
static inline const char *parse_ether(struct packet *pkt, const char *data, uint16_t len);
static inline const char *parse_pweth(struct packet *pkt, const char *data, uint16_t len);
static inline const char *parse_ppp(struct packet *pkt, const char *data, uint16_t len);
static inline const char *parse_l2tpv2(struct packet *pkt, const char *data, uint16_t len);
static inline const char *parse_l2tpv3_over_udp(struct packet *pkt, const char *data, uint16_t len);
@@ -95,113 +91,6 @@ static inline const char *parse_l4(struct packet *pkt, uint8_t next_proto, const
* Private API -- Utils
******************************************************************************/
static const char *ethproto_to_str(uint16_t proto)
{
switch (proto)
{
case ETH_P_LOOP:
return "LOOP";
case ETH_P_PUP:
return "PUP";
case ETH_P_PUPAT:
return "PUPAT";
case ETH_P_IP:
return "IP";
case ETH_P_X25:
return "X25";
case ETH_P_ARP:
return "ARP";
case ETH_P_BPQ:
return "BPQ";
case ETH_P_IEEEPUP:
return "IEEEPUP";
case ETH_P_IEEEPUPAT:
return "IEEEPUPAT";
case ETH_P_DEC:
return "DEC";
case ETH_P_DNA_DL:
return "DNA_DL";
case ETH_P_DNA_RC:
return "DNA_RC";
case ETH_P_DNA_RT:
return "DNA_RT";
case ETH_P_LAT:
return "LAT";
case ETH_P_DIAG:
return "DIAG";
case ETH_P_CUST:
return "CUST";
case ETH_P_SCA:
return "SCA";
case ETH_P_TEB:
return "TEB";
case ETH_P_RARP:
return "RARP";
case ETH_P_ATALK:
return "ATALK";
case ETH_P_AARP:
return "AARP";
case ETH_P_8021Q:
return "8021Q";
case ETH_P_IPX:
return "IPX";
case ETH_P_IPV6:
return "IPV6";
case ETH_P_PAUSE:
return "PAUSE";
case ETH_P_SLOW:
return "SLOW";
case ETH_P_WCCP:
return "WCCP";
case ETH_P_PPP_DISC:
return "PPP_DISC";
case ETH_P_PPP_SES:
return "PPP_SES";
case ETH_P_MPLS_UC:
return "MPLS_UC";
case ETH_P_MPLS_MC:
return "MPLS_MC";
case ETH_P_ATMMPOA:
return "ATMMPOA";
case ETH_P_LINK_CTL:
return "LINK_CTL";
case ETH_P_ATMFATE:
return "ATMFATE";
case ETH_P_PAE:
return "PAE";
case ETH_P_AOE:
return "AOE";
case ETH_P_8021AD:
return "8021AD";
case ETH_P_802_EX1:
return "802_EX1";
case ETH_P_TIPC:
return "TIPC";
case ETH_P_8021AH:
return "8021AH";
case ETH_P_1588:
return "1588";
case ETH_P_FCOE:
return "FCOE";
case ETH_P_TDLS:
return "TDLS";
case ETH_P_FIP:
return "FIP";
case ETH_P_QINQ1:
return "QINQ1";
case ETH_P_QINQ2:
return "QINQ2";
case ETH_P_QINQ3:
return "QINQ3";
case ETH_P_EDSA:
return "EDSA";
case ETH_P_AF_IUCV:
return "AF_IUCV";
default:
return "UNKNOWN";
}
}
static const char *ipproto_to_str(uint16_t proto)
{
switch (proto)
@@ -292,6 +181,8 @@ static inline const char *layer_type_to_str(enum layer_type type)
{
case LAYER_TYPE_ETHER:
return "ETH";
case LAYER_TYPE_PWETH:
return "PWETH";
case LAYER_TYPE_PPP:
return "PPP";
case LAYER_TYPE_HDLC:
@@ -764,17 +655,43 @@ static inline const char *parse_ether(struct packet *pkt, const char *data, uint
{
return data;
}
uint16_t next_proto = ntohs(((struct ethhdr *)data)->h_proto);
uint16_t next_proto = eth_hdr_get_proto((const struct ethhdr *)data);
SET_LAYER(pkt, layer, LAYER_TYPE_ETHER, sizeof(struct ethhdr), data, len, 0);
// TESTED
return parse_l3(pkt, next_proto, layer->pld_ptr, layer->pld_len);
}
static inline int next_proto_is_ppp(uint16_t next_proto)
static inline const char *parse_pweth(struct packet *pkt, const char *data, uint16_t len)
{
/*
* PW Ethernet Control Word
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |0 0 0 0| Reserved | Sequence Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* Reference: https://tools.ietf.org/html/rfc4448
*/
if (unlikely(len < 4))
{
PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_PWETH);
return data;
}
struct packet_layer *layer = get_free_layer(pkt);
if (unlikely(layer == NULL))
{
return data;
}
SET_LAYER(pkt, layer, LAYER_TYPE_PWETH, 4, data, len, 0);
return parse_ether(pkt, layer->pld_ptr, layer->pld_len);
}
static inline int is_ppp_proto(uint16_t proto)
{
// /usr/include/linux/ppp_defs.h.html
switch (next_proto)
switch (proto)
{
case PPP_IP: /* Internet Protocol */
case PPP_AT: /* AppleTalk Protocol */
@@ -835,7 +752,7 @@ static inline const char *parse_ppp(struct packet *pkt, const char *data, uint16
// ppp header 1 byte
next_proto = *((uint8_t *)data);
if (next_proto_is_ppp(next_proto))
if (is_ppp_proto(next_proto))
{
hdr_len = 1;
goto success;
@@ -843,7 +760,7 @@ static inline const char *parse_ppp(struct packet *pkt, const char *data, uint16
// ppp header 2 bytes
next_proto = ntohs(*((uint16_t *)data));
if (next_proto_is_ppp(next_proto))
if (is_ppp_proto(next_proto))
{
hdr_len = 2;
goto success;
@@ -862,7 +779,6 @@ success:
SET_LAYER(pkt, layer, LAYER_TYPE_PPP, hdr_len, data, len, 0);
switch (next_proto)
{
// TESTED
case PPP_IP:
return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len);
case PPP_IPV6:
@@ -936,13 +852,11 @@ static inline const char *parse_vlan(struct packet *pkt, const char *data, uint1
uint16_t next_proto = ntohs(((struct vlan_hdr *)data)->protocol);
SET_LAYER(pkt, layer, LAYER_TYPE_VLAN, sizeof(struct vlan_hdr), data, len, 0);
// TESTED
return parse_l3(pkt, next_proto, layer->pld_ptr, layer->pld_len);
}
static inline const char *parse_pppoe_ses(struct packet *pkt, const char *data, uint16_t len)
{
if (unlikely(len < 6))
{
PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_PPPOE);
@@ -956,40 +870,12 @@ static inline const char *parse_pppoe_ses(struct packet *pkt, const char *data,
}
SET_LAYER(pkt, layer, LAYER_TYPE_PPPOE, 6, data, len, 0);
// TESTED
return parse_ppp(pkt, layer->pld_ptr, layer->pld_len);
}
static inline const char *parse_mpls(struct packet *pkt, const char *data, uint16_t len)
{
/*
* MPLS 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Label | Exp |S| TTL |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* Label : Label Value 20 bits
* Exp : Experimental Use 3 bits
* S : Bottom of Stack 1 bit
* TTL : Time to Live 8 bits
*/
#define MPLS_LABEL_MASK (0xFFFFF000)
#define MPLS_EXP_MASK (0x00000E00)
#define MPLS_BLS_MASK (0x00000100)
#define MPLS_TTL_MASK (0x000000FF)
enum mpls_next_proto
{
MPLS_NEXT_PROTO_ETHER = 0x0,
MPLS_NEXT_PROTO_MPLS = 0x1,
MPLS_NEXT_PROTO_IPV4 = 0x4,
MPLS_NEXT_PROTO_IPV6 = 0x6,
};
// 4 + 1
if (unlikely(len < 5))
if (unlikely(len < 4))
{
PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_MPLS);
return data;
@@ -1001,65 +887,38 @@ static inline const char *parse_mpls(struct packet *pkt, const char *data, uint1
return data;
}
uint16_t hdr_len = 4;
uint32_t *hdr = (uint32_t *)data;
unsigned int mpls_bls = (ntohl(*hdr) & MPLS_BLS_MASK) >> 8;
enum mpls_next_proto next_proto;
if (mpls_bls == 1)
if (mpls_hdr_get_bos((const struct mpls_hdr *)data))
{
switch ((((uint8_t *)(data + 4))[0]) >> 4)
SET_LAYER(pkt, layer, LAYER_TYPE_MPLS, 4, data, len, 0);
if (layer->pld_len == 0)
{
return layer->pld_ptr;
}
uint8_t next_proto = layer->pld_ptr[0] >> 4;
switch (next_proto)
{
case 0:
/*
* PW Ethernet Control Word
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |0 0 0 0| Reserved | Sequence Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* Reference: https://tools.ietf.org/html/rfc4448
*/
hdr_len += 4; // skip PW Ethernet Control Word
next_proto = MPLS_NEXT_PROTO_ETHER;
break;
// the first four digits of the PW Ethernet control word must be "00000", but the first four digits of Ethernet may also be "0000"
if (layer->pld_len >= sizeof(struct ethhdr) && is_eth_proto(eth_hdr_get_proto((const struct ethhdr *)layer->pld_ptr)))
{
return parse_ether(pkt, layer->pld_ptr, layer->pld_len);
}
else
{
return parse_pweth(pkt, layer->pld_ptr, layer->pld_len);
}
case 4:
next_proto = MPLS_NEXT_PROTO_IPV4;
break;
return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len);
case 6:
next_proto = MPLS_NEXT_PROTO_IPV6;
break;
return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len);
default:
next_proto = MPLS_NEXT_PROTO_ETHER;
break;
return parse_ether(pkt, layer->pld_ptr, layer->pld_len);
}
}
else
{
next_proto = MPLS_NEXT_PROTO_MPLS;
}
if (unlikely(hdr_len > len))
{
PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_MPLS);
return data;
}
SET_LAYER(pkt, layer, LAYER_TYPE_MPLS, hdr_len, data, len, 0);
switch (next_proto)
{
// TESTED
case MPLS_NEXT_PROTO_IPV4:
return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len);
case MPLS_NEXT_PROTO_IPV6:
return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len);
// TESTED
case MPLS_NEXT_PROTO_ETHER:
return parse_ether(pkt, layer->pld_ptr, layer->pld_len);
// TESTED
case MPLS_NEXT_PROTO_MPLS:
SET_LAYER(pkt, layer, LAYER_TYPE_MPLS, 4, data, len, 0);
return parse_mpls(pkt, layer->pld_ptr, layer->pld_len);
default:
// unreachable
return layer->pld_ptr;
}
}
@@ -1076,7 +935,7 @@ static inline const char *parse_ipv4(struct packet *pkt, const char *data, uint1
{
return data;
}
struct ip *hdr = (struct ip *)data;
const struct ip *hdr = (const struct ip *)data;
uint16_t hdr_len = ipv4_hdr_get_hdr_len(hdr);
if (unlikely(hdr_len > len))
{
@@ -1101,7 +960,6 @@ static inline const char *parse_ipv4(struct packet *pkt, const char *data, uint1
// try continue parse
}
// TESTED
uint8_t next_proto = ipv4_hdr_get_proto(hdr);
return parse_l4(pkt, next_proto, layer->pld_ptr, layer->pld_len);
}
@@ -1138,13 +996,14 @@ static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint1
{
return data;
}
uint16_t pld_len = ipv6_hdr_get_payload_len((const struct ip6_hdr *)data);
const struct ip6_hdr *hdr = (const struct ip6_hdr *)data;
uint16_t pld_len = ipv6_hdr_get_payload_len(hdr);
if (unlikely(pld_len + sizeof(struct ip6_hdr) > len))
{
PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_IPV6);
return data;
}
uint8_t next_proto = ipv6_hdr_get_next_header((const struct ip6_hdr *)data);
uint8_t next_proto = ipv6_hdr_get_next_header(hdr);
uint16_t hdr_len = sizeof(struct ip6_hdr);
uint16_t trim_len = len - pld_len - sizeof(struct ip6_hdr);
const char *next_hdr_ptr = data + hdr_len;
@@ -1177,7 +1036,6 @@ static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint1
// try continue parse
}
// TESTED
return parse_l4(pkt, next_proto, layer->pld_ptr, layer->pld_len);
}
@@ -1209,7 +1067,6 @@ static inline const char *parse_gre(struct packet *pkt, const char *data, uint16
return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len);
case GRE_PRO_IPV6:
return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len);
// TESTED
case GRE_PRO_PPP:
return parse_ppp(pkt, layer->pld_ptr, layer->pld_len);
default:
@@ -1231,19 +1088,17 @@ static inline const char *parse_udp(struct packet *pkt, const char *data, uint16
{
return data;
}
struct udphdr *hdr = (struct udphdr *)data;
const struct udphdr *hdr = (struct udphdr *)data;
SET_LAYER(pkt, layer, LAYER_TYPE_UDP, sizeof(struct udphdr), data, len, 0);
if (udp_hdr_get_dst_port(hdr) == 4789)
{
// TESTED
// VXLAN_DPORT 4789
return parse_vxlan(pkt, layer->pld_ptr, layer->pld_len);
}
if (udp_hdr_get_dst_port(hdr) == 2152 || udp_hdr_get_src_port(hdr) == 2152)
{
// TESTED
// GTP1U_PORT 2152
return parse_gtpv1_u(pkt, layer->pld_ptr, layer->pld_len);
}
@@ -1260,7 +1115,6 @@ static inline const char *parse_udp(struct packet *pkt, const char *data, uint16
switch (L2TP_VERSION(control))
{
case 2:
// TESTED
return parse_l2tpv2(pkt, layer->pld_ptr, layer->pld_len);
case 3:
return parse_l2tpv3_over_udp(pkt, layer->pld_ptr, layer->pld_len);
@@ -1285,7 +1139,7 @@ static inline const char *parse_tcp(struct packet *pkt, const char *data, uint16
{
return data;
}
uint16_t hdr_len = tcp_hdr_get_hdr_len((struct tcphdr *)data);
uint16_t hdr_len = tcp_hdr_get_hdr_len((const struct tcphdr *)data);
if (unlikely(hdr_len > len))
{
PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_TCP);
@@ -1355,7 +1209,6 @@ static inline const char *parse_vxlan(struct packet *pkt, const char *data, uint
}
SET_LAYER(pkt, layer, LAYER_TYPE_VXLAN, sizeof(struct vxlan_hdr), data, len, 0);
// TESTED
return parse_ether(pkt, layer->pld_ptr, layer->pld_len);
}
@@ -1378,10 +1231,8 @@ static inline const char *parse_gtpv1_u(struct packet *pkt, const char *data, ui
switch (next_proto)
{
// TESTED
case 4:
return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len);
// TESTED
case 6:
return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len);
default:
@@ -1394,24 +1245,18 @@ static inline const char *parse_l3(struct packet *pkt, uint16_t next_proto, cons
{
switch (next_proto)
{
// TESTED
case ETH_P_8021Q:
case ETH_P_8021AD:
return parse_vlan(pkt, data, len);
// TESTED
case ETH_P_IP:
return parse_ipv4(pkt, data, len);
// TESTED
case ETH_P_IPV6:
return parse_ipv6(pkt, data, len);
// TESTED
case ETH_P_PPP_SES:
return parse_pppoe_ses(pkt, data, len);
// TESTED
case ETH_P_MPLS_UC:
return parse_mpls(pkt, data, len);
default:
// TESTED ARP
PACKET_LOG_UNSUPPORT_ETHPROTO("l3", next_proto);
return data;
}
@@ -1421,25 +1266,18 @@ static inline const char *parse_l4(struct packet *pkt, uint8_t next_proto, const
{
switch (next_proto)
{
// TESTED
case IPPROTO_TCP:
return parse_tcp(pkt, data, len);
// TESTED
case IPPROTO_UDP:
return parse_udp(pkt, data, len);
// TESTED
case IPPROTO_IPIP:
return parse_ipv4(pkt, data, len);
// TESTED
case IPPROTO_IPV6:
return parse_ipv6(pkt, data, len);
// TESTED
case IPPROTO_GRE:
return parse_gre(pkt, data, len);
// TESTED
case IPPROTO_ICMP:
return parse_icmp(pkt, data, len);
// TESTED
case IPPROTO_ICMPV6:
return parse_icmp6(pkt, data, len);
case 115:
@@ -1465,7 +1303,6 @@ const char *packet_parse(struct packet *pkt, const char *data, uint16_t len)
pkt->data_len = len;
pkt->trim_len = 0;
// TESTED
return parse_ether(pkt, data, len);
}
@@ -1490,6 +1327,9 @@ void packet_print_str(const struct packet *pkt)
switch (layer->type)
{
case LAYER_TYPE_ETHER:
used = eth_hdr_to_str((const struct ethhdr *)layer->hdr_ptr, buffer, sizeof(buffer));
break;
case LAYER_TYPE_PWETH:
break;
case LAYER_TYPE_PPP:
break;
@@ -1502,6 +1342,8 @@ void packet_print_str(const struct packet *pkt)
case LAYER_TYPE_PPPOE:
break;
case LAYER_TYPE_MPLS:
used = mpls_hdr_to_str((const struct mpls_hdr *)layer->hdr_ptr, buffer, sizeof(buffer));
break;
break;
case LAYER_TYPE_IPV4:
used = ipv4_hdr_to_str((const struct ip *)layer->hdr_ptr, buffer, sizeof(buffer));