diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index e231241..2e5b316 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1,5 +1,6 @@ install(FILES stellar/utils.h DESTINATION include/stellar/ COMPONENT LIBRARIES) install(FILES stellar/layer.h DESTINATION include/stellar/ COMPONENT LIBRARIES) +install(FILES stellar/tunnel.h DESTINATION include/stellar/ COMPONENT LIBRARIES) install(FILES stellar/packet.h DESTINATION include/stellar/ COMPONENT LIBRARIES) install(FILES stellar/session.h DESTINATION include/stellar/ COMPONENT LIBRARIES) install(FILES stellar/stellar.h DESTINATION include/stellar/ COMPONENT LIBRARIES) diff --git a/include/stellar/layer.h b/include/stellar/layer.h index fce1315..f77e021 100644 --- a/include/stellar/layer.h +++ b/include/stellar/layer.h @@ -81,15 +81,12 @@ int packet_get_layer(const struct packet *pkt, int idx, struct layer *out); #define PACKET_FOREACH_LAYER_REVERSE(pkt, layer) \ for (int i = packet_get_layer_count(pkt) - 1; i >= 0 && packet_get_layer(pkt, i, &layer) == 0; i--) -#define PACKET_GETALL_LAYERS(pkt, layers) \ - { \ - int size = sizeof(layers) / sizeof(layers[0]); \ - int num = packet_get_layer_count(pkt); \ - if (num > size) \ - num = size; \ - for (int i = 0; i < num && packet_get_layer(pkt, i, &layers[i]) == 0; i++) \ - /* void */; \ - return num; \ +#define PACKET_GETALL_LAYERS(pkt, layers) \ + { \ + int num = MIN(packet_get_layer_count(pkt), (sizeof(layers) / sizeof(layers[0]))); \ + for (int i = 0; i < num && packet_get_layer(pkt, i, &layers[i]) == 0; i++) \ + /* void */; \ + return num; \ } #ifdef __cplusplus diff --git a/include/stellar/tunnel.h b/include/stellar/tunnel.h new file mode 100644 index 0000000..b1ef626 --- /dev/null +++ b/include/stellar/tunnel.h @@ -0,0 +1,67 @@ +#ifndef _TUNNEL_H +#define _TUNNEL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include "layer.h" + +enum tunnel_type +{ + // none tunnel + TUNNEL_NONE = 0, // contain layers: IPv4 + TCP + // contain layers: IPv4 + UDP + // contain layers: IPv4 + // contain layers: IPv6 + TCP + // contain layers: IPv6 + UDP + // contain layers: IPv6 + + // GRE tunnel + TUNNEL_GRE, // contain layers: IPv4 + GRE + // contain layers: IPv6 + GRE + + // GTP tunnel + TUNNEL_GTP, // contain layers: IPv4 + UDP + GTP + // contain layers: IPv6 + UDP + GTP + + // IP tunnel + TUNNEL_IPV4, // contain layers: IPv4, (next inner layer must be IPv4 / IPv6) + TUNNEL_IPV6, // contain layers: IPv6, (next inner layer must be IPv4 / IPv6) +}; + +#define MAX_LAYERS_PER_TUNNEL 3 +struct tunnel +{ + enum tunnel_type type; + + int used; + struct layer layers[MAX_LAYERS_PER_TUNNEL]; +}; + +int packet_get_tunnel_count(const struct packet *pkt); +// return 0: success  +// return -1: failed +int packet_get_tunnel(const struct packet *pkt, int idx, struct tunnel *out); + +#define PACKET_FOREACH_TUNNEL_INORDER(pkt, tunnel) \ + for (int i = 0; i < packet_get_tunnel_count(pkt) && packet_get_tunnel(pkt, i, &tunnel) == 0; i++) + +#define PACKET_FOREACH_TUNNEL_REVERSE(pkt, tunnel) \ + for (int i = packet_get_tunnel_count(pkt) - 1; i >= 0 && packet_get_tunnel(pkt, i, &tunnel) == 0; i--) + +#define PACKET_GETALL_TUNNELS(pkt, tunnels) \ + { \ + int num = MIN(packet_get_tunnel_count(pkt), (sizeof(tunnels) / sizeof(tunnels[0]))); \ + for (int i = 0; i < num && packet_get_tunnel(pkt, i, &tunnels[i]) == 0; i++) \ + /* void */; \ + return num; \ + } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/packet/CMakeLists.txt b/src/packet/CMakeLists.txt index c4195d5..c155847 100644 --- a/src/packet/CMakeLists.txt +++ b/src/packet/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(packet packet.cpp packet_utils.cpp packet_layer.cpp) +add_library(packet packet.cpp packet_utils.cpp packet_layer.cpp packet_tunnel.cpp) target_include_directories(packet PUBLIC ${CMAKE_CURRENT_LIST_DIR}) target_include_directories(packet PUBLIC ${CMAKE_SOURCE_DIR}/deps/uthash) target_include_directories(packet PUBLIC ${CMAKE_SOURCE_DIR}/include) diff --git a/src/packet/packet_layer.cpp b/src/packet/packet_layer.cpp index 1fe59ea..a9c37d4 100644 --- a/src/packet/packet_layer.cpp +++ b/src/packet/packet_layer.cpp @@ -1,23 +1,16 @@ #include "packet_priv.h" +#include "packet_utils.h" int packet_get_layer(const struct packet *pkt, int idx, struct layer *out) { - if (pkt == NULL || out == NULL) + const struct raw_layer *raw = packet_get_raw_layer(pkt, idx); + if (raw == NULL) { return -1; } - - if (idx < 0 || idx >= pkt->layers_used) + else { - return -1; + layer_convert(raw, out); + return 0; } - - const struct raw_layer *raw = &pkt->layers[idx]; - out->proto = raw->proto; - out->header_len = raw->hdr_len; - out->payload_len = raw->pld_len; - out->header.raw = raw->hdr_ptr; - out->payload = raw->pld_ptr; - - return 0; } diff --git a/src/packet/packet_tunnel.cpp b/src/packet/packet_tunnel.cpp new file mode 100644 index 0000000..e05bd15 --- /dev/null +++ b/src/packet/packet_tunnel.cpp @@ -0,0 +1,99 @@ +#include + +#include "stellar/tunnel.h" +#include "packet_priv.h" +#include "packet_utils.h" + +static void layers_to_tunnel(const struct raw_layer *curr, const struct raw_layer *next1, const struct raw_layer *next2, struct tunnel *out) +{ + assert(curr); + + // GRE tunnel + if (next1 && next1->proto == LAYER_PROTO_GRE) + { + out->type = TUNNEL_GRE; + out->used = 2; + layer_convert(curr, &out->layers[0]); + layer_convert(next1, &out->layers[1]); + return; + } + + // GTP tunnel + if (next1 && next1->proto == LAYER_PROTO_UDP && next2 && next2->proto == LAYER_PROTO_GTPV1_U) + { + out->type = TUNNEL_GTP; + out->used = 3; + layer_convert(curr, &out->layers[0]); + layer_convert(next1, &out->layers[1]); + layer_convert(next2, &out->layers[2]); + return; + } + + // IP tunnel + if (next1 && (next1->proto == LAYER_PROTO_IPV4 || next1->proto == LAYER_PROTO_IPV6)) + { + out->type = curr->proto == LAYER_PROTO_IPV4 ? TUNNEL_IPV4 : TUNNEL_IPV6; + out->used = 1; + layer_convert(curr, &out->layers[0]); + return; + } + + // none tunnel + out->type = TUNNEL_NONE; + layer_convert(curr, &out->layers[out->used++]); + if (next1 && (next1->proto == LAYER_PROTO_TCP || next1->proto == LAYER_PROTO_UDP)) + { + layer_convert(next1, &out->layers[out->used++]); + } + return; +} + +int packet_get_tunnel_count(const struct packet *pkt) +{ + int count = 0; + int used = packet_get_layer_count(pkt); + const struct raw_layer *curr = NULL; + + for (int i = 0; i < used; i++) + { + curr = packet_get_raw_layer(pkt, i); + if (curr->proto == LAYER_PROTO_IPV4 || curr->proto == LAYER_PROTO_IPV6) + { + count++; + } + } + + return count; +} + +// return 0: success  +// return -1: failed +int packet_get_tunnel(const struct packet *pkt, int idx, struct tunnel *out) +{ + int count = 0; + int used = packet_get_layer_count(pkt); + const struct raw_layer *curr = NULL; + const struct raw_layer *next1 = NULL; + const struct raw_layer *next2 = NULL; + memset(out, 0, sizeof(struct tunnel)); + + for (int i = 0; i < used; i++) + { + curr = packet_get_raw_layer(pkt, i); + next1 = packet_get_raw_layer(pkt, i + 1); + next2 = packet_get_raw_layer(pkt, i + 2); + + if (curr->proto == LAYER_PROTO_IPV4 || curr->proto == LAYER_PROTO_IPV6) + { + if (count == idx) + { + layers_to_tunnel(curr, next1, next2, out); + return 0; + } + + count++; + } + } + + return -1; +} diff --git a/src/packet/packet_utils.cpp b/src/packet/packet_utils.cpp index 6fb52fa..ac413dc 100644 --- a/src/packet/packet_utils.cpp +++ b/src/packet/packet_utils.cpp @@ -186,4 +186,18 @@ void packet_free(struct packet *pkt) { free((void *)pkt); } +} + +void layer_convert(const struct raw_layer *in, struct layer *out) +{ + if (in == NULL || out == NULL) + { + return; + } + + out->proto = in->proto; + out->header_len = in->hdr_len; + out->payload_len = in->pld_len; + out->header.raw = in->hdr_ptr; + out->payload = in->pld_ptr; } \ No newline at end of file diff --git a/src/packet/packet_utils.h b/src/packet/packet_utils.h index 55bf1e6..f609556 100644 --- a/src/packet/packet_utils.h +++ b/src/packet/packet_utils.h @@ -50,6 +50,8 @@ struct packet *packet_new(uint16_t pkt_len); struct packet *packet_dup(const struct packet *pkt); void packet_free(struct packet *pkt); +void layer_convert(const struct raw_layer *in, struct layer *out); + #ifdef __cplusplus } #endif diff --git a/src/stellar/version.map b/src/stellar/version.map index f3d0576..d6b92df 100644 --- a/src/stellar/version.map +++ b/src/stellar/version.map @@ -1,16 +1,20 @@ LIBSTELLAR_DEVEL { global: - packet_get_direction; - packet_get_session_id; - packet_prepend_sids; packet_get_layer_count; packet_get_layer; + + packet_get_tunnel_count; + packet_get_tunnel; + + packet_prepend_sids; + packet_get_direction; + packet_get_session_id; + packet_set_action; + packet_get_action; packet_get_raw_data; packet_get_raw_len; packet_get_payload; packet_get_payload_len; - packet_set_action; - packet_get_action; session_exdata_free; stellar_session_exdata_new_index;