diff --git a/bpf/counters.h b/bpf/counters.h new file mode 100644 index 000000000..7df8d1b18 --- /dev/null +++ b/bpf/counters.h @@ -0,0 +1,19 @@ +#ifndef __COUNTERS_H__ +#define __COUNTERS_H__ + +#include +#include "maps_definition.h" + +// Update global counter for hashmap update errors +static inline void increase_counter(u32 key) { + u32 *error_counter_p = NULL; + u32 initVal = 1; + error_counter_p = bpf_map_lookup_elem(&global_counters, &key); + if (!error_counter_p) { + bpf_map_update_elem(&global_counters, &key, &initVal, BPF_ANY); + } else { + __sync_fetch_and_add(error_counter_p, 1); + } +} + +#endif // __COUNTERS_H__ diff --git a/bpf/flows.c b/bpf/flows.c index a226af3c8..a1b918f2c 100644 --- a/bpf/flows.c +++ b/bpf/flows.c @@ -18,6 +18,10 @@ #include #include "configs.h" #include "utils.h" +#include "counters.h" + +/* Do flow filtering. Is optional. */ +#include "flows_filter.h" /* * Defines a packet drops statistics tracker, @@ -42,9 +46,6 @@ * It is enabled by setting env var ENABLE_PCA= true. Is Optional */ #include "pca.h" - -/* Do flow filtering. Is optional. */ -#include "flows_filter.h" /* * Defines an Network events monitoring tracker, * which runs inside flow_monitor. Is optional. diff --git a/bpf/flows_filter.h b/bpf/flows_filter.h index 74e8553aa..918016558 100644 --- a/bpf/flows_filter.h +++ b/bpf/flows_filter.h @@ -5,8 +5,6 @@ #ifndef __FLOWS_FILTER_H__ #define __FLOWS_FILTER_H__ -#include "utils.h" - #define BPF_PRINTK(fmt, args...) \ if (trace_messages) \ bpf_printk(fmt, ##args) @@ -266,4 +264,59 @@ static __always_inline int is_flow_filtered(flow_id *id, filter_action *action, return do_flow_filter_lookup(id, &key, action, len, offset, flags, drop_reason, sampling); } +static inline bool is_filter_enabled() { + if (enable_flows_filtering || enable_pca) { + return true; + } + return false; +} + +/* + * check if flow filter is enabled and if we need to continue processing the packet or not + */ +static inline bool check_and_do_flow_filtering(flow_id *id, u16 flags, u32 drop_reason, + u16 eth_protocol, u32 *sampling) { + // check if this packet need to be filtered if filtering feature is enabled + if (is_filter_enabled()) { + filter_action action = ACCEPT; + if (is_flow_filtered(id, &action, flags, drop_reason, eth_protocol, sampling) != 0 && + action != MAX_FILTER_ACTIONS) { + // we have matching rules follow through the actions to decide if we should accept or reject the flow + // and update global counter for both cases + bool skip = false; + u32 key = 0; + + switch (action) { + case REJECT: + key = FILTER_REJECT; + skip = true; + break; + case ACCEPT: + key = FILTER_ACCEPT; + break; + // should never come here + case MAX_FILTER_ACTIONS: + return true; + } + + // update global counter for flows dropped by filter + increase_counter(key); + if (skip) { + return true; + } + } else { + // we have no matching rules so we update global counter for flows that are not matched by any rule + increase_counter(FILTER_NOMATCH); + // we have accept rule but no match so we can't let mismatched flows in the hashmap table or + // we have no match at all and the action is the default value MAX_FILTER_ACTIONS. + if (action == ACCEPT || action == MAX_FILTER_ACTIONS) { + return true; + } else { + // we have reject rule and no match so we can add the flows to the hashmap table. + } + } + } + return false; +} + #endif //__FLOWS_FILTER_H__ diff --git a/bpf/test.c b/bpf/test.c new file mode 100644 index 000000000..89ad1541d --- /dev/null +++ b/bpf/test.c @@ -0,0 +1,114 @@ +#include +#include + +#define false 0 +#define true 1 +#define bpf_printk printf + +typedef int bool; +typedef unsigned char __u8; +typedef unsigned short __u16; +typedef unsigned long __u32; +typedef unsigned long long __u64; + +enum { + IPPROTO_ICMP = 1, + IPPROTO_TCP = 6, + IPPROTO_UDP = 17, + IPPROTO_SCTP = 132, +}; + +struct bpf_spin_lock { + __u32 val; +}; + +#include "types.h" + +volatile u32 sampling = 0; +volatile u8 trace_messages = 0; +volatile u8 enable_rtt = 0; +volatile u8 enable_pca = 0; +volatile u8 enable_dns_tracking = 0; +volatile u8 enable_flows_filtering = 0; +volatile u16 dns_port = 0; +volatile u8 enable_network_events_monitoring = 0; +volatile u8 network_events_monitoring_groupid = 0; +volatile u8 enable_pkt_translation_tracking = 0; + +typedef enum mock_scenario_t { + NO_RULE, + REJECT_1_2_3_4_ALLOW_OTHER, +} mock_scenario; + +struct mocked_map { + mock_scenario scen; +}; + +struct filter_value_t reject_filter = { + .action = REJECT, +}; +struct filter_value_t accept_filter = { + .action = ACCEPT, +}; + +volatile struct mocked_map filter_map; + +static struct filter_value_t* bpf_map_lookup_elem(struct mocked_map *map, struct filter_key_t *key) { + if (map->scen == NO_RULE) { + return NULL; + } + u8 ip1234[IP_MAX_LEN] = {1, 2, 3, 4}; + if (__builtin_memcmp(ip1234, key->ip_data, IP_MAX_LEN) == 0) { + return &reject_filter; + } + return &accept_filter; +} + +static void increase_counter(u32 key) { +} + +#include "flows_filter.h" + +int main(int argc, char *argv[]) { + flow_id id; + filter_action action; + u32 sampling = 0; + filter_map.scen = NO_RULE; + int skip = check_and_do_flow_filtering(&id, 0, 0, ETH_P_IP, &sampling); + printf("skip=%d\n", skip); + assert(skip == 0); + printf("filter disabled [success]\n"); + + enable_flows_filtering = 1; + skip = check_and_do_flow_filtering(&id, 0, 0, ETH_P_IP, &sampling); + printf("skip=%d\n", skip); + assert(skip == 1); + printf("filter enabled [success]\n"); + + filter_map.scen = REJECT_1_2_3_4_ALLOW_OTHER; + __builtin_memcpy(id.src_ip, (u8[IP_MAX_LEN]){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4}, IP_MAX_LEN); + __builtin_memcpy(id.dst_ip, (u8[IP_MAX_LEN]){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8}, IP_MAX_LEN); + printf("filter should reject from 1.2.3.4 [...]\n"); + skip = check_and_do_flow_filtering(&id, 0, 0, ETH_P_IP, &sampling); + printf("skip=%d\n", skip); + assert(skip == 1); + printf("filter reject from 1.2.3.4 [success]\n"); + + __builtin_memcpy(id.src_ip, (u8[IP_MAX_LEN]){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8}, IP_MAX_LEN); + __builtin_memcpy(id.dst_ip, (u8[IP_MAX_LEN]){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4}, IP_MAX_LEN); + printf("filter should reject to 1.2.3.4 [...]\n"); + skip = check_and_do_flow_filtering(&id, 0, 0, ETH_P_IP, &sampling); + printf("skip=%d\n", skip); + assert(skip == 1); + printf("filter reject to 1.2.3.4 [success]\n"); + + __builtin_memcpy(id.src_ip, (u8[IP_MAX_LEN]){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 5}, IP_MAX_LEN); + __builtin_memcpy(id.dst_ip, (u8[IP_MAX_LEN]){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8}, IP_MAX_LEN); + printf("filter should accept others [...]\n"); + skip = check_and_do_flow_filtering(&id, 0, 0, ETH_P_IP, &sampling); + printf("skip=%d\n", skip); + assert(skip == 0); + printf("filter accept others [success]\n"); + + return 0; +} diff --git a/bpf/utils.h b/bpf/utils.h index 64b6a6ce9..7824bdbd9 100644 --- a/bpf/utils.h +++ b/bpf/utils.h @@ -3,23 +3,9 @@ #include #include "types.h" -#include "maps_definition.h" -#include "flows_filter.h" static u8 do_sampling = 0; -// Update global counter for hashmap update errors -static inline void increase_counter(u32 key) { - u32 *error_counter_p = NULL; - u32 initVal = 1; - error_counter_p = bpf_map_lookup_elem(&global_counters, &key); - if (!error_counter_p) { - bpf_map_update_elem(&global_counters, &key, &initVal, BPF_ANY); - } else { - __sync_fetch_and_add(error_counter_p, 1); - } -} - // sets the TCP header flags for connection information static inline void set_flags(struct tcphdr *th, u16 *flags) { //If both ACK and SYN are set, then it is server -> client communication during 3-way handshake. @@ -174,61 +160,6 @@ static inline int fill_ethhdr(struct ethhdr *eth, void *data_end, pkt_info *pkt, return SUBMIT; } -static inline bool is_filter_enabled() { - if (enable_flows_filtering || enable_pca) { - return true; - } - return false; -} - -/* - * check if flow filter is enabled and if we need to continue processing the packet or not - */ -static inline bool check_and_do_flow_filtering(flow_id *id, u16 flags, u32 drop_reason, - u16 eth_protocol, u32 *sampling) { - // check if this packet need to be filtered if filtering feature is enabled - if (is_filter_enabled()) { - filter_action action = ACCEPT; - if (is_flow_filtered(id, &action, flags, drop_reason, eth_protocol, sampling) != 0 && - action != MAX_FILTER_ACTIONS) { - // we have matching rules follow through the actions to decide if we should accept or reject the flow - // and update global counter for both cases - bool skip = false; - u32 key = 0; - - switch (action) { - case REJECT: - key = FILTER_REJECT; - skip = true; - break; - case ACCEPT: - key = FILTER_ACCEPT; - break; - // should never come here - case MAX_FILTER_ACTIONS: - return true; - } - - // update global counter for flows dropped by filter - increase_counter(key); - if (skip) { - return true; - } - } else { - // we have no matching rules so we update global counter for flows that are not matched by any rule - increase_counter(FILTER_NOMATCH); - // we have accept rule but no match so we can't let mismatched flows in the hashmap table or - // we have no match at all and the action is the default value MAX_FILTER_ACTIONS. - if (action == ACCEPT || action == MAX_FILTER_ACTIONS) { - return true; - } else { - // we have reject rule and no match so we can add the flows to the hashmap table. - } - } - } - return false; -} - static inline void core_fill_in_l2(struct sk_buff *skb, u16 *eth_protocol, u16 *family) { struct ethhdr eth;