diff options
| author | liuxueli <[email protected]> | 2024-11-19 07:18:00 +0000 |
|---|---|---|
| committer | liuxueli <[email protected]> | 2024-11-27 06:37:23 +0000 |
| commit | 38307ed232012dcbd44bd95167b8f37c7186d1fb (patch) | |
| tree | f2be8c66d3e62b18ccb76b0a02a8424ee3edf6ce | |
| parent | 409833b463c7e43eec4b4cb332485d4755d92486 (diff) | |
Implement security_enforcer.cpp
| -rw-r--r-- | conf/stellar.toml | 7 | ||||
| -rw-r--r-- | enforcer/security/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | enforcer/security/bucket.h | 9 | ||||
| -rw-r--r-- | enforcer/security/security_enforcer.c | 1264 | ||||
| -rw-r--r-- | enforcer/security/security_enforcer.cpp | 1343 | ||||
| -rw-r--r-- | enforcer/security/security_enforcer.h | 29 | ||||
| -rw-r--r-- | exporter/session_exporter.c | 2 | ||||
| -rw-r--r-- | include/stellar/scanner.h | 1 | ||||
| -rw-r--r-- | vendors/CMakeLists.txt | 17 | ||||
| -rw-r--r-- | vendors/ctemplate-2.3.tar.gz | bin | 0 -> 720717 bytes | |||
| -rw-r--r-- | vendors/patch/compile_ctemplate_use_centos8_with_gcc7.patch | 10 |
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 Binary files differnew file mode 100644 index 0000000..6ec1a72 --- /dev/null +++ b/vendors/ctemplate-2.3.tar.gz 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 |
