2024-06-27 15:07:54 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
|
|
#include "toml.h"
|
2024-08-06 20:37:59 +08:00
|
|
|
#include "stellar/stellar.h"
|
2024-06-27 15:07:54 +08:00
|
|
|
#include "stellar/layer.h"
|
2024-08-06 20:37:59 +08:00
|
|
|
#include "stellar/session.h"
|
|
|
|
|
#include "stellar/stellar_mq.h"
|
2024-06-27 15:07:54 +08:00
|
|
|
|
|
|
|
|
#define LOG_ERR(fmt, ...) printf("ERROR [packet inject] " fmt, ##__VA_ARGS__)
|
|
|
|
|
#define LOG_INFO(fmt, ...) printf("INFO [packet inject] " fmt, ##__VA_ARGS__)
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
* Config
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
enum inject_type
|
|
|
|
|
{
|
|
|
|
|
INJECT_TCP_RST = 1,
|
|
|
|
|
INJECT_TCP_FIN = 2,
|
|
|
|
|
INJECT_TCP_PAYLOAD = 3,
|
|
|
|
|
INJECT_TCP_PAYLOAD_FIN_RST = 4,
|
|
|
|
|
INJECT_UDP_PAYLOAD = 5,
|
|
|
|
|
INJECT_CTRL_MSG = 6,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct config
|
|
|
|
|
{
|
|
|
|
|
int family; // AF_INET or AF_INET6
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
struct sockaddr_in v4;
|
|
|
|
|
struct sockaddr_in6 v6;
|
|
|
|
|
} addr;
|
|
|
|
|
uint16_t port;
|
|
|
|
|
uint64_t number; // inject packet after (C2S/S2C) direction receiving n packets
|
|
|
|
|
enum inject_type type;
|
|
|
|
|
enum flow_direction direction;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char *inject_type_to_str(enum inject_type type)
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case INJECT_TCP_RST:
|
|
|
|
|
return "TCP-RST";
|
|
|
|
|
case INJECT_TCP_FIN:
|
|
|
|
|
return "TCP-FIN";
|
|
|
|
|
case INJECT_TCP_PAYLOAD:
|
|
|
|
|
return "TCP-PAYLOAD";
|
|
|
|
|
case INJECT_TCP_PAYLOAD_FIN_RST:
|
|
|
|
|
return "TCP-PAYLOAD-FIN-RST";
|
|
|
|
|
case INJECT_UDP_PAYLOAD:
|
|
|
|
|
return "UDP-PAYLOAD";
|
|
|
|
|
case INJECT_CTRL_MSG:
|
|
|
|
|
return "CTRL-MSG";
|
|
|
|
|
default:
|
|
|
|
|
return "UNKNOWN";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int load_config(struct config *config, const char *file)
|
|
|
|
|
{
|
|
|
|
|
int ret = -1;
|
|
|
|
|
char errbuf[200];
|
|
|
|
|
const char *ptr;
|
|
|
|
|
FILE *fp = NULL;
|
|
|
|
|
toml_table_t *root = NULL;
|
|
|
|
|
toml_table_t *sub = NULL;
|
|
|
|
|
memset(config, 0, sizeof(struct config));
|
|
|
|
|
|
|
|
|
|
fp = fopen(file, "r");
|
|
|
|
|
if (fp == NULL)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("open config file %s failed, %s\n", file, strerror(errno));
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
root = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
|
|
|
|
if (root == NULL)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("parse config file %s failed, %s\n", file, errbuf);
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub = toml_table_in(root, "packet_inject");
|
|
|
|
|
if (sub == NULL)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("config file missing packet_inject section\n");
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptr = toml_raw_in(sub, "filter_ip");
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("config file missing packet_inject->filter_ip\n");
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(ptr, "any") == 0)
|
|
|
|
|
{
|
|
|
|
|
config->family = AF_UNSPEC;
|
|
|
|
|
}
|
|
|
|
|
else if (inet_pton(AF_INET, ptr, &config->addr.v4.sin_addr) == 1)
|
|
|
|
|
{
|
|
|
|
|
config->family = AF_INET;
|
|
|
|
|
}
|
|
|
|
|
else if (inet_pton(AF_INET6, ptr, &config->addr.v6.sin6_addr) == 1)
|
|
|
|
|
{
|
|
|
|
|
config->family = AF_INET6;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("parse packet_inject->filter_ip failed, invalid ip address: %s\n", ptr);
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptr = toml_raw_in(sub, "filter_port");
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("config file missing packet_inject->filter_port\n");
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
config->port = atoi(ptr);
|
|
|
|
|
|
|
|
|
|
ptr = toml_raw_in(sub, "filter_dir");
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("config file missing packet_inject->filter_dir\n");
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(ptr, "C2S") == 0)
|
|
|
|
|
{
|
|
|
|
|
config->direction = FLOW_DIRECTION_C2S;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(ptr, "S2C") == 0)
|
|
|
|
|
{
|
|
|
|
|
config->direction = FLOW_DIRECTION_S2C;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("parse packet_inject->filter_dir failed, invalid direction: %s\n", ptr);
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptr = toml_raw_in(sub, "filter_pkts");
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("config file missing packet_inject->filter_pkts\n");
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
config->number = atoi(ptr);
|
|
|
|
|
if (config->number == 0)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("parse packet_inject->filter_pkts failed, invalid number: %s\n", ptr);
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptr = toml_raw_in(sub, "inject_type");
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("config file missing packet_inject->inject_type\n");
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(ptr, "TCP-RST") == 0)
|
|
|
|
|
{
|
|
|
|
|
config->type = INJECT_TCP_RST;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(ptr, "TCP-FIN") == 0)
|
|
|
|
|
{
|
|
|
|
|
config->type = INJECT_TCP_FIN;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(ptr, "TCP-PAYLOAD") == 0)
|
|
|
|
|
{
|
|
|
|
|
config->type = INJECT_TCP_PAYLOAD;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(ptr, "TCP-PAYLOAD-FIN-RST") == 0)
|
|
|
|
|
{
|
|
|
|
|
config->type = INJECT_TCP_PAYLOAD_FIN_RST;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(ptr, "UDP-PAYLOAD") == 0)
|
|
|
|
|
{
|
|
|
|
|
config->type = INJECT_UDP_PAYLOAD;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(ptr, "CTRL-MSG") == 0)
|
|
|
|
|
{
|
|
|
|
|
config->type = INJECT_CTRL_MSG;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("parse packet_inject->inject_type failed, invalid inject type: %s\n", ptr);
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
|
|
error_out:
|
|
|
|
|
if (root)
|
|
|
|
|
{
|
|
|
|
|
toml_free(root);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fp)
|
|
|
|
|
{
|
|
|
|
|
fclose(fp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void print_config(const struct config *config)
|
|
|
|
|
{
|
|
|
|
|
char addr_str[INET6_ADDRSTRLEN] = {0};
|
|
|
|
|
|
|
|
|
|
switch (config->family)
|
|
|
|
|
{
|
|
|
|
|
case AF_INET:
|
|
|
|
|
inet_ntop(AF_INET, &config->addr.v4, addr_str, INET6_ADDRSTRLEN);
|
|
|
|
|
break;
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
inet_ntop(AF_INET6, &config->addr.v6, addr_str, INET6_ADDRSTRLEN);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
snprintf(addr_str, INET6_ADDRSTRLEN, "any");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_INFO("config->filter_ip : %s\n", addr_str);
|
|
|
|
|
LOG_INFO("config->filter_port : %d\n", config->port);
|
|
|
|
|
LOG_INFO("config->filter_dir : %s\n", config->direction == FLOW_DIRECTION_C2S ? "C2S" : "S2C");
|
|
|
|
|
LOG_INFO("config->filter_pkts : %lu\n", config->number);
|
|
|
|
|
LOG_INFO("config->inject_type : %s\n", inject_type_to_str(config->type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
* Utils
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
struct packet_exdata
|
|
|
|
|
{
|
|
|
|
|
enum flow_direction flow_dir;
|
|
|
|
|
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
struct in_addr v4;
|
|
|
|
|
struct in6_addr v6;
|
|
|
|
|
} src_addr, dst_addr;
|
|
|
|
|
|
|
|
|
|
uint16_t src_port; // host byte order
|
|
|
|
|
uint16_t dst_port; // host byte order
|
|
|
|
|
|
|
|
|
|
uint16_t tcp_payload_len;
|
|
|
|
|
uint32_t tcp_seq; // host byte order
|
|
|
|
|
uint32_t tcp_ack; // host byte order
|
|
|
|
|
uint8_t tcp_flags;
|
|
|
|
|
|
|
|
|
|
uint32_t inc_seq;
|
|
|
|
|
uint32_t inc_ack;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static inline void packet_exdata_init(const struct packet *pkt, enum flow_direction dir, struct packet_exdata *pkt_exdata)
|
|
|
|
|
{
|
|
|
|
|
memset(pkt_exdata, 0, sizeof(struct packet_exdata));
|
|
|
|
|
|
|
|
|
|
pkt_exdata->flow_dir = dir;
|
|
|
|
|
|
|
|
|
|
int get_inner_addr = 0;
|
|
|
|
|
struct layer layer;
|
|
|
|
|
PACKET_FOREACH_LAYER_REVERSE(pkt, layer)
|
|
|
|
|
{
|
|
|
|
|
switch (layer.proto)
|
|
|
|
|
{
|
|
|
|
|
case LAYER_PROTO_TCP:
|
|
|
|
|
pkt_exdata->src_port = ntohs(layer.hdr.tcp->th_sport);
|
|
|
|
|
pkt_exdata->dst_port = ntohs(layer.hdr.tcp->th_dport);
|
|
|
|
|
pkt_exdata->tcp_seq = ntohl(layer.hdr.tcp->th_seq);
|
|
|
|
|
pkt_exdata->tcp_ack = ntohl(layer.hdr.tcp->th_ack);
|
|
|
|
|
pkt_exdata->tcp_flags = layer.hdr.tcp->th_flags;
|
|
|
|
|
pkt_exdata->tcp_payload_len = packet_get_payload_len(pkt);
|
|
|
|
|
break;
|
|
|
|
|
case LAYER_PROTO_UDP:
|
|
|
|
|
pkt_exdata->src_port = ntohs(layer.hdr.udp->uh_sport);
|
|
|
|
|
pkt_exdata->dst_port = ntohs(layer.hdr.udp->uh_dport);
|
|
|
|
|
break;
|
|
|
|
|
case LAYER_PROTO_IPV4:
|
|
|
|
|
pkt_exdata->src_addr.v4 = layer.hdr.ip4->ip_src;
|
|
|
|
|
pkt_exdata->dst_addr.v4 = layer.hdr.ip4->ip_dst;
|
|
|
|
|
get_inner_addr = 1;
|
|
|
|
|
break;
|
|
|
|
|
case LAYER_PROTO_IPV6:
|
|
|
|
|
pkt_exdata->src_addr.v6 = layer.hdr.ip6->ip6_src;
|
|
|
|
|
pkt_exdata->dst_addr.v6 = layer.hdr.ip6->ip6_dst;
|
|
|
|
|
get_inner_addr = 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (get_inner_addr)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline uint32_t uint32_add(uint32_t seq, uint32_t inc)
|
|
|
|
|
{
|
|
|
|
|
if (seq > UINT32_MAX - inc)
|
|
|
|
|
{
|
|
|
|
|
seq = ((uint64_t)seq + (uint64_t)inc) % (4294967296);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
seq += inc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return seq;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-15 15:07:38 +08:00
|
|
|
static void craft_and_send_udp_packet(struct stellar *st, struct session *sess, struct packet_exdata *pkt_exdata,
|
|
|
|
|
enum flow_direction inject_dir, const char *udp_payload, uint16_t udp_payload_len)
|
2024-06-27 15:07:54 +08:00
|
|
|
{
|
|
|
|
|
const struct packet *origin_pkt = session_get_first_packet(sess, inject_dir);
|
|
|
|
|
if (origin_pkt == NULL)
|
|
|
|
|
{
|
2024-07-15 15:07:38 +08:00
|
|
|
LOG_ERR("craft UDP packet failed, %s origin packet is NULL\n", inject_dir == FLOW_DIRECTION_C2S ? "C2S" : "S2C");
|
2024-06-27 15:07:54 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-15 15:07:38 +08:00
|
|
|
struct packet *craft_pkt = craft_udp_packet(origin_pkt, udp_payload, udp_payload_len);
|
|
|
|
|
if (craft_pkt == NULL)
|
2024-06-27 15:07:54 +08:00
|
|
|
{
|
2024-07-15 15:07:38 +08:00
|
|
|
LOG_ERR("craft UDP packet failed\n");
|
2024-06-27 15:07:54 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-15 15:07:38 +08:00
|
|
|
stellar_send_crafted_packet(st, craft_pkt);
|
2024-06-27 15:07:54 +08:00
|
|
|
}
|
|
|
|
|
|
2024-07-15 15:07:38 +08:00
|
|
|
static void craft_and_send_tcp_packet(struct stellar *st, struct session *sess, struct packet_exdata *pkt_exdata,
|
|
|
|
|
enum flow_direction inject_dir, uint8_t tcp_flags, const char *tcp_payload, uint16_t tcp_payload_len)
|
2024-06-27 15:07:54 +08:00
|
|
|
{
|
|
|
|
|
uint32_t tcp_seq = 0;
|
|
|
|
|
uint32_t tcp_ack = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* +--------+ current packet +---------+ C2S RST +--------+
|
|
|
|
|
* | |----------------->| |----------------->| |
|
|
|
|
|
* | Client | | Stellar | | Server |
|
|
|
|
|
* | |<-----------------| |<-----------------| |
|
|
|
|
|
* +--------+ S2C RST +---------+ +--------+
|
|
|
|
|
*
|
|
|
|
|
* for example: current packet is C2S
|
|
|
|
|
*
|
|
|
|
|
* inject direction == current direction (inject C2S RST)
|
|
|
|
|
* tcp_seq = current_packet_seq
|
|
|
|
|
* tcp_ack = current_packet_ack
|
|
|
|
|
*
|
|
|
|
|
* inject direction != current direction (inject S2C RST)
|
|
|
|
|
* tcp_seq = current_packet_ack
|
|
|
|
|
* tcp_ack = current_packet_seq + current_packet_payload_len
|
|
|
|
|
* or if current packet is a SYN-ACK packet
|
|
|
|
|
* tcp_seq = current_packet_seq
|
|
|
|
|
* tcp_ack = current_packet_ack + current_packet_payload_len + 1
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (inject_dir == pkt_exdata->flow_dir)
|
|
|
|
|
{
|
|
|
|
|
tcp_seq = uint32_add(pkt_exdata->tcp_seq, pkt_exdata->inc_seq);
|
|
|
|
|
tcp_ack = pkt_exdata->tcp_ack;
|
|
|
|
|
|
|
|
|
|
pkt_exdata->inc_seq += tcp_payload_len;
|
|
|
|
|
pkt_exdata->inc_seq += (tcp_flags & TH_FIN) ? 1 : 0; // inject RST packer after FIN packer, tcp_seq should be increased by 1
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tcp_seq = uint32_add(pkt_exdata->tcp_ack, pkt_exdata->inc_ack);
|
|
|
|
|
tcp_ack = uint32_add(pkt_exdata->tcp_seq, pkt_exdata->tcp_payload_len + (pkt_exdata->tcp_flags & TH_SYN ? 1 : 0));
|
|
|
|
|
|
|
|
|
|
pkt_exdata->inc_ack += tcp_payload_len;
|
|
|
|
|
pkt_exdata->inc_ack += (tcp_flags & TH_FIN) ? 1 : 0; // inject RST packer after FIN packer, ack should be increased by 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const struct packet *origin_pkt = session_get_first_packet(sess, inject_dir);
|
|
|
|
|
if (origin_pkt == NULL)
|
|
|
|
|
{
|
2024-07-15 15:07:38 +08:00
|
|
|
LOG_ERR("craft TCP packet failed, %s origin packet is NULL\n", inject_dir == FLOW_DIRECTION_C2S ? "C2S" : "S2C");
|
2024-06-27 15:07:54 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-15 15:07:38 +08:00
|
|
|
struct packet *craft_pkt = craft_tcp_packet(origin_pkt, tcp_seq, tcp_ack, tcp_flags, NULL, 0, tcp_payload, tcp_payload_len);
|
|
|
|
|
if (craft_pkt == NULL)
|
2024-06-27 15:07:54 +08:00
|
|
|
{
|
2024-07-15 15:07:38 +08:00
|
|
|
LOG_ERR("craft TCP packet failed\n");
|
2024-06-27 15:07:54 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-15 15:07:38 +08:00
|
|
|
stellar_send_crafted_packet(st, craft_pkt);
|
2024-06-27 15:07:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
* Core logic
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
struct plugin_ctx
|
|
|
|
|
{
|
|
|
|
|
struct config config;
|
|
|
|
|
struct stellar *st;
|
|
|
|
|
int sess_plug_id;
|
|
|
|
|
int tcp_topic_id;
|
|
|
|
|
int udp_topic_id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void *on_sess_new(struct session *sess, void *plugin_ctx)
|
|
|
|
|
{
|
|
|
|
|
// struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx;
|
|
|
|
|
LOG_INFO("handle session new: %s\n", session_get0_readable_addr(sess));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void on_sess_free(struct session *sess, void *sess_ctx, void *plugin_ctx)
|
|
|
|
|
{
|
|
|
|
|
// struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx;
|
|
|
|
|
LOG_INFO("handle session free: %s\n", session_get0_readable_addr(sess));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void on_sess_msg(struct session *sess, int topic_id, const void *msg, void *sess_ctx, void *plugin_ctx)
|
|
|
|
|
{
|
2024-08-07 10:56:58 +08:00
|
|
|
if(msg==NULL)return;// session closing, return directly
|
|
|
|
|
|
2024-06-27 15:07:54 +08:00
|
|
|
char buffer[1024] = {0};
|
|
|
|
|
struct packet *pkt = (struct packet *)msg;
|
|
|
|
|
struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx;
|
|
|
|
|
struct stellar *st = ctx->st;
|
|
|
|
|
struct config *config = &ctx->config;
|
|
|
|
|
enum flow_direction flow_dir = session_get_current_flow_direction(sess);
|
|
|
|
|
LOG_INFO("handle session msg: %s (C2S received packets: %lu, S2C received packets: %lu)\n",
|
|
|
|
|
session_get0_readable_addr(sess),
|
|
|
|
|
session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_RAW_PACKETS_RECEIVED),
|
|
|
|
|
session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_RAW_PACKETS_RECEIVED));
|
|
|
|
|
|
|
|
|
|
struct packet_exdata pkt_exdata;
|
|
|
|
|
packet_exdata_init(pkt, flow_dir, &pkt_exdata);
|
|
|
|
|
|
|
|
|
|
if (config->family == AF_INET &&
|
|
|
|
|
memcmp(&config->addr.v4, &pkt_exdata.src_addr.v4, sizeof(struct in_addr)) != 0 &&
|
|
|
|
|
memcmp(&config->addr.v4, &pkt_exdata.dst_addr.v4, sizeof(struct in_addr)) != 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config->family == AF_INET6 &&
|
|
|
|
|
memcmp(&config->addr.v6, &pkt_exdata.src_addr.v6, sizeof(struct in6_addr)) != 0 &&
|
|
|
|
|
memcmp(&config->addr.v6, &pkt_exdata.dst_addr.v6, sizeof(struct in6_addr)) != 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config->port &&
|
|
|
|
|
pkt_exdata.src_port != config->port &&
|
|
|
|
|
pkt_exdata.dst_port != config->port)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_INJECTED_PACKETS_SUCCESS) > 0 ||
|
|
|
|
|
session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_INJECTED_PACKETS_SUCCESS) > 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config->direction == FLOW_DIRECTION_C2S && session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_RAW_PACKETS_RECEIVED) != config->number)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config->direction == FLOW_DIRECTION_S2C && session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_RAW_PACKETS_RECEIVED) != config->number)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (config->type)
|
|
|
|
|
{
|
|
|
|
|
case INJECT_TCP_RST:
|
2024-07-15 15:07:38 +08:00
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_C2S, TH_RST | TH_ACK, NULL, 0);
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, TH_RST | TH_ACK, NULL, 0);
|
2024-06-27 15:07:54 +08:00
|
|
|
session_set_discard(sess);
|
|
|
|
|
break;
|
|
|
|
|
case INJECT_TCP_FIN:
|
2024-07-15 15:07:38 +08:00
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_C2S, TH_FIN | TH_ACK, NULL, 0);
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, TH_FIN | TH_ACK, NULL, 0);
|
2024-06-27 15:07:54 +08:00
|
|
|
session_set_discard(sess);
|
|
|
|
|
break;
|
|
|
|
|
case INJECT_TCP_PAYLOAD:
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s", 5 + 5 + 2, "Hello");
|
2024-07-15 15:07:38 +08:00
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, TH_ACK, buffer, strlen(buffer)); // inject payload to client
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, TH_ACK, "World\r\n", 7); // inject payload to client
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, TH_RST | TH_ACK, NULL, 0); // inject RST to client
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_C2S, TH_RST | TH_ACK, NULL, 0); // inject RST to server
|
2024-06-27 15:07:54 +08:00
|
|
|
session_set_discard(sess);
|
|
|
|
|
break;
|
|
|
|
|
case INJECT_TCP_PAYLOAD_FIN_RST:
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s", 5 + 5 + 2, "Hello");
|
2024-07-15 15:07:38 +08:00
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, TH_ACK, buffer, strlen(buffer)); // inject payload to client
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, TH_ACK, "World\r\n", 7); // inject payload to client
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, TH_FIN | TH_ACK, NULL, 0); // inject FIN to client
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, TH_RST | TH_ACK, NULL, 0); // inject RST to client
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_C2S, TH_FIN | TH_ACK, NULL, 0); // inject FIN to server
|
|
|
|
|
craft_and_send_tcp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_C2S, TH_RST | TH_ACK, NULL, 0); // inject RST to server
|
2024-06-27 15:07:54 +08:00
|
|
|
session_set_discard(sess);
|
|
|
|
|
break;
|
|
|
|
|
case INJECT_UDP_PAYLOAD:
|
2024-07-15 15:07:38 +08:00
|
|
|
craft_and_send_udp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_C2S, "Hello Server", 12);
|
|
|
|
|
craft_and_send_udp_packet(st, sess, &pkt_exdata, FLOW_DIRECTION_S2C, "Hello Client", 12);
|
2024-06-27 15:07:54 +08:00
|
|
|
session_set_discard(sess);
|
|
|
|
|
break;
|
|
|
|
|
case INJECT_CTRL_MSG:
|
|
|
|
|
// TOOD
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
* Plugin API
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
void *packet_inject_init(struct stellar *st)
|
|
|
|
|
{
|
|
|
|
|
struct plugin_ctx *ctx = (struct plugin_ctx *)calloc(1, sizeof(struct plugin_ctx));
|
|
|
|
|
if (ctx == NULL)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (load_config(&ctx->config, "./plugin/inject.toml") == -1)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("load config failed\n");
|
|
|
|
|
free(ctx);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
print_config(&ctx->config);
|
|
|
|
|
|
|
|
|
|
ctx->st = st;
|
|
|
|
|
ctx->sess_plug_id = stellar_session_plugin_register(st, on_sess_new, on_sess_free, ctx);
|
2024-08-06 20:37:59 +08:00
|
|
|
ctx->tcp_topic_id = stellar_mq_get_topic_id(st, TOPIC_TCP);
|
|
|
|
|
ctx->udp_topic_id = stellar_mq_get_topic_id(st, TOPIC_UDP);
|
2024-06-27 15:07:54 +08:00
|
|
|
|
|
|
|
|
stellar_session_mq_subscribe(st, ctx->tcp_topic_id, on_sess_msg, ctx->sess_plug_id);
|
|
|
|
|
stellar_session_mq_subscribe(st, ctx->udp_topic_id, on_sess_msg, ctx->sess_plug_id);
|
|
|
|
|
|
|
|
|
|
LOG_INFO("init\n");
|
|
|
|
|
|
|
|
|
|
return ctx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void packet_inject_exit(void *plugin_ctx)
|
|
|
|
|
{
|
|
|
|
|
struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx;
|
|
|
|
|
if (ctx)
|
|
|
|
|
{
|
|
|
|
|
LOG_INFO("exit\n");
|
|
|
|
|
free(ctx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|