Add support for IP range drop and make features more modular.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -268,6 +281,9 @@ 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;
|
||||
|
||||
#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";
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <xdp/utils/helpers.h>
|
||||
|
||||
#include <xdp/utils/maps.h>
|
||||
|
||||
/**
|
||||
* Checks if an IP is within a specific CIDR range.
|
||||
*
|
||||
@@ -13,3 +15,37 @@ static __always_inline int IsIpInRange(u32 src_ip, u32 net_ip, u8 cidr)
|
||||
{
|
||||
return !((src_ip ^ net_ip) & htonl(0xFFFFFFFFu << (32 - cidr)));
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <xdp/utils/helpers.h>
|
||||
#include <xdp/utils/maps.h>
|
||||
|
||||
#if defined(ENABLE_FILTERS) && defined(ENABLE_FILTER_LOGGING)
|
||||
/**
|
||||
* Logs a message to the filter ringbuffer map.
|
||||
*
|
||||
@@ -51,3 +52,4 @@ static __always_inline int LogFilterMsg(struct iphdr* iph, struct ipv6hdr* iph6,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -5,7 +5,9 @@
|
||||
#include <xdp/xdp_helpers.h>
|
||||
#include <xdp/prog_dispatcher.h>
|
||||
|
||||
#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.
|
||||
|
||||
@@ -5,14 +5,6 @@
|
||||
|
||||
#include <xdp/utils/helpers.h>
|
||||
|
||||
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
|
||||
@@ -68,3 +79,4 @@ struct
|
||||
__uint(max_entries, 1 << 16);
|
||||
} map_filter_log SEC(".maps");
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <xdp/utils/rl.h>
|
||||
|
||||
#ifdef ENABLE_FILTERS
|
||||
/**
|
||||
* Updates IPv4 client stats.
|
||||
*
|
||||
@@ -129,3 +130,4 @@ static __always_inline void UpdateIp6Stats(u64 *pps, u64 *bps, u128 *ip, u16 por
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -6,8 +6,10 @@
|
||||
|
||||
#include <xdp/utils/maps.h>
|
||||
|
||||
#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.
|
||||
|
||||
Reference in New Issue
Block a user