修正部分编译错误
This commit is contained in:
441
plugin/business/traffic-mirror/src/entry.cpp
Normal file
441
plugin/business/traffic-mirror/src/entry.cpp
Normal file
@@ -0,0 +1,441 @@
|
||||
#include <assert.h>
|
||||
#include <cjson/cJSON.h>
|
||||
#include <tfe_stream.h>
|
||||
#include <tfe_plugin.h>
|
||||
#include <tfe_proxy.h>
|
||||
#include "../include/traffic_mirror.h"
|
||||
|
||||
extern Maat_feather_t g_business_maat;
|
||||
|
||||
struct traffic_mirror_me
|
||||
{
|
||||
struct profile_table_ex_data * profile_ex_data;
|
||||
struct traffic_mirror_rebuild * rebuild_ctx;
|
||||
};
|
||||
|
||||
struct traffic_mirror_instance __g_traffic_mirror_instance;
|
||||
struct traffic_mirror_instance * g_traffic_mirror_instance = &__g_traffic_mirror_instance;
|
||||
|
||||
void policy_table_ex_data_free(struct policy_table_ex_data * object)
|
||||
{
|
||||
if ((__sync_sub_and_fetch(&object->atomic_refcnt, 1) == 0)) free(object);
|
||||
}
|
||||
|
||||
void policy_table_ex_data_dup_cb(int table_id, MAAT_PLUGIN_EX_DATA * to,
|
||||
MAAT_PLUGIN_EX_DATA * from, long argl, void * argp)
|
||||
{
|
||||
struct policy_table_ex_data * ex_data = (struct policy_table_ex_data *)from;
|
||||
__sync_add_and_fetch(&ex_data->atomic_refcnt, 1);
|
||||
*to = (void *)ex_data;
|
||||
}
|
||||
|
||||
void policy_table_ex_data_free_cb(int table_id, MAAT_PLUGIN_EX_DATA * ad, long argl, void * argp)
|
||||
{
|
||||
struct policy_table_ex_data * ex_data = (struct policy_table_ex_data *)argp;
|
||||
policy_table_ex_data_free(ex_data);
|
||||
}
|
||||
|
||||
void policy_table_ex_data_new_cb(int table_id, const char * key, const char * table_line,
|
||||
MAAT_PLUGIN_EX_DATA * ad, long argl, void * argp)
|
||||
{
|
||||
struct traffic_mirror_instance * instance = (struct traffic_mirror_instance *) argp;
|
||||
assert(instance != nullptr && instance->logger != nullptr);
|
||||
|
||||
char * str_json = NULL;
|
||||
cJSON * json_root = NULL;
|
||||
cJSON * json_subroot = NULL;
|
||||
cJSON * json_item = NULL;
|
||||
|
||||
struct policy_table_ex_data * ex_data = NULL;
|
||||
|
||||
size_t user_region_offset;
|
||||
size_t user_region_len;
|
||||
|
||||
int result = Maat_helper_read_column(table_line, 7, &user_region_offset, &user_region_len);
|
||||
if (unlikely(result < 0))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "Failed at get policy table's user region.");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
str_json = ALLOC(char, user_region_len + 1);
|
||||
memcpy(str_json, table_line + user_region_offset, user_region_len);
|
||||
|
||||
json_root = cJSON_Parse(str_json);
|
||||
if (unlikely(!json_root))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "failed at parsing user region as JSON format.");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
json_subroot = cJSON_GetObjectItem(json_root, "decrypt_mirror");
|
||||
if (unlikely(!json_subroot))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "invalid format, decrypt_mirror is not defined.");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
ex_data = ALLOC(struct policy_table_ex_data, 1);
|
||||
ex_data->atomic_refcnt = 1;
|
||||
ex_data->enable = 0;
|
||||
ex_data->profile_id = 0;
|
||||
|
||||
json_item = cJSON_GetObjectItem(json_subroot, "enable");
|
||||
if (unlikely(!json_item || cJSON_IsNumber(json_item)))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "invalid JSON, decrypt_mirror->enable not existed or invalid type.");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
ex_data->enable = json_item->valueint;
|
||||
if (!ex_data->enable)
|
||||
{
|
||||
goto success;
|
||||
}
|
||||
|
||||
json_item = cJSON_GetObjectItem(json_subroot, "mirror_profile");
|
||||
if (unlikely(!json_item || cJSON_IsNumber(json_item)))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "invalid JSON, decrypt_mirror->mirror_profile not existed or invalid type.");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
success:
|
||||
TFE_LOG_DEBUG(instance->logger, "table line in PXY_INTERCEPT_COMPILE added: %s", table_line);
|
||||
*ad = ex_data;
|
||||
ex_data = nullptr;
|
||||
goto out;
|
||||
|
||||
ignore:
|
||||
TFE_LOG_ERROR(instance->logger, "table line in PXY_INTERCEPT_COMPILE ignored: %s", table_line);
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (ex_data) policy_table_ex_data_free(ex_data);
|
||||
if (json_root) cJSON_Delete(json_root);
|
||||
if (str_json) free(str_json);
|
||||
}
|
||||
|
||||
void profile_table_ex_data_free(struct profile_table_ex_data * object)
|
||||
{
|
||||
if ((__sync_sub_and_fetch(&object->atomic_refcnt, 1) == 0)) free(object);
|
||||
}
|
||||
|
||||
void profile_table_ex_data_dup_cb(int table_id, MAAT_PLUGIN_EX_DATA * to,
|
||||
MAAT_PLUGIN_EX_DATA * from, long argl, void * argp)
|
||||
{
|
||||
struct profile_table_ex_data * ex_data = (struct profile_table_ex_data *)from;
|
||||
__sync_add_and_fetch(&ex_data->atomic_refcnt, 1);
|
||||
*to = (void *)ex_data;
|
||||
}
|
||||
|
||||
void profile_table_ex_data_free_cb(int table_id, MAAT_PLUGIN_EX_DATA * ad, long argl, void * argp)
|
||||
{
|
||||
struct profile_table_ex_data * ex_data = (struct profile_table_ex_data *)ad;
|
||||
profile_table_ex_data_free(ex_data);
|
||||
}
|
||||
|
||||
void profile_table_ex_data_new_cb(int table_id, const char * key, const char * table_line,
|
||||
MAAT_PLUGIN_EX_DATA * ad, long argl, void * argp)
|
||||
{
|
||||
struct traffic_mirror_instance * instance = (struct traffic_mirror_instance *) argp;
|
||||
assert(instance != nullptr && instance->logger != nullptr);
|
||||
|
||||
const static struct ether_addr ether_addr_broadcast{0xff,0xff,0xff,0xff, 0xff, 0xff};
|
||||
char * str_json = NULL;
|
||||
cJSON * json_root = NULL;
|
||||
cJSON * json_item = NULL;
|
||||
|
||||
struct profile_table_ex_data * ex_data = NULL;
|
||||
size_t addr_list_offset;
|
||||
size_t addr_list_len;
|
||||
|
||||
int result = Maat_helper_read_column(table_line, 3, &addr_list_offset, &addr_list_len);
|
||||
if (unlikely(result < 0))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "Failed at get profile table's addrlist.");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
str_json = ALLOC(char, addr_list_len + 1);
|
||||
memcpy(str_json, table_line + addr_list_offset, addr_list_len);
|
||||
|
||||
json_root = cJSON_Parse(str_json);
|
||||
if (unlikely(!json_root))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "failed at parsing addrlist as JSON format.");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
ex_data = ALLOC(struct profile_table_ex_data, 1);
|
||||
ex_data->atomic_refcnt = 1;
|
||||
|
||||
json_item = cJSON_GetObjectItem(json_root, "vlan");
|
||||
if (json_item)
|
||||
{
|
||||
if (unlikely(!cJSON_IsArray(json_item)))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "invalid JSON, mirror_profile->vlan is not a array.");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
ex_data->nr_targets = cJSON_GetArraySize(json_item);
|
||||
ex_data->vlans = (unsigned int *)calloc(ex_data->nr_targets, sizeof(unsigned int));
|
||||
ex_data->ether_addrs = (struct ether_addr *)calloc(ex_data->nr_targets, sizeof(struct ether_addr));
|
||||
|
||||
cJSON * element;
|
||||
unsigned int iter = 0;
|
||||
cJSON_ArrayForEach(element, json_item)
|
||||
{
|
||||
if (unlikely(!cJSON_IsNumber(element)))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "invalid JSON, "
|
||||
"elements in mirror_profile->vlan is not a number");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
ex_data->vlans[iter] = element->valueint;
|
||||
ex_data->ether_addrs[iter] = ether_addr_broadcast;
|
||||
iter++;
|
||||
}
|
||||
|
||||
assert(iter + 1 == ex_data->nr_targets);
|
||||
goto success;
|
||||
}
|
||||
|
||||
json_item = cJSON_GetObjectItem(json_item, "mac");
|
||||
if (json_item)
|
||||
{
|
||||
if (unlikely(!cJSON_IsArray(json_item)))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "invalid JSON, mirror_profile->mac is not a array.");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
ex_data->nr_targets = cJSON_GetArraySize(json_item);
|
||||
ex_data->vlans = (unsigned int *)calloc(ex_data->nr_targets, sizeof(unsigned int));
|
||||
ex_data->ether_addrs = (struct ether_addr *)calloc(ex_data->nr_targets, sizeof(struct ether_addr));
|
||||
|
||||
cJSON * element;
|
||||
unsigned int iter = 0;
|
||||
cJSON_ArrayForEach(element, json_item)
|
||||
{
|
||||
if (unlikely(!cJSON_IsString(element)))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "invalid JSON, "
|
||||
"elements in mirror_profile->mac is not a string");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
struct ether_addr ether_addr_aton{};
|
||||
if (unlikely(!ether_aton_r(element->valuestring, ðer_addr_aton)))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "invalid JSON, "
|
||||
"elements in mirror_profile->mac is not a valid ether address");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
ex_data->ether_addrs[iter] = ether_addr_aton;
|
||||
ex_data->vlans[iter] = 0;
|
||||
iter++;
|
||||
}
|
||||
|
||||
assert(iter + 1 == ex_data->nr_targets);
|
||||
}
|
||||
|
||||
success:
|
||||
*ad = (void *)ex_data;
|
||||
ex_data = nullptr;
|
||||
|
||||
TFE_LOG_DEBUG(instance->logger, "table line in PXY_PROFILE_TRAFFIC_MIRROR added: %s", table_line);
|
||||
goto out;
|
||||
|
||||
ignore:
|
||||
TFE_LOG_ERROR(instance->logger, "table line in PXY_PROFILE_TRAFFIC_MIRROR ignored: %s", table_line);
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (ex_data)
|
||||
{
|
||||
profile_table_ex_data_free(ex_data);
|
||||
}
|
||||
|
||||
if (str_json)
|
||||
{
|
||||
free(str_json);
|
||||
}
|
||||
|
||||
if (json_root)
|
||||
{
|
||||
cJSON_Delete(json_root);
|
||||
}
|
||||
}
|
||||
|
||||
int traffic_mirror_init(struct tfe_proxy * proxy)
|
||||
{
|
||||
int result = 0;
|
||||
struct traffic_mirror_instance * instance = g_traffic_mirror_instance;
|
||||
|
||||
/* INIT DECRYPT MIRROR INSTANCE */
|
||||
instance->maat_feather = g_business_maat;
|
||||
instance->logger = tfe_proxy_get_error_logger();
|
||||
instance->nr_threads = tfe_proxy_get_work_thread_count();
|
||||
|
||||
/* REGISTER MAAT FEATHER */
|
||||
instance->policy_table_id = Maat_table_register(instance->maat_feather, "PXY_INTERCEPT_COMPILE");
|
||||
if (unlikely(instance->policy_table_id < 0))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "failed at register table PXY_INTERCEPT_COMPILE, ret = %d",
|
||||
instance->policy_table_id); goto errout;
|
||||
}
|
||||
|
||||
instance->profile_table_id = Maat_table_register(instance->maat_feather, "PXY_PROFILE_TRAFFIC_MIRROR");
|
||||
if (unlikely(instance->profile_table_id < 0))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "failed at register table PXY_PROFILE_TRAFFIC_MIRROR, ret = %d",
|
||||
instance->profile_table_id); goto errout;
|
||||
}
|
||||
|
||||
result = Maat_plugin_EX_register(instance->maat_feather, instance->policy_table_id,
|
||||
policy_table_ex_data_new_cb, policy_table_ex_data_free_cb, policy_table_ex_data_dup_cb,
|
||||
nullptr, 0, instance);
|
||||
|
||||
if(unlikely(result < 0))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "failed at Maat_plugin_EX_register(PXY_INTERCEPT_COMPILE), "
|
||||
"table_id = %d, ret = %d", instance->policy_table_id, result);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
result = Maat_plugin_EX_register(instance->maat_feather, instance->policy_table_id,
|
||||
profile_table_ex_data_new_cb, profile_table_ex_data_free_cb, policy_table_ex_data_dup_cb,
|
||||
nullptr, 0, instance);
|
||||
|
||||
if (unlikely(result < 0))
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "failed at Maat_plugin_EX_register(PXY_PROFILE_TRAFFIC_MIRROR), "
|
||||
"table_id = %d, ret = %d", instance->policy_table_id, result);
|
||||
}
|
||||
|
||||
errout:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int traffic_mirror_on_open_cb(const struct tfe_stream * stream, unsigned int thread_id,
|
||||
enum tfe_conn_dir dir, void ** pme)
|
||||
{
|
||||
/* Firstly, fetch destination address of traffic mirror */
|
||||
struct traffic_mirror_me * me = NULL;
|
||||
struct traffic_mirror_instance * instance = g_traffic_mirror_instance;
|
||||
struct tfe_cmsg * cmsg = tfe_stream_get0_cmsg(stream);
|
||||
|
||||
assert(instance != NULL);
|
||||
assert(cmsg != NULL);
|
||||
|
||||
char str_policy_id[TFE_SYMBOL_MAX];
|
||||
char str_profile_id[TFE_SYMBOL_MAX];
|
||||
|
||||
unsigned int opt_val;
|
||||
uint16_t opt_out_size;
|
||||
|
||||
struct policy_table_ex_data * policy_ex_data = NULL;
|
||||
struct profile_table_ex_data * profile_ex_data = NULL;
|
||||
|
||||
int ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_POLICY_ID, (unsigned char*)&opt_val, sizeof(opt_val), &opt_out_size);
|
||||
if (ret < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "failed at getting policy id from cmsg, detach the stream.");
|
||||
goto detach;
|
||||
}
|
||||
|
||||
snprintf(str_policy_id, sizeof(str_policy_id), "%u", opt_val);
|
||||
policy_ex_data = (struct policy_table_ex_data *)Maat_plugin_get_EX_data(instance->maat_feather,
|
||||
instance->policy_table_id, str_policy_id);
|
||||
|
||||
if (!policy_ex_data)
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "failed at getting policy %s's EXDATA, detach the stream", str_policy_id);
|
||||
goto detach;
|
||||
}
|
||||
|
||||
if (!policy_ex_data->enable)
|
||||
{
|
||||
goto detach;
|
||||
}
|
||||
|
||||
snprintf(str_profile_id, sizeof(str_policy_id), "%u", policy_ex_data->profile_id);
|
||||
profile_ex_data = (struct profile_table_ex_data *)Maat_plugin_get_EX_data(instance->maat_feather,
|
||||
instance->profile_table_id, str_profile_id);
|
||||
|
||||
if (!profile_ex_data)
|
||||
{
|
||||
TFE_LOG_ERROR(instance->logger, "failed at getting policy %s's profile, profile id = %s, "
|
||||
"detach the stream", str_policy_id, str_profile_id);
|
||||
goto detach;
|
||||
}
|
||||
|
||||
|
||||
me = ALLOC(struct traffic_mirror_me, 1);
|
||||
me->rebuild_ctx = traffic_mirror_rebuild_create(stream->addr, profile_ex_data, NULL);
|
||||
me->profile_ex_data = profile_ex_data;
|
||||
|
||||
/* profile_ex_data's ownership is transfer to me */
|
||||
profile_ex_data = NULL;
|
||||
traffic_mirror_rebuild_handshake(me->rebuild_ctx);
|
||||
|
||||
*pme = (void *)me;
|
||||
return ACTION_FORWARD_DATA;
|
||||
|
||||
detach:
|
||||
if (me)
|
||||
{
|
||||
free(me);
|
||||
}
|
||||
|
||||
if (policy_ex_data)
|
||||
{
|
||||
policy_table_ex_data_free(policy_ex_data);
|
||||
}
|
||||
|
||||
if (profile_ex_data)
|
||||
{
|
||||
profile_table_ex_data_free(profile_ex_data);
|
||||
}
|
||||
|
||||
tfe_stream_detach(stream);
|
||||
return ACTION_FORWARD_DATA;
|
||||
}
|
||||
|
||||
enum tfe_stream_action traffic_mirror_on_data_cb(const struct tfe_stream * stream, unsigned int thread_id,
|
||||
enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme)
|
||||
{
|
||||
struct traffic_mirror_me * me = (struct traffic_mirror_me *)(*pme);
|
||||
traffic_mirror_rebuild_data(me->rebuild_ctx, (const char *)data, (size_t)len, dir);
|
||||
}
|
||||
|
||||
void traffic_mirror_on_close_cb(const struct tfe_stream * stream, unsigned int thread_id,
|
||||
enum tfe_stream_close_reason reason, void ** pme)
|
||||
{
|
||||
struct traffic_mirror_me * me = (struct traffic_mirror_me *)(*pme);
|
||||
traffic_mirror_rebuild_farewell(me->rebuild_ctx);
|
||||
traffic_mirror_rebuild_destroy(me->rebuild_ctx);
|
||||
profile_table_ex_data_free(me->profile_ex_data);
|
||||
|
||||
free(me);
|
||||
*pme = NULL;
|
||||
}
|
||||
|
||||
void traffic_mirror_deinit(struct tfe_proxy * proxy){}
|
||||
|
||||
struct tfe_plugin traffic_mirror_plugin_desc =
|
||||
{
|
||||
.symbol= "traffic_mirror",
|
||||
.type = TFE_PLUGIN_TYPE_BUSINESS,
|
||||
.on_init = traffic_mirror_init,
|
||||
.on_deinit = traffic_mirror_deinit,
|
||||
.on_open = traffic_mirror_on_open_cb,
|
||||
.on_data = traffic_mirror_on_data_cb,
|
||||
.on_close = traffic_mirror_on_close_cb
|
||||
};
|
||||
|
||||
TFE_PLUGIN_REGISTER(traffic_mirror, traffic_mirror_plugin_desc)
|
||||
110
plugin/business/traffic-mirror/src/ethdev.cpp
Normal file
110
plugin/business/traffic-mirror/src/ethdev.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include <unistd.h>
|
||||
#include <pcap/pcap.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <tfe_utils.h>
|
||||
#include <tfe_proxy.h>
|
||||
#include <traffic_mirror.h>
|
||||
|
||||
struct traffic_mirror_ethdev_pkt_desc{};
|
||||
struct traffic_mirror_ethdev_pkt_desc_pcap
|
||||
{
|
||||
unsigned int pktlen;
|
||||
char * pkt;
|
||||
};
|
||||
|
||||
static int pcap_ethdev_inject(struct traffic_mirror_ethdev * ethdev, const char * pkt, unsigned int pktlen)
|
||||
{
|
||||
return pcap_sendpacket(ethdev->pcap_device_handle, (const u_char *)pkt, pktlen);
|
||||
}
|
||||
|
||||
static void pcap_ethdev_destroy(struct traffic_mirror_ethdev * ethdev)
|
||||
{
|
||||
pcap_close(ethdev->pcap_device_handle);
|
||||
return free(ethdev);
|
||||
}
|
||||
|
||||
void traffic_mirror_ethdev_destroy(struct traffic_mirror_ethdev * ethdev)
|
||||
{
|
||||
ethdev->fn_destroy(ethdev);
|
||||
}
|
||||
|
||||
int traffic_mirror_ethdev_inject(struct traffic_mirror_ethdev * ethdev, const char * pkt, unsigned int pktlen)
|
||||
{
|
||||
return ethdev->fn_inject(ethdev, pkt, pktlen);
|
||||
}
|
||||
|
||||
struct traffic_mirror_ethdev * traffic_mirror_ethdev_pcap_create(const char * str_ethdev, void * logger)
|
||||
{
|
||||
struct traffic_mirror_ethdev * ethdev = ALLOC(struct traffic_mirror_ethdev, 1);
|
||||
char pcap_errbuf[PCAP_ERRBUF_SIZE] = {};
|
||||
|
||||
int fd = 0;
|
||||
struct ifreq if_req{};
|
||||
|
||||
ethdev->en_offload_ip_cksum = 0;
|
||||
ethdev->en_offload_tcp_cksum = 0;
|
||||
ethdev->en_offload_vlan = 0;
|
||||
|
||||
/* open the device by pcap */
|
||||
ethdev->pcap_device_handle = pcap_open_live(str_ethdev, 0, 0, 0, pcap_errbuf);
|
||||
if (!ethdev->pcap_device_handle)
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "failed at pcap_open_live(), device = %s: %s", str_ethdev, pcap_errbuf);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* local ether address */
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(fd < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "failed at create socket: %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memset(&if_req, 0, sizeof(if_req));
|
||||
strncpy(if_req.ifr_ifrn.ifrn_name, str_ethdev, IFNAMSIZ - 1);
|
||||
|
||||
if(ioctl(fd, SIOCGIFHWADDR, &if_req) < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "failed at read hwaddr of device %s: %s", str_ethdev, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 6; i++)
|
||||
{
|
||||
ethdev->local_ether_addr[i] = if_req.ifr_ifru.ifru_hwaddr.sa_data[i];
|
||||
}
|
||||
|
||||
/* MTU */
|
||||
memset(&if_req, 0, sizeof(if_req));
|
||||
strncpy(if_req.ifr_ifrn.ifrn_name, str_ethdev, IFNAMSIZ - 1);
|
||||
|
||||
if (ioctl(fd, SIOCGIFMTU, &if_req) < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "failed at read mtu of device %s: %s", str_ethdev, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ethdev->mtu = if_req.ifr_ifru.ifru_mtu;
|
||||
strncpy(ethdev->str_device, str_ethdev, sizeof(ethdev->str_device) - 1);
|
||||
|
||||
TFE_LOG_INFO(logger, "traffic mirror device %s (pcap mode): %02X:%02X:%02X:%02X:%02X:%02X, mtu=%u",
|
||||
ethdev->str_device, ethdev->local_ether_addr[0], ethdev->local_ether_addr[1],
|
||||
ethdev->local_ether_addr[2], ethdev->local_ether_addr[3],
|
||||
ethdev->local_ether_addr[4], ethdev->local_ether_addr[5], ethdev->mtu);
|
||||
|
||||
ethdev->fn_inject = pcap_ethdev_inject;
|
||||
ethdev->fn_destroy = pcap_ethdev_destroy;
|
||||
|
||||
close(fd);
|
||||
return ethdev;
|
||||
|
||||
errout:
|
||||
if (fd > 0) close(fd);
|
||||
if (ethdev->pcap_device_handle) pcap_close(ethdev->pcap_device_handle);
|
||||
if (ethdev) FREE(ðdev);
|
||||
return nullptr;
|
||||
}
|
||||
279
plugin/business/traffic-mirror/src/rebuild.cpp
Normal file
279
plugin/business/traffic-mirror/src/rebuild.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
|
||||
#include <tfe_proxy.h>
|
||||
#include <tfe_utils.h>
|
||||
#include <tfe_types.h>
|
||||
#include <traffic_mirror.h>
|
||||
|
||||
struct traffic_mirror_rebuild
|
||||
{
|
||||
struct tfe_stream_addr * addr;
|
||||
struct profile_table_ex_data * target;
|
||||
struct traffic_mirror_ethdev * ethdev;
|
||||
|
||||
uint32_t c_seq;
|
||||
uint32_t s_seq;
|
||||
uint32_t c_ipid;
|
||||
uint32_t s_ipid;
|
||||
uint8_t c_ttl;
|
||||
uint8_t s_ttl;
|
||||
};
|
||||
|
||||
/* The definition of vlan_hdr and tcp_hdr is from DPDK 17.05 */
|
||||
struct vlan_hdr
|
||||
{
|
||||
uint16_t vlan_tci; /**< Priority (3) + CFI (1) + Identifier Code (12) */
|
||||
uint16_t eth_proto;/**< Ethernet type of encapsulated frame. */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct tcp_hdr {
|
||||
uint16_t src_port; /**< TCP source port. */
|
||||
uint16_t dst_port; /**< TCP destination port. */
|
||||
uint32_t sent_seq; /**< TX data sequence number. */
|
||||
uint32_t recv_ack; /**< RX data acknowledgement sequence number. */
|
||||
uint8_t data_off; /**< Data offset. */
|
||||
uint8_t tcp_flags; /**< TCP flags */
|
||||
uint16_t rx_win; /**< RX flow control window. */
|
||||
uint16_t cksum; /**< TCP checksum. */
|
||||
uint16_t tcp_urp; /**< TCP urgent pointer, if any. */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define TCP_URG_FLAG 0x20
|
||||
#define TCP_ACK_FLAG 0x10
|
||||
#define TCP_PSH_FLAG 0x08
|
||||
#define TCP_RST_FLAG 0x04
|
||||
#define TCP_SYN_FLAG 0x02
|
||||
#define TCP_FIN_FLAG 0x01
|
||||
#define TCP_FLAG_ALL 0x3F
|
||||
|
||||
static int tcp_header_construct(unsigned char *buf, unsigned short sp,
|
||||
unsigned short dp, unsigned int seq, unsigned int ack,
|
||||
unsigned char flags, unsigned short win, unsigned short urg)
|
||||
{
|
||||
struct tcp_hdr * tcp_hdr = (struct tcp_hdr *) buf;
|
||||
assert(tcp_hdr != NULL);
|
||||
|
||||
tcp_hdr->src_port = sp;
|
||||
tcp_hdr->dst_port = dp;
|
||||
tcp_hdr->sent_seq = htonl(seq);
|
||||
tcp_hdr->recv_ack = htonl(ack);
|
||||
tcp_hdr->data_off = 5;
|
||||
tcp_hdr->tcp_flags = flags;
|
||||
tcp_hdr->rx_win = htons(win);
|
||||
tcp_hdr->cksum = 0;
|
||||
tcp_hdr->tcp_urp = 0;
|
||||
return sizeof(struct tcp_hdr);
|
||||
}
|
||||
|
||||
static int tcp_header_construct_by_stream_addr(struct tfe_stream_addr * addr, unsigned char *buf,
|
||||
unsigned int seq, unsigned int ack, unsigned char flags, unsigned short win, unsigned short urg)
|
||||
{
|
||||
unsigned short sport;
|
||||
unsigned short dport;
|
||||
|
||||
if (addr->addrtype == TFE_ADDR_STREAM_TUPLE4_V4)
|
||||
{
|
||||
sport = addr->tuple4_v4->source;
|
||||
dport = addr->tuple4_v4->dest;
|
||||
}
|
||||
else if (addr->addrtype == TFE_ADDR_STREAM_TUPLE4_V6)
|
||||
{
|
||||
sport = addr->tuple4_v6->source;
|
||||
dport = addr->tuple4_v6->dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return tcp_header_construct(buf, sport, dport, seq, ack, flags, win, urg);
|
||||
}
|
||||
|
||||
static int ipv4_header_construct(unsigned char *buf, unsigned short carry_layer_len,
|
||||
unsigned char tos, unsigned short id, unsigned short frag, unsigned char ttl,
|
||||
unsigned char protocol, unsigned int src, unsigned int dst)
|
||||
{
|
||||
struct iphdr * ip_hdr = (struct iphdr *) buf;
|
||||
ip_hdr->version = 4;
|
||||
ip_hdr->ihl = 5;
|
||||
ip_hdr->tos = tos;
|
||||
ip_hdr->tot_len = htons(sizeof(struct iphdr) + carry_layer_len);
|
||||
ip_hdr->id = htons(id);
|
||||
ip_hdr->frag_off = 0;
|
||||
ip_hdr->ttl = ttl;
|
||||
ip_hdr->protocol = protocol;
|
||||
ip_hdr->check = 0;
|
||||
ip_hdr->saddr = src;
|
||||
ip_hdr->daddr = dst;
|
||||
|
||||
return sizeof(struct iphdr);
|
||||
}
|
||||
|
||||
static int ip_header_construct_by_stream_addr(struct tfe_stream_addr * addr,
|
||||
unsigned char *buf, unsigned short carry_layer_len, unsigned char tos,
|
||||
unsigned short id, unsigned short frag, unsigned char ttl, unsigned char protocol)
|
||||
{
|
||||
if (addr->addrtype == TFE_ADDR_STREAM_TUPLE4_V4)
|
||||
{
|
||||
return ipv4_header_construct(buf, carry_layer_len, tos, id,
|
||||
frag, ttl, protocol, addr->tuple4_v4->saddr.s_addr, addr->tuple4_v4->daddr.s_addr);
|
||||
}
|
||||
else if (addr->addrtype == TFE_ADDR_STREAM_TUPLE4_V6)
|
||||
{
|
||||
/* TODO: IPv6 */
|
||||
assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ether_header_construct(unsigned char *buf, unsigned char *dst,
|
||||
unsigned char *src, unsigned short type)
|
||||
{
|
||||
struct ethhdr * eth_hdr = (struct ethhdr *) buf;
|
||||
memcpy(eth_hdr->h_dest, dst, ETHER_ADDR_LEN);
|
||||
memcpy(eth_hdr->h_source, src, ETHER_ADDR_LEN);
|
||||
eth_hdr->h_proto = htons(type);
|
||||
}
|
||||
|
||||
static void vlan_tag_construct(unsigned char *buf, unsigned short tci, unsigned short type)
|
||||
{
|
||||
struct vlan_hdr * vlan_hdr = (struct vlan_hdr *)buf;
|
||||
vlan_hdr->vlan_tci = htons(tci);
|
||||
vlan_hdr->eth_proto = htons(type);
|
||||
}
|
||||
|
||||
static void l2_send_to_target(struct traffic_mirror_ethdev * ethdev,
|
||||
unsigned char * snd_buffer, unsigned int l3_data_offset, unsigned int l3_data_len,
|
||||
struct ether_addr * target_addr, unsigned int vlan_tci, unsigned l3_protocol)
|
||||
{
|
||||
assert(l3_data_offset >= (sizeof(struct ethhdr) + sizeof(struct vlan_hdr)));
|
||||
unsigned int header_offset = l3_data_offset;
|
||||
|
||||
/* need to construct vlan header */
|
||||
if (vlan_tci > 0)
|
||||
{
|
||||
header_offset -= sizeof(struct vlan_hdr);
|
||||
vlan_tag_construct(snd_buffer + header_offset, vlan_tci, l3_protocol);
|
||||
}
|
||||
|
||||
unsigned int eth_protocol = vlan_tci > 0 ? ETH_P_8021Q : l3_protocol;
|
||||
header_offset -= sizeof(struct ethhdr);
|
||||
|
||||
ether_header_construct(snd_buffer + header_offset, (unsigned char *)target_addr->ether_addr_octet,
|
||||
(unsigned char *)ethdev->local_ether_addr, eth_protocol);
|
||||
}
|
||||
|
||||
static void l2_send_to_target_group(struct traffic_mirror_ethdev * ethdev, struct profile_table_ex_data * t_group,
|
||||
unsigned char * snd_buffer, unsigned int l3_data_offset, unsigned int l3_data_len, unsigned l3_protocol)
|
||||
{
|
||||
for(unsigned int i = 0; i < t_group->nr_targets; i++)
|
||||
{
|
||||
l2_send_to_target(ethdev, snd_buffer, l3_data_offset, l3_data_len,
|
||||
&t_group->ether_addrs[i], t_group->vlans[i], l3_protocol);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcp_segment_send_to_target_group(struct tfe_stream_addr * addr, struct traffic_mirror_ethdev * ethdev,
|
||||
struct profile_table_ex_data * t_group, const char * payload, unsigned int payload_len,
|
||||
unsigned int seq, unsigned int ack, char flags)
|
||||
{
|
||||
char pkt[ETHER_MAX_LEN];
|
||||
unsigned sz_pkt_prepend = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr);
|
||||
unsigned l3_l4_header_len = 0;
|
||||
|
||||
l3_l4_header_len += tcp_header_construct_by_stream_addr(addr,
|
||||
(unsigned char *)pkt + sz_pkt_prepend, seq, ack, flags, 0xffff, 0);
|
||||
|
||||
l3_l4_header_len += ip_header_construct_by_stream_addr(addr, (unsigned char *)pkt + sz_pkt_prepend,
|
||||
sizeof(struct tcphdr) + payload_len, 0, 0x1000, 0, 128, IPPROTO_TCP);
|
||||
|
||||
sz_pkt_prepend -= l3_l4_header_len;
|
||||
|
||||
l2_send_to_target_group(ethdev, t_group, (unsigned char *)pkt,
|
||||
sz_pkt_prepend, l3_l4_header_len + payload_len, ETHERTYPE_IP);
|
||||
}
|
||||
|
||||
static void tcp_send_to_target_group(struct tfe_stream_addr * addr, struct traffic_mirror_ethdev * ethdev,
|
||||
struct profile_table_ex_data * t_group, const char * payload,
|
||||
unsigned int payload_len, unsigned int seq, unsigned int ack, char flags)
|
||||
{
|
||||
unsigned int payload_offset = 0;
|
||||
unsigned mss = ethdev->mtu - (sizeof(struct iphdr) + sizeof(struct tcphdr));
|
||||
|
||||
while(payload_offset < payload_len)
|
||||
{
|
||||
unsigned int payload_sz_seg = MIN(payload_offset, mss);
|
||||
const char * payload_ptr_seg = payload + payload_offset;
|
||||
|
||||
tcp_segment_send_to_target_group(addr, ethdev, t_group, payload_ptr_seg, payload_sz_seg, seq, ack, flags);
|
||||
seq += payload_sz_seg;
|
||||
payload_offset += payload_sz_seg;
|
||||
}
|
||||
}
|
||||
|
||||
struct traffic_mirror_rebuild * traffic_mirror_rebuild_create(struct tfe_stream_addr * addr,
|
||||
struct profile_table_ex_data * target, struct traffic_mirror_ethdev * ethdev)
|
||||
{
|
||||
struct traffic_mirror_rebuild * instance = ALLOC(struct traffic_mirror_rebuild, 1);
|
||||
instance->target = target;
|
||||
instance->ethdev = ethdev;
|
||||
|
||||
/* the c_seq, s_seq, c_ipid, s_ipid is random
|
||||
* TODO: use the fast random algorithm like Linux TCP/IP stack */
|
||||
instance->c_seq = random();
|
||||
instance->s_seq = random();
|
||||
instance->c_ipid = random();
|
||||
instance->s_ipid = random();
|
||||
instance->s_ttl = 128;
|
||||
instance->c_ttl = 64;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void traffic_mirror_rebuild_destroy(struct traffic_mirror_rebuild * instance)
|
||||
{
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void traffic_mirror_rebuild_handshake(struct traffic_mirror_rebuild * instance)
|
||||
{
|
||||
tcp_send_to_target_group(instance->addr, instance->ethdev, instance->target,
|
||||
NULL, 0, instance->c_seq, 0, TCP_SYN_FLAG);
|
||||
|
||||
tcp_send_to_target_group(instance->addr, instance->ethdev, instance->target,
|
||||
NULL, 0, instance->s_seq, instance->c_seq + 1, TCP_SYN_FLAG | TCP_ACK_FLAG);
|
||||
|
||||
tcp_send_to_target_group(instance->addr, instance->ethdev, instance->target,
|
||||
NULL, 0, instance->c_seq + 1, instance->s_seq + 1, TCP_ACK_FLAG);
|
||||
|
||||
instance->s_seq++;
|
||||
instance->c_seq++;
|
||||
}
|
||||
|
||||
void traffic_mirror_rebuild_data(struct traffic_mirror_rebuild * instance,
|
||||
const char * data, unsigned int datalen, enum tfe_conn_dir dir)
|
||||
{
|
||||
if (dir == CONN_DIR_DOWNSTREAM)
|
||||
{
|
||||
tcp_send_to_target_group(instance->addr, instance->ethdev, instance->target,
|
||||
NULL, 0, instance->c_seq, instance->s_seq + 1, TCP_ACK_FLAG);
|
||||
|
||||
instance->c_seq += datalen;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcp_send_to_target_group(instance->addr, instance->ethdev, instance->target,
|
||||
NULL, 0, instance->s_seq, instance->c_seq + 1, TCP_ACK_FLAG);
|
||||
|
||||
instance->s_seq += datalen;
|
||||
}
|
||||
}
|
||||
|
||||
void traffic_mirror_rebuild_farewell(struct traffic_mirror_rebuild * instance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Reference in New Issue
Block a user