diff --git a/src/xdp/prog.c b/src/xdp/prog.c index 6425b91..d631312 100644 --- a/src/xdp/prog.c +++ b/src/xdp/prog.c @@ -44,9 +44,6 @@ int xdp_prog_main(struct xdp_md *ctx) return XDP_PASS; } - u8 action = 0; - u64 block_time = 1; - // Initialize IP headers. struct iphdr *iph = NULL; struct ipv6hdr *iph6 = NULL; @@ -62,7 +59,7 @@ int xdp_prog_main(struct xdp_md *ctx) return XDP_DROP; } - memcpy(&src_ip6, &iph6->saddr.in6_u.u6_addr32, sizeof(src_ip6)); + memcpy(&src_ip6, iph6->saddr.in6_u.u6_addr32, sizeof(src_ip6)); } else { @@ -74,28 +71,29 @@ int xdp_prog_main(struct xdp_md *ctx) } } - // Check IP header protocols. + // We only want to process TCP, UDP, and ICMP packets. if ((iph6 && iph6->nexthdr != IPPROTO_UDP && iph6->nexthdr != IPPROTO_TCP && iph6->nexthdr != IPPROTO_ICMP) && (iph && iph->protocol != IPPROTO_UDP && iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_ICMP)) { return XDP_PASS; } - // Get stats map. + // Retrieve stats map value. u32 key = 0; stats_t*stats = bpf_map_lookup_elem(&map_stats, &key); + // Retrieve nanoseconds since system boot as timestamp. u64 now = bpf_ktime_get_ns(); - // Check blacklist map. + // Check block map. u64 *blocked = NULL; if (iph6) { - blocked = bpf_map_lookup_elem(&map_ip6_blacklist, &src_ip6); + blocked = bpf_map_lookup_elem(&map_block6, &src_ip6); } else if (iph) { - blocked = bpf_map_lookup_elem(&map_ip_blacklist, &iph->saddr); + blocked = bpf_map_lookup_elem(&map_block, &iph->saddr); } if (blocked != NULL && *blocked > 0) @@ -105,11 +103,11 @@ int xdp_prog_main(struct xdp_md *ctx) // Remove element from map. if (iph6) { - bpf_map_delete_elem(&map_ip6_blacklist, &src_ip6); + bpf_map_delete_elem(&map_block6, &src_ip6); } else if (iph) { - bpf_map_delete_elem(&map_ip_blacklist, &iph->saddr); + bpf_map_delete_elem(&map_block, &iph->saddr); } } else @@ -127,6 +125,21 @@ int xdp_prog_main(struct xdp_md *ctx) } } +#ifdef ENABLE_IP_RANGE_DROP + if (iph && CheckIpRangeDrop(iph->saddr)) + { +#ifdef DO_STATS_ON_IP_RANGE_DROP_MAP + if (stats) + { + stats->dropped++; + } +#endif + + return XDP_DROP; + } +#endif + +#ifdef ENABLE_FILTERS // Retrieve total packet length. u16 pkt_len = data_end - data; @@ -267,7 +280,10 @@ int xdp_prog_main(struct xdp_md *ctx) { UpdateIpStats(&pps, &bps, iph->saddr, src_port, protocol, pkt_len, now); } - + + int action = 0; + u64 block_time = 1; + for (int i = 0; i < MAX_FILTERS; i++) { u32 key = i; @@ -543,6 +559,7 @@ int xdp_prog_main(struct xdp_md *ctx) goto matched; } +#endif if (stats) { @@ -551,21 +568,22 @@ int xdp_prog_main(struct xdp_md *ctx) return XDP_PASS; - matched: +#ifdef ENABLE_FILTERS +matched: if (action == 0) { - // Before dropping, update the blacklist map. + // Before dropping, update the block map. if (block_time > 0) { u64 new_time = now + (block_time * NANO_TO_SEC); if (iph6) { - bpf_map_update_elem(&map_ip6_blacklist, &src_ip6, &new_time, BPF_ANY); + bpf_map_update_elem(&map_block6, &src_ip6, &new_time, BPF_ANY); } else if (iph) { - bpf_map_update_elem(&map_ip_blacklist, &iph->saddr, &new_time, BPF_ANY); + bpf_map_update_elem(&map_block, &iph->saddr, &new_time, BPF_ANY); } } @@ -585,6 +603,7 @@ int xdp_prog_main(struct xdp_md *ctx) } return XDP_PASS; +#endif } char _license[] SEC("license") = "GPL"; diff --git a/src/xdp/utils/helpers.c b/src/xdp/utils/helpers.c index 5b10d10..36d3785 100644 --- a/src/xdp/utils/helpers.c +++ b/src/xdp/utils/helpers.c @@ -1,5 +1,7 @@ #include +#include + /** * Checks if an IP is within a specific CIDR range. * @@ -12,4 +14,38 @@ static __always_inline int IsIpInRange(u32 src_ip, u32 net_ip, u8 cidr) { return !((src_ip ^ net_ip) & htonl(0xFFFFFFFFu << (32 - cidr))); -} \ No newline at end of file +} + +#ifdef ENABLE_IP_RANGE_DROP +/** + * Checks if the IP is in the IP range drop map. + * + * @param ip The IP address. + * + * @return 1 on yes or 0 on no. + */ +static __always_inline int CheckIpRangeDrop(u32 ip) +{ + LpmTrieKey key = + { + .prefix_len = 32, + .data = ip + }; + + u64 *lookup = bpf_map_lookup_elem(&map_range_drop, &key); + + if (lookup) + { + u32 bit_mask = *lookup >> 32; + u32 prefix = *lookup & 0xFFFFFFFF; + + // Check if matched. + if ((ip & bit_mask) == prefix) + { + return 1; + } + } + + return 0; +} +#endif \ No newline at end of file diff --git a/src/xdp/utils/helpers.h b/src/xdp/utils/helpers.h index 14b99e5..e268b73 100644 --- a/src/xdp/utils/helpers.h +++ b/src/xdp/utils/helpers.h @@ -34,6 +34,10 @@ static __always_inline int IsIpInRange(u32 src_ip, u32 net_ip, u8 cidr); +#ifdef ENABLE_IP_RANGE_DROP +static __always_inline int CheckIpRangeDrop(u32 ip); +#endif + // The source file is included directly below instead of compiled and linked as an object because when linking, there is no guarantee the compiler will inline the function (which is crucial for performance). // I'd prefer not to include the function logic inside of the header file. // More Info: https://stackoverflow.com/questions/24289599/always-inline-does-not-work-when-function-is-implemented-in-different-file diff --git a/src/xdp/utils/logging.c b/src/xdp/utils/logging.c index 0268ebf..9cda33b 100644 --- a/src/xdp/utils/logging.c +++ b/src/xdp/utils/logging.c @@ -4,6 +4,7 @@ #include #include +#if defined(ENABLE_FILTERS) && defined(ENABLE_FILTER_LOGGING) /** * Logs a message to the filter ringbuffer map. * @@ -50,4 +51,5 @@ static __always_inline int LogFilterMsg(struct iphdr* iph, struct ipv6hdr* iph6, } return 0; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/xdp/utils/logging.h b/src/xdp/utils/logging.h index 4b42072..d3c395d 100644 --- a/src/xdp/utils/logging.h +++ b/src/xdp/utils/logging.h @@ -5,7 +5,9 @@ #include #include +#if defined(ENABLE_FILTERS) && defined(ENABLE_FILTER_LOGGING) static __always_inline int LogFilterMsg(struct iphdr* iph, struct ipv6hdr* iph6, u16 src_port, u16 dst_port, u8 protocol, u64 now, u64 pps, u64 bps, int filter_id); +#endif // The source file is included directly below instead of compiled and linked as an object because when linking, there is no guarantee the compiler will inline the function (which is crucial for performance). // I'd prefer not to include the function logic inside of the header file. diff --git a/src/xdp/utils/maps.h b/src/xdp/utils/maps.h index f48b225..a1eebfe 100644 --- a/src/xdp/utils/maps.h +++ b/src/xdp/utils/maps.h @@ -5,14 +5,6 @@ #include -struct -{ - __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); - __uint(max_entries, MAX_FILTERS); - __type(key, u32); - __type(value, filter_t); -} map_filters SEC(".maps"); - struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); @@ -21,6 +13,33 @@ struct __type(value, stats_t); } map_stats SEC(".maps"); +struct +{ + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_TRACK_IPS); + __type(key, u32); + __type(value, u64); +} map_block SEC(".maps"); + +struct +{ + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_TRACK_IPS); + __type(key, u128); + __type(value, u64); +} map_block6 SEC(".maps"); + +#ifdef ENABLE_IP_RANGE_DROP +struct { + __uint(type, BPF_MAP_TYPE_LPM_TRIE); + __uint(max_entries, MAX_IP_RANGES); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, LpmTrieKey); + __type(value, u64); +} map_range_drop SEC(".maps"); +#endif + +#ifdef ENABLE_FILTERS struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); @@ -33,14 +52,6 @@ struct __type(value, ip_stats_t); } map_ip_stats SEC(".maps"); -struct -{ - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(max_entries, MAX_TRACK_IPS); - __type(key, u32); - __type(value, u64); -} map_ip_blacklist SEC(".maps"); - struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); @@ -55,11 +66,11 @@ struct struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(max_entries, MAX_TRACK_IPS); - __type(key, u128); - __type(value, u64); -} map_ip6_blacklist SEC(".maps"); + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(max_entries, MAX_FILTERS); + __type(key, u32); + __type(value, filter_t); +} map_filters SEC(".maps"); #ifdef ENABLE_FILTER_LOGGING struct @@ -67,4 +78,5 @@ struct __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 1 << 16); } map_filter_log SEC(".maps"); +#endif #endif \ No newline at end of file diff --git a/src/xdp/utils/rl.c b/src/xdp/utils/rl.c index f02f0aa..31b124a 100644 --- a/src/xdp/utils/rl.c +++ b/src/xdp/utils/rl.c @@ -1,5 +1,6 @@ #include +#ifdef ENABLE_FILTERS /** * Updates IPv4 client stats. * @@ -128,4 +129,5 @@ static __always_inline void UpdateIp6Stats(u64 *pps, u64 *bps, u128 *ip, u16 por bpf_map_update_elem(&map_ip6_stats, ip, &new, BPF_ANY); #endif } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/xdp/utils/rl.h b/src/xdp/utils/rl.h index 85ec5eb..13a1127 100644 --- a/src/xdp/utils/rl.h +++ b/src/xdp/utils/rl.h @@ -6,8 +6,10 @@ #include +#ifdef ENABLE_FILTERS static __always_inline void UpdateIpStats(u64 *pps, u64 *bps, u32 ip, u16 port, u8 protocol, u16 pkt_len, u64 now); static __always_inline void UpdateIp6Stats(u64 *pps, u64 *bps, u128 *ip, u16 port, u8 protocol, u16 pkt_len, u64 now); +#endif // The source file is included directly below instead of compiled and linked as an object because when linking, there is no guarantee the compiler will inline the function (which is crucial for performance). // I'd prefer not to include the function logic inside of the header file.