2023-12-15 18:57:13 +08:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
2024-04-22 16:38:24 +08:00
|
|
|
#include <netinet/icmp6.h>
|
|
|
|
|
#include <netinet/ip_icmp.h>
|
2023-12-15 18:57:13 +08:00
|
|
|
#include <linux/ppp_defs.h>
|
|
|
|
|
|
2024-06-24 17:07:05 +08:00
|
|
|
#include "log.h"
|
2024-08-16 16:12:12 +08:00
|
|
|
#include "packet_helper.h"
|
2024-08-16 15:13:37 +08:00
|
|
|
#include "packet_private.h"
|
2024-08-16 11:49:54 +08:00
|
|
|
#include "packet_parser.h"
|
2023-12-15 18:57:13 +08:00
|
|
|
|
|
|
|
|
#define likely(expr) __builtin_expect((expr), 1)
|
|
|
|
|
#define unlikely(expr) __builtin_expect((expr), 0)
|
|
|
|
|
|
2024-06-24 17:07:05 +08:00
|
|
|
#define PACKET_PARSE_LOG_DEBUG(format, ...) void(0) // LOG_DEBUG("packet parse", format, ##__VA_ARGS__)
|
|
|
|
|
#define PACKET_PARSE_LOG_WARN(format, ...) LOG_WARN("packet parse", format, ##__VA_ARGS__)
|
|
|
|
|
#define PACKET_PARSE_LOG_ERROR(format, ...) LOG_ERROR("packet parse", format, ##__VA_ARGS__)
|
|
|
|
|
|
|
|
|
|
#define PACKET_LOG_DATA_INSUFFICIENCY(pkt, layer) \
|
|
|
|
|
{ \
|
|
|
|
|
PACKET_PARSE_LOG_WARN("pkt: %p, layer: %s, data insufficiency", \
|
|
|
|
|
(pkt), layer_proto_to_str(layer)); \
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-06-24 17:07:05 +08:00
|
|
|
#define PACKET_LOG_UNSUPPORT_PROTO(pkt, layer, next_proto) \
|
|
|
|
|
{ \
|
2024-07-09 11:17:03 +08:00
|
|
|
PACKET_PARSE_LOG_WARN("pkt: %p, layer: %s, unsupport next proto: %d", \
|
2024-06-24 17:07:05 +08:00
|
|
|
(pkt), layer_proto_to_str(layer), (next_proto)); \
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-07-09 11:17:03 +08:00
|
|
|
#define PACKET_LOG_UNSUPPORT_ETHPROTO(pkt, next_proto) \
|
|
|
|
|
{ \
|
|
|
|
|
PACKET_PARSE_LOG_WARN("pkt: %p, layer: L3, unsupport next proto: %d %s", \
|
|
|
|
|
(pkt), (next_proto), eth_proto_to_str(next_proto)); \
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-07-09 11:17:03 +08:00
|
|
|
#define PACKET_LOG_UNSUPPORT_IPPROTO(pkt, next_proto) \
|
|
|
|
|
{ \
|
|
|
|
|
PACKET_PARSE_LOG_WARN("pkt: %p, layer: L4, unsupport next proto: %d %s", \
|
|
|
|
|
(pkt), (next_proto), ip_proto_to_str(next_proto)); \
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
* Static API
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
static inline struct raw_layer *get_free_layer(struct packet *pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
|
|
|
|
// 数据链路层
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_ether(struct packet *pkt, const char *data, uint16_t len);
|
2024-06-02 00:07:33 +08:00
|
|
|
static inline const char *parse_pweth(struct packet *pkt, const char *data, uint16_t len);
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_ppp(struct packet *pkt, const char *data, uint16_t len);
|
2024-06-07 14:47:38 +08:00
|
|
|
static inline const char *parse_l2tpv2_over_udp(struct packet *pkt, const char *data, uint16_t len);
|
2024-05-24 16:14:20 +08:00
|
|
|
static inline const char *parse_l2tpv3_over_udp(struct packet *pkt, const char *data, uint16_t len);
|
|
|
|
|
static inline const char *parse_l2tpv3_over_ip(struct packet *pkt, const char *data, uint16_t len);
|
|
|
|
|
|
2023-12-15 18:57:13 +08:00
|
|
|
// 数据链路层 -- 隧道
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_vlan(struct packet *pkt, const char *data, uint16_t len);
|
|
|
|
|
static inline const char *parse_pppoe_ses(struct packet *pkt, const char *data, uint16_t len);
|
|
|
|
|
static inline const char *parse_mpls(struct packet *pkt, const char *data, uint16_t len);
|
2023-12-15 18:57:13 +08:00
|
|
|
// 网络层
|
2024-03-09 19:28:14 +08:00
|
|
|
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);
|
2024-06-04 15:48:34 +08:00
|
|
|
static inline const char *parse_auth(struct packet *pkt, const char *data, uint16_t len);
|
2023-12-15 18:57:13 +08:00
|
|
|
// 网络层 -- 隧道
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_gre(struct packet *pkt, const char *data, uint16_t len);
|
2023-12-15 18:57:13 +08:00
|
|
|
// 传输层
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_udp(struct packet *pkt, const char *data, uint16_t len);
|
|
|
|
|
static inline const char *parse_tcp(struct packet *pkt, const char *data, uint16_t len);
|
2024-04-22 16:38:24 +08:00
|
|
|
static inline const char *parse_icmp(struct packet *pkt, const char *data, uint16_t len);
|
|
|
|
|
static inline const char *parse_icmp6(struct packet *pkt, const char *data, uint16_t len);
|
2023-12-15 18:57:13 +08:00
|
|
|
// 传输层 -- 隧道
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_vxlan(struct packet *pkt, const char *data, uint16_t len);
|
2024-07-09 11:17:03 +08:00
|
|
|
static inline const char *parse_gtp_u(struct packet *pkt, const char *data, uint16_t len);
|
|
|
|
|
static inline const char *parse_gtp_c(struct packet *pkt, const char *data, uint16_t len);
|
2023-12-15 18:57:13 +08:00
|
|
|
// L3/L4
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_l3(struct packet *pkt, uint16_t next_proto, const char *data, uint16_t len);
|
|
|
|
|
static inline const char *parse_l4(struct packet *pkt, uint8_t next_proto, const char *data, uint16_t len);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
* Private API -- Utils
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
static inline struct raw_layer *get_free_layer(struct packet *pkt)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-03-09 19:28:14 +08:00
|
|
|
if (pkt->layers_used >= pkt->layers_size)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
return &pkt->layers[pkt->layers_used];
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-06-24 17:07:05 +08:00
|
|
|
#define SET_LAYER(_pkt, _layer, _proto, _hdr_len, _data, _len, _trim) \
|
|
|
|
|
{ \
|
|
|
|
|
(_layer)->proto = (_proto); \
|
|
|
|
|
(_layer)->hdr_offset = (_pkt)->data_len - (_pkt)->trim_len - (_len); \
|
|
|
|
|
(_layer)->hdr_ptr = (_data); \
|
|
|
|
|
(_layer)->hdr_len = (_hdr_len); \
|
|
|
|
|
(_layer)->pld_ptr = (_data) + (_hdr_len); \
|
|
|
|
|
(_layer)->pld_len = (_len) - (_hdr_len) - (_trim); \
|
|
|
|
|
(_pkt)->trim_len += (_trim); \
|
|
|
|
|
(_pkt)->layers_used++; \
|
2024-07-15 15:07:38 +08:00
|
|
|
PACKET_PARSE_LOG_DEBUG("layer[%d/%d]: %s, header: {offset: %d, ptr: %p, len: %d}, payload: {ptr: %p, len: %d}", \
|
2024-06-24 17:07:05 +08:00
|
|
|
(_pkt)->layers_used - 1, (_pkt)->layers_size, layer_proto_to_str((_proto)), \
|
|
|
|
|
(_layer)->hdr_offset, (_layer)->hdr_ptr, (_layer)->hdr_len, (_layer)->pld_ptr, (_layer)->pld_len); \
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
* Private API -- Parses
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_ether(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
if (unlikely(len < sizeof(struct ethhdr)))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_ETHER);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-02 00:07:33 +08:00
|
|
|
uint16_t next_proto = eth_hdr_get_proto((const struct ethhdr *)data);
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_ETHER, sizeof(struct ethhdr), data, len, 0);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_l3(pkt, next_proto, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-06-02 00:07:33 +08:00
|
|
|
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))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_PWETH);
|
2024-06-02 00:07:33 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2024-06-02 00:07:33 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_PWETH, 4, data, len, 0);
|
2024-06-02 00:07:33 +08:00
|
|
|
|
|
|
|
|
return parse_ether(pkt, layer->pld_ptr, layer->pld_len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int is_ppp_proto(uint16_t proto)
|
2024-05-31 14:35:58 +08:00
|
|
|
{
|
|
|
|
|
// /usr/include/linux/ppp_defs.h.html
|
2024-06-02 00:07:33 +08:00
|
|
|
switch (proto)
|
2024-05-31 14:35:58 +08:00
|
|
|
{
|
|
|
|
|
case PPP_IP: /* Internet Protocol */
|
|
|
|
|
case PPP_AT: /* AppleTalk Protocol */
|
|
|
|
|
case PPP_IPX: /* IPX protocol */
|
|
|
|
|
case PPP_VJC_COMP: /* VJ compressed TCP */
|
|
|
|
|
case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */
|
|
|
|
|
case PPP_MP: /* Multilink protocol */
|
|
|
|
|
case PPP_IPV6: /* Internet Protocol Version 6 */
|
|
|
|
|
case PPP_COMPFRAG: /* fragment compressed below bundle */
|
|
|
|
|
case PPP_COMP: /* compressed packet */
|
|
|
|
|
case PPP_MPLS_UC: /* Multi Protocol Label Switching - Unicast */
|
|
|
|
|
case PPP_MPLS_MC: /* Multi Protocol Label Switching - Multicast */
|
|
|
|
|
case PPP_IPCP: /* IP Control Protocol */
|
|
|
|
|
case PPP_ATCP: /* AppleTalk Control Protocol */
|
|
|
|
|
case PPP_IPXCP: /* IPX Control Protocol */
|
|
|
|
|
case PPP_IPV6CP: /* IPv6 Control Protocol */
|
|
|
|
|
case PPP_CCPFRAG: /* CCP at link level (below MP bundle) */
|
|
|
|
|
// case PPP_CCP: /* Compression Control Protocol */ (same as PPP_CCPFRAG)
|
|
|
|
|
case PPP_MPLSCP: /* MPLS Control Protocol */
|
|
|
|
|
case PPP_LCP: /* Link Control Protocol */
|
|
|
|
|
case PPP_PAP: /* Password Authentication Protocol */
|
|
|
|
|
case PPP_LQR: /* Link Quality Report protocol */
|
|
|
|
|
case PPP_CHAP: /* Cryptographic Handshake Auth. Protocol */
|
|
|
|
|
case PPP_CBCP: /* Callback Control Protocol */
|
|
|
|
|
return 1;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_ppp(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-05-31 14:35:58 +08:00
|
|
|
/*
|
|
|
|
|
* https://datatracker.ietf.org/doc/html/rfc1661#section-2
|
|
|
|
|
* +----------+-------------+---------+
|
|
|
|
|
* | Protocol | Information | Padding |
|
|
|
|
|
* | 8/16 bits| * | * |
|
|
|
|
|
* +----------+-------------+---------+
|
|
|
|
|
*
|
|
|
|
|
* https://datatracker.ietf.org/doc/html/rfc1331#section-3.1
|
|
|
|
|
* +----------+----------+----------+----------+------------
|
|
|
|
|
* | Flag | Address | Control | Protocol | Information
|
|
|
|
|
* | 01111110 | 11111111 | 00000011 | 16 bits | *
|
|
|
|
|
* +----------+----------+----------+----------+------------
|
|
|
|
|
* ---+----------+----------+-----------------
|
|
|
|
|
* | FCS | Flag | Inter-frame Fill
|
|
|
|
|
* | 16 bits | 01111110 | or next Address
|
|
|
|
|
* ---+----------+----------+-----------------
|
|
|
|
|
*/
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(len < 4))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_PPP);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-31 14:35:58 +08:00
|
|
|
uint16_t hdr_len = 0;
|
|
|
|
|
uint16_t next_proto = 0;
|
|
|
|
|
|
|
|
|
|
// ppp header 1 byte
|
|
|
|
|
next_proto = *((uint8_t *)data);
|
2024-06-02 00:07:33 +08:00
|
|
|
if (is_ppp_proto(next_proto))
|
2024-05-31 14:35:58 +08:00
|
|
|
{
|
|
|
|
|
hdr_len = 1;
|
|
|
|
|
goto success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ppp header 2 bytes
|
|
|
|
|
next_proto = ntohs(*((uint16_t *)data));
|
2024-06-02 00:07:33 +08:00
|
|
|
if (is_ppp_proto(next_proto))
|
2024-05-31 14:35:58 +08:00
|
|
|
{
|
|
|
|
|
hdr_len = 2;
|
|
|
|
|
goto success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ppp header 4 bytes
|
|
|
|
|
next_proto = ntohs(*((uint16_t *)data + 1));
|
|
|
|
|
hdr_len = 4;
|
|
|
|
|
|
|
|
|
|
success:
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_PPP, hdr_len, data, len, 0);
|
2023-12-15 18:57:13 +08:00
|
|
|
switch (next_proto)
|
|
|
|
|
{
|
|
|
|
|
case PPP_IP:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case PPP_IPV6:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
default:
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_UNSUPPORT_PROTO(pkt, LAYER_PROTO_PPP, next_proto);
|
2023-12-15 18:57:13 +08:00
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-07 14:47:38 +08:00
|
|
|
static inline const char *parse_l2tpv2_over_udp(struct packet *pkt, const char *data, uint16_t len)
|
2024-05-24 16:14:20 +08:00
|
|
|
{
|
2024-06-07 14:47:38 +08:00
|
|
|
uint16_t hdr_len = calc_udp_l2tpv2_hdr_len(data, len);
|
2024-05-24 16:14:20 +08:00
|
|
|
if (unlikely(hdr_len == 0 || hdr_len > len))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_L2TP);
|
2024-05-24 16:14:20 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2024-05-24 16:14:20 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_L2TP, hdr_len, data, len, 0);
|
2024-05-24 16:14:20 +08:00
|
|
|
|
2024-06-07 14:47:38 +08:00
|
|
|
// control message
|
|
|
|
|
if (l2tp_hdr_get_type((const struct l2tp_hdr *)data))
|
2024-05-24 16:14:20 +08:00
|
|
|
{
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
2024-06-07 14:47:38 +08:00
|
|
|
// data message
|
2024-05-24 16:14:20 +08:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return parse_ppp(pkt, layer->pld_ptr, layer->pld_len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline const char *parse_l2tpv3_over_udp(struct packet *pkt, const char *data, uint16_t len)
|
|
|
|
|
{
|
2024-06-07 14:47:38 +08:00
|
|
|
uint16_t hdr_len = calc_udp_l2tpv3_hdr_len(data, len);
|
|
|
|
|
if (unlikely(hdr_len == 0 || hdr_len > len))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_L2TP);
|
2024-06-07 14:47:38 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2024-06-07 14:47:38 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_L2TP, hdr_len, data, len, 0);
|
2024-06-07 14:47:38 +08:00
|
|
|
|
|
|
|
|
// control message
|
|
|
|
|
if (l2tp_hdr_get_type((const struct l2tp_hdr *)data))
|
|
|
|
|
{
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
// data message
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// TOOD
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
2024-05-24 16:14:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline const char *parse_l2tpv3_over_ip(struct packet *pkt, const char *data, uint16_t len)
|
|
|
|
|
{
|
2024-06-07 14:47:38 +08:00
|
|
|
uint16_t hdr_len = calc_ip_l2tpv3_hdr_len(data, len);
|
|
|
|
|
if (unlikely(hdr_len == 0 || hdr_len > len))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_L2TP);
|
2024-06-07 14:47:38 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2024-06-07 14:47:38 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_L2TP, hdr_len, data, len, 0);
|
2024-06-07 14:47:38 +08:00
|
|
|
|
|
|
|
|
// data message
|
|
|
|
|
if (ntohl(*((uint32_t *)data)))
|
|
|
|
|
{
|
|
|
|
|
// TOOD
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
// control message
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
2024-05-24 16:14:20 +08:00
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_vlan(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
if (unlikely(len < sizeof(struct vlan_hdr)))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_VLAN);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-05 11:41:46 +08:00
|
|
|
uint16_t next_proto = vlan_hdr_get_ethertype((const struct vlan_hdr *)data);
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_VLAN, sizeof(struct vlan_hdr), data, len, 0);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_l3(pkt, next_proto, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_pppoe_ses(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-05-31 14:35:58 +08:00
|
|
|
if (unlikely(len < 6))
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_PPPOE);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_PPPOE, 6, data, len, 0);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
2024-05-31 14:35:58 +08:00
|
|
|
return parse_ppp(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_mpls(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-06-02 00:07:33 +08:00
|
|
|
if (unlikely(len < 4))
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_MPLS);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 10:39:57 +08:00
|
|
|
if (mpls_label_get_bos((const struct mpls_label *)data))
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_MPLS, 4, data, len, 0);
|
2024-06-02 00:07:33 +08:00
|
|
|
if (layer->pld_len == 0)
|
|
|
|
|
{
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
uint8_t next_proto = layer->pld_ptr[0] >> 4;
|
|
|
|
|
switch (next_proto)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
case 0:
|
2024-06-02 00:07:33 +08:00
|
|
|
// 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);
|
|
|
|
|
}
|
2023-12-15 18:57:13 +08:00
|
|
|
case 4:
|
2024-06-02 00:07:33 +08:00
|
|
|
return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case 6:
|
2024-06-02 00:07:33 +08:00
|
|
|
return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
default:
|
2024-06-02 00:07:33 +08:00
|
|
|
return parse_ether(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_MPLS, 4, data, len, 0);
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_mpls(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_ipv4(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
if (unlikely(len < sizeof(struct ip)))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_IPV4);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-07-12 14:14:45 +08:00
|
|
|
|
2024-06-02 00:07:33 +08:00
|
|
|
const struct ip *hdr = (const struct ip *)data;
|
2024-07-12 14:14:45 +08:00
|
|
|
uint8_t version = ip4_hdr_get_version(hdr);
|
|
|
|
|
if (unlikely(version != 4))
|
|
|
|
|
{
|
|
|
|
|
PACKET_PARSE_LOG_ERROR("packet %p ipv4 version %d != 4", pkt, version);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-09 11:17:03 +08:00
|
|
|
uint16_t hdr_len = ip4_hdr_get_hdr_len(hdr);
|
2024-03-27 17:11:38 +08:00
|
|
|
if (unlikely(hdr_len > len))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_IPV4);
|
2024-03-27 17:11:38 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
2024-05-24 19:10:33 +08:00
|
|
|
|
2024-07-09 11:17:03 +08:00
|
|
|
uint16_t total_len = ip4_hdr_get_total_len(hdr);
|
2024-05-24 19:10:33 +08:00
|
|
|
if (unlikely(total_len > len))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_IPV4);
|
2024-06-03 17:50:52 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
if (unlikely(total_len < hdr_len))
|
|
|
|
|
{
|
2024-06-24 17:07:05 +08:00
|
|
|
PACKET_PARSE_LOG_ERROR("packet %p ip total_len %d < hdr_len %d", pkt, total_len, hdr_len);
|
2024-05-24 19:10:33 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
uint16_t trim_len = len - total_len;
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_IPV4, hdr_len, data, len, trim_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
2023-12-18 16:51:17 +08:00
|
|
|
// ip fragmented
|
2024-07-09 11:17:03 +08:00
|
|
|
if (ip4_hdr_get_mf_flag(hdr) || ip4_hdr_get_frag_offset(hdr))
|
2023-12-18 16:51:17 +08:00
|
|
|
{
|
2024-06-24 17:07:05 +08:00
|
|
|
PACKET_PARSE_LOG_WARN("packet %p ip layer %p is fragmented", pkt, layer);
|
2024-03-09 19:28:14 +08:00
|
|
|
pkt->frag_layer = layer;
|
2024-06-03 17:50:52 +08:00
|
|
|
return layer->pld_ptr;
|
2023-12-18 16:51:17 +08:00
|
|
|
}
|
|
|
|
|
|
2024-07-09 11:17:03 +08:00
|
|
|
uint8_t next_proto = ip4_hdr_get_proto(hdr);
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_l4(pkt, next_proto, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-05-30 13:49:31 +08:00
|
|
|
/*
|
|
|
|
|
* IP6 Extension Headers
|
|
|
|
|
*
|
|
|
|
|
* Internet Protocol, Version 6 (IPv6) : https://datatracker.ietf.org/doc/html/rfc2460
|
|
|
|
|
* IP Encapsulating Security Payload (ESP) : https://datatracker.ietf.org/doc/html/rfc2406
|
|
|
|
|
* IP Authentication Header : https://datatracker.ietf.org/doc/html/rfc4302
|
|
|
|
|
*
|
|
|
|
|
* skip next header
|
|
|
|
|
* #define IPPROTO_HOPOPTS 0 // IP6 hop-by-hop options
|
|
|
|
|
* #define IPPROTO_ROUTING 43 // IP6 routing header
|
|
|
|
|
* #define IPPROTO_AH 51 // IP6 Auth Header
|
|
|
|
|
* #define IPPROTO_DSTOPTS 60 // IP6 destination option
|
|
|
|
|
*
|
|
|
|
|
* not skip next header
|
|
|
|
|
* #define IPPROTO_FRAGMENT 44 // IP6 fragmentation header
|
|
|
|
|
* #define IPPROTO_ESP 50 // IP6 Encap Sec. Payload
|
|
|
|
|
* #define IPPROTO_NONE 59 // IP6 no next header
|
|
|
|
|
*/
|
|
|
|
|
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(len < sizeof(struct ip6_hdr)))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_IPV6);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-02 00:07:33 +08:00
|
|
|
const struct ip6_hdr *hdr = (const struct ip6_hdr *)data;
|
2024-07-12 14:14:45 +08:00
|
|
|
uint8_t version = ip6_hdr_get_version(hdr);
|
|
|
|
|
if (unlikely(version != 6))
|
|
|
|
|
{
|
|
|
|
|
PACKET_PARSE_LOG_ERROR("packet %p ipv6 version %d != 6", pkt, version);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-09 11:17:03 +08:00
|
|
|
uint16_t pld_len = ip6_hdr_get_payload_len(hdr);
|
2024-05-24 19:10:33 +08:00
|
|
|
if (unlikely(pld_len + sizeof(struct ip6_hdr) > len))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_IPV6);
|
2024-05-24 19:10:33 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
2024-07-09 11:17:03 +08:00
|
|
|
uint8_t next_proto = ip6_hdr_get_next_header(hdr);
|
2024-05-30 13:49:31 +08:00
|
|
|
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;
|
|
|
|
|
while (next_proto == IPPROTO_HOPOPTS || next_proto == IPPROTO_ROUTING || next_proto == IPPROTO_AH || next_proto == IPPROTO_DSTOPTS)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(pld_len < 2))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_IPV6);
|
2024-05-30 13:49:31 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
struct ip6_ext *ext = (struct ip6_ext *)next_hdr_ptr;
|
2024-06-04 15:48:34 +08:00
|
|
|
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;
|
|
|
|
|
}
|
2024-05-30 13:49:31 +08:00
|
|
|
if (unlikely(skip_len > pld_len))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_IPV6);
|
2024-05-30 13:49:31 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
hdr_len += skip_len;
|
|
|
|
|
pld_len -= skip_len;
|
|
|
|
|
next_hdr_ptr += skip_len;
|
|
|
|
|
next_proto = ext->ip6e_nxt;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_IPV6, hdr_len, data, len, trim_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
2024-02-22 18:52:04 +08:00
|
|
|
// ipv6 fragment
|
|
|
|
|
if (next_proto == IPPROTO_FRAGMENT)
|
|
|
|
|
{
|
2024-06-24 17:07:05 +08:00
|
|
|
PACKET_PARSE_LOG_WARN("packet %p ipv6 layer %p is fragmented", pkt, layer);
|
2024-03-09 19:28:14 +08:00
|
|
|
pkt->frag_layer = layer;
|
2024-06-03 17:50:52 +08:00
|
|
|
return layer->pld_ptr;
|
2024-02-22 18:52:04 +08:00
|
|
|
}
|
2024-02-21 11:14:21 +08:00
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_l4(pkt, next_proto, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-06-04 15:48:34 +08:00
|
|
|
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))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_IPAH);
|
2024-06-04 15:48:34 +08:00
|
|
|
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))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_IPAH);
|
2024-06-04 15:48:34 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2024-06-04 15:48:34 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_IPAH, hdr_len, data, len, 0);
|
2024-06-04 15:48:34 +08:00
|
|
|
|
|
|
|
|
return parse_l4(pkt, next_proto, layer->pld_ptr, layer->pld_len);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_gre(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-06-05 16:44:32 +08:00
|
|
|
uint16_t hdr_len = calc_gre_hdr_len(data, len);
|
2024-03-27 17:11:38 +08:00
|
|
|
if (unlikely(hdr_len == 0 || hdr_len > len))
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_GRE);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-07-11 14:19:38 +08:00
|
|
|
uint16_t next_proto = peek_gre_proto(data, len);
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_GRE, hdr_len, data, len, 0);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
2024-06-05 16:44:32 +08:00
|
|
|
return parse_l3(pkt, next_proto, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_udp(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
if (unlikely(len < sizeof(struct udphdr)))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_UDP);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-08-07 13:07:00 +08:00
|
|
|
const struct udphdr *udp_hdr = (struct udphdr *)data;
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_UDP, sizeof(struct udphdr), data, len, 0);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
2024-08-07 13:07:00 +08:00
|
|
|
uint16_t src_port = udp_hdr_get_src_port(udp_hdr);
|
|
|
|
|
uint16_t dst_port = udp_hdr_get_dst_port(udp_hdr);
|
2024-06-04 18:08:45 +08:00
|
|
|
|
|
|
|
|
if (dst_port == 4789)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-03-21 10:06:11 +08:00
|
|
|
// VXLAN_DPORT 4789
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_vxlan(pkt, layer->pld_ptr, layer->pld_len);
|
2024-03-21 10:06:11 +08:00
|
|
|
}
|
|
|
|
|
|
2024-06-04 18:08:45 +08:00
|
|
|
if (dst_port == 2152 || src_port == 2152)
|
2024-03-21 10:06:11 +08:00
|
|
|
{
|
2024-07-09 11:17:03 +08:00
|
|
|
// only GTPv1-U, no GTPv2-U
|
|
|
|
|
return parse_gtp_u(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
2024-03-21 10:06:11 +08:00
|
|
|
|
2024-06-04 18:08:45 +08:00
|
|
|
if (dst_port == 2123 || src_port == 2123)
|
2024-06-04 15:48:34 +08:00
|
|
|
{
|
2024-07-09 11:17:03 +08:00
|
|
|
// GTPv1-C or GTPv2-C
|
|
|
|
|
return parse_gtp_c(pkt, layer->pld_ptr, layer->pld_len);
|
2024-06-04 15:48:34 +08:00
|
|
|
}
|
|
|
|
|
|
2024-06-04 18:08:45 +08:00
|
|
|
if (dst_port == 1701 || src_port == 1701)
|
2024-05-24 16:14:20 +08:00
|
|
|
{
|
|
|
|
|
// L2TP_DPORT 1701
|
|
|
|
|
if (unlikely(layer->pld_len < 8))
|
|
|
|
|
{
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-07 14:47:38 +08:00
|
|
|
switch (l2tp_hdr_get_ver((const struct l2tp_hdr *)layer->pld_ptr))
|
2024-05-24 16:14:20 +08:00
|
|
|
{
|
|
|
|
|
case 2:
|
2024-06-07 14:47:38 +08:00
|
|
|
return parse_l2tpv2_over_udp(pkt, layer->pld_ptr, layer->pld_len);
|
2024-05-24 16:14:20 +08:00
|
|
|
case 3:
|
|
|
|
|
return parse_l2tpv3_over_udp(pkt, layer->pld_ptr, layer->pld_len);
|
|
|
|
|
default:
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-04 18:08:45 +08:00
|
|
|
if (dst_port == 3544 || src_port == 3544)
|
|
|
|
|
{
|
|
|
|
|
// Teredo IPv6 tunneling 3544
|
|
|
|
|
if (unlikely(layer->pld_len < sizeof(struct ip6_hdr)))
|
|
|
|
|
{
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
2024-08-07 13:07:00 +08:00
|
|
|
const struct ip6_hdr *ipv6_hdr = (const struct ip6_hdr *)layer->pld_ptr;
|
|
|
|
|
if (ip6_hdr_get_version(ipv6_hdr) != 6)
|
2024-06-04 18:08:45 +08:00
|
|
|
{
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-21 10:06:11 +08:00
|
|
|
return layer->pld_ptr;
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_tcp(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
if (unlikely(len < sizeof(struct tcphdr)))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_TCP);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-02 00:07:33 +08:00
|
|
|
uint16_t hdr_len = tcp_hdr_get_hdr_len((const struct tcphdr *)data);
|
2024-03-27 17:11:38 +08:00
|
|
|
if (unlikely(hdr_len > len))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_TCP);
|
2024-03-27 17:11:38 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_TCP, hdr_len, data, len, 0);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-22 16:38:24 +08:00
|
|
|
static inline const char *parse_icmp(struct packet *pkt, const char *data, uint16_t len)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(len < sizeof(struct icmphdr)))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_ICMP);
|
2024-04-22 16:38:24 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2024-04-22 16:38:24 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_ICMP, sizeof(struct icmphdr), data, len, 0);
|
2024-04-22 16:38:24 +08:00
|
|
|
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline const char *parse_icmp6(struct packet *pkt, const char *data, uint16_t len)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(len < sizeof(struct icmp6_hdr)))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_ICMP6);
|
2024-04-22 16:38:24 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2024-04-22 16:38:24 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_ICMP6, sizeof(struct icmp6_hdr), data, len, 0);
|
2024-04-22 16:38:24 +08:00
|
|
|
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_vxlan(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
if (unlikely(len < sizeof(struct vxlan_hdr)))
|
|
|
|
|
{
|
2024-06-12 18:21:45 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_VXLAN);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-06-12 18:21:45 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_VXLAN, sizeof(struct vxlan_hdr), data, len, 0);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ether(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-07-09 11:17:03 +08:00
|
|
|
static inline const char *parse_gtp_u(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-07-09 11:17:03 +08:00
|
|
|
// only GTPv1-U, no GTPv2-U
|
|
|
|
|
uint8_t version = peek_gtp_version(data, len);
|
|
|
|
|
if (unlikely(version != 1))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-11 14:19:38 +08:00
|
|
|
uint16_t hdr_len = calc_gtp_hdr_len(data, len);
|
2024-03-27 17:11:38 +08:00
|
|
|
if (unlikely(hdr_len == 0 || hdr_len > len))
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-07-09 11:17:03 +08:00
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_GTP_U);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-14 17:24:26 +08:00
|
|
|
uint8_t next_proto = (((const uint8_t *)(data + hdr_len))[0]) >> 4;
|
|
|
|
|
if (next_proto != 4 && next_proto != 6)
|
|
|
|
|
{
|
|
|
|
|
// next_proto is not IPv4 or IPv6, this is not a normal GTP-U packet, fallback to UDP
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 10:48:11 +08:00
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
2023-12-15 18:57:13 +08:00
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2024-07-09 11:17:03 +08:00
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_GTP_U, hdr_len, data, len, 0);
|
2023-12-15 18:57:13 +08:00
|
|
|
|
|
|
|
|
switch (next_proto)
|
|
|
|
|
{
|
|
|
|
|
case 4:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case 6:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len);
|
2023-12-15 18:57:13 +08:00
|
|
|
default:
|
2024-07-09 11:17:03 +08:00
|
|
|
PACKET_LOG_UNSUPPORT_PROTO(pkt, LAYER_PROTO_GTP_U, next_proto);
|
2023-12-15 18:57:13 +08:00
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-09 11:17:03 +08:00
|
|
|
static inline const char *parse_gtp_c(struct packet *pkt, const char *data, uint16_t len)
|
|
|
|
|
{
|
|
|
|
|
// GTPv1-C or GTPv2-C
|
2024-07-11 14:19:38 +08:00
|
|
|
uint16_t hdr_len = calc_gtp_hdr_len(data, len);
|
2024-07-09 11:17:03 +08:00
|
|
|
if (unlikely(hdr_len == 0 || hdr_len > len))
|
|
|
|
|
{
|
|
|
|
|
PACKET_LOG_DATA_INSUFFICIENCY(pkt, LAYER_PROTO_GTP_C);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct raw_layer *layer = get_free_layer(pkt);
|
|
|
|
|
if (unlikely(layer == NULL))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
SET_LAYER(pkt, layer, LAYER_PROTO_GTP_C, hdr_len, data, len, 0);
|
|
|
|
|
|
|
|
|
|
return layer->pld_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_l3(struct packet *pkt, uint16_t next_proto, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
switch (next_proto)
|
|
|
|
|
{
|
|
|
|
|
case ETH_P_8021Q:
|
|
|
|
|
case ETH_P_8021AD:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_vlan(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case ETH_P_IP:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ipv4(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case ETH_P_IPV6:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ipv6(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case ETH_P_PPP_SES:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_pppoe_ses(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case ETH_P_MPLS_UC:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_mpls(pkt, data, len);
|
2024-06-05 16:44:32 +08:00
|
|
|
case 0x880b:
|
|
|
|
|
return parse_ppp(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
default:
|
2024-06-03 17:50:52 +08:00
|
|
|
PACKET_LOG_UNSUPPORT_ETHPROTO(pkt, next_proto);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
static inline const char *parse_l4(struct packet *pkt, uint8_t next_proto, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
|
|
|
|
switch (next_proto)
|
|
|
|
|
{
|
2024-06-04 15:48:34 +08:00
|
|
|
case IPPROTO_AH:
|
|
|
|
|
return parse_auth(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case IPPROTO_TCP:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_tcp(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case IPPROTO_UDP:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_udp(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case IPPROTO_IPIP:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ipv4(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case IPPROTO_IPV6:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ipv6(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
case IPPROTO_GRE:
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_gre(pkt, data, len);
|
2024-04-22 16:38:24 +08:00
|
|
|
case IPPROTO_ICMP:
|
|
|
|
|
return parse_icmp(pkt, data, len);
|
|
|
|
|
case IPPROTO_ICMPV6:
|
|
|
|
|
return parse_icmp6(pkt, data, len);
|
2024-05-24 16:14:20 +08:00
|
|
|
case 115:
|
|
|
|
|
// L2TP
|
|
|
|
|
return parse_l2tpv3_over_ip(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
default:
|
2024-06-03 17:50:52 +08:00
|
|
|
PACKET_LOG_UNSUPPORT_IPPROTO(pkt, next_proto);
|
2023-12-15 18:57:13 +08:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
* Public API
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
// return innermost payload
|
2024-03-09 19:28:14 +08:00
|
|
|
const char *packet_parse(struct packet *pkt, const char *data, uint16_t len)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-03-09 19:28:14 +08:00
|
|
|
pkt->frag_layer = NULL;
|
|
|
|
|
pkt->layers_used = 0;
|
|
|
|
|
pkt->layers_size = PACKET_MAX_LAYERS;
|
|
|
|
|
pkt->data_ptr = data;
|
|
|
|
|
pkt->data_len = len;
|
2024-05-24 19:10:33 +08:00
|
|
|
pkt->trim_len = 0;
|
2023-12-15 18:57:13 +08:00
|
|
|
|
2024-03-09 19:28:14 +08:00
|
|
|
return parse_ether(pkt, data, len);
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-13 10:24:26 +08:00
|
|
|
const char *layer_proto_to_str(enum layer_proto proto)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-08-13 10:24:26 +08:00
|
|
|
switch (proto)
|
2023-12-15 18:57:13 +08:00
|
|
|
{
|
2024-08-13 10:24:26 +08:00
|
|
|
case LAYER_PROTO_ETHER:
|
|
|
|
|
return "ETH";
|
|
|
|
|
case LAYER_PROTO_PWETH:
|
|
|
|
|
return "PWETH";
|
|
|
|
|
case LAYER_PROTO_PPP:
|
|
|
|
|
return "PPP";
|
|
|
|
|
case LAYER_PROTO_L2TP:
|
|
|
|
|
return "L2TP";
|
|
|
|
|
case LAYER_PROTO_VLAN:
|
|
|
|
|
return "VLAN";
|
|
|
|
|
case LAYER_PROTO_PPPOE:
|
|
|
|
|
return "PPPOE";
|
|
|
|
|
case LAYER_PROTO_MPLS:
|
|
|
|
|
return "MPLS";
|
|
|
|
|
case LAYER_PROTO_IPV4:
|
|
|
|
|
return "IPV4";
|
|
|
|
|
case LAYER_PROTO_IPV6:
|
|
|
|
|
return "IPV6";
|
|
|
|
|
case LAYER_PROTO_IPAH:
|
|
|
|
|
return "IPAH";
|
|
|
|
|
case LAYER_PROTO_GRE:
|
|
|
|
|
return "GRE";
|
|
|
|
|
case LAYER_PROTO_UDP:
|
|
|
|
|
return "UDP";
|
|
|
|
|
case LAYER_PROTO_TCP:
|
|
|
|
|
return "TCP";
|
|
|
|
|
case LAYER_PROTO_ICMP:
|
|
|
|
|
return "ICMP";
|
|
|
|
|
case LAYER_PROTO_ICMP6:
|
|
|
|
|
return "ICMP6";
|
|
|
|
|
case LAYER_PROTO_VXLAN:
|
|
|
|
|
return "VXLAN";
|
|
|
|
|
case LAYER_PROTO_GTP_C:
|
|
|
|
|
return "GTP-C";
|
|
|
|
|
case LAYER_PROTO_GTP_U:
|
|
|
|
|
return "GTP-U";
|
|
|
|
|
default:
|
|
|
|
|
return "UNKNOWN";
|
2023-12-15 18:57:13 +08:00
|
|
|
}
|
2024-08-01 11:40:00 +08:00
|
|
|
}
|