1020 lines
28 KiB
C
1020 lines
28 KiB
C
#include <assert.h>
|
||
#include <sys/queue.h>
|
||
|
||
#include "tuple.h"
|
||
#include "uthash.h"
|
||
#include "log_internal.h"
|
||
#include "packet_helper.h"
|
||
#include "packet_internal.h"
|
||
#include "stellar/exdata.h"
|
||
|
||
#define PACKET_LOG_ERROR(format, ...) STELLAR_LOG_ERROR(__thread_local_logger, "packet", format, ##__VA_ARGS__)
|
||
|
||
/******************************************************************************
|
||
* metadata utils
|
||
******************************************************************************/
|
||
|
||
void packet_set_route_ctx(struct packet *pkt, const struct route_ctx *ctx)
|
||
{
|
||
pkt->meta.route_ctx = *ctx;
|
||
}
|
||
|
||
const struct route_ctx *packet_get_route_ctx(const struct packet *pkt)
|
||
{
|
||
return &pkt->meta.route_ctx;
|
||
}
|
||
|
||
void packet_set_origin(struct packet *pkt, struct packet_origin *origin)
|
||
{
|
||
pkt->origin = *origin;
|
||
}
|
||
|
||
struct packet_origin *packet_get_origin(struct packet *pkt)
|
||
{
|
||
return &pkt->origin;
|
||
}
|
||
|
||
void packet_set_sids(struct packet *pkt, const struct sids *sids)
|
||
{
|
||
pkt->meta.sids = *sids;
|
||
}
|
||
|
||
const struct sids *packet_get_sids(const struct packet *pkt)
|
||
{
|
||
return &pkt->meta.sids;
|
||
}
|
||
|
||
void packet_prepend_sids(struct packet *pkt, const struct sids *sids)
|
||
{
|
||
if (pkt->meta.sids.used + sids->used > MAX_SIDS)
|
||
{
|
||
PACKET_LOG_ERROR("sids overflow");
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
for (int i = pkt->meta.sids.used - 1; i >= 0; i--)
|
||
{
|
||
pkt->meta.sids.sid[i + sids->used] = pkt->meta.sids.sid[i];
|
||
}
|
||
for (int i = 0; i < sids->used; i++)
|
||
{
|
||
pkt->meta.sids.sid[i] = sids->sid[i];
|
||
}
|
||
pkt->meta.sids.used += sids->used;
|
||
}
|
||
}
|
||
|
||
void packet_set_session_id(struct packet *pkt, uint64_t id)
|
||
{
|
||
pkt->meta.session_id = id;
|
||
}
|
||
|
||
uint64_t packet_get_session_id(const struct packet *pkt)
|
||
{
|
||
return pkt->meta.session_id;
|
||
}
|
||
|
||
void packet_set_domain(struct packet *pkt, uint64_t domain)
|
||
{
|
||
pkt->meta.domain = domain;
|
||
}
|
||
|
||
uint64_t packet_get_domain(const struct packet *pkt)
|
||
{
|
||
return pkt->meta.domain;
|
||
}
|
||
|
||
void packet_set_link_id(struct packet *pkt, uint16_t id)
|
||
{
|
||
pkt->meta.link_id = id;
|
||
}
|
||
|
||
uint16_t packet_get_link_id(const struct packet *pkt)
|
||
{
|
||
return pkt->meta.link_id;
|
||
}
|
||
|
||
void packet_set_claim(struct packet *pkt, bool claim)
|
||
{
|
||
pkt->meta.is_claim = claim;
|
||
}
|
||
|
||
bool packet_is_claim(const struct packet *pkt)
|
||
{
|
||
return pkt->meta.is_claim;
|
||
}
|
||
|
||
void packet_set_direction(struct packet *pkt, enum packet_direction dir)
|
||
{
|
||
pkt->meta.direction = dir;
|
||
}
|
||
|
||
enum packet_direction packet_get_direction(const struct packet *pkt)
|
||
{
|
||
return pkt->meta.direction;
|
||
}
|
||
|
||
enum packet_type packet_get_type(const struct packet *pkt)
|
||
{
|
||
return pkt->type;
|
||
}
|
||
|
||
void packet_set_type(struct packet *pkt, enum packet_type type)
|
||
{
|
||
pkt->type = type;
|
||
}
|
||
|
||
void packet_set_action(struct packet *pkt, enum packet_action action)
|
||
{
|
||
pkt->meta.action = action;
|
||
}
|
||
|
||
enum packet_action packet_get_action(const struct packet *pkt)
|
||
{
|
||
return pkt->meta.action;
|
||
}
|
||
|
||
void packet_set_timeval(struct packet *pkt, const struct timeval *tv)
|
||
{
|
||
pkt->meta.tv = *tv;
|
||
}
|
||
|
||
const struct timeval *packet_get_timeval(const struct packet *pkt)
|
||
{
|
||
return &pkt->meta.tv;
|
||
}
|
||
|
||
void packet_set_user_data(struct packet *pkt, void *data)
|
||
{
|
||
pkt->user_data = data;
|
||
}
|
||
|
||
void *packet_get_user_data(struct packet *pkt)
|
||
{
|
||
return pkt->user_data;
|
||
}
|
||
|
||
/******************************************************************************
|
||
* tuple uitls
|
||
******************************************************************************/
|
||
|
||
// return 0 : found
|
||
// return -1 : not found
|
||
int packet_get_innermost_tuple2(const struct packet *pkt, struct tuple2 *tuple)
|
||
{
|
||
memset(tuple, 0, sizeof(struct tuple2));
|
||
const struct layer_internal *layer = NULL;
|
||
|
||
for (int8_t i = pkt->layers_used - 1; i >= 0; i--)
|
||
{
|
||
layer = &pkt->layers[i];
|
||
|
||
if (layer->proto == LAYER_PROTO_IPV4)
|
||
{
|
||
const struct ip *ip4_hdr = (const struct ip *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET;
|
||
tuple->src_addr.v4 = ip4_hdr_get_src_in_addr(ip4_hdr);
|
||
tuple->dst_addr.v4 = ip4_hdr_get_dst_in_addr(ip4_hdr);
|
||
return 0;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_IPV6)
|
||
{
|
||
const struct ip6_hdr *ip6_hdr = (const struct ip6_hdr *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET6;
|
||
tuple->src_addr.v6 = ip6_hdr_get_src_in6_addr(ip6_hdr);
|
||
tuple->dst_addr.v6 = ip6_hdr_get_dst_in6_addr(ip6_hdr);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
// return 0 : found
|
||
// return -1 : not found
|
||
int packet_get_outermost_tuple2(const struct packet *pkt, struct tuple2 *tuple)
|
||
{
|
||
memset(tuple, 0, sizeof(struct tuple2));
|
||
const struct layer_internal *layer = NULL;
|
||
|
||
for (int8_t i = 0; i < pkt->layers_used; i++)
|
||
{
|
||
layer = &pkt->layers[i];
|
||
|
||
if (layer->proto == LAYER_PROTO_IPV4)
|
||
{
|
||
const struct ip *ip4_hdr = (const struct ip *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET;
|
||
tuple->src_addr.v4 = ip4_hdr_get_src_in_addr(ip4_hdr);
|
||
tuple->dst_addr.v4 = ip4_hdr_get_dst_in_addr(ip4_hdr);
|
||
return 0;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_IPV6)
|
||
{
|
||
const struct ip6_hdr *ip6_hdr = (const struct ip6_hdr *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET6;
|
||
tuple->src_addr.v6 = ip6_hdr_get_src_in6_addr(ip6_hdr);
|
||
tuple->dst_addr.v6 = ip6_hdr_get_dst_in6_addr(ip6_hdr);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
// return 0 : found
|
||
// return -1 : not found
|
||
int packet_get_innermost_tuple4(const struct packet *pkt, struct tuple4 *tuple)
|
||
{
|
||
memset(tuple, 0, sizeof(struct tuple4));
|
||
const struct layer_internal *layer_l3 = NULL;
|
||
const struct layer_internal *layer_l4 = NULL;
|
||
const struct layer_internal *layer = NULL;
|
||
|
||
for (int8_t i = pkt->layers_used - 1; i >= 0; i--)
|
||
{
|
||
layer = &pkt->layers[i];
|
||
|
||
// first get L4 layer
|
||
if (layer->proto == LAYER_PROTO_UDP)
|
||
{
|
||
const struct udphdr *udp_hdr = (const struct udphdr *)layer->hdr_ptr;
|
||
tuple->src_port = udp_hdr->uh_sport;
|
||
tuple->dst_port = udp_hdr->uh_dport;
|
||
layer_l4 = layer;
|
||
continue;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_TCP)
|
||
{
|
||
const struct tcphdr *tcp_hdr = (const struct tcphdr *)layer->hdr_ptr;
|
||
tuple->src_port = tcp_hdr->th_sport;
|
||
tuple->dst_port = tcp_hdr->th_dport;
|
||
layer_l4 = layer;
|
||
continue;
|
||
}
|
||
|
||
// second get L3 layer
|
||
if (layer->proto == LAYER_PROTO_IPV4)
|
||
{
|
||
const struct ip *ip4_hdr = (const struct ip *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET;
|
||
tuple->src_addr.v4 = ip4_hdr_get_src_in_addr(ip4_hdr);
|
||
tuple->dst_addr.v4 = ip4_hdr_get_dst_in_addr(ip4_hdr);
|
||
layer_l3 = layer;
|
||
break;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_IPV6)
|
||
{
|
||
const struct ip6_hdr *ip6_hdr = (const struct ip6_hdr *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET6;
|
||
tuple->src_addr.v6 = ip6_hdr_get_src_in6_addr(ip6_hdr);
|
||
tuple->dst_addr.v6 = ip6_hdr_get_dst_in6_addr(ip6_hdr);
|
||
layer_l3 = layer;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (layer_l3 && layer_l4 && layer_l4 - layer_l3 == 1)
|
||
{
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
// return 0 : found
|
||
// return -1 : not found
|
||
int packet_get_outermost_tuple4(const struct packet *pkt, struct tuple4 *tuple)
|
||
{
|
||
memset(tuple, 0, sizeof(struct tuple4));
|
||
const struct layer_internal *layer_l3 = NULL;
|
||
const struct layer_internal *layer_l4 = NULL;
|
||
const struct layer_internal *layer = NULL;
|
||
|
||
for (int8_t i = 0; i < pkt->layers_used; i++)
|
||
{
|
||
layer = &pkt->layers[i];
|
||
|
||
// first get L3 layer
|
||
if (layer->proto == LAYER_PROTO_IPV4)
|
||
{
|
||
const struct ip *ip4_hdr = (const struct ip *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET;
|
||
tuple->src_addr.v4 = ip4_hdr_get_src_in_addr(ip4_hdr);
|
||
tuple->dst_addr.v4 = ip4_hdr_get_dst_in_addr(ip4_hdr);
|
||
layer_l3 = layer;
|
||
continue;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_IPV6)
|
||
{
|
||
const struct ip6_hdr *ip6_hdr = (const struct ip6_hdr *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET6;
|
||
tuple->src_addr.v6 = ip6_hdr_get_src_in6_addr(ip6_hdr);
|
||
tuple->dst_addr.v6 = ip6_hdr_get_dst_in6_addr(ip6_hdr);
|
||
layer_l3 = layer;
|
||
continue;
|
||
}
|
||
|
||
// second get L4 layer
|
||
if (layer->proto == LAYER_PROTO_UDP)
|
||
{
|
||
const struct udphdr *udp_hdr = (const struct udphdr *)layer->hdr_ptr;
|
||
tuple->src_port = udp_hdr->uh_sport;
|
||
tuple->dst_port = udp_hdr->uh_dport;
|
||
layer_l4 = layer;
|
||
break;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_TCP)
|
||
{
|
||
const struct tcphdr *tcp_hdr = (const struct tcphdr *)layer->hdr_ptr;
|
||
tuple->src_port = tcp_hdr->th_sport;
|
||
tuple->dst_port = tcp_hdr->th_dport;
|
||
layer_l4 = layer;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (layer_l3 && layer_l4 && layer_l4 - layer_l3 == 1)
|
||
{
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
// return 0 : found
|
||
// return -1 : not found
|
||
int packet_get_innermost_tuple6(const struct packet *pkt, struct tuple6 *tuple)
|
||
{
|
||
memset(tuple, 0, sizeof(struct tuple6));
|
||
const struct layer_internal *layer_l3 = NULL;
|
||
const struct layer_internal *layer_l4 = NULL;
|
||
const struct layer_internal *layer = NULL;
|
||
|
||
for (int8_t i = pkt->layers_used - 1; i >= 0; i--)
|
||
{
|
||
layer = &pkt->layers[i];
|
||
|
||
// first get L4 layer
|
||
if (layer->proto == LAYER_PROTO_UDP)
|
||
{
|
||
const struct udphdr *udp_hdr = (const struct udphdr *)layer->hdr_ptr;
|
||
tuple->ip_proto = IPPROTO_UDP;
|
||
tuple->src_port = udp_hdr->uh_sport;
|
||
tuple->dst_port = udp_hdr->uh_dport;
|
||
layer_l4 = layer;
|
||
continue;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_TCP)
|
||
{
|
||
const struct tcphdr *tcp_hdr = (const struct tcphdr *)layer->hdr_ptr;
|
||
tuple->ip_proto = IPPROTO_TCP;
|
||
tuple->src_port = tcp_hdr->th_sport;
|
||
tuple->dst_port = tcp_hdr->th_dport;
|
||
layer_l4 = layer;
|
||
continue;
|
||
}
|
||
|
||
// second get L3 layer
|
||
if (layer->proto == LAYER_PROTO_IPV4)
|
||
{
|
||
const struct ip *ip4_hdr = (const struct ip *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET;
|
||
tuple->src_addr.v4 = ip4_hdr_get_src_in_addr(ip4_hdr);
|
||
tuple->dst_addr.v4 = ip4_hdr_get_dst_in_addr(ip4_hdr);
|
||
layer_l3 = layer;
|
||
break;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_IPV6)
|
||
{
|
||
const struct ip6_hdr *ip6_hdr = (const struct ip6_hdr *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET6;
|
||
tuple->src_addr.v6 = ip6_hdr_get_src_in6_addr(ip6_hdr);
|
||
tuple->dst_addr.v6 = ip6_hdr_get_dst_in6_addr(ip6_hdr);
|
||
layer_l3 = layer;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (layer_l3 && layer_l4 && layer_l4 - layer_l3 == 1)
|
||
{
|
||
tuple->domain = packet_get_domain(pkt);
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
// return 0 : found
|
||
// return -1 : not found
|
||
int packet_get_outermost_tuple6(const struct packet *pkt, struct tuple6 *tuple)
|
||
{
|
||
memset(tuple, 0, sizeof(struct tuple6));
|
||
const struct layer_internal *layer_l3 = NULL;
|
||
const struct layer_internal *layer_l4 = NULL;
|
||
const struct layer_internal *layer = NULL;
|
||
|
||
for (int8_t i = 0; i < pkt->layers_used; i++)
|
||
{
|
||
layer = &pkt->layers[i];
|
||
|
||
// first get L3 layer
|
||
if (layer->proto == LAYER_PROTO_IPV4)
|
||
{
|
||
const struct ip *ip4_hdr = (const struct ip *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET;
|
||
tuple->src_addr.v4 = ip4_hdr_get_src_in_addr(ip4_hdr);
|
||
tuple->dst_addr.v4 = ip4_hdr_get_dst_in_addr(ip4_hdr);
|
||
layer_l3 = layer;
|
||
continue;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_IPV6)
|
||
{
|
||
const struct ip6_hdr *ip6_hdr = (const struct ip6_hdr *)layer->hdr_ptr;
|
||
tuple->addr_family = AF_INET6;
|
||
tuple->src_addr.v6 = ip6_hdr_get_src_in6_addr(ip6_hdr);
|
||
tuple->dst_addr.v6 = ip6_hdr_get_dst_in6_addr(ip6_hdr);
|
||
layer_l3 = layer;
|
||
continue;
|
||
}
|
||
|
||
// second get L4 layer
|
||
if (layer->proto == LAYER_PROTO_UDP)
|
||
{
|
||
const struct udphdr *udp_hdr = (const struct udphdr *)layer->hdr_ptr;
|
||
tuple->ip_proto = IPPROTO_UDP;
|
||
tuple->src_port = udp_hdr->uh_sport;
|
||
tuple->dst_port = udp_hdr->uh_dport;
|
||
layer_l4 = layer;
|
||
break;
|
||
}
|
||
if (layer->proto == LAYER_PROTO_TCP)
|
||
{
|
||
const struct tcphdr *tcp_hdr = (const struct tcphdr *)layer->hdr_ptr;
|
||
tuple->ip_proto = IPPROTO_TCP;
|
||
tuple->src_port = tcp_hdr->th_sport;
|
||
tuple->dst_port = tcp_hdr->th_dport;
|
||
layer_l4 = layer;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (layer_l3 && layer_l4 && layer_l4 - layer_l3 == 1)
|
||
{
|
||
tuple->domain = packet_get_domain(pkt);
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/******************************************************************************
|
||
* layer uitls
|
||
******************************************************************************/
|
||
|
||
int packet_get_layer_count(const struct packet *pkt)
|
||
{
|
||
return pkt->layers_used;
|
||
}
|
||
|
||
const struct layer *packet_get_layer_by_idx(const struct packet *pkt, int idx)
|
||
{
|
||
const struct layer_internal *layer = packet_get_layer(pkt, idx);
|
||
if (layer == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
else
|
||
{
|
||
return (const struct layer *)layer;
|
||
}
|
||
}
|
||
|
||
const struct layer_internal *packet_get_layer(const struct packet *pkt, int idx)
|
||
{
|
||
if (idx < 0 || idx >= pkt->layers_used)
|
||
{
|
||
return NULL;
|
||
}
|
||
return &pkt->layers[idx];
|
||
}
|
||
|
||
const struct layer_internal *packet_get_innermost_layer(const struct packet *pkt, enum layer_proto proto)
|
||
{
|
||
const struct layer_internal *layer = NULL;
|
||
|
||
for (int8_t i = pkt->layers_used - 1; i >= 0; i--)
|
||
{
|
||
layer = &pkt->layers[i];
|
||
if (layer->proto == proto)
|
||
{
|
||
return layer;
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
const struct layer_internal *packet_get_outermost_layer(const struct packet *pkt, enum layer_proto proto)
|
||
{
|
||
const struct layer_internal *layer = NULL;
|
||
|
||
for (int8_t i = 0; i < pkt->layers_used; i++)
|
||
{
|
||
layer = &pkt->layers[i];
|
||
if (layer->proto == proto)
|
||
{
|
||
return layer;
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
/******************************************************************************
|
||
* tunnel uitls
|
||
******************************************************************************/
|
||
|
||
struct tunnel_detector
|
||
{
|
||
enum tunnel_type type;
|
||
int contain_layers;
|
||
int (*identify_func)(const struct layer_internal *curr, const struct layer_internal *next1, const struct layer_internal *next2);
|
||
};
|
||
|
||
static int is_ipv4_tunnel(const struct layer_internal *curr, const struct layer_internal *next1, const struct layer_internal *next2 __attribute__((unused)))
|
||
{
|
||
if (curr && curr->proto == LAYER_PROTO_IPV4 &&
|
||
next1 && (next1->proto == LAYER_PROTO_IPV4 || next1->proto == LAYER_PROTO_IPV6))
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int is_ipv6_tunnel(const struct layer_internal *curr, const struct layer_internal *next1, const struct layer_internal *next2 __attribute__((unused)))
|
||
{
|
||
if (curr && curr->proto == LAYER_PROTO_IPV6 &&
|
||
next1 && (next1->proto == LAYER_PROTO_IPV4 || next1->proto == LAYER_PROTO_IPV6))
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int is_gre_tunnel(const struct layer_internal *curr, const struct layer_internal *next1, const struct layer_internal *next2 __attribute__((unused)))
|
||
{
|
||
if (curr && (curr->proto == LAYER_PROTO_IPV4 || curr->proto == LAYER_PROTO_IPV6) &&
|
||
next1 && next1->proto == LAYER_PROTO_GRE)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int is_gtp_tunnel(const struct layer_internal *curr, const struct layer_internal *next1, const struct layer_internal *next2)
|
||
{
|
||
if (curr && (curr->proto == LAYER_PROTO_IPV4 || curr->proto == LAYER_PROTO_IPV6) &&
|
||
next1 && next1->proto == LAYER_PROTO_UDP &&
|
||
next2 && next2->proto == LAYER_PROTO_GTP_U)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int is_vxlan_tunnel(const struct layer_internal *curr, const struct layer_internal *next1, const struct layer_internal *next2)
|
||
{
|
||
if (curr && (curr->proto == LAYER_PROTO_IPV4 || curr->proto == LAYER_PROTO_IPV6) &&
|
||
next1 && next1->proto == LAYER_PROTO_UDP &&
|
||
next2 && next2->proto == LAYER_PROTO_VXLAN)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int is_l2tp_tunnel(const struct layer_internal *curr, const struct layer_internal *next1, const struct layer_internal *next2)
|
||
{
|
||
if (curr && (curr->proto == LAYER_PROTO_IPV4 || curr->proto == LAYER_PROTO_IPV6) &&
|
||
next1 && next1->proto == LAYER_PROTO_UDP &&
|
||
next2 && next2->proto == LAYER_PROTO_L2TP)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int is_teredo_tunnel(const struct layer_internal *curr, const struct layer_internal *next1, const struct layer_internal *next2)
|
||
{
|
||
if (curr && curr->proto == LAYER_PROTO_IPV4 &&
|
||
next1 && next1->proto == LAYER_PROTO_UDP &&
|
||
next2 && next2->proto == LAYER_PROTO_IPV6)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static struct tunnel_detector detectors[] = {
|
||
{TUNNEL_IPV4, 1, is_ipv4_tunnel},
|
||
{TUNNEL_IPV6, 1, is_ipv6_tunnel},
|
||
{TUNNEL_GRE, 2, is_gre_tunnel},
|
||
{TUNNEL_GTP, 3, is_gtp_tunnel},
|
||
{TUNNEL_VXLAN, 3, is_vxlan_tunnel},
|
||
{TUNNEL_L2TP, 3, is_l2tp_tunnel},
|
||
{TUNNEL_TEREDO, 2, is_teredo_tunnel},
|
||
};
|
||
|
||
// return index of detectors
|
||
static int detect_tunnel(const struct layer_internal *curr, const struct layer_internal *next1, const struct layer_internal *next2)
|
||
{
|
||
for (int i = 0; i < (int)(sizeof(detectors) / sizeof(detectors[0])); i++)
|
||
{
|
||
if (detectors[i].identify_func(curr, next1, next2))
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
int packet_get_tunnel_count(const struct packet *pkt)
|
||
{
|
||
int count = 0;
|
||
int used = packet_get_layer_count(pkt);
|
||
const struct layer_internal *curr = NULL;
|
||
const struct layer_internal *next1 = NULL;
|
||
const struct layer_internal *next2 = NULL;
|
||
|
||
for (int i = 0; i < used; i++)
|
||
{
|
||
curr = packet_get_layer(pkt, i);
|
||
next1 = packet_get_layer(pkt, i + 1);
|
||
next2 = packet_get_layer(pkt, i + 2);
|
||
if (detect_tunnel(curr, next1, next2) >= 0)
|
||
{
|
||
count++;
|
||
}
|
||
}
|
||
|
||
return count;
|
||
}
|
||
|
||
// return 0: success
|
||
// return -1: failed
|
||
int packet_get_tunnel_by_idx(const struct packet *pkt, int idx, struct tunnel *out)
|
||
{
|
||
int ret = -1;
|
||
int count = 0;
|
||
int used = packet_get_layer_count(pkt);
|
||
const struct layer_internal *curr = NULL;
|
||
const struct layer_internal *next1 = NULL;
|
||
const struct layer_internal *next2 = NULL;
|
||
memset(out, 0, sizeof(struct tunnel));
|
||
|
||
for (int i = 0; i < used; i++)
|
||
{
|
||
curr = packet_get_layer(pkt, i);
|
||
next1 = packet_get_layer(pkt, i + 1);
|
||
next2 = packet_get_layer(pkt, i + 2);
|
||
ret = detect_tunnel(curr, next1, next2);
|
||
if (ret >= 0 && count++ == idx)
|
||
{
|
||
struct tunnel_detector *hit = &detectors[ret];
|
||
out->type = hit->type;
|
||
out->layer_count = hit->contain_layers;
|
||
if (out->layer_count >= 1)
|
||
out->layers[0] = (const struct layer *)curr;
|
||
if (out->layer_count >= 2)
|
||
out->layers[1] = (const struct layer *)next1;
|
||
if (out->layer_count >= 3)
|
||
out->layers[2] = (const struct layer *)next2;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/******************************************************************************
|
||
* load balance uitls
|
||
******************************************************************************/
|
||
|
||
uint64_t packet_ldbc_hash(const struct packet *pkt, enum packet_load_balance_method method, enum packet_direction direction)
|
||
{
|
||
uint64_t temp = 0;
|
||
uint64_t hash_value = 1;
|
||
|
||
int inner_addr_len = 0;
|
||
int outer_addr_len = 0;
|
||
const char *inner_src_addr = NULL;
|
||
const char *inner_dst_addr = NULL;
|
||
const char *outer_src_addr = NULL;
|
||
const char *outer_dst_addr = NULL;
|
||
|
||
struct tuple2 inner_addr;
|
||
struct tuple2 outer_addr;
|
||
|
||
if (pkt == NULL)
|
||
{
|
||
return hash_value;
|
||
}
|
||
|
||
if (packet_get_innermost_tuple2(pkt, &inner_addr) == -1)
|
||
{
|
||
return hash_value;
|
||
}
|
||
|
||
if (packet_get_outermost_tuple2(pkt, &outer_addr) == -1)
|
||
{
|
||
return hash_value;
|
||
}
|
||
|
||
if (inner_addr.addr_family == AF_INET)
|
||
{
|
||
inner_src_addr = (const char *)&inner_addr.src_addr.v4;
|
||
inner_dst_addr = (const char *)&inner_addr.dst_addr.v4;
|
||
inner_addr_len = sizeof(struct in_addr);
|
||
}
|
||
else
|
||
{
|
||
inner_src_addr = (const char *)&inner_addr.src_addr.v6;
|
||
inner_dst_addr = (const char *)&inner_addr.dst_addr.v6;
|
||
inner_addr_len = sizeof(struct in6_addr);
|
||
}
|
||
|
||
if (outer_addr.addr_family == AF_INET)
|
||
{
|
||
outer_src_addr = (const char *)&outer_addr.src_addr.v4;
|
||
outer_dst_addr = (const char *)&outer_addr.dst_addr.v4;
|
||
outer_addr_len = sizeof(struct in_addr);
|
||
}
|
||
else
|
||
{
|
||
outer_src_addr = (const char *)&outer_addr.src_addr.v6;
|
||
outer_dst_addr = (const char *)&outer_addr.dst_addr.v6;
|
||
outer_addr_len = sizeof(struct in6_addr);
|
||
}
|
||
|
||
switch (method)
|
||
{
|
||
case PKT_LDBC_METH_OUTERMOST_INT_IP:
|
||
if (direction == PACKET_DIRECTION_INCOMING)
|
||
{
|
||
// direction 1: E2I
|
||
HASH_VALUE(outer_dst_addr, outer_addr_len, hash_value);
|
||
}
|
||
else
|
||
{
|
||
// direction 0: I2E
|
||
HASH_VALUE(outer_src_addr, outer_addr_len, hash_value);
|
||
}
|
||
break;
|
||
case PKT_LDBC_METH_OUTERMOST_EXT_IP:
|
||
if (direction == PACKET_DIRECTION_INCOMING)
|
||
{
|
||
// direction 1: E2I
|
||
HASH_VALUE(outer_src_addr, outer_addr_len, hash_value);
|
||
}
|
||
else
|
||
{
|
||
// direction 0: I2E
|
||
HASH_VALUE(outer_dst_addr, outer_addr_len, hash_value);
|
||
}
|
||
break;
|
||
case PKT_LDBC_METH_OUTERMOST_INT_EXT_IP:
|
||
HASH_VALUE(outer_src_addr, outer_addr_len, hash_value);
|
||
HASH_VALUE(outer_dst_addr, outer_addr_len, temp);
|
||
hash_value = hash_value ^ temp;
|
||
break;
|
||
case PKT_LDBC_METH_INNERMOST_INT_IP:
|
||
if (direction == PACKET_DIRECTION_INCOMING)
|
||
{
|
||
// direction 1: E2I
|
||
HASH_VALUE(inner_dst_addr, inner_addr_len, hash_value);
|
||
}
|
||
else
|
||
{
|
||
// direction 0: I2E
|
||
HASH_VALUE(inner_src_addr, inner_addr_len, hash_value);
|
||
}
|
||
break;
|
||
case PKT_LDBC_METH_INNERMOST_EXT_IP:
|
||
if (direction == PACKET_DIRECTION_INCOMING)
|
||
{
|
||
// direction 1: E2I
|
||
HASH_VALUE(inner_src_addr, inner_addr_len, hash_value);
|
||
}
|
||
else
|
||
{
|
||
// direction 0: I2E
|
||
HASH_VALUE(inner_dst_addr, inner_addr_len, hash_value);
|
||
}
|
||
break;
|
||
default:
|
||
return hash_value;
|
||
}
|
||
|
||
return hash_value;
|
||
}
|
||
|
||
/******************************************************************************
|
||
* other uitls
|
||
******************************************************************************/
|
||
|
||
const char *packet_get_raw_data(const struct packet *pkt)
|
||
{
|
||
return pkt->data_ptr;
|
||
}
|
||
|
||
uint16_t packet_get_raw_len(const struct packet *pkt)
|
||
{
|
||
return pkt->data_len;
|
||
}
|
||
|
||
const char *packet_get_payload_data(const struct packet *pkt)
|
||
{
|
||
if (pkt == NULL || pkt->layers_used == 0)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
if (pkt->layers[pkt->layers_used - 1].pld_len)
|
||
{
|
||
return pkt->layers[pkt->layers_used - 1].pld_ptr;
|
||
}
|
||
else
|
||
{
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
uint16_t packet_get_payload_len(const struct packet *pkt)
|
||
{
|
||
if (pkt == NULL || pkt->layers_used == 0)
|
||
{
|
||
return 0;
|
||
}
|
||
return pkt->layers[pkt->layers_used - 1].pld_len;
|
||
}
|
||
|
||
struct packet *packet_new(uint16_t pkt_len)
|
||
{
|
||
struct packet *pkt = (struct packet *)calloc(1, sizeof(struct packet) + pkt_len);
|
||
if (pkt == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
pkt->data_len = pkt_len;
|
||
pkt->data_ptr = (const char *)pkt + sizeof(struct packet);
|
||
pkt->need_free = 1;
|
||
|
||
return pkt;
|
||
}
|
||
|
||
struct packet *packet_dup(const struct packet *pkt)
|
||
{
|
||
if (pkt == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
struct packet *dup_pkt = packet_new(pkt->data_len);
|
||
if (dup_pkt == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
dup_pkt->layers_used = pkt->layers_used;
|
||
dup_pkt->layers_size = pkt->layers_size;
|
||
|
||
memcpy((char *)dup_pkt->data_ptr, pkt->data_ptr, pkt->data_len);
|
||
dup_pkt->data_len = pkt->data_len;
|
||
packet_set_action(dup_pkt, PACKET_ACTION_DROP);
|
||
|
||
for (int8_t i = 0; i < pkt->layers_used; i++)
|
||
{
|
||
dup_pkt->layers[i].proto = pkt->layers[i].proto;
|
||
dup_pkt->layers[i].hdr_ptr = dup_pkt->data_ptr + pkt->layers[i].hdr_offset;
|
||
dup_pkt->layers[i].pld_ptr = dup_pkt->data_ptr + pkt->layers[i].hdr_offset + pkt->layers[i].hdr_len;
|
||
dup_pkt->layers[i].hdr_offset = pkt->layers[i].hdr_offset;
|
||
dup_pkt->layers[i].hdr_len = pkt->layers[i].hdr_len;
|
||
dup_pkt->layers[i].pld_len = pkt->layers[i].pld_len;
|
||
}
|
||
|
||
// update frag_layer
|
||
if (pkt->frag_layer)
|
||
{
|
||
dup_pkt->frag_layer = &dup_pkt->layers[pkt->frag_layer - pkt->layers];
|
||
}
|
||
memcpy(&dup_pkt->meta, &pkt->meta, sizeof(struct metadata));
|
||
struct packet_origin origin = {
|
||
.type = ORIGIN_TYPE_USER,
|
||
.ctx = NULL,
|
||
.cb = NULL,
|
||
.args = NULL,
|
||
.thr_idx = -1,
|
||
};
|
||
packet_set_origin(dup_pkt, &origin);
|
||
|
||
return dup_pkt;
|
||
}
|
||
|
||
void packet_free(struct packet *pkt)
|
||
{
|
||
if (pkt)
|
||
{
|
||
if (packet_is_claim(pkt))
|
||
{
|
||
PACKET_LOG_ERROR("packet has been claimed and cannot be released, please check the module arrangement order");
|
||
assert(0);
|
||
return;
|
||
}
|
||
|
||
if (pkt->origin.cb)
|
||
{
|
||
pkt->origin.cb(pkt, pkt->origin.args);
|
||
}
|
||
|
||
if (pkt->need_free)
|
||
{
|
||
free((void *)pkt);
|
||
}
|
||
}
|
||
}
|
||
|
||
int packet_is_fragment(const struct packet *pkt)
|
||
{
|
||
return (pkt->frag_layer) ? 1 : 0;
|
||
}
|
||
|
||
int packet_is_defraged(const struct packet *pkt)
|
||
{
|
||
return pkt->is_defraged;
|
||
}
|
||
|
||
void packet_set_defraged(struct packet *pkt)
|
||
{
|
||
pkt->is_defraged = 1;
|
||
TAILQ_INIT(&pkt->frag_list);
|
||
}
|
||
|
||
void packet_push_frag(struct packet *pkt, struct packet *frag)
|
||
{
|
||
if (!packet_is_defraged(pkt))
|
||
{
|
||
assert(0);
|
||
return;
|
||
}
|
||
|
||
TAILQ_INSERT_TAIL(&pkt->frag_list, frag, frag_tqe);
|
||
}
|
||
|
||
struct packet *packet_pop_frag(struct packet *pkt)
|
||
{
|
||
if (!packet_is_defraged(pkt))
|
||
{
|
||
assert(0);
|
||
return NULL;
|
||
}
|
||
|
||
struct packet *frag = TAILQ_FIRST(&pkt->frag_list);
|
||
if (frag)
|
||
{
|
||
TAILQ_REMOVE(&pkt->frag_list, frag, frag_tqe);
|
||
}
|
||
return frag;
|
||
}
|
||
|
||
void packet_set_exdata(struct packet *pkt, int idx, void *ex_ptr)
|
||
{
|
||
struct exdata_runtime *exdata_rt = (struct exdata_runtime *)packet_get_user_data(pkt);
|
||
assert(exdata_rt);
|
||
exdata_set(exdata_rt, idx, ex_ptr);
|
||
}
|
||
|
||
void *packet_get_exdata(struct packet *pkt, int idx)
|
||
{
|
||
struct exdata_runtime *exdata_rt = (struct exdata_runtime *)packet_get_user_data(pkt);
|
||
assert(exdata_rt);
|
||
return exdata_get(exdata_rt, idx);
|
||
}
|