summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorliuxueli <[email protected]>2024-11-19 07:18:00 +0000
committerliuxueli <[email protected]>2024-11-27 06:37:23 +0000
commit38307ed232012dcbd44bd95167b8f37c7186d1fb (patch)
treef2be8c66d3e62b18ccb76b0a02a8424ee3edf6ce
parent409833b463c7e43eec4b4cb332485d4755d92486 (diff)
Implement security_enforcer.cpp
-rw-r--r--conf/stellar.toml7
-rw-r--r--enforcer/security/CMakeLists.txt6
-rw-r--r--enforcer/security/bucket.h9
-rw-r--r--enforcer/security/security_enforcer.c1264
-rw-r--r--enforcer/security/security_enforcer.cpp1343
-rw-r--r--enforcer/security/security_enforcer.h29
-rw-r--r--exporter/session_exporter.c2
-rw-r--r--include/stellar/scanner.h1
-rw-r--r--vendors/CMakeLists.txt17
-rw-r--r--vendors/ctemplate-2.3.tar.gzbin0 -> 720717 bytes
-rw-r--r--vendors/patch/compile_ctemplate_use_centos8_with_gcc7.patch10
11 files changed, 1398 insertions, 1290 deletions
diff --git a/conf/stellar.toml b/conf/stellar.toml
index 7e748b8..79575fa 100644
--- a/conf/stellar.toml
+++ b/conf/stellar.toml
@@ -119,6 +119,13 @@
table_info="conf/scanner_sd_maat_tableinfo.json"
json_config_path="conf/scanner_sd_maat_rule.json"
+[security_enforcer]
+http_page_200="./tsgconf/HTTP200.html"
+http_page_403="./tsgconf/HTTP403.html"
+http_page_404="./tsgconf/HTTP404.html"
+#response_packet_mode=[replace, hijack]
+response_packet_mode="replace"
+
[monitor_enforcer]
default_vlan_id=2
diff --git a/enforcer/security/CMakeLists.txt b/enforcer/security/CMakeLists.txt
index 8996c6c..ba6869a 100644
--- a/enforcer/security/CMakeLists.txt
+++ b/enforcer/security/CMakeLists.txt
@@ -1,16 +1,16 @@
add_definitions(-fPIC)
include_directories(${CMAKE_SOURCE_DIR}/deps)
-set(SECURITY_ENFORCER_SRC ${DEPS_SRC} security_maat.c bucket.c)
+set(SECURITY_ENFORCER_SRC ${DEPS_SRC} security_maat.c security_enforcer.cpp bucket.c)
add_library(security_enforcer-static STATIC ${SECURITY_ENFORCER_SRC})
-target_link_libraries(security_enforcer-static fieldstat4 yyjson toml uuid maatframe)
+target_link_libraries(security_enforcer-static fieldstat4 yyjson toml uuid maatframe ctemplate-static)
set_target_properties(security_enforcer-static PROPERTIES OUTPUT_NAME security_enforcer PREFIX "")
set_target_properties(security_enforcer-static PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version.map")
# add_library(security_enforcer-shared SHARED ${SECURITY_ENFORCER_SRC})
# set_target_properties(security_enforcer-shared PROPERTIES OUTPUT_NAME security_enforcer PREFIX "")
# set_target_properties(security_enforcer-shared PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version.map")
-# target_link_libraries(security_enforcer-shared fieldstat4 yyjson toml uuid maatframe)
+# target_link_libraries(security_enforcer-shared fieldstat4 yyjson toml uuid maatframe ctemplate-static)
add_subdirectory(test) \ No newline at end of file
diff --git a/enforcer/security/bucket.h b/enforcer/security/bucket.h
index f5d091e..b4a39c6 100644
--- a/enforcer/security/bucket.h
+++ b/enforcer/security/bucket.h
@@ -1,7 +1,16 @@
#pragma once
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
struct leaky_bucket;
struct leaky_bucket *create_bucket(int bucket_size);
void destroy_bucket(struct leaky_bucket **bucket);
int is_permit_pass(struct leaky_bucket *bucket, int pkt_size);
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/enforcer/security/security_enforcer.c b/enforcer/security/security_enforcer.c
deleted file mode 100644
index 77c7d9c..0000000
--- a/enforcer/security/security_enforcer.c
+++ /dev/null
@@ -1,1264 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stddef.h>
-#include <assert.h>
-#include <arpa/inet.h>
-#include <netinet/ip6.h>
-#include <netinet/tcp.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/icmp6.h>
-#include <netinet/ip_icmp.h>
-
-#include <ctemplate/template.h>
-
-#include <utable.h>
-#include <dns.h>
-
-#include <stellar/utils.h>
-#include <stellar/scanner.h>
-#include <stellar/module.h>
-#include <stellar/session.h>
-#include <stellar/packet.h>
-
-enum PACKET_RESPONSE_MODE
-{
- PACKET_RESPONSE_MODE_NONE=0,
- PACKET_RESPONSE_MODE_REPLACE,
- PACKET_RESPONSE_MODE_HIJACK,
- PACKET_RESPONSE_MODE_MAX
-
-};
-
-struct maat_plugin_table
-{
- const char *name;
- maat_ex_new_func_t *ex_new;
- maat_ex_free_func_t *ex_free;
- maat_ex_dup_func_t *ex_dup;
-};
-
-enum SECURITY_MAAT_PLUGIN
-{
- SECURITY_PLUGIN_UNKNOWN=0,
- SECURITY_PLUGIN_SECURITY_RULE,
- SECURITY_PLUGIN_HTTP_RESPONSE_PAGES,
- SECURITY_PLUGIN_DNS_RESOURCE_RECORD,
- SECURITY_PLUGIN_MAX
-};
-
-struct security_enforcer
-{
- struct logger *logger;
- struct module_manager *mod_mgr;
-
- struct maat *cm_maat;
- struct maat_plugin_table plugin_table[SECURITY_PLUGIN_MAX];
-};
-
-
-struct firewall_rule_enforce_runtime_param
-{
- int packet_response_mode;
- struct tcp_reset_para reset;
- ctemplate::Template *tpl_403,*tpl_404;
- ctemplate::Template *tpl_200,*tpl_204;
- ctemplate::Template *tpl_303;
-};
-
-struct firewall_rule_enforce_runtime_param firewall_rule_enforce_runtime;
-
-
-uint32_t random_integer_generate(int min, int max)
-{
- if(max>min)
- {
- return (rand()%(max-min+1));
- }
-
- return 0;
-}
-
-void uint32_append(char *payload, size_t payload_sz, size_t *payload_offset, uint32_t value)
-{
- if(payload_sz>(*payload_offset)+4)
- {
- *(uint32_t *)(payload+*payload_offset)=(uint32_t)(value);
- (*payload_offset)+=4;
- }
-}
-
-void uint16_hton_append(char *payload, size_t payload_sz, size_t *payload_offset, uint16_t value)
-{
- if(payload_sz>(*payload_offset)+2)
- {
- *(uint16_t *)(payload+*payload_offset)=(uint16_t)htons(value);
- (*payload_offset)+=2;
- }
-}
-
-void uint32_hton_append(char *payload, size_t payload_sz, size_t *payload_offset, uint32_t value)
-{
- if(payload_sz>(*payload_offset)+4)
- {
- *(uint32_t *)(payload+*payload_offset)=(uint32_t)htonl(value);
- (*payload_offset)+=4;
- }
-}
-
-extern "C" int sendpacket_do_checksum(unsigned char *buf, int protocol, int len);
-
-// https://datatracker.ietf.org/doc/html/rfc1071#section-4.1
-
-short computing_ip_checksum(void *payload, int payload_sz)
-{
- int nleft=payload_sz;
- long reverse_checksum=0;
- uint16_t *ushort_ptr=(uint16_t *)payload;
-
- while(nleft>1)
- {
- reverse_checksum+=*ushort_ptr++;
- nleft-=2;
- }
-
- if(nleft==1)
- {
- reverse_checksum=*(unsigned char *)ushort_ptr;
- }
-
- while(reverse_checksum>>16)
- {
- reverse_checksum=(reverse_checksum&0xFFFF)+(reverse_checksum>>16);
- }
-
- return (~reverse_checksum &0xFFFF);
-}
-
-#define ICMPV4_SRCPACKET_MAX_LEN 576
-#define ICMPV6_SRCPACKET_MTU 1280
-
-void deny_sub_action_icmp_enforce(struct session *ss)
-{
- uint16_t l3hdr_len=0;
- uint16_t origin_ip_total_len=0;
- struct iphdr *origin_ipv4=NULL;
- struct ip6_hdr *origin_ipv6=NULL;
- struct iphdr *built_ipv4=NULL;
- struct ip6_hdr *built_ipv6=NULL;
- struct icmphdr *icmp4=NULL;
- struct icmp6_hdr *icmp6=NULL;
-
- uint16_t ip_icmp_hdr_sz=0;
- uint16_t icmp_packe_sz=0;
- char icmp_packet[1500]={0};
- const char *l3hdr=session_get0_current_l3_header(ss);
- if(l3hdr==NULL)
- {
- return ;
- }
-
- enum session_addr_type addr_type=__SESSION_ADDR_TYPE_MAX;
- session_get0_addr(ss, &addr_type);
- switch(addr_type)
- {
- case SESSION_ADDR_TYPE_IPV4_TCP:
- case SESSION_ADDR_TYPE_IPV4_UDP:
- origin_ipv4=(struct iphdr *)l3hdr;
- l3hdr_len=origin_ipv4->ihl*4;
- memcpy(icmp_packet, l3hdr, l3hdr_len);
- origin_ip_total_len=ntohs(origin_ipv4->tot_len);
-
- built_ipv4=(struct iphdr *)icmp_packet;
- built_ipv4->saddr=origin_ipv4->daddr;
- built_ipv4->daddr=origin_ipv4->saddr;
-
- //built_ipv4->check=computing_ip_checksum(icmp_packet, sizeof(struct iphdr));
- ip_icmp_hdr_sz=sizeof(struct iphdr)+sizeof(struct icmphdr);
- icmp_packe_sz=MIN(origin_ip_total_len, ICMPV4_SRCPACKET_MAX_LEN-ip_icmp_hdr_sz)+ip_icmp_hdr_sz;
- built_ipv4->tot_len=htons(icmp_packe_sz);
- built_ipv4->protocol=IPPROTO_ICMP;
-
- icmp4=(struct icmphdr *)(icmp_packet+l3hdr_len);
- icmp4->type=ICMP_UNREACH;
- icmp4->code=ICMP_UNREACH_FILTER_PROHIB;
-
- memcpy(icmp_packet+ip_icmp_hdr_sz, l3hdr, icmp_packe_sz-ip_icmp_hdr_sz);
- sendpacket_do_checksum((unsigned char *)icmp_packet, IPPROTO_ICMP, icmp_packe_sz-l3hdr_len);
- sendpacket_do_checksum((unsigned char *)icmp_packet, IPPROTO_IP, l3hdr_len);
- //icmp4->checksum=computing_ip_checksum(icmp_packet+l3hdr_len, sizeof(struct icmphdr));
- break;
- case SESSION_ADDR_TYPE_IPV6_TCP:
- case SESSION_ADDR_TYPE_IPV6_UDP:
- origin_ipv6=(struct ip6_hdr *)l3hdr;
- l3hdr_len=sizeof(struct ip6_hdr);
- memcpy(icmp_packet, l3hdr, l3hdr_len);
- origin_ip_total_len=ntohs(origin_ipv6->ip6_ctlun.ip6_un1.ip6_un1_plen);
-
- built_ipv6=(struct ip6_hdr *)icmp_packet;
- memcpy((void *)&(built_ipv6->ip6_src), (void *)&(origin_ipv6->ip6_dst), sizeof(struct in6_addr));
- memcpy((void *)&(built_ipv6->ip6_dst), (void *)&(origin_ipv6->ip6_src), sizeof(struct in6_addr));
-
- ip_icmp_hdr_sz=sizeof(struct ip6_hdr)+sizeof(struct icmp6_hdr);
- icmp_packe_sz=MIN(origin_ip_total_len, ICMPV6_SRCPACKET_MTU-ip_icmp_hdr_sz)+ip_icmp_hdr_sz;
- icmp_packe_sz=icmp_packe_sz-(icmp_packe_sz%4); // 4 bytes alignment
- built_ipv6->ip6_ctlun.ip6_un1.ip6_un1_plen=htons(icmp_packe_sz);
- built_ipv6->ip6_ctlun.ip6_un1.ip6_un1_nxt=IPPROTO_ICMPV6;
-
- icmp6=(struct icmp6_hdr *)(icmp_packet+l3hdr_len);
- icmp6->icmp6_type=ICMP6_DST_UNREACH;
- icmp6->icmp6_code=ICMP6_DST_UNREACH;
-
- memcpy(icmp_packet+ip_icmp_hdr_sz, l3hdr, icmp_packe_sz-ip_icmp_hdr_sz);
- //icmp6->icmp6_cksum=computing_ip_checksum(icmp_packet+l3hdr_len, icmp_packe_sz);
- sendpacket_do_checksum((unsigned char *)icmp_packet, IPPROTO_ICMPV6, icmp_packe_sz-l3hdr_len);
- break;
- default:
- return ;
- }
-
- int ret=firewall_packet_inject(ss, icmp_packet, icmp_packe_sz, FALSE);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "icmp", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-}
-
-void deny_sub_action_reset_enforce(struct session *ss)
-{
- enum session_addr_type addr_type=__SESSION_ADDR_TYPE_MAX;
- session_get0_addr(ss, &addr_type);
- if(addr_type==SESSION_ADDR_TYPE_IPV4_TCP || addr_type==SESSION_ADDR_TYPE_IPV6_TCP)
- {
- int ret=firewall_tcp_session_reset(ss, &firewall_rule_enforce_runtime.reset);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "reset", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-
- if(firewall_rule_enforce_runtime.reset.remedy==1)
- {
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_TCP_RESET_REMEDY);
- }
-
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_SESSION);
- }
-}
-
-void deny_sub_action_drop_enforce(struct session *ss, struct sub_action_drop *drop)
-{
- if(drop==NULL)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "drop", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return;
- }
-
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_SESSION);
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
-
- if(drop->send_icmp_enable)
- {
- deny_sub_action_icmp_enforce(ss);
- }
-
- if(drop->send_reset_enable)
- {
- deny_sub_action_reset_enforce(ss);
- }
-
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_OK, TAG_KEY_SUB_ACTION_ENFORCE, "drop", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-}
-
-void firewall_session_drop(struct session *ss, char *service)
-{
- if(ss==NULL)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, service, "drop", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_SESSION);
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_OK, service, "drop", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-}
-
-size_t sip_response_body_append(char *response_body, size_t response_body_sz, struct utable *putable, const char *field_name, const char *field_prefix)
-{
- char *sip_field=NULL;
- size_t sip_field_sz=0;
- size_t field_prefix_sz=strlen(field_prefix);
-
- utable_get0_cstring_value(putable, field_name, &sip_field, &sip_field_sz);
- if(response_body_sz<sip_field_sz+field_prefix_sz)
- {
- return 0;
- }
-
- memcpy(response_body, field_prefix, field_prefix_sz);
- memcpy(response_body+field_prefix_sz, sip_field, sip_field_sz);
-
- return sip_field_sz+field_prefix_sz;
-}
-
-void deny_sub_action_sip_block_enforce(struct session *ss, struct sub_action_response *response, struct utable *putable)
-{
- if(putable==NULL)
- {
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
- return ;
- }
-
- int64_t sip_is_req=0;
- utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_IS_REQUERST].log_field_name, &sip_is_req);
- switch(firewall_rule_enforce_runtime.packet_response_mode)
- {
- case PACKET_RESPONSE_MODE_HIJACK:
- if(sip_is_req==0) // response
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_OK, TAG_KEY_SUB_ACTION_ENFORCE, "block_sip_request", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
- break;
- case PACKET_RESPONSE_MODE_REPLACE:
- if(sip_is_req==1) // query
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_OK, TAG_KEY_SUB_ACTION_ENFORCE, "block_sip_response", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
- break;
- default:
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "packet_response_mode", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- int offset=0;
- char payload[1024]={0};
- switch(response->code)
- {
- case 480:
- //"SIP/2.0 480 Temporarily Unavailable\r\n"
- offset=strlen("SIP/2.0 480 Temporarily Unavailable\r\n");
- memcpy(payload, "SIP/2.0 480 Temporarily Unavailable\r\n", offset);
- break;
- case 500:
- //"SIP/2.0 500 Server Internal Error\r\n",
- offset=strlen("SIP/2.0 500 Server Internal Error\r\n");
- memcpy(payload, "SIP/2.0 500 Server Internal Error\r\n", offset);
- break;
- default:
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
- return ;
- }
-
- offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_VIA].log_field_name, "Via: ");
- offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_ORIGINATOR_DESCRIPTION].log_field_name, "\r\nFrom: ");
- // offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_ORIGINATOR_TAGS].log_field_name, "tag=");
- offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_RESPONDER_DESCRIPTION].log_field_name, "\r\nTo: ");
- offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_CALL_ID].log_field_name, "\r\nCall-ID: ");
- offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_CSEQ].log_field_name, "\r\nCSeq: ");
-
- const char *p="\r\nServer: (Very nice Sip Registrar/Proxy Server)\r\nAllow: ACK,BYE,CANCEL,INVITE,REGISTER,OPTIONS,INFO,MESSAGE\r\nContent-Length: 0\r\n\r\n";
- size_t p_sz=MIN(sizeof(payload)-offset, strlen(p));
- if(p_sz>0)
- {
- memcpy(payload+offset, p, p_sz);
- offset+=p_sz;
- }
-
- const struct packet *pkt=session_get0_current_packet(ss);
- int exchange_direction=(packet_get_direction(pkt)==PACKET_DIRECTION_C2S) ? TRUE : FALSE;
- int ret=firewall_payload_inject(ss, payload, offset, exchange_direction);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "block_sip", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-}
-
-void deny_sub_action_mail_block_enforce(struct session *ss, struct sub_action_response *response, struct utable *putable)
-{
- const struct packet *pkt=session_get0_current_packet(ss);
- int exchange_direction=(packet_get_direction(pkt)==PACKET_DIRECTION_C2S) ? TRUE : FALSE;
-
- int ret=-1;
- switch(response->code)
- {
- case 550:
- ret=firewall_payload_inject(ss, (char *)"550 Mail was identified as spam.\r\n", strlen("550 Mail was identified as spam.\r\n"), exchange_direction);
- break;
- case 551:
- ret=firewall_payload_inject(ss, (char *)"551 User not local; please try <forward-path>\r\n", strlen("551 User not local; please try <forward-path>\r\n"), exchange_direction);
- break;
- default:
- break;
- }
-
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_SESSION);
-
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "block_mail", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-}
-
-void packet_l34_header_reverse(char *message, enum session_addr_type addr_type_v46)
-{
- int l3hdr_len=0;
- struct iphdr *ipv4=NULL;
- struct ip6_hdr *ipv6=NULL;
-
- uint32_t ipv4_addr=0;
- struct in6_addr ipv6_addr;
-
- switch(addr_type_v46)
- {
- case SESSION_ADDR_TYPE_IPV4_TCP:
- ipv4=(struct iphdr *)message;
- l3hdr_len=ipv4->ihl*4;
-
- ipv4_addr=ipv4->saddr;
- ipv4->saddr=ipv4->daddr;
- ipv4->daddr=ipv4_addr;
- break;
- case SESSION_ADDR_TYPE_IPV6_TCP:
- ipv6=(struct ip6_hdr *)message;
- l3hdr_len=sizeof(struct ip6_hdr);
-
- memcpy((void *)&ipv6_addr, (void *)&(ipv6->ip6_src), sizeof(struct in6_addr));
- memcpy((void *)&(ipv6->ip6_src), (void *)&(ipv6->ip6_dst), sizeof(struct in6_addr));
- memcpy((void *)&(ipv6->ip6_dst), (void *)&ipv6_addr, sizeof(struct in6_addr));
- break;
- default:
- return ;
- }
-
- struct tcphdr *tcp=(struct tcphdr *)((char *)message+l3hdr_len);
- uint16_t port=tcp->source;
- tcp->source=tcp->dest;
- tcp->dest=port;
-
- uint32_t seq=tcp->seq;
- tcp->seq=tcp->ack_seq;
- tcp->ack_seq=seq;
-}
-
-static void packet_l34_header_append(struct session *ss, char *message, uint16_t *l3hdr_len, uint16_t *l4hdr_len, enum session_addr_type addr_type_v46)
-{
- uint16_t origin_payload_len=0;
- struct iphdr *origin_ipv4=NULL;
- struct ip6_hdr *origin_ipv6=NULL;
-
- const char *l3hdr=session_get0_current_l3_header(ss);
- if(l3hdr==NULL)
- {
- return ;
- }
-
- switch(addr_type_v46)
- {
- case SESSION_ADDR_TYPE_IPV4_TCP:
- origin_ipv4=(struct iphdr *)l3hdr;
- *l3hdr_len=origin_ipv4->ihl*4;
- origin_payload_len=ntohs(origin_ipv4->tot_len)-(*l3hdr_len);
-
- memcpy(message, l3hdr, *l3hdr_len);
- break;
- case SESSION_ADDR_TYPE_IPV6_TCP:
- origin_ipv6=(struct ip6_hdr *)l3hdr;
- *l3hdr_len=sizeof(struct ip6_hdr);
- origin_payload_len=ntohs(origin_ipv6->ip6_ctlun.ip6_un1.ip6_un1_plen);
-
- memcpy(message, l3hdr, *l3hdr_len);
- break;
- default:
- return ;
- }
-
- const char *l4hdr=session_get0_current_l4_header(ss);
- struct tcphdr *origin_tcp=(struct tcphdr *)l4hdr;
- *l4hdr_len=origin_tcp->doff*4;
- origin_payload_len-=(*l4hdr_len);
-
- memcpy(message+(*l3hdr_len), l4hdr, 20);
- struct tcphdr *built_tcp=(struct tcphdr *)((char *)message+(*l3hdr_len));
- built_tcp->seq=(uint32_t)htonl((uint32_t)ntohl(built_tcp->seq)+origin_payload_len); // length of packet payload
- built_tcp->doff=5;
- *l4hdr_len=20; // tcp head length=20
-}
-
-void user_define_policy_variable_replace(struct session *ss, ctemplate::TemplateDictionary *tpl_dict, uuid_t rule_uuid)
-{
- char ipstr[64]={0};
- char *subscriber=NULL;
-
- char rule_uuid_str[UUID_STR_LEN]={0};
- uuid_unparse_lower(rule_uuid, rule_uuid_str);
- tpl_dict->SetFormattedValue("tsg_policy_uuid", "%s", rule_uuid_str);
-
- firewall_session_attribute_cstring_value_get0(ss, SESSION_ATTRIBUTE_CLIENT_SUBSCRIBER, &subscriber);
- tpl_dict->SetFormattedValue("tsg_subscriber_id", "%s", (subscriber!=NULL) ? subscriber : "");
-
- enum session_addr_type addr_type=__SESSION_ADDR_TYPE_MAX;
- struct session_addr *ss_addr=session_get0_addr(ss, &addr_type);
- switch(addr_type)
- {
- case SESSION_ADDR_TYPE_IPV4_TCP:
- case SESSION_ADDR_TYPE_IPV4_UDP:
- inet_ntop(AF_INET, (const void *)&(ss_addr->ipv4.saddr), ipstr, sizeof(ipstr));
- break;
- case SESSION_ADDR_TYPE_IPV6_TCP:
- case SESSION_ADDR_TYPE_IPV6_UDP:
- inet_ntop(AF_INET6, (const void *)(ss_addr->ipv6.saddr), ipstr, sizeof(ipstr));
- break;
- default:
- break;
- }
-
- tpl_dict->SetFormattedValue("tsg_client_ip", "%s", strlen(ipstr)==0 ? "" : ipstr);
-}
-
-void http_response_body_template_value_get(struct session *ss, ctemplate::Template *pg_template, uuid_t rule_uuid, const char* message, char **response_body, size_t *response_body_sz)
-{
- std::string page_output, msg_output;
- ctemplate::TemplateDictionary dict("pg_page_dict"); //dict is automatically finalized after function returned.
-
- if(message!=NULL)
- {
- ctemplate::Template *tpl_message=ctemplate::Template::StringToTemplate(message, strlen(message), ctemplate::DO_NOT_STRIP);
- if(tpl_message!=NULL)
- {
- ctemplate::TemplateDictionary dict_msg("msg_dict"); //dict is automatically finalized after function returned.
-
- user_define_policy_variable_replace(ss, &dict_msg, rule_uuid);
-
- tpl_message->Expand(&msg_output, &dict_msg);
-
- size_t output_msg_sz=msg_output.length();
- char *output_msg=(char *)CALLOC(char, output_msg_sz+1);
- memcpy(output_msg, msg_output.c_str(), output_msg_sz);
- output_msg[output_msg_sz]='\0';
-
- dict.SetValue("msg", output_msg);
-
- FREE(output_msg);
- output_msg=NULL;
-
- delete tpl_message;
- }
- else
- {
- dict.SetValue("msg", message);
- }
- }
- else
- {
- dict.SetValue("msg", "NULL");
- }
-
- pg_template->Expand(&page_output, &dict);
-
- *response_body_sz=page_output.length()+1;
- *response_body=(char *)CALLOC(char, *response_body_sz);
- memcpy(*response_body, page_output.c_str(), *response_body_sz);
-}
-
-void http_response_body_profile_value_get(struct session *ss, struct sub_action_response *response, ctemplate::Template *pg_template, uuid_t rule_uuid, char **response_body, size_t *response_body_sz)
-{
- struct http_response_pages *response_pages=(struct http_response_pages *)plugin_ex_data_http_response_pages_get(firewall_cm_maat, response->profile_uuid);
- if(response_pages==NULL)
- {
- return ;
- }
-
- switch(response_pages->format)
- {
- case RESPONSE_PROFILE:
- *response_body=(char *)CALLOC(char, response_pages->content_sz);
- memcpy(*response_body, response_pages->content, response_pages->content_sz);
- *response_body_sz=response_pages->content_sz;
- break;
- case RESPONSE_TEMPLATE:
- http_response_body_template_value_get(ss, pg_template, rule_uuid, response_pages->content, response_body, response_body_sz);
- break;
- default:
- break;
- }
-}
-
-void packet_tcp_flags_enable(struct tcphdr *tcp, char rst, char ack, char fin)
-{
- tcp->rst=(rst==1) ? 1 : 0;
- tcp->ack=(ack==1) ? 1 : 0;
- tcp->fin=(fin==1) ? 1 : 0;
- tcp->psh=0;
-}
-
-void http_reponse_packet_checksum(char *packet, size_t packet_sz, enum session_addr_type addr_type_v46, int l34hdr_len)
-{
- struct iphdr *ipv4=NULL;
- struct ip6_hdr *ipv6=NULL;
- struct tcphdr *tcp=NULL;
-
- switch(addr_type_v46)
- {
- case SESSION_ADDR_TYPE_IPV4_TCP:
- ipv4=(struct iphdr *)packet;
- ipv4->tot_len=htons(l34hdr_len+packet_sz);
- tcp=(struct tcphdr *)(packet+(ipv4->ihl*4));
- sendpacket_do_checksum((unsigned char *)packet, IPPROTO_TCP, tcp->doff*4+packet_sz);
- sendpacket_do_checksum((unsigned char *)packet, IPPROTO_IP, ipv4->ihl*4);
- break;
- case SESSION_ADDR_TYPE_IPV6_TCP:
- ipv6=(struct ip6_hdr *)packet;
- tcp=(struct tcphdr *)(packet+sizeof(struct ip6_hdr));
- ipv6->ip6_ctlun.ip6_un1.ip6_un1_plen=htons(tcp->doff*4+packet_sz);
- sendpacket_do_checksum((unsigned char *)packet, IPPROTO_TCP, tcp->doff*4+packet_sz);
- break;
- default:
- return ;
- }
-}
-
-void deny_sub_action_http_block_enforce(struct session *ss, struct sub_action_response *response, struct utable *putable, uuid_t rule_uuid)
-{
- if(firewall_rule_enforce_runtime.reset.remedy==1)
- {
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_TCP_RESET_REMEDY);
- }
-
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_SESSION);
-
- uint16_t l3hdr_len=0,l4hdr_len=0;
- char packet[1024*64]={0};
- enum session_addr_type addr_type_v46=__SESSION_ADDR_TYPE_MAX;
- session_get0_addr(ss, &addr_type_v46);
- if(addr_type_v46!=SESSION_ADDR_TYPE_IPV4_TCP && addr_type_v46!=SESSION_ADDR_TYPE_IPV6_TCP)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "block_http", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- packet_l34_header_append(ss, packet, &l3hdr_len, &l4hdr_len, addr_type_v46);
- if(l3hdr_len==0 || l4hdr_len==0)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "block_http", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- const struct packet *pkt=session_get0_current_packet(ss);
- int direction=packet_get_direction( pkt);
- if(direction==PACKET_DIRECTION_C2S)
- {
- packet_l34_header_reverse(packet, addr_type_v46);
- }
-
- int exchange_direction=(packet_get_direction(pkt)==PACKET_DIRECTION_C2S) ? TRUE : FALSE;
-
- uint16_t http_hdr_len=0;
- ctemplate::Template *pg_template=NULL;
- switch(response->code)
- {
- case 200:
- http_hdr_len=snprintf(packet+l3hdr_len+l4hdr_len, sizeof(packet)-l3hdr_len-l4hdr_len, "HTTP/1.1 %d OK\r\nContent-Type: text/html\r\n\r\n", response->code);
- pg_template=firewall_rule_enforce_runtime.tpl_200;
- break;
- case 204:
- http_hdr_len=snprintf(packet+l3hdr_len+l4hdr_len, sizeof(packet)-l3hdr_len-l4hdr_len, "HTTP/1.1 %d No Content\r\nContent-Type: text/html\r\n\r\n", response->code);
- pg_template=firewall_rule_enforce_runtime.tpl_204;
- break;
- case 403:
- http_hdr_len=snprintf(packet+l3hdr_len+l4hdr_len, sizeof(packet)-l3hdr_len-l4hdr_len, "HTTP/1.1 %d Forbidden\r\nContent-Type: text/html\r\n\r\n", response->code);
- pg_template=firewall_rule_enforce_runtime.tpl_403;
- break;
- case 404:
- http_hdr_len=snprintf(packet+l3hdr_len+l4hdr_len, sizeof(packet)-l3hdr_len-l4hdr_len, "HTTP/1.1 %d Not Found\r\nContent-Type: text/html\r\n\r\n", response->code);
- pg_template=firewall_rule_enforce_runtime.tpl_404;
- break;
- default:
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "block_http", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- char *response_body=NULL;
- size_t response_body_sz=0;
- switch(response->rtype)
- {
- case RESPONSE_TEXT:
- case RESPONSE_TEMPLATE:
- http_response_body_template_value_get(ss, pg_template, rule_uuid, response->message, &response_body, &response_body_sz);
- case RESPONSE_PROFILE:
- http_response_body_profile_value_get(ss, response, pg_template, rule_uuid, &response_body, &response_body_sz);
- break;
- case RESPONSE_ALERT204:
- break;
- default:
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "block_http", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- if((response_body==NULL || response_body_sz==0) && http_hdr_len==0)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "block_http", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- if(response_body_sz>0)
- {
- firewall_attribute_integer_utable_add(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_HTTP_ACTION_FILE_SIZE].log_field_name, firewall_attribute_schema[SCHEMA_ATTRIBUTE_HTTP_ACTION_FILE_SIZE].log_field_name_sz, response_body_sz);
- }
-
- int ret=0;
- struct tcphdr *tcp=(struct tcphdr *)(packet+l3hdr_len);
- uint16_t max_segment_size=firewall_tcp_mss_option_get(ss);
- max_segment_size=(max_segment_size==0) ? 1400 : max_segment_size;
-
- size_t one_payload_len=0;
- for(size_t i=0; i<=response_body_sz && http_hdr_len>0 ; i+=one_payload_len)
- {
- one_payload_len=MIN(response_body_sz-i, (size_t)(max_segment_size-http_hdr_len));
- memcpy((char *)packet+l3hdr_len+l4hdr_len+http_hdr_len, response_body+i, one_payload_len);
-
- http_reponse_packet_checksum(packet, one_payload_len+http_hdr_len, addr_type_v46, l3hdr_len+l4hdr_len);
- ret=firewall_packet_inject(ss, packet, l3hdr_len+l4hdr_len+http_hdr_len+one_payload_len, exchange_direction);
- tcp->seq=htonl(ntohl(tcp->seq)+one_payload_len+http_hdr_len);
- http_hdr_len=0;
-
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "block_http", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- }
-
- FREE(response_body);
- response_body=NULL;
-
- packet_tcp_flags_enable(tcp, 0, 1, 1); //rst, ack, fin
- http_reponse_packet_checksum(packet, 0, addr_type_v46, l3hdr_len+l4hdr_len); //fin
- ret=firewall_packet_inject(ss, packet, l3hdr_len+l4hdr_len, exchange_direction);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "block_http_fin", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-
- packet_l34_header_reverse(packet, addr_type_v46);
- http_reponse_packet_checksum(packet, 0, addr_type_v46, l3hdr_len+l4hdr_len); //fin
- ret=firewall_packet_inject(ss, packet, l3hdr_len+l4hdr_len, exchange_direction);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "block_http_fin", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-
- packet_tcp_flags_enable(tcp, 1, 1, 0); //rst, ack, fin
- http_reponse_packet_checksum(packet, 0, addr_type_v46, l3hdr_len+l4hdr_len); //rst
- ret=firewall_packet_inject(ss, packet, l3hdr_len+l4hdr_len, exchange_direction);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "block_http_rst", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-
- packet_l34_header_reverse(packet, addr_type_v46);
- http_reponse_packet_checksum(packet, 0, addr_type_v46, l3hdr_len+l4hdr_len); //rst
- ret=firewall_packet_inject(ss, packet, l3hdr_len+l4hdr_len, exchange_direction);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "block_http_rst", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-}
-
-void dns_response_header_append(struct utable *putable, struct _dns_hdr *dnshdr, int record_num)
-{
- dnshdr->qr=1; // 1bit: Response
- dnshdr->opcode=0; // 4bits: Query
- dnshdr->aa=0; // 1bit: authoritative answer
- dnshdr->tc=0; // 1bit: Not truncated
- dnshdr->rd=1; // 1bit: Recursion Desired
- dnshdr->ra=1; // 1bit: Recursion Available
- dnshdr->z=0; // 3bits: Reserved for future use: Must be zero in all queries and responses
- dnshdr->rcode = 0; // 4bits: 0: No error condition
-
- dnshdr->ancount=record_num;
-
- int64_t message_id=0;
- utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_MESSAGE_ID].log_field_name, &message_id);
- dnshdr->id=(uint16_t)message_id;
- dnshdr->id=htons(dnshdr->id);
-
- dnshdr->qdcount=1;
- dnshdr->qdcount=htons(dnshdr->qdcount); // 16bits: QDCOUNT: number of questions
- dnshdr->ancount=htons(dnshdr->ancount); // 16bits: ANCOUNT: number of answer resource records
- dnshdr->aucount=htons(dnshdr->aucount); // 16bits: NSCOUNT: number of authority resource records
- dnshdr->adcount=htons(dnshdr->adcount); // 16bits: ARCOUNT: number of additional resource records
-}
-
-static int dns_qanme_compress(char *qname, int qname_sz, char *compress_qname, int compress_qname_sz)
-{
- int c_offset=1;
- int d_offset=0;
-
- if(qname==NULL || qname_sz<=0 || compress_qname==NULL || compress_qname_sz<=0 || qname_sz>=compress_qname_sz)
- {
- return 0;
- }
-
- if(('.'==qname[0]) || ('.'==qname[qname_sz-1]))
- {
- return 0;
- }
-
- while((qname[d_offset]!='\n') && (qname[d_offset]!='\0') && (c_offset<compress_qname_sz) && (d_offset<qname_sz))
- {
- int section_len=0;
- while((d_offset<qname_sz) && (qname[d_offset]!='.') && (qname[d_offset]!='\n') && (qname[d_offset]!='\0'))
- {
- section_len++;
- compress_qname[c_offset++]=qname[d_offset++];
- }
-
- compress_qname[c_offset-section_len-1]=section_len;
-
- if((d_offset>=qname_sz) || (qname[d_offset]=='\n') || (qname[d_offset]=='\0'))
- {
- break;
- }
-
- c_offset++;
- d_offset++;
- }
-
- compress_qname[c_offset++]='\0';
-
- return c_offset;
-}
-
-void dns_response_question_append(struct utable *putable, char *payload, size_t payload_sz, size_t *payload_offset)
-{
- size_t qname_sz=0;
- char *qname=NULL;
- utable_get0_cstring_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QNAME].log_field_name, &qname, &qname_sz);
- if(qname==NULL || qname_sz<=0)
- {
- return ;
- }
-
- (*payload_offset)+=dns_qanme_compress(qname, qname_sz, payload+(*payload_offset), payload_sz-(*payload_offset));
-
- int64_t qtype=0;
- utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QTYPE].log_field_name, &qtype);
- uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)qtype);
-
- int64_t qclass=0;
- utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QCLASS].log_field_name, &qclass);
- uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)qclass);
-}
-
-void dns_response_answer_records_append(UT_array *records, char *payload, size_t payload_sz, size_t *payload_offset, int selected_num, int min_ttl, int max_ttl, uint16_t *n_records)
-{
- if(records==NULL || selected_num<=0)
- {
- return ;
- }
-
- uint32_t idx=0;
- uint32_t n=MIN(utarray_len(records), (uint32_t)selected_num);
- if(utarray_len(records) > (uint32_t)selected_num)
- {
- idx=random_integer_generate(0, n-selected_num);
- }
-
- for(uint32_t i=idx; i<n; i++)
- {
- struct dns_answer_record *answer_record=(struct dns_answer_record *)utarray_eltptr(records, i);
- if(answer_record==NULL)
- {
- continue;
- }
-
- uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)0xc00c);
- uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)(answer_record->atype));
- uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)1);
-
- int ttl=random_integer_generate(min_ttl, max_ttl)+min_ttl;
- uint32_hton_append(payload, payload_sz, payload_offset, (uint32_t)ttl);
-
- switch(answer_record->atype)
- {
- case RR_TYPE_A:
- if(payload_sz-(*payload_offset) > 6)
- {
- uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)4);
- uint32_append(payload, payload_sz, payload_offset, (uint32_t)(answer_record->v4_addr.s_addr));
- }
- break;
- case RR_TYPE_AAAA:
- if(payload_sz-(*payload_offset) > 18)
- {
- uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)16);
- memcpy(payload+(*payload_offset), answer_record->v6_addr.s6_addr, 16);
- (*payload_offset)+=16;
- }
- break;
- case RR_TYPE_CNAME:
- {
- char compress_cname[1024]={0};
- int compress_sz=dns_qanme_compress(answer_record->cname, strlen(answer_record->cname), compress_cname, sizeof(compress_cname));
- uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)compress_sz);
- compress_sz=MIN((size_t)compress_sz, payload_sz-(*payload_offset));
- memcpy(payload+(*payload_offset), compress_cname, compress_sz);
- (*payload_offset)+=compress_sz;
- }
- break;
- default:
- continue;
- }
-
- (*n_records)++;
- }
-}
-
-void deny_sub_action_dns_redirect_enforce(struct session *ss, struct dns_setting_details *dns_redirect, struct utable *putable)
-{
- if(dns_redirect==NULL || putable==NULL)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "redirect_dns", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- int64_t dns_qr=0;
- utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QR].log_field_name, &dns_qr);
- switch(firewall_rule_enforce_runtime.packet_response_mode)
- {
- case PACKET_RESPONSE_MODE_HIJACK:
- if(dns_qr==1) // dns_qr==1: response
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_OK, TAG_KEY_SUB_ACTION_ENFORCE, "redirect_dns_qr_1_response", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
- break;
- case PACKET_RESPONSE_MODE_REPLACE:
- if(dns_qr==0) // dns_qr==0: query
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_OK, TAG_KEY_SUB_ACTION_ENFORCE, "redirect_dns_qr_0_query", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
- break;
- default:
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "packet_response_mode", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- char payload[1024]={0};
- size_t payload_sz=sizeof(payload);
- size_t payload_offset=0;
-
- payload_offset+=sizeof(struct _dns_hdr);
- dns_response_question_append(putable, payload, payload_sz, &payload_offset);
-
- int64_t qtype=0;
- utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QTYPE].log_field_name, &qtype);
-
- uint16_t n_records=0;
- for(uint32_t i=0; i<DNS_ANSWER_TYPE_MAX; i++)
- {
- struct dns_answer_record *record=(struct dns_answer_record *)utarray_eltptr(dns_redirect->answer_array[i], 0);
- if(record==NULL || record->qtype!=qtype)
- {
- continue;
- }
-
- switch(record->rtype)
- {
- case RESPONSE_PROFILE:
- {
- struct dns_profile_records *profile_records=(struct dns_profile_records *)plugin_ex_data_dns_profile_records_get(firewall_cm_maat, record->profile_uuid);
- if(profile_records==NULL)
- {
- return ;
- }
- dns_response_answer_records_append(profile_records->answer_array, payload, payload_sz, &payload_offset, record->selected_num, record->min_ttl, record->max_ttl, &n_records);
- }
- break;
- case RESPONSE_TEXT:
- {
- dns_response_answer_records_append(dns_redirect->answer_array[i], payload, payload_sz, &payload_offset, record->selected_num, record->min_ttl, record->max_ttl, &n_records);
- }
- break;
- default:
- break;
- }
- }
-
- if(n_records<=0)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "redirect_dns", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- dns_response_header_append(putable, (struct _dns_hdr *)payload, n_records);
-
- const struct packet *pkt=session_get0_current_packet(ss);
- int exchange_direction=(packet_get_direction(pkt)==PACKET_DIRECTION_C2S) ? TRUE : FALSE;
- int ret=firewall_payload_inject(ss, payload, payload_offset, exchange_direction);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "redirect_dns", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
-}
-
-void deny_sub_action_http_redirect_enforce(struct session *ss, struct sub_action_response *response, struct utable *putable, uuid_t rule_uuid)
-{
- if(response->code!=303)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "redirect_http", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- size_t payload_offset=0;
- char payload[1024]={0};
-
- ctemplate::Template *tpl_303=ctemplate::Template::StringToTemplate(response->redirect_url_to, strlen(response->redirect_url_to), ctemplate::DO_NOT_STRIP);
- if(tpl_303!=NULL)
- {
- ctemplate::TemplateDictionary dict_303("url_dict"); //dict is automatically finalized after function returned.
-
- user_define_policy_variable_replace(ss, &dict_303, rule_uuid);
-
- std::string output;
- tpl_303->Expand(&output, &dict_303);
-
- size_t output_url_sz=output.length();
- char *output_url=(char *)CALLOC(char, output_url_sz+1);
- memcpy(output_url, output.c_str(), output_url_sz);
- output_url[output_url_sz]='\0';
-
- payload_offset+=snprintf(payload+payload_offset, sizeof(payload)-payload_offset, "HTTP/1.1 %d See Other\r\nLocation: %s\r\n\r\n", response->code, output_url);
-
- FREE(output_url);
- output_url=NULL;
- delete tpl_303;
- }
- else
- {
- payload_offset=snprintf(payload+payload_offset, sizeof(payload)-payload_offset, "HTTP/1.1 %d See Other\r\nLocation: %s\r\n\r\n", response->code, response->redirect_url_to);
- }
-
- const struct packet *pkt=session_get0_current_packet(ss);
- int exchange_direction=(packet_get_direction(pkt)==PACKET_DIRECTION_C2S) ? TRUE : FALSE;
- int ret=firewall_payload_inject(ss, payload, payload_offset, exchange_direction);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "redirect_http", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_SESSION);
-}
-
-size_t payload_first_last_2bytes_swap(char *payload, size_t payload_sz)
-{
- size_t swap_count=0;
- for(size_t i=0, j=payload_sz-1; i<payload_sz && j> i; i++, j--)
- {
- if(swap_count>=2)
- {
- break;
- }
-
- if(payload[i]==payload[j])
- {
- continue;
- }
-
- char temp=payload[i];
- payload[i]=payload[j];
- payload[j]=temp;
- swap_count++;
- }
-
- return swap_count;
-}
-
-#define TAMPER_MIN_PAYLOAD_LEN 4
-void deny_sub_action_tamper_enforce(struct session *ss)
-{
- if(ss==NULL)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "tamper", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- size_t payload_sz=0;
- char *payload=(char *)session_get0_current_payload(ss, &payload_sz);
- if(payload==NULL || payload_sz<TAMPER_MIN_PAYLOAD_LEN)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "tamper", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- size_t swap_count=payload_first_last_2bytes_swap(payload, payload_sz);
- if(swap_count>0)
- {
- int ret=firewall_payload_inject(ss, payload, payload_sz, FALSE);
- firewall_local_file_counter_incby(((ret>=0) ? LOCAL_STAT_COUNTER_OK : LOCAL_STAT_COUNTER_ERROR), TAG_KEY_SUB_ACTION_ENFORCE, "tamper", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
- }
- else
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_OK, TAG_KEY_SUB_ACTION_ENFORCE, "tamper", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- }
-}
-
-void deny_sub_action_ratelimit_enforce(struct session *ss, struct leaky_bucket *bucket)
-{
- if(ss==NULL || bucket==NULL)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "ratelimit", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- size_t payload_sz=0;
- char *payload=(char *)session_get0_current_payload(ss, &payload_sz);
- if(payload==NULL || payload_sz==0)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "ratelimit", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- if((is_permit_pass(bucket, payload_sz*8))==0)
- {
- firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_OK, TAG_KEY_SUB_ACTION_ENFORCE, "ratelimit", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "ratelimit", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-}
-
-void deny_sub_action_packet_ratelimit_enforce(struct packet *rawpkt, struct leaky_bucket *bucket)
-{
- if(rawpkt==NULL || bucket==NULL)
- {
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "packet_ratelimit", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- size_t rawpkt_sz=0;
- packet_get0_data(rawpkt, &rawpkt_sz);
- if((is_permit_pass(bucket, rawpkt_sz*8))==0)
- {
- packet_drop(rawpkt);
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_OK, TAG_KEY_SUB_ACTION_ENFORCE, "packet_ratelimit", 1, stellar_get_current_thread_id(firewall_stellar_instance));
- return ;
- }
-
- firewall_local_file_counter_incby(LOCAL_STAT_COUNTER_ERROR, TAG_KEY_SUB_ACTION_ENFORCE, "packet_ratelimit", 1, stellar_get_current_thread_id(firewall_stellar_instance));
-}
-
-void firewall_rule_enforce_init(const char *config_file)
-{
- int temp=0;
- MESA_load_profile_int_def(config_file, "RESET", "NUM", &temp, 1);
- firewall_rule_enforce_runtime.reset.pkt_num=temp;
- MESA_load_profile_int_def(config_file, "RESET", "SEED1", &temp, 65535);
- firewall_rule_enforce_runtime.reset.seed1=temp;
- MESA_load_profile_int_def(config_file, "RESET", "SEED2", &temp, 13);
- firewall_rule_enforce_runtime.reset.seed2=temp;
- MESA_load_profile_int_def(config_file, "RESET", "FLAGS", &temp, 0x14);
- firewall_rule_enforce_runtime.reset.th_flags=temp;
- MESA_load_profile_int_def(config_file, "RESET", "DIR", &temp, 3); // 1: c2s, 2: s2c, 3: both
- firewall_rule_enforce_runtime.reset.dir=temp;
- MESA_load_profile_int_def(config_file, "RESET", "REMEDY", &temp, 1);
- firewall_rule_enforce_runtime.reset.remedy=temp;
-
- char page_path[256];
- memset(page_path, 0, sizeof(page_path));
- MESA_load_profile_string_def(config_file, "FIREWALL", "HTTP_PAGE403", page_path, sizeof(page_path), "./tsgconf/HTTP403.html");
- firewall_rule_enforce_runtime.tpl_403 = ctemplate::Template::GetTemplate(page_path, ctemplate::DO_NOT_STRIP);
-
- memset(page_path, 0, sizeof(page_path));
- MESA_load_profile_string_def(config_file, "FIREWALL", "HTTP_PAGE404", page_path, sizeof(page_path), "./tsgconf/HTTP404.html");
- firewall_rule_enforce_runtime.tpl_404 = ctemplate::Template::GetTemplate(page_path, ctemplate::DO_NOT_STRIP);
-
- memset(page_path, 0, sizeof(page_path));
- MESA_load_profile_string_def(config_file, "FIREWALL", "HTTP_PAGE200", page_path, sizeof(page_path), "./tsgconf/HTTP200.html");
- firewall_rule_enforce_runtime.tpl_200 = ctemplate::Template::GetTemplate(page_path, ctemplate::DO_NOT_STRIP);
-
- memset(page_path, 0, sizeof(page_path));
- MESA_load_profile_string_def(config_file, "FIREWALL", "HTTP_PAGE204", page_path, sizeof(page_path), "./tsgconf/HTTP204.html");
- firewall_rule_enforce_runtime.tpl_204 = ctemplate::Template::GetTemplate(page_path, ctemplate::DO_NOT_STRIP);
-
- char packet_response_mode[32]={0};
- MESA_load_profile_string_def(config_file, "FIREWALL", "PACKET_RESPONSE_MODE", packet_response_mode, sizeof(packet_response_mode), "replace");
- if((strlen(packet_response_mode)==strlen("replace")) && (strcasecmp(packet_response_mode, "replace")==0))
- {
- firewall_rule_enforce_runtime.packet_response_mode=PACKET_RESPONSE_MODE_REPLACE;
- }
- else
- {
- firewall_rule_enforce_runtime.packet_response_mode=PACKET_RESPONSE_MODE_HIJACK;
- }
-}
-
-void security_enforcer_module_exit(struct module_manager *mod_mgr, struct module *mod)
-{
- if(mod_mgr==NULL)return;
- if(mod)
- {
- struct security_enforcer *enforcer=(struct security_enforcer *)module_get_ctx(mod);
- FREE(enforcer);
- module_free(mod);
- }
-}
-
-struct module *security_enforcer_module_init(struct module_manager *mod_mgr)
-{
- if(mod_mgr==NULL)return NULL;
-
- struct security_enforcer *enforcer=CALLOC(struct security_enforcer, 1);
- struct module *mod=module_new(SECUIRTY_ENFORCER_MODULE_NAME, (void *)enforcer);
- if(mod==NULL)
- {
- goto INIT_ERROR;
- }
-
- enforcer->mod_mgr=mod_mgr;
- enforcer->logger=module_manager_get_logger(mod_mgr);
- // int max_thread_num=module_manager_get_max_thread_num(mod_mgr);
- // const char *toml_path=module_manager_get_toml_path(mod_mgr);
-
- enforcer->plugin_table[SECURITY_PLUGIN_UNKNOWN]=(struct maat_plugin_table){
- .name="unknown",
- .ex_new=NULL,
- .ex_free=NULL,
- .ex_dup=NULL
- };
-
- enforcer->plugin_table[SECURITY_PLUGIN_SECURITY_RULE]=(struct maat_plugin_table){
- .name="SECURITY_RULE_PLUGIN",
- .ex_new=security_rule_new,
- .ex_free=security_rule_free,
- .ex_dup=security_rule_dup
- };
-
- enforcer->plugin_table[SECURITY_PLUGIN_HTTP_RESPONSE_PAGES]=(struct maat_plugin_table){
- .name="RESPONSE_PAGE",
- .ex_new=response_page_new,
- .ex_free=response_page_free,
- .ex_dup=response_page_dup
- };
-
- enforcer->plugin_table[SECURITY_PLUGIN_DNS_RESOURCE_RECORD]=(struct maat_plugin_table){
- .name="DNS_RESOURCE_RECORD",
- .ex_new=dns_resource_record_new,
- .ex_free=dns_resource_record_free,
- .ex_dup=dns_resource_record_dup
- };
-
- enforcer->cm_maat=scanner_get_maat_instance(scanner_module_to_scanner(module_manager_get_module(mod_mgr, SCANNER_MODULE_NAME)));
- if(enforcer->cm_maat==NULL)
- {
- STELLAR_LOG_FATAL(enforcer->logger, SECUIRTY_ENFORCER_MODULE_NAME, "scanner_get_maat_instance/scanner_module_to_scanner/module_manager_get_module failed, module_name: %s", SCANNER_MODULE_NAME);
- goto INIT_ERROR;
- }
-
- for(int i=SECURITY_PLUGIN_UNKNOWN; i<SECURITY_PLUGIN_MAX; i++)
- {
- if(enforcer->plugin_table[i].name==NULL)
- {
- continue;
- }
-
- int ret=maat_plugin_table_ex_schema_register(enforcer->cm_maat,
- enforcer->plugin_table[i].name,
- enforcer->plugin_table[i].ex_new,
- enforcer->plugin_table[i].ex_free,
- enforcer->plugin_table[i].ex_dup,
- 0,
- NULL
- );
- if(ret<0)
- {
- STELLAR_LOG_FATAL(enforcer->logger, SECUIRTY_ENFORCER_MODULE_NAME, "maat_plugin_table_ex_schema_register failed, table_name: %s", enforcer->plugin_table[i].name);
- goto INIT_ERROR;
- }
- }
-
- return mod;
-
-INIT_ERROR:
- security_enforcer_module_exit(mod_mgr, mod);
- exit(-1);
- return NULL;
-}
diff --git a/enforcer/security/security_enforcer.cpp b/enforcer/security/security_enforcer.cpp
new file mode 100644
index 0000000..309a453
--- /dev/null
+++ b/enforcer/security/security_enforcer.cpp
@@ -0,0 +1,1343 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <arpa/inet.h>
+#include <linux/limits.h>
+
+#include <toml/toml.h>
+
+#include <ctemplate/template.h>
+
+#include <stellar/utils.h>
+#include <stellar/scanner.h>
+#include <stellar/module.h>
+#include <stellar/session.h>
+#include <stellar/packet.h>
+
+#include "bucket.h"
+#include "security_maat.h"
+#include "security_enforcer.h"
+
+#define ENFORCER_RULE_UUID_NUM 128
+
+enum PACKET_RESPONSE_MODE
+{
+ PACKET_RESPONSE_MODE_NONE=0,
+ PACKET_RESPONSE_MODE_REPLACE,
+ PACKET_RESPONSE_MODE_HIJACK,
+ PACKET_RESPONSE_MODE_MAX
+};
+
+struct maat_plugin_table
+{
+ const char *name;
+ maat_ex_new_func_t *ex_new;
+ maat_ex_free_func_t *ex_free;
+ maat_ex_dup_func_t *ex_dup;
+};
+
+enum SECURITY_MAAT_PLUGIN
+{
+ SECURITY_PLUGIN_UNKNOWN=0,
+ SECURITY_PLUGIN_SECURITY_RULE,
+ SECURITY_PLUGIN_RESPONSE_PAGE,
+ SECURITY_PLUGIN_DNS_RESOURCE_RECORD,
+ SECURITY_PLUGIN_MAX
+};
+
+struct security_enforcer_env
+{
+ int exdata_idx;
+
+ struct logger *logger;
+ struct scanner *scanner;
+ struct module_manager *mod_mgr;
+ struct packet_manager *pkt_mgr;
+ struct session_manager *sess_mgr;
+
+ int packet_response_mode;
+ ctemplate::Template *tpl_403;
+ ctemplate::Template *tpl_404;
+ ctemplate::Template *tpl_200;
+ ctemplate::Template *tpl_204;
+ ctemplate::Template *tpl_303;
+
+ struct maat *cm_maat;
+ struct maat_plugin_table plugin_table[SECURITY_PLUGIN_MAX];
+};
+
+struct security_enforcer_per_session_context
+{
+ enum RULE_SUB_ACTION sub_action_type;
+ union
+ {
+ struct sub_action_drop drop;
+ struct leaky_bucket *bucket;
+ struct sub_action_tamper tamper;
+ };
+
+ uint64_t packet_count; // packet contains payload
+};
+
+static void toml_string_get1(struct logger *logger, const char *module, const char *toml_path, const char *table_key, const char *key, char **value)
+{
+ FILE *fp=fopen(toml_path, "r");
+ if (NULL==fp)
+ {
+ STELLAR_LOG_FATAL(logger, module, "toml_bool_get can't open config file: %s", toml_path);
+ return ;
+ }
+
+ fclose(fp);
+
+ char errbuf[256]={0};
+ toml_table_t *root=toml_parse_file(fp, errbuf, sizeof(errbuf));
+ if(NULL==root)
+ {
+ return ;
+ }
+
+ toml_table_t *table=toml_table_in(root, table_key);
+ if(NULL==table)
+ {
+ STELLAR_LOG_FATAL(logger, module, "toml_string_get1 can't find key: [%s] in config file: %s", table_key, toml_path);
+ toml_free(root);
+ return ;
+ }
+
+ toml_datum_t val=toml_string_in(table, key);
+ if(val.ok>0)
+ {
+ (*value)=val.u.s;
+ }
+ else
+ {
+ (*value)=NULL;
+ }
+
+ toml_free(root);
+}
+
+uint32_t random_integer_generate(int min, int max)
+{
+ if(max>min)
+ {
+ return (rand()%(max-min+1));
+ }
+
+ return 0;
+}
+
+void uint32_append(char *payload, size_t payload_sz, size_t *payload_offset, uint32_t value)
+{
+ if(payload_sz>(*payload_offset)+4)
+ {
+ *(uint32_t *)(payload+*payload_offset)=(uint32_t)(value);
+ (*payload_offset)+=4;
+ }
+}
+
+void uint16_hton_append(char *payload, size_t payload_sz, size_t *payload_offset, uint16_t value)
+{
+ if(payload_sz>(*payload_offset)+2)
+ {
+ *(uint16_t *)(payload+*payload_offset)=(uint16_t)htons(value);
+ (*payload_offset)+=2;
+ }
+}
+
+void uint32_hton_append(char *payload, size_t payload_sz, size_t *payload_offset, uint32_t value)
+{
+ if(payload_sz>(*payload_offset)+4)
+ {
+ *(uint32_t *)(payload+*payload_offset)=(uint32_t)htonl(value);
+ (*payload_offset)+=4;
+ }
+}
+
+// https://datatracker.ietf.org/doc/html/rfc1071#section-4.1
+
+short computing_ip_checksum(void *payload, int payload_sz)
+{
+ int nleft=payload_sz;
+ long reverse_checksum=0;
+ uint16_t *ushort_ptr=(uint16_t *)payload;
+
+ while(nleft>1)
+ {
+ reverse_checksum+=*ushort_ptr++;
+ nleft-=2;
+ }
+
+ if(nleft==1)
+ {
+ reverse_checksum=*(unsigned char *)ushort_ptr;
+ }
+
+ while(reverse_checksum>>16)
+ {
+ reverse_checksum=(reverse_checksum&0xFFFF)+(reverse_checksum>>16);
+ }
+
+ return (~reverse_checksum &0xFFFF);
+}
+
+#define ICMPV4_SRCPACKET_MAX_LEN 576
+#define ICMPV6_SRCPACKET_MTU 1280
+
+// void deny_sub_action_icmp_enforce(struct session *ss)
+// {
+// uint16_t l3hdr_len=0;
+// uint16_t origin_ip_total_len=0;
+// struct iphdr *origin_ipv4=NULL;
+// struct ip6_hdr *origin_ipv6=NULL;
+// struct iphdr *built_ipv4=NULL;
+// struct ip6_hdr *built_ipv6=NULL;
+// struct icmphdr *icmp4=NULL;
+// struct icmp6_hdr *icmp6=NULL;
+
+// uint16_t ip_icmp_hdr_sz=0;
+// uint16_t icmp_packe_sz=0;
+// char icmp_packet[1500]={0};
+// const char *l3hdr=session_get0_current_l3_header(ss);
+// if(l3hdr==NULL)
+// {
+// return ;
+// }
+
+// enum session_addr_type addr_type=__SESSION_ADDR_TYPE_MAX;
+// session_get0_addr(ss, &addr_type);
+// switch(addr_type)
+// {
+// case SESSION_ADDR_TYPE_IPV4_TCP:
+// case SESSION_ADDR_TYPE_IPV4_UDP:
+// origin_ipv4=(struct iphdr *)l3hdr;
+// l3hdr_len=origin_ipv4->ihl*4;
+// memcpy(icmp_packet, l3hdr, l3hdr_len);
+// origin_ip_total_len=ntohs(origin_ipv4->tot_len);
+
+// built_ipv4=(struct iphdr *)icmp_packet;
+// built_ipv4->saddr=origin_ipv4->daddr;
+// built_ipv4->daddr=origin_ipv4->saddr;
+
+// //built_ipv4->check=computing_ip_checksum(icmp_packet, sizeof(struct iphdr));
+// ip_icmp_hdr_sz=sizeof(struct iphdr)+sizeof(struct icmphdr);
+// icmp_packe_sz=MIN(origin_ip_total_len, ICMPV4_SRCPACKET_MAX_LEN-ip_icmp_hdr_sz)+ip_icmp_hdr_sz;
+// built_ipv4->tot_len=htons(icmp_packe_sz);
+// built_ipv4->protocol=IPPROTO_ICMP;
+
+// icmp4=(struct icmphdr *)(icmp_packet+l3hdr_len);
+// icmp4->type=ICMP_UNREACH;
+// icmp4->code=ICMP_UNREACH_FILTER_PROHIB;
+
+// memcpy(icmp_packet+ip_icmp_hdr_sz, l3hdr, icmp_packe_sz-ip_icmp_hdr_sz);
+// sendpacket_do_checksum((unsigned char *)icmp_packet, IPPROTO_ICMP, icmp_packe_sz-l3hdr_len);
+// sendpacket_do_checksum((unsigned char *)icmp_packet, IPPROTO_IP, l3hdr_len);
+// //icmp4->checksum=computing_ip_checksum(icmp_packet+l3hdr_len, sizeof(struct icmphdr));
+// break;
+// case SESSION_ADDR_TYPE_IPV6_TCP:
+// case SESSION_ADDR_TYPE_IPV6_UDP:
+// origin_ipv6=(struct ip6_hdr *)l3hdr;
+// l3hdr_len=sizeof(struct ip6_hdr);
+// memcpy(icmp_packet, l3hdr, l3hdr_len);
+// origin_ip_total_len=ntohs(origin_ipv6->ip6_ctlun.ip6_un1.ip6_un1_plen);
+
+// built_ipv6=(struct ip6_hdr *)icmp_packet;
+// memcpy((void *)&(built_ipv6->ip6_src), (void *)&(origin_ipv6->ip6_dst), sizeof(struct in6_addr));
+// memcpy((void *)&(built_ipv6->ip6_dst), (void *)&(origin_ipv6->ip6_src), sizeof(struct in6_addr));
+
+// ip_icmp_hdr_sz=sizeof(struct ip6_hdr)+sizeof(struct icmp6_hdr);
+// icmp_packe_sz=MIN(origin_ip_total_len, ICMPV6_SRCPACKET_MTU-ip_icmp_hdr_sz)+ip_icmp_hdr_sz;
+// icmp_packe_sz=icmp_packe_sz-(icmp_packe_sz%4); // 4 bytes alignment
+// built_ipv6->ip6_ctlun.ip6_un1.ip6_un1_plen=htons(icmp_packe_sz);
+// built_ipv6->ip6_ctlun.ip6_un1.ip6_un1_nxt=IPPROTO_ICMPV6;
+
+// icmp6=(struct icmp6_hdr *)(icmp_packet+l3hdr_len);
+// icmp6->icmp6_type=ICMP6_DST_UNREACH;
+// icmp6->icmp6_code=ICMP6_DST_UNREACH;
+
+// memcpy(icmp_packet+ip_icmp_hdr_sz, l3hdr, icmp_packe_sz-ip_icmp_hdr_sz);
+// //icmp6->icmp6_cksum=computing_ip_checksum(icmp_packet+l3hdr_len, icmp_packe_sz);
+// sendpacket_do_checksum((unsigned char *)icmp_packet, IPPROTO_ICMPV6, icmp_packe_sz-l3hdr_len);
+// break;
+// default:
+// return ;
+// }
+
+// int ret=firewall_packet_inject(ss, icmp_packet, icmp_packe_sz, FALSE);
+// }
+
+void security_enforcer_get_origin_packet(const struct session *sess, const struct packet *rawpkt, const struct packet **c2s_origin_pkt, const struct packet **s2c_origin_pkt, uint32_t *th_seq, uint32_t *th_ack)
+{
+ int layer_count=packet_get_layer_count(rawpkt);
+ if(layer_count<=0)
+ {
+ return ;
+ }
+
+ const struct layer *l4_layer=packet_get_layer_by_idx(rawpkt, layer_count-1);
+ if(l4_layer==NULL)
+ {
+ return ;
+ }
+
+ switch(session_get_flow_type(sess))
+ {
+ case FLOW_TYPE_C2S:
+ (*th_seq)=l4_layer->hdr.tcp->th_seq;
+ (*th_ack)=l4_layer->hdr.tcp->th_ack;
+
+ if(c2s_origin_pkt!=NULL)
+ {
+ (*c2s_origin_pkt)=rawpkt;
+ }
+
+ if(s2c_origin_pkt!=NULL)
+ {
+ (*s2c_origin_pkt)=session_get_first_packet(sess, FLOW_TYPE_S2C);
+ }
+
+ break;
+ case FLOW_TYPE_S2C:
+ (*th_seq)=l4_layer->hdr.tcp->th_ack;
+ (*th_ack)=l4_layer->hdr.tcp->th_seq;
+
+ if(s2c_origin_pkt!=NULL)
+ {
+ (*s2c_origin_pkt)=rawpkt;
+ }
+
+ if(c2s_origin_pkt!=NULL)
+ {
+ (*c2s_origin_pkt)=session_get_first_packet(sess, FLOW_TYPE_C2S);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void security_enforcer_enforce_reset(struct security_enforcer_env *enforcer_env, const struct session *sess, const struct packet *rawpkt)
+{
+ enum session_type sess_type=session_get_type(sess);
+ if(sess_type!=SESSION_TYPE_TCP)
+ {
+ return ;
+ }
+
+ uint32_t th_seq=0;
+ uint32_t th_ack=0;
+ const struct packet *c2s_origin_pkt=NULL;
+ const struct packet *s2c_origin_pkt=NULL;
+ security_enforcer_get_origin_packet(sess, rawpkt, &c2s_origin_pkt, &s2c_origin_pkt, &th_seq, &th_ack);
+
+ if(c2s_origin_pkt!=NULL)
+ {
+ struct packet *c2s_rst_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_origin_pkt, th_seq, th_ack, TH_ACK|TH_RST, NULL, 0, NULL, 0);
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_rst_pkt, PACKET_STAGE_POSTROUTING);
+ }
+
+ if(s2c_origin_pkt!=NULL)
+ {
+ struct packet *s2c_rst_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), s2c_origin_pkt, th_ack, th_seq, TH_ACK|TH_RST, NULL, 0, NULL, 0);
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), s2c_rst_pkt, PACKET_STAGE_POSTROUTING);
+ }
+}
+
+void security_enforcer_enforce_drop(struct security_enforcer_env *enforcer_env, const struct session *sess, const struct packet *rawpkt, struct sub_action_drop *drop)
+{
+ if(enforcer_env==NULL || rawpkt==NULL || drop==NULL)
+ {
+ return;
+ }
+
+ packet_set_action((struct packet *)rawpkt, PACKET_ACTION_DROP);
+ session_set_discard((struct session *)sess);
+
+ // if(drop->send_icmp_enable)
+ // {
+ // deny_sub_action_icmp_enforce(sess);
+ // }
+
+ if(drop->send_reset_enable)
+ {
+ security_enforcer_enforce_reset(enforcer_env, sess, rawpkt);
+ }
+}
+
+// TODO: implement this function
+// size_t sip_response_body_append(char *response_body, size_t response_body_sz, struct utable *putable, const char *field_name, const char *field_prefix)
+// {
+// char *sip_field=NULL;
+// size_t sip_field_sz=0;
+// size_t field_prefix_sz=strlen(field_prefix);
+
+// utable_get0_cstring_value(putable, field_name, &sip_field, &sip_field_sz);
+// if(response_body_sz<sip_field_sz+field_prefix_sz)
+// {
+// return 0;
+// }
+
+// memcpy(response_body, field_prefix, field_prefix_sz);
+// memcpy(response_body+field_prefix_sz, sip_field, sip_field_sz);
+
+// return sip_field_sz+field_prefix_sz;
+// }
+
+// void security_enforcer_enforce_sip_block(struct session *ss, struct sub_action_response *response, struct utable *putable)
+// {
+// if(putable==NULL)
+// {
+// firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
+// return ;
+// }
+
+// int64_t sip_is_req=0;
+// utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_IS_REQUERST].log_field_name, &sip_is_req);
+// switch(firewall_rule_enforce_runtime.packet_response_mode)
+// {
+// case PACKET_RESPONSE_MODE_HIJACK:
+// if(sip_is_req==0) // response
+// {
+// return ;
+// }
+// break;
+// case PACKET_RESPONSE_MODE_REPLACE:
+// if(sip_is_req==1) // query
+// {
+// return ;
+// }
+// break;
+// default:
+// return ;
+// }
+
+// int offset=0;
+// char payload[1024]={0};
+// switch(response->code)
+// {
+// case 480:
+// //"SIP/2.0 480 Temporarily Unavailable\r\n"
+// offset=strlen("SIP/2.0 480 Temporarily Unavailable\r\n");
+// memcpy(payload, "SIP/2.0 480 Temporarily Unavailable\r\n", offset);
+// break;
+// case 500:
+// //"SIP/2.0 500 Server Internal Error\r\n",
+// offset=strlen("SIP/2.0 500 Server Internal Error\r\n");
+// memcpy(payload, "SIP/2.0 500 Server Internal Error\r\n", offset);
+// break;
+// default:
+// firewall_session_deny_para_set(ss, SESSION_DENY_PARA_DROP_CURRENT_PACKET);
+// return ;
+// }
+
+// offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_VIA].log_field_name, "Via: ");
+// offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_ORIGINATOR_DESCRIPTION].log_field_name, "\r\nFrom: ");
+// // offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_ORIGINATOR_TAGS].log_field_name, "tag=");
+// offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_RESPONDER_DESCRIPTION].log_field_name, "\r\nTo: ");
+// offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_CALL_ID].log_field_name, "\r\nCall-ID: ");
+// offset+=sip_response_body_append(payload+offset, sizeof(payload)-offset, putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_SIP_CSEQ].log_field_name, "\r\nCSeq: ");
+
+// const char *p="\r\nServer: (Very nice Sip Registrar/Proxy Server)\r\nAllow: ACK,BYE,CANCEL,INVITE,REGISTER,OPTIONS,INFO,MESSAGE\r\nContent-Length: 0\r\n\r\n";
+// size_t p_sz=MIN(sizeof(payload)-offset, strlen(p));
+// if(p_sz>0)
+// {
+// memcpy(payload+offset, p, p_sz);
+// offset+=p_sz;
+// }
+
+// const struct packet *pkt=session_get0_current_packet(ss);
+// int exchange_direction=(packet_get_direction(pkt)==PACKET_DIRECTION_C2S) ? TRUE : FALSE;
+// int ret=firewall_payload_inject(ss, payload, offset, exchange_direction);
+// }
+
+void security_enforcer_enforce_mail_block(struct security_enforcer_env *enforcer_env, const struct session *sess, const struct packet *rawpkt, struct sub_action_response *response)
+{
+ if(enforcer_env==NULL || rawpkt==NULL || response==NULL)
+ {
+ return ;
+ }
+
+ uint32_t th_seq=0;
+ uint32_t th_ack=0;
+ const struct packet *c2s_origin_pkt=NULL;
+ const struct packet *s2c_origin_pkt=NULL;
+ security_enforcer_get_origin_packet(sess, rawpkt, &c2s_origin_pkt, &s2c_origin_pkt, &th_seq, &th_ack);
+ if(c2s_origin_pkt==NULL)
+ {
+ return ;
+ }
+
+ char *block_buff=NULL;
+ switch(response->code)
+ {
+ case 550:
+ block_buff=(char *)"550 Mail was identified as spam.\r\n";
+ break;
+ case 551:
+ block_buff=(char *)"551 User not local; please try <forward-path>\r\n";
+ break;
+ default:
+ break;
+ }
+
+ if(block_buff!=NULL)
+ {
+ struct packet *redirect_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_origin_pkt, th_seq, th_ack, TH_ACK|TH_PUSH, NULL, 0, block_buff, strlen(block_buff));
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), redirect_pkt, PACKET_STAGE_POSTROUTING);
+ }
+
+ packet_set_action((struct packet *)rawpkt, PACKET_ACTION_DROP);
+ session_set_discard((struct session *)sess);
+}
+
+void policy_user_define_variable_replace(ctemplate::TemplateDictionary *tpl_dict, uuid_t rule_uuid, char *client_ip, char *subscriber)
+{
+ char rule_uuid_str[UUID_STR_LEN]={0};
+ uuid_unparse_lower(rule_uuid, rule_uuid_str);
+ tpl_dict->SetFormattedValue("tsg_policy_uuid", "%s", rule_uuid_str);
+ tpl_dict->SetFormattedValue("tsg_subscriber_id", "%s", (subscriber!=NULL) ? subscriber : "");
+ tpl_dict->SetFormattedValue("tsg_client_ip", "%s", (client_ip!=NULL) ? client_ip : "");
+}
+
+void http_response_body_template_value_get(const struct packet *rawpkt __attribute__((unused)), ctemplate::Template *pg_template, uuid_t rule_uuid, const char* message, char **output, size_t *output_sz)
+{
+ std::string page_output, msg_output;
+ ctemplate::TemplateDictionary dict("pg_page_dict"); //dict is automatically finalized after function returned.
+
+ if(message!=NULL)
+ {
+ ctemplate::Template *tpl_message=ctemplate::Template::StringToTemplate(message, strlen(message), ctemplate::DO_NOT_STRIP);
+ if(tpl_message!=NULL)
+ {
+ ctemplate::TemplateDictionary dict_msg("msg_dict"); //dict is automatically finalized after function returned.
+
+ char *client_ip=NULL;
+ char *subscriber=NULL;
+ policy_user_define_variable_replace(&dict_msg, rule_uuid, client_ip, subscriber);
+
+ tpl_message->Expand(&msg_output, &dict_msg);
+
+ size_t output_msg_sz=msg_output.length();
+ char *output_msg=(char *)CALLOC(char, output_msg_sz+1);
+ memcpy(output_msg, msg_output.c_str(), output_msg_sz);
+ output_msg[output_msg_sz]='\0';
+
+ dict.SetValue("msg", output_msg);
+
+ FREE(output_msg);
+ output_msg=NULL;
+
+ delete tpl_message;
+ }
+ else
+ {
+ dict.SetValue("msg", message);
+ }
+ }
+ else
+ {
+ dict.SetValue("msg", "NULL");
+ }
+
+ pg_template->Expand(&page_output, &dict);
+
+ *output_sz=page_output.length();
+ *output=(char *)CALLOC(char, *output_sz);
+ memcpy(*output, page_output.c_str(), *output_sz);
+}
+
+void security_enforcer_enforce_http_block(struct security_enforcer_env *enforcer_env, const struct session *sess, const struct packet *rawpkt, struct sub_action_response *response, uuid_t rule_uuid)
+{
+ if(enforcer_env==NULL || rawpkt==NULL || response==NULL)
+ {
+ return ;
+ }
+
+ packet_set_action((struct packet *)rawpkt, PACKET_ACTION_DROP);
+ session_set_discard((struct session *)sess);
+
+ uint16_t http_hdr_len=0;
+ char http_hdr[512]={0};
+ ctemplate::Template *pg_template=NULL;
+ switch(response->code)
+ {
+ case 200:
+ http_hdr_len=snprintf(http_hdr, sizeof(http_hdr), "HTTP/1.1 %d OK\r\nContent-Type: text/html\r\n\r\n", response->code);
+ pg_template=enforcer_env->tpl_200;
+ break;
+ case 204:
+ http_hdr_len=snprintf(http_hdr, sizeof(http_hdr), "HTTP/1.1 %d No Content\r\nContent-Type: text/html\r\n\r\n", response->code);
+ pg_template=enforcer_env->tpl_204;
+ break;
+ case 403:
+ http_hdr_len=snprintf(http_hdr, sizeof(http_hdr), "HTTP/1.1 %d Forbidden\r\nContent-Type: text/html\r\n\r\n", response->code);
+ pg_template=enforcer_env->tpl_403;
+ break;
+ case 404:
+ http_hdr_len=snprintf(http_hdr, sizeof(http_hdr), "HTTP/1.1 %d Not Found\r\nContent-Type: text/html\r\n\r\n", response->code);
+ pg_template=enforcer_env->tpl_404;
+ break;
+ default:
+ return ;
+ }
+
+ char *response_body=NULL;
+ size_t response_body_sz=0;
+ switch(response->rtype)
+ {
+ case RESPONSE_TEXT:
+ case RESPONSE_TEMPLATE:
+ http_response_body_template_value_get(rawpkt, pg_template, rule_uuid, response->message, &response_body, &response_body_sz);
+ break;
+ case RESPONSE_PROFILE:
+ {
+ const struct response_page *page=security_enforcer_get_response_page(enforcer_env->cm_maat, enforcer_env->plugin_table[SECURITY_PLUGIN_RESPONSE_PAGE].name, rule_uuid);
+ if(page==NULL)
+ {
+ break;
+ }
+
+ switch(page->rtype)
+ {
+ case RESPONSE_PROFILE:
+ response_body=(char *)CALLOC(char, page->content_sz);
+ memcpy(response_body, page->content, page->content_sz);
+ response_body_sz=page->content_sz;
+ break;
+ case RESPONSE_TEMPLATE:
+ http_response_body_template_value_get(rawpkt, pg_template, rule_uuid, page->content, &response_body, &response_body_sz);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case RESPONSE_NO_CONTENT:
+ break;
+ default:
+ return ;
+ }
+
+ if((response_body==NULL || response_body_sz==0) && http_hdr_len==0)
+ {
+ return ;
+ }
+
+ if(response_body_sz>0)
+ {
+ // TODO: set http_action_file_size
+ }
+
+ uint32_t th_seq=0;
+ uint32_t th_ack=0;
+ const struct packet *c2s_origin_pkt=NULL;
+ const struct packet *s2c_origin_pkt=NULL;
+ security_enforcer_get_origin_packet(sess, rawpkt, &c2s_origin_pkt, &s2c_origin_pkt, &th_seq, &th_ack);
+ if(c2s_origin_pkt==NULL)
+ {
+ return ;
+ }
+
+ char one_payload[1460]={0};
+ uint16_t th_seq_offset=0;
+ uint16_t one_payload_len=0;
+ uint16_t max_segment_size=1400;
+
+ for(size_t i=0; i<=response_body_sz; i+=one_payload_len)
+ {
+ if(http_hdr_len>0)
+ {
+ memcpy(one_payload, http_hdr, MIN(http_hdr_len, sizeof(one_payload)));
+ }
+
+ one_payload_len=MIN(response_body_sz-i, (size_t)(max_segment_size-http_hdr_len));
+ memcpy(one_payload+http_hdr_len, response_body+i, one_payload_len);
+
+ struct packet *redirect_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_origin_pkt, th_seq+i, th_ack, TH_ACK|TH_PUSH, NULL, 0, one_payload, http_hdr_len+one_payload_len);
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), redirect_pkt, PACKET_STAGE_POSTROUTING);
+
+ th_seq_offset+=(one_payload_len+http_hdr_len);
+ http_hdr_len=0;
+ }
+
+ FREE(response_body);
+ response_body=NULL;
+
+ struct packet *c2s_fin_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_origin_pkt, th_seq+th_seq_offset, th_ack, TH_ACK|TH_FIN, NULL, 0, NULL, 0);
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_fin_pkt, PACKET_STAGE_POSTROUTING);
+
+ struct packet *c2s_rst_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_origin_pkt, th_seq+th_seq_offset, th_ack, TH_ACK|TH_RST, NULL, 0, NULL, 0);
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_rst_pkt, PACKET_STAGE_POSTROUTING);
+
+ if(s2c_origin_pkt!=NULL)
+ {
+ struct packet *s2c_fin_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), s2c_origin_pkt, th_ack, th_seq+th_seq_offset, TH_ACK|TH_FIN, NULL, 0, NULL, 0);
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), s2c_fin_pkt, PACKET_STAGE_POSTROUTING);
+
+ struct packet *s2c_rst_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), s2c_origin_pkt, th_ack, th_seq+th_seq_offset, TH_ACK|TH_RST, NULL, 0, NULL, 0);
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), s2c_rst_pkt, PACKET_STAGE_POSTROUTING);
+ }
+}
+
+// void dns_response_header_append(struct utable *putable, struct _dns_hdr *dnshdr, int record_num)
+// {
+// dnshdr->qr=1; // 1bit: Response
+// dnshdr->opcode=0; // 4bits: Query
+// dnshdr->aa=0; // 1bit: authoritative answer
+// dnshdr->tc=0; // 1bit: Not truncated
+// dnshdr->rd=1; // 1bit: Recursion Desired
+// dnshdr->ra=1; // 1bit: Recursion Available
+// dnshdr->z=0; // 3bits: Reserved for future use: Must be zero in all queries and responses
+// dnshdr->rcode=0; // 4bits: 0: No error condition
+
+// dnshdr->ancount=record_num;
+
+// int64_t message_id=0;
+// utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_MESSAGE_ID].log_field_name, &message_id);
+// dnshdr->id=(uint16_t)message_id;
+// dnshdr->id=htons(dnshdr->id);
+
+// dnshdr->qdcount=1;
+// dnshdr->qdcount=htons(dnshdr->qdcount); // 16bits: QDCOUNT: number of questions
+// dnshdr->ancount=htons(dnshdr->ancount); // 16bits: ANCOUNT: number of answer resource records
+// dnshdr->aucount=htons(dnshdr->aucount); // 16bits: NSCOUNT: number of authority resource records
+// dnshdr->adcount=htons(dnshdr->adcount); // 16bits: ARCOUNT: number of additional resource records
+// }
+
+// static int dns_qanme_compress(char *qname, int qname_sz, char *compress_qname, int compress_qname_sz)
+// {
+// int c_offset=1;
+// int d_offset=0;
+
+// if(qname==NULL || qname_sz<=0 || compress_qname==NULL || compress_qname_sz<=0 || qname_sz>=compress_qname_sz)
+// {
+// return 0;
+// }
+
+// if(('.'==qname[0]) || ('.'==qname[qname_sz-1]))
+// {
+// return 0;
+// }
+
+// while((qname[d_offset]!='\n') && (qname[d_offset]!='\0') && (c_offset<compress_qname_sz) && (d_offset<qname_sz))
+// {
+// int section_len=0;
+// while((d_offset<qname_sz) && (qname[d_offset]!='.') && (qname[d_offset]!='\n') && (qname[d_offset]!='\0'))
+// {
+// section_len++;
+// compress_qname[c_offset++]=qname[d_offset++];
+// }
+
+// compress_qname[c_offset-section_len-1]=section_len;
+
+// if((d_offset>=qname_sz) || (qname[d_offset]=='\n') || (qname[d_offset]=='\0'))
+// {
+// break;
+// }
+
+// c_offset++;
+// d_offset++;
+// }
+
+// compress_qname[c_offset++]='\0';
+
+// return c_offset;
+// }
+
+// void dns_response_question_append(struct utable *putable, char *payload, size_t payload_sz, size_t *payload_offset)
+// {
+// size_t qname_sz=0;
+// char *qname=NULL;
+// utable_get0_cstring_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QNAME].log_field_name, &qname, &qname_sz);
+// if(qname==NULL || qname_sz<=0)
+// {
+// return ;
+// }
+
+// (*payload_offset)+=dns_qanme_compress(qname, qname_sz, payload+(*payload_offset), payload_sz-(*payload_offset));
+
+// int64_t qtype=0;
+// utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QTYPE].log_field_name, &qtype);
+// uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)qtype);
+
+// int64_t qclass=0;
+// utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QCLASS].log_field_name, &qclass);
+// uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)qclass);
+// }
+
+// void dns_response_answer_records_append(UT_array *records, char *payload, size_t payload_sz, size_t *payload_offset, int selected_num, int min_ttl, int max_ttl, uint16_t *n_records)
+// {
+// if(records==NULL || selected_num<=0)
+// {
+// return ;
+// }
+
+// uint32_t idx=0;
+// uint32_t n=MIN(utarray_len(records), (uint32_t)selected_num);
+// if(utarray_len(records) > (uint32_t)selected_num)
+// {
+// idx=random_integer_generate(0, n-selected_num);
+// }
+
+// for(uint32_t i=idx; i<n; i++)
+// {
+// struct dns_answer_record *answer_record=(struct dns_answer_record *)utarray_eltptr(records, i);
+// if(answer_record==NULL)
+// {
+// continue;
+// }
+
+// uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)0xc00c);
+// uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)(answer_record->atype));
+// uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)1);
+
+// int ttl=random_integer_generate(min_ttl, max_ttl)+min_ttl;
+// uint32_hton_append(payload, payload_sz, payload_offset, (uint32_t)ttl);
+
+// switch(answer_record->atype)
+// {
+// case RR_TYPE_A:
+// if(payload_sz-(*payload_offset) > 6)
+// {
+// uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)4);
+// uint32_append(payload, payload_sz, payload_offset, (uint32_t)(answer_record->v4_addr.s_addr));
+// }
+// break;
+// case RR_TYPE_AAAA:
+// if(payload_sz-(*payload_offset) > 18)
+// {
+// uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)16);
+// memcpy(payload+(*payload_offset), answer_record->v6_addr.s6_addr, 16);
+// (*payload_offset)+=16;
+// }
+// break;
+// case RR_TYPE_CNAME:
+// {
+// char compress_cname[1024]={0};
+// int compress_sz=dns_qanme_compress(answer_record->cname, strlen(answer_record->cname), compress_cname, sizeof(compress_cname));
+// uint16_hton_append(payload, payload_sz, payload_offset, (uint16_t)compress_sz);
+// compress_sz=MIN((size_t)compress_sz, payload_sz-(*payload_offset));
+// memcpy(payload+(*payload_offset), compress_cname, compress_sz);
+// (*payload_offset)+=compress_sz;
+// }
+// break;
+// default:
+// continue;
+// }
+
+// (*n_records)++;
+// }
+// }
+
+// //TODO: get dns profile records
+// void security_enforcer_enforce_dns_redirect(struct security_enforcer_env *enforcer_env, const struct packet *rawpkt, struct dns_setting_details *dns_redirect)
+// {
+// // if(enforcer_env==NULL || dns_redirect==NULL || rawpkt==NULL)
+// // {
+// // return ;
+// // }
+
+// // int64_t dns_qr=0;
+// // utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QR].log_field_name, &dns_qr);
+// // switch(firewall_rule_enforce_runtime.packet_response_mode)
+// // {
+// // case PACKET_RESPONSE_MODE_HIJACK:
+// // if(dns_qr==1) // dns_qr==1: response
+// // {
+// // return ;
+// // }
+// // break;
+// // case PACKET_RESPONSE_MODE_REPLACE:
+// // if(dns_qr==0) // dns_qr==0: query
+// // {
+// // return ;
+// // }
+// // break;
+// // default:
+// // return ;
+// // }
+
+// // char payload[1024]={0};
+// // size_t payload_sz=sizeof(payload);
+// // size_t payload_offset=0;
+
+// // payload_offset+=sizeof(struct _dns_hdr);
+// // dns_response_question_append(putable, payload, payload_sz, &payload_offset);
+
+// // int64_t qtype=0;
+// // utable_get0_integer_value(putable, firewall_attribute_schema[SCHEMA_ATTRIBUTE_DNS_QTYPE].log_field_name, &qtype);
+
+// // uint16_t n_records=0;
+// // for(uint32_t i=0; i<DNS_ANSWER_TYPE_MAX; i++)
+// // {
+// // struct dns_answer_record *record=(struct dns_answer_record *)utarray_eltptr(dns_redirect->answer_array[i], 0);
+// // if(record==NULL || record->qtype!=qtype)
+// // {
+// // continue;
+// // }
+
+// // switch(record->rtype)
+// // {
+// // case RESPONSE_PROFILE:
+// // {
+// // struct dns_profile_records *profile_records=(struct dns_profile_records *)plugin_ex_data_dns_profile_records_get(firewall_cm_maat, record->profile_uuid);
+// // if(profile_records==NULL)
+// // {
+// // return ;
+// // }
+// // dns_response_answer_records_append(profile_records->answer_array, payload, payload_sz, &payload_offset, record->selected_num, record->min_ttl, record->max_ttl, &n_records);
+// // }
+// // break;
+// // case RESPONSE_TEXT:
+// // {
+// // dns_response_answer_records_append(dns_redirect->answer_array[i], payload, payload_sz, &payload_offset, record->selected_num, record->min_ttl, record->max_ttl, &n_records);
+// // }
+// // break;
+// // default:
+// // break;
+// // }
+// // }
+
+// // if(n_records<=0)
+// // {
+// // return ;
+// // }
+
+// // dns_response_header_append(putable, (struct _dns_hdr *)payload, n_records);
+
+// // const struct packet *pkt=session_get0_current_packet(ss);
+// // int exchange_direction=(packet_get_direction(pkt)==PACKET_DIRECTION_C2S) ? TRUE : FALSE;
+// // int ret=firewall_payload_inject(ss, payload, payload_offset, exchange_direction);
+
+// // // TODO: get session from pkt
+// // const struct packet *c2s_first_pkt=session_get_first_packet(const struct session *sess, FLOW_TYPE_C2S);
+// // struct packet *redirect_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_first_pkt, innermost->tcp->th_seq, innermost->tcp->th_ack, innermost->tcp->th_flags, NULL, 0, payload, payload_offset);
+
+// // packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), redirect_pkt, PACKET_STAGE_POSTROUTING);
+// // packet_set_action(rawpkt, PACKET_ACTION_DROP);
+// }
+
+void security_enforcer_enforce_http_redirect(struct security_enforcer_env *enforcer_env, const struct session *sess, const struct packet *rawpkt, struct sub_action_response *response, uuid_t rule_uuid)
+{
+ if(enforcer_env==NULL || rawpkt==NULL || response==NULL || response->code!=303)
+ {
+ return ;
+ }
+
+ char payload[1024]={0};
+ uint16_t payload_offset=0;
+
+ ctemplate::Template *tpl_303=ctemplate::Template::StringToTemplate(response->redirect_url_to, strlen(response->redirect_url_to), ctemplate::DO_NOT_STRIP);
+ if(tpl_303!=NULL)
+ {
+ ctemplate::TemplateDictionary dict_303("url_dict"); //dict is automatically finalized after function returned.
+
+ char *client_ip=NULL;
+ char *subscriber=NULL;
+ policy_user_define_variable_replace(&dict_303, rule_uuid, client_ip, subscriber);
+
+ std::string output;
+ tpl_303->Expand(&output, &dict_303);
+
+ size_t output_url_sz=output.length();
+ char *output_url=(char *)CALLOC(char, output_url_sz+1);
+ memcpy(output_url, output.c_str(), output_url_sz);
+ output_url[output_url_sz]='\0';
+
+ payload_offset=snprintf(payload, sizeof(payload), "HTTP/1.1 %d See Other\r\nLocation: %s\r\n\r\n", response->code, output_url);
+
+ FREE(output_url);
+ output_url=NULL;
+ delete tpl_303;
+ }
+ else
+ {
+ payload_offset=snprintf(payload, sizeof(payload), "HTTP/1.1 %d See Other\r\nLocation: %s\r\n\r\n", response->code, response->redirect_url_to);
+ }
+
+ uint32_t th_seq=0;
+ uint32_t th_ack=0;
+ const struct packet *c2s_origin_pkt=NULL;
+ security_enforcer_get_origin_packet(sess, rawpkt, &c2s_origin_pkt, NULL, &th_seq, &th_ack);
+
+ if(c2s_origin_pkt!=NULL)
+ {
+ struct packet *redirect_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), c2s_origin_pkt, th_seq, th_ack, TH_PUSH, NULL, 0, payload, payload_offset);
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), redirect_pkt, PACKET_STAGE_POSTROUTING);
+ packet_set_action((struct packet *)rawpkt, PACKET_ACTION_DROP);
+ session_set_discard((struct session *)sess);
+ }
+}
+
+size_t payload_first_last_2bytes_swap(char *payload, uint16_t payload_sz)
+{
+ uint16_t swap_count=0;
+ for(uint16_t i=0, j=payload_sz-1; i<payload_sz && j> i; i++, j--)
+ {
+ if(swap_count>=2)
+ {
+ break;
+ }
+
+ if(payload[i]==payload[j])
+ {
+ continue;
+ }
+
+ char temp=payload[i];
+ payload[i]=payload[j];
+ payload[j]=temp;
+ swap_count++;
+ }
+
+ return swap_count;
+}
+
+#define TAMPER_MIN_PAYLOAD_LEN 4
+void security_enforcer_enforce_tamper(struct security_enforcer_env *enforcer_env, const struct packet *rawpkt)
+{
+ if(rawpkt==NULL)
+ {
+ return ;
+ }
+
+ int layer_count=packet_get_layer_count(rawpkt);
+ if(layer_count<=0)
+ {
+ return ;
+ }
+
+ const struct layer *innermost=packet_get_layer_by_idx(rawpkt, layer_count-1);
+ if(innermost==NULL)
+ {
+ return ;
+ }
+
+ const char *data=packet_get_raw_data(rawpkt);
+ uint16_t data_sz=packet_get_raw_len(rawpkt);
+ if(data==NULL || data_sz<TAMPER_MIN_PAYLOAD_LEN)
+ {
+ return ;
+ }
+
+ char payload[data_sz];
+ memcpy(payload, data, data_sz);
+ uint16_t payload_sz=data_sz;
+ size_t swap_count=payload_first_last_2bytes_swap(payload, payload_sz);
+ if(swap_count==0)
+ {
+ return ;
+ }
+
+ struct packet *tamper_pkt=NULL;
+ switch(innermost->proto)
+ {
+ case LAYER_PROTO_TCP:
+ {
+ uint16_t options_len=((innermost->hdr_len == sizeof(struct tcphdr)) ? 0 : (innermost->hdr_len - sizeof(struct tcphdr)));
+ const char *options=((options_len==0) ? NULL : innermost->hdr.raw + sizeof(struct tcphdr));
+ tamper_pkt=packet_manager_build_tcp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), rawpkt, innermost->hdr.tcp->th_seq, innermost->hdr.tcp->th_ack, innermost->hdr.tcp->th_flags, options, options_len, payload, payload_sz);
+ }
+ break;
+ case LAYER_PROTO_UDP:
+ tamper_pkt=packet_manager_build_udp_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), rawpkt, payload, payload_sz);
+ break;
+ default:
+ return ;
+ }
+
+ if(tamper_pkt==NULL)
+ {
+ return ;
+ }
+
+ packet_manager_schedule_packet(enforcer_env->pkt_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), tamper_pkt, PACKET_STAGE_POSTROUTING);
+ packet_set_action((struct packet *)rawpkt, PACKET_ACTION_DROP);
+}
+
+void security_enforcer_enforce_ratelimit(struct security_enforcer_env *enforcer_env __attribute__((unused)), const struct packet *rawpkt, struct leaky_bucket *bucket)
+{
+ if(rawpkt==NULL || bucket==NULL)
+ {
+ return ;
+ }
+
+ size_t rawpkt_sz=packet_get_raw_len(rawpkt);
+ if((is_permit_pass(bucket, rawpkt_sz*8))==0)
+ {
+ packet_set_action((struct packet *)rawpkt, PACKET_ACTION_DROP);
+ }
+}
+
+size_t maat_state_compile(struct maat_state *state __attribute__((unused)), const char *rule_table_name __attribute__((unused)), uuid_t rule_array[] __attribute__((unused)), void *rule_exdata[] __attribute__((unused)), size_t rule_array_num __attribute__((unused)))
+{
+ return 0;
+}
+
+void security_enforcer_packet_based_node_callback(const struct packet *rawpkt, void *arg)
+{
+ struct security_enforcer_env *enforcer_env=(struct security_enforcer_env *)arg;
+ if(enforcer_env==NULL || rawpkt==NULL)
+ {
+ return ;
+ }
+
+ struct session *sess=session_manager_lookup_session_by_packet(enforcer_env->sess_mgr, module_manager_get_thread_id(enforcer_env->mod_mgr), rawpkt);
+ if(sess!=NULL)
+ {
+ return ;
+ }
+
+ size_t rule_array_capacity=ENFORCER_RULE_UUID_NUM;
+ uuid_t rule_array[rule_array_capacity];
+ struct security_rule *rule_exdata[rule_array_capacity]={NULL};
+ struct maat_state *scan_state=scanner_get_maat_state_from_packet(enforcer_env->scanner, rawpkt);
+ size_t rule_array_offset=maat_state_compile(scan_state, enforcer_env->plugin_table[SECURITY_PLUGIN_SECURITY_RULE].name, rule_array, (void **)rule_exdata, rule_array_capacity);
+ if(rule_array_offset==0 || rule_exdata[0]==NULL)
+ {
+ return ;
+ }
+
+ // int ipproto=packet_get_ip_proto(rawpkt);
+
+ // uint64_t pkt_tag_key_bits=0;
+ // uint64_t pkt_tag_val_bits=0;
+ // packet_tag_get(rawpkt, &pkt_tag_key_bits, &pkt_tag_val_bits);
+}
+
+void security_enforcer_session_based_node_callback(const struct packet *rawpkt, void *arg)
+{
+ struct security_enforcer_env *enforcer_env=(struct security_enforcer_env *)arg;
+ if(enforcer_env==NULL || rawpkt==NULL)
+ {
+ return ;
+ }
+
+ struct session *sess=packet_exdata_to_session(enforcer_env->sess_mgr, rawpkt);
+ if(sess==NULL)
+ {
+ return ;
+ }
+
+ size_t rule_array_capacity=ENFORCER_RULE_UUID_NUM;
+ uuid_t rule_array[rule_array_capacity];
+ struct override_sub_action *override_action=NULL;
+ struct security_enforcer_per_session_context *per_sess_ctx=(struct security_enforcer_per_session_context *)session_get_exdata(sess, enforcer_env->exdata_idx);
+ if(per_sess_ctx!=NULL)
+ {
+ return ;
+ }
+ else
+ {
+ struct security_rule *rule_exdata[rule_array_capacity]={NULL};
+ struct maat_state *scan_state=scanner_get_maat_state_from_packet(enforcer_env->scanner, rawpkt);
+ size_t rule_array_offset=maat_state_compile(scan_state, enforcer_env->plugin_table[SECURITY_PLUGIN_SECURITY_RULE].name, rule_array, (void **)rule_exdata, rule_array_capacity);
+ if(rule_array_offset==0 || rule_exdata[0]==NULL)
+ {
+ return ;
+ }
+
+ if(rule_exdata[0]->action==SECURITY_RULE_ACTION_ALLOW)
+ {
+ return ;
+ }
+ else if(rule_exdata[0]->action==SECURITY_RULE_ACTION_DENY)
+ {
+
+ }
+
+ switch(rule_exdata[0]->deny->origin)
+ {
+ case origin_app_id_dict:
+ break;
+ case origin_override:
+ override_action=rule_exdata[0]->deny->override_action;
+ break;
+ default:
+ break;
+ }
+
+ if(override_action==NULL)
+ {
+ return ;
+ }
+
+ per_sess_ctx=(struct security_enforcer_per_session_context *)CALLOC(struct security_enforcer_per_session_context, 1);
+ session_set_exdata(sess, enforcer_env->exdata_idx, (void *)per_sess_ctx);
+ }
+
+ switch(override_action->sub_action_type)
+ {
+ case RULE_SUB_ACTION_DROP:
+ security_enforcer_enforce_drop(enforcer_env, sess, rawpkt, &(override_action->drop));
+ break;
+ case RULE_SUB_ACTION_ALERT:
+ security_enforcer_enforce_http_block(enforcer_env, sess, rawpkt, override_action->http_alert, rule_array[0]);
+ break;
+ case RULE_SUB_ACTION_TAMPER:
+ security_enforcer_enforce_tamper(enforcer_env, rawpkt);
+ break;
+ case RULE_SUB_ACTION_RATE_LIMIT:
+ security_enforcer_enforce_ratelimit(enforcer_env, rawpkt, per_sess_ctx->bucket);
+ break;
+ case RULE_SUB_ACTION_SIP_BLOCK:
+ break;
+ case RULE_SUB_ACTION_HTTP_BLOCK:
+ security_enforcer_enforce_http_block(enforcer_env, sess, rawpkt, override_action->block, rule_array[0]);
+ break;
+ case RULE_SUB_ACTION_MAIL_BLOCK:
+ security_enforcer_enforce_mail_block(enforcer_env, sess, rawpkt, override_action->block);
+ break;
+ case RULE_SUB_ACTION_HTTP_REDIRECT:
+ security_enforcer_enforce_http_redirect(enforcer_env, sess, rawpkt, override_action->http_redirect, rule_array[0]);
+ break;
+ case RULE_SUB_ACTION_DNS_REDIRECT:
+ break;
+ default:
+ break;
+ }
+}
+
+void security_enforcer_module_exit(struct module_manager *mod_mgr, struct module *mod)
+{
+ if(mod_mgr==NULL)return;
+ if(mod)
+ {
+ struct security_enforcer_env *enforcer_env=(struct security_enforcer_env *)module_get_ctx(mod);
+ FREE(enforcer_env);
+ module_free(mod);
+ }
+}
+
+struct module *security_enforcer_module_init(struct module_manager *mod_mgr)
+{
+ if(mod_mgr==NULL)return NULL;
+
+ char *page_403_path=NULL;
+ char *page_404_path=NULL;
+ char *page_200_path=NULL;
+ char *packet_response_mode=NULL;
+ // int max_thread_num=module_manager_get_max_thread_num(mod_mgr);
+ const char *toml_path=module_manager_get_toml_path(mod_mgr);
+
+ struct security_enforcer_env *enforcer_env=CALLOC(struct security_enforcer_env, 1);
+ struct module *mod=module_new(SECUIRTY_ENFORCER_MODULE_NAME, (void *)enforcer_env);
+ if(mod==NULL)
+ {
+ goto INIT_ERROR;
+ }
+
+ enforcer_env->mod_mgr=mod_mgr;
+ enforcer_env->logger=module_manager_get_logger(mod_mgr);
+
+ toml_string_get1(enforcer_env->logger, SECUIRTY_ENFORCER_MODULE_NAME, toml_path, "security_enforcer", "http_page_403", &page_403_path);
+ if(page_403_path==NULL)
+ {
+ goto INIT_ERROR;
+ }
+
+ enforcer_env->tpl_403=ctemplate::Template::GetTemplate(page_403_path, ctemplate::DO_NOT_STRIP);
+ free(page_403_path);
+
+ toml_string_get1(enforcer_env->logger, SECUIRTY_ENFORCER_MODULE_NAME, toml_path, "security_enforcer", "http_page_404", &page_404_path);
+ if(page_404_path==NULL)
+ {
+ goto INIT_ERROR;
+ }
+
+ enforcer_env->tpl_404=ctemplate::Template::GetTemplate(page_404_path, ctemplate::DO_NOT_STRIP);
+ free(page_404_path);
+
+ toml_string_get1(enforcer_env->logger, SECUIRTY_ENFORCER_MODULE_NAME, toml_path, "security_enforcer", "http_page_200", &page_200_path);
+ if(page_200_path==NULL)
+ {
+ goto INIT_ERROR;
+ }
+
+ enforcer_env->tpl_200=ctemplate::Template::GetTemplate(page_200_path, ctemplate::DO_NOT_STRIP);
+ free(page_200_path);
+
+ toml_string_get1(enforcer_env->logger, SECUIRTY_ENFORCER_MODULE_NAME, toml_path, "security_enforcer", "response_packet_mode", &packet_response_mode);
+ if(packet_response_mode==NULL)
+ {
+ goto INIT_ERROR;
+ }
+
+ if((strlen(packet_response_mode)==strlen("replace")) && (strcasecmp(packet_response_mode, "replace")==0))
+ {
+ enforcer_env->packet_response_mode=PACKET_RESPONSE_MODE_REPLACE;
+ free(packet_response_mode);
+ }
+ else
+ {
+ enforcer_env->packet_response_mode=PACKET_RESPONSE_MODE_HIJACK;
+ free(packet_response_mode);
+ }
+
+ enforcer_env->plugin_table[SECURITY_PLUGIN_UNKNOWN]=(struct maat_plugin_table){
+ .name="unknown",
+ .ex_new=NULL,
+ .ex_free=NULL,
+ .ex_dup=NULL
+ };
+
+ enforcer_env->plugin_table[SECURITY_PLUGIN_SECURITY_RULE]=(struct maat_plugin_table){
+ .name="SECURITY_RULE",
+ .ex_new=security_rule_new,
+ .ex_free=security_rule_free,
+ .ex_dup=security_rule_dup
+ };
+
+ enforcer_env->plugin_table[SECURITY_PLUGIN_RESPONSE_PAGE]=(struct maat_plugin_table){
+ .name="RESPONSE_PAGE",
+ .ex_new=response_page_new,
+ .ex_free=response_page_free,
+ .ex_dup=response_page_dup
+ };
+
+ enforcer_env->plugin_table[SECURITY_PLUGIN_DNS_RESOURCE_RECORD]=(struct maat_plugin_table){
+ .name="DNS_RESOURCE_RECORD",
+ .ex_new=dns_resource_record_new,
+ .ex_free=dns_resource_record_free,
+ .ex_dup=dns_resource_record_dup
+ };
+
+ enforcer_env->scanner=scanner_module_to_scanner(module_manager_get_module(mod_mgr, SCANNER_MODULE_NAME));
+ enforcer_env->cm_maat=scanner_get_maat_instance(enforcer_env->scanner);
+ if(enforcer_env->cm_maat==NULL)
+ {
+ STELLAR_LOG_FATAL(enforcer_env->logger, SECUIRTY_ENFORCER_MODULE_NAME, "scanner_get_maat_instance/scanner_module_to_scanner/module_manager_get_module failed, module_name: %s", SCANNER_MODULE_NAME);
+ goto INIT_ERROR;
+ }
+
+ for(int i=SECURITY_PLUGIN_UNKNOWN; i<SECURITY_PLUGIN_MAX; i++)
+ {
+ if(enforcer_env->plugin_table[i].name==NULL)
+ {
+ continue;
+ }
+
+ int ret=maat_plugin_table_ex_schema_register(enforcer_env->cm_maat,
+ enforcer_env->plugin_table[i].name,
+ enforcer_env->plugin_table[i].ex_new,
+ enforcer_env->plugin_table[i].ex_free,
+ enforcer_env->plugin_table[i].ex_dup,
+ 0,
+ NULL
+ );
+ if(ret<0)
+ {
+ STELLAR_LOG_FATAL(enforcer_env->logger, SECUIRTY_ENFORCER_MODULE_NAME, "maat_plugin_table_ex_schema_register failed, table_name: %s", enforcer_env->plugin_table[i].name);
+ goto INIT_ERROR;
+ }
+ }
+
+ return mod;
+
+INIT_ERROR:
+ security_enforcer_module_exit(mod_mgr, mod);
+ exit(-1);
+ return NULL;
+}
diff --git a/enforcer/security/security_enforcer.h b/enforcer/security/security_enforcer.h
index 3fa89b0..43f0f67 100644
--- a/enforcer/security/security_enforcer.h
+++ b/enforcer/security/security_enforcer.h
@@ -1,30 +1,15 @@
#pragma once
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include <uthash/utarray.h>
-
-#include "bucket.h"
-#include "sapp_adaptor.h"
-#include "policy_match.h"
-
+#ifdef __cplusplus
+extern "C"
+{
+#endif
#define SECUIRTY_ENFORCER_MODULE_NAME "security_enforcer_module"
struct security_enforcer;
struct security_enforcer *security_enforcer_module_to_enforcer(struct module *mod);
-void firewall_rule_enforce_init(const char *config_file);
-
-void deny_sub_action_reset_enforce(struct session *ss);
-void deny_sub_action_tamper_enforce(struct session *ss);
-void deny_sub_action_drop_enforce(struct session *ss, struct sub_action_drop *drop);
-void deny_sub_action_ratelimit_enforce(struct session *ss, struct leaky_bucket *bucket);
-void deny_sub_action_packet_ratelimit_enforce(struct packet *rawpkt, struct leaky_bucket *bucket);
-
-void deny_sub_action_sip_block_enforce(struct session *ss, struct sub_action_response *block, struct utable *putable);
-void deny_sub_action_mail_block_enforce(struct session *ss, struct sub_action_response *block, struct utable *putable);
-void deny_sub_action_http_block_enforce(struct session *ss, struct sub_action_response *response, struct utable *putable, uuid_t rule_uuid);
-void deny_sub_action_dns_redirect_enforce(struct session *ss, struct dns_setting_details *dns_redirect, struct utable *putable);
-void deny_sub_action_http_redirect_enforce(struct session *ss, struct sub_action_response *response, struct utable *putable, uuid_t rule_uuid);
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/exporter/session_exporter.c b/exporter/session_exporter.c
index 859311d..f65e245 100644
--- a/exporter/session_exporter.c
+++ b/exporter/session_exporter.c
@@ -84,7 +84,7 @@ struct exporter_context *exporter_aquire_transaction_context(struct exporter *ex
}
struct transaction_unique_key key;
- strncpy(key.decode_as, decode_as, MIN(sizeof(key.decode_as), strlen(decode_as)));
+ memcpy(key.decode_as, decode_as, MIN(sizeof(key.decode_as), strlen(decode_as)));
key.transaction_sequence=transaction_sequence;
struct exporter_transaction *transaction=NULL;
diff --git a/include/stellar/scanner.h b/include/stellar/scanner.h
index 11d0b4e..fdabaa4 100644
--- a/include/stellar/scanner.h
+++ b/include/stellar/scanner.h
@@ -18,6 +18,7 @@ struct scanner *scanner_module_to_scanner(struct module *mod);
/* return NULL if not found */
struct maat *scanner_get_maat_instance(struct scanner *scanner);
+struct maat_state *scanner_get_maat_state_from_packet(struct scanner *scanner, const struct packet *pkt);
const char *scanner_get_object_type(struct scanner *scanner, const char *attribute_name);
const char *scanner_get_object_table_name(struct scanner *scanner, const char *attribute_name);
diff --git a/vendors/CMakeLists.txt b/vendors/CMakeLists.txt
index db34d81..b69f3b5 100644
--- a/vendors/CMakeLists.txt
+++ b/vendors/CMakeLists.txt
@@ -98,3 +98,20 @@ add_dependencies(libevent-static libevent)
set_property(TARGET libevent-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libevent.a)
set_property(TARGET libevent-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
set_property(TARGET libevent-static PROPERTY INTERFACE_LINK_LIBRARIES pthread)
+
+### ctemplate
+ExternalProject_Add(ctemplate PREFIX ctemplate
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/ctemplate-2.3.tar.gz
+ URL_MD5 3b91f3c1e7aa55cb4c2957acf77d6b9a
+ PATCH_COMMAND patch -p1 < ${CMAKE_CURRENT_LIST_DIR}/patch/compile_ctemplate_use_centos8_with_gcc7.patch
+ BUILD_COMMAND sh autogen.sh
+ CONFIGURE_COMMAND CPPFLAGS=-fPIC ./configure --prefix=<INSTALL_DIR> CFLAGS=-fPIC CXXFLAGS=-fPIC LDFLAGS=-fPIC
+ BUILD_IN_SOURCE 1)
+
+ExternalProject_Get_Property(ctemplate INSTALL_DIR)
+file(MAKE_DIRECTORY ${INSTALL_DIR}/include)
+
+add_library(ctemplate-static STATIC IMPORTED GLOBAL)
+add_dependencies(ctemplate-static ctemplate)
+set_property(TARGET ctemplate-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libctemplate.a)
+set_property(TARGET ctemplate-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
diff --git a/vendors/ctemplate-2.3.tar.gz b/vendors/ctemplate-2.3.tar.gz
new file mode 100644
index 0000000..6ec1a72
--- /dev/null
+++ b/vendors/ctemplate-2.3.tar.gz
Binary files differ
diff --git a/vendors/patch/compile_ctemplate_use_centos8_with_gcc7.patch b/vendors/patch/compile_ctemplate_use_centos8_with_gcc7.patch
new file mode 100644
index 0000000..9b5f5c1
--- /dev/null
+++ b/vendors/patch/compile_ctemplate_use_centos8_with_gcc7.patch
@@ -0,0 +1,10 @@
+diff --git a/src/htmlparser/generate_fsm.py b/src/htmlparser/generate_fsm.py
+index 9106b96..3f1e535 100755
+--- a/src/htmlparser/generate_fsm.py
++++ b/src/htmlparser/generate_fsm.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python2
+ #
+ # Copyright (c) 2008, Google Inc.
+ # All rights reserved. \ No newline at end of file