Add support for bpf_loop().
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
// The maximum amount of filters allowed.
|
// The maximum amount of filters allowed.
|
||||||
// Decrease this value if you receive errors related to the BPF program being too large.
|
// Decrease this value if you receive errors related to the BPF program being too large.
|
||||||
#define MAX_FILTERS 60
|
#define MAX_FILTERS 1000
|
||||||
|
|
||||||
// Feel free to comment this out if you don't want the `blocked` entry on the stats map to be incremented every single time a packet is dropped from the source IP being on the blocked map.
|
// Feel free to comment this out if you don't want the `blocked` entry on the stats map to be incremented every single time a packet is dropped from the source IP being on the blocked map.
|
||||||
// Commenting this line out should increase performance when blocking malicious traffic.
|
// Commenting this line out should increase performance when blocking malicious traffic.
|
||||||
@@ -54,3 +54,7 @@
|
|||||||
// Enables IPv6.
|
// Enables IPv6.
|
||||||
// If you're not using IPv6, this will speed up performance of the XDP program.
|
// If you're not using IPv6, this will speed up performance of the XDP program.
|
||||||
#define ENABLE_IPV6
|
#define ENABLE_IPV6
|
||||||
|
|
||||||
|
// If enabled, uses a newer bpf_loop() function when choosing a source port for a new connection.
|
||||||
|
// This allows for a much higher source port range. However, it requires a more recent kernel.
|
||||||
|
#define USE_NEW_LOOP
|
||||||
334
src/xdp/prog.c
334
src/xdp/prog.c
@@ -11,7 +11,7 @@
|
|||||||
#include <common/all.h>
|
#include <common/all.h>
|
||||||
|
|
||||||
#include <xdp/utils/rl.h>
|
#include <xdp/utils/rl.h>
|
||||||
#include <xdp/utils/logging.h>
|
#include <xdp/utils/rule.h>
|
||||||
#include <xdp/utils/stats.h>
|
#include <xdp/utils/stats.h>
|
||||||
#include <xdp/utils/helpers.h>
|
#include <xdp/utils/helpers.h>
|
||||||
|
|
||||||
@@ -332,316 +332,40 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int action = 0;
|
// Create rule context.
|
||||||
u64 block_time = 1;
|
rule_ctx_t rule = {0};
|
||||||
|
rule.flow_pps = flow_pps;
|
||||||
|
rule.flow_bps = flow_bps;
|
||||||
|
rule.ip_pps = ip_pps;
|
||||||
|
rule.ip_bps = ip_bps;
|
||||||
|
rule.now = now;
|
||||||
|
rule.pkt_len = pkt_len;
|
||||||
|
rule.src_port = src_port;
|
||||||
|
rule.dst_port = dst_port;
|
||||||
|
rule.protocol = protocol;
|
||||||
|
|
||||||
|
rule.iph = iph;
|
||||||
|
rule.iph6 = iph6;
|
||||||
|
rule.tcph = tcph;
|
||||||
|
rule.udph = udph;
|
||||||
|
rule.icmph = icmph;
|
||||||
|
rule.icmph6 = icmp6h;
|
||||||
|
|
||||||
|
#ifdef USE_NEW_LOOP
|
||||||
|
bpf_loop(MAX_FILTERS, process_rule, &rule, 0);
|
||||||
|
#else
|
||||||
#pragma unroll 30
|
#pragma unroll 30
|
||||||
for (int i = 0; i < MAX_FILTERS; i++)
|
for (int i = 0; i < MAX_FILTERS; i++)
|
||||||
{
|
{
|
||||||
u32 key = i;
|
if (process_rule(i, &rule))
|
||||||
|
|
||||||
filter_t *filter = bpf_map_lookup_elem(&map_filters, &key);
|
|
||||||
|
|
||||||
if (!filter || !filter->set)
|
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#ifdef ENABLE_RL_IP
|
|
||||||
// Check source IP rate limits.
|
|
||||||
if (filter->do_ip_pps && ip_pps < filter->ip_pps)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter->do_ip_bps && ip_bps < filter->ip_bps)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_RL_FLOW
|
if (rule.matched)
|
||||||
// Check source flow rate limits.
|
{
|
||||||
if (filter->do_flow_pps && flow_pps < filter->flow_pps)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter->do_flow_bps && flow_bps < filter->flow_bps)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Match IP settings.
|
|
||||||
if (iph)
|
|
||||||
{
|
|
||||||
// Source address.
|
|
||||||
if (filter->ip.src_ip)
|
|
||||||
{
|
|
||||||
if (filter->ip.src_cidr == 32 && iph->saddr != filter->ip.src_ip)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_ip_in_range(iph->saddr, filter->ip.src_ip, filter->ip.src_cidr))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destination address.
|
|
||||||
if (filter->ip.dst_ip)
|
|
||||||
{
|
|
||||||
if (filter->ip.dst_cidr == 32 && iph->daddr != filter->ip.dst_ip)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_ip_in_range(iph->daddr, filter->ip.dst_ip, filter->ip.dst_cidr))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(ENABLE_IPV6) && defined(ALLOW_SINGLE_IP_V4_V6)
|
|
||||||
if ((filter->ip.src_ip6[0] != 0 || filter->ip.src_ip6[1] != 0 || filter->ip.src_ip6[2] != 0 || filter->ip.src_ip6[3] != 0) || (filter->ip.dst_ip6[0] != 0 || filter->ip.dst_ip6[1] != 0 || filter->ip.dst_ip6[2] != 0 || filter->ip.dst_ip6[3] != 0))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TOS.
|
|
||||||
if (filter->ip.do_tos && filter->ip.tos != iph->tos)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max TTL.
|
|
||||||
if (filter->ip.do_max_ttl && filter->ip.max_ttl < iph->ttl)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Min TTL.
|
|
||||||
if (filter->ip.do_min_ttl && filter->ip.min_ttl > iph->ttl)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max packet length.
|
|
||||||
if (filter->ip.do_max_len && filter->ip.max_len < pkt_len)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Min packet length.
|
|
||||||
if (filter->ip.do_min_len && filter->ip.min_len > pkt_len)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef ENABLE_IPV6
|
|
||||||
else if (iph6)
|
|
||||||
{
|
|
||||||
// Source address.
|
|
||||||
if (filter->ip.src_ip6[0] != 0 && (iph6->saddr.in6_u.u6_addr32[0] != filter->ip.src_ip6[0] || iph6->saddr.in6_u.u6_addr32[1] != filter->ip.src_ip6[1] || iph6->saddr.in6_u.u6_addr32[2] != filter->ip.src_ip6[2] || iph6->saddr.in6_u.u6_addr32[3] != filter->ip.src_ip6[3]))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destination address.
|
|
||||||
if (filter->ip.dst_ip6[0] != 0 && (iph6->daddr.in6_u.u6_addr32[0] != filter->ip.dst_ip6[0] || iph6->daddr.in6_u.u6_addr32[1] != filter->ip.dst_ip6[1] || iph6->daddr.in6_u.u6_addr32[2] != filter->ip.dst_ip6[2] || iph6->daddr.in6_u.u6_addr32[3] != filter->ip.dst_ip6[3]))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ALLOW_SINGLE_IP_V4_V6
|
|
||||||
if (filter->ip.src_ip != 0 || filter->ip.dst_ip != 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Max TTL length.
|
|
||||||
if (filter->ip.do_max_ttl && filter->ip.max_ttl < iph6->hop_limit)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Min TTL length.
|
|
||||||
if (filter->ip.do_min_ttl && filter->ip.min_ttl > iph6->hop_limit)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max packet length.
|
|
||||||
if (filter->ip.do_max_len && filter->ip.max_len < pkt_len)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Min packet length.
|
|
||||||
if (filter->ip.do_min_len && filter->ip.min_len > pkt_len)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check TCP matches.
|
|
||||||
if (filter->tcp.enabled)
|
|
||||||
{
|
|
||||||
if (!tcph)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source port checks.
|
|
||||||
if (filter->tcp.do_sport_min && ntohs(tcph->source) < filter->tcp.sport_min)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter->tcp.do_sport_max && ntohs(tcph->source) > filter->tcp.sport_max)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destination port checks.
|
|
||||||
if (filter->tcp.do_dport_min && ntohs(tcph->dest) < filter->tcp.dport_min)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter->tcp.do_dport_max && ntohs(tcph->dest) > filter->tcp.dport_max)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// URG flag.
|
|
||||||
if (filter->tcp.do_urg && filter->tcp.urg != tcph->urg)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ACK flag.
|
|
||||||
if (filter->tcp.do_ack && filter->tcp.ack != tcph->ack)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// RST flag.
|
|
||||||
if (filter->tcp.do_rst && filter->tcp.rst != tcph->rst)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PSH flag.
|
|
||||||
if (filter->tcp.do_psh && filter->tcp.psh != tcph->psh)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SYN flag.
|
|
||||||
if (filter->tcp.do_syn && filter->tcp.syn != tcph->syn)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIN flag.
|
|
||||||
if (filter->tcp.do_fin && filter->tcp.fin != tcph->fin)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ECE flag.
|
|
||||||
if (filter->tcp.do_ece && filter->tcp.ece != tcph->ece)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CWR flag.
|
|
||||||
if (filter->tcp.do_cwr && filter->tcp.cwr != tcph->cwr)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check UDP matches.
|
|
||||||
else if (filter->udp.enabled)
|
|
||||||
{
|
|
||||||
if (!udph)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source port checks.
|
|
||||||
if (filter->udp.do_sport_min && ntohs(udph->source) < filter->udp.sport_min)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter->udp.do_sport_max && ntohs(udph->source) > filter->udp.sport_max)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destination port checks.
|
|
||||||
if (filter->udp.do_dport_min && ntohs(udph->dest) < filter->udp.dport_min)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter->udp.do_dport_max && ntohs(udph->dest) > filter->udp.dport_max)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (filter->icmp.enabled)
|
|
||||||
{
|
|
||||||
if (icmph)
|
|
||||||
{
|
|
||||||
// Code.
|
|
||||||
if (filter->icmp.do_code && filter->icmp.code != icmph->code)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type.
|
|
||||||
if (filter->icmp.do_type && filter->icmp.type != icmph->type)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef ENABLE_IPV6
|
|
||||||
else if (icmp6h)
|
|
||||||
{
|
|
||||||
// Code.
|
|
||||||
if (filter->icmp.do_code && filter->icmp.code != icmp6h->icmp6_code)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type.
|
|
||||||
if (filter->icmp.do_type && filter->icmp.type != icmp6h->icmp6_type)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_FILTER_LOGGING
|
|
||||||
if (filter->log > 0)
|
|
||||||
{
|
|
||||||
log_filter_msg(iph, iph6, src_port, dst_port, protocol, now, ip_pps, ip_bps, flow_pps, flow_bps, pkt_len, i);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Matched.
|
|
||||||
action = filter->action;
|
|
||||||
block_time = filter->block_time;
|
|
||||||
|
|
||||||
goto matched;
|
goto matched;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -652,12 +376,12 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
|
|
||||||
#ifdef ENABLE_FILTERS
|
#ifdef ENABLE_FILTERS
|
||||||
matched:
|
matched:
|
||||||
if (action == 0)
|
if (rule.action == 0)
|
||||||
{
|
{
|
||||||
// Before dropping, update the block map.
|
// Before dropping, update the block map.
|
||||||
if (block_time > 0)
|
if (rule.block_time > 0)
|
||||||
{
|
{
|
||||||
u64 new_time = now + (block_time * NANO_TO_SEC);
|
u64 new_time = now + (rule.block_time * NANO_TO_SEC);
|
||||||
|
|
||||||
if (iph)
|
if (iph)
|
||||||
{
|
{
|
||||||
|
|||||||
313
src/xdp/utils/rule.c
Normal file
313
src/xdp/utils/rule.c
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
#include <xdp/utils/rule.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_FILTERS
|
||||||
|
/**
|
||||||
|
* Processes a filter rule.
|
||||||
|
*
|
||||||
|
* @param idx The rule index.
|
||||||
|
* @param data A pointer to the rule context.
|
||||||
|
*
|
||||||
|
* @return 1 to break the loop or 0 to continue.
|
||||||
|
*/
|
||||||
|
static __always_inline long process_rule(u32 idx, void* data)
|
||||||
|
{
|
||||||
|
rule_ctx_t* ctx = data;
|
||||||
|
|
||||||
|
filter_t *filter = bpf_map_lookup_elem(&map_filters, &idx);
|
||||||
|
|
||||||
|
if (!filter || !filter->set)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_RL_IP
|
||||||
|
// Check source IP rate limits.
|
||||||
|
if (filter->do_ip_pps && ctx->ip_pps < filter->ip_pps)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter->do_ip_bps && ctx->ip_bps < filter->ip_bps)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_RL_FLOW
|
||||||
|
// Check source flow rate limits.
|
||||||
|
if (filter->do_flow_pps && ctx->flow_pps < filter->flow_pps)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter->do_flow_bps && ctx->flow_bps < filter->flow_bps)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Max packet length.
|
||||||
|
if (filter->ip.do_max_len && filter->ip.max_len < ctx->pkt_len)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Min packet length.
|
||||||
|
if (filter->ip.do_min_len && filter->ip.min_len > ctx->pkt_len)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match IP settings.
|
||||||
|
if (ctx->iph)
|
||||||
|
{
|
||||||
|
// Source address.
|
||||||
|
if (filter->ip.src_ip)
|
||||||
|
{
|
||||||
|
if (filter->ip.src_cidr == 32 && ctx->iph->saddr != filter->ip.src_ip)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_ip_in_range(ctx->iph->saddr, filter->ip.src_ip, filter->ip.src_cidr))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination address.
|
||||||
|
if (filter->ip.dst_ip)
|
||||||
|
{
|
||||||
|
if (filter->ip.dst_cidr == 32 && ctx->iph->daddr != filter->ip.dst_ip)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_ip_in_range(ctx->iph->daddr, filter->ip.dst_ip, filter->ip.dst_cidr))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(ENABLE_IPV6) && defined(ALLOW_SINGLE_IP_V4_V6)
|
||||||
|
if ((filter->ip.src_ip6[0] != 0 || filter->ip.src_ip6[1] != 0 || filter->ip.src_ip6[2] != 0 || filter->ip.src_ip6[3] != 0) || (filter->ip.dst_ip6[0] != 0 || filter->ip.dst_ip6[1] != 0 || filter->ip.dst_ip6[2] != 0 || filter->ip.dst_ip6[3] != 0))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TOS.
|
||||||
|
if (filter->ip.do_tos && filter->ip.tos != ctx->iph->tos)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max TTL.
|
||||||
|
if (filter->ip.do_max_ttl && filter->ip.max_ttl < ctx->iph->ttl)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Min TTL.
|
||||||
|
if (filter->ip.do_min_ttl && filter->ip.min_ttl > ctx->iph->ttl)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
else if (ctx->iph6)
|
||||||
|
{
|
||||||
|
// Source address.
|
||||||
|
if (filter->ip.src_ip6[0] != 0 && (ctx->iph6->saddr.in6_u.u6_addr32[0] != filter->ip.src_ip6[0] || ctx->iph6->saddr.in6_u.u6_addr32[1] != filter->ip.src_ip6[1] || ctx->iph6->saddr.in6_u.u6_addr32[2] != filter->ip.src_ip6[2] || ctx->iph6->saddr.in6_u.u6_addr32[3] != filter->ip.src_ip6[3]))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination address.
|
||||||
|
if (filter->ip.dst_ip6[0] != 0 && (ctx->iph6->daddr.in6_u.u6_addr32[0] != filter->ip.dst_ip6[0] || ctx->iph6->daddr.in6_u.u6_addr32[1] != filter->ip.dst_ip6[1] || ctx->iph6->daddr.in6_u.u6_addr32[2] != filter->ip.dst_ip6[2] || ctx->iph6->daddr.in6_u.u6_addr32[3] != filter->ip.dst_ip6[3]))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ALLOW_SINGLE_IP_V4_V6
|
||||||
|
if (filter->ip.src_ip != 0 || filter->ip.dst_ip != 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Max TTL length.
|
||||||
|
if (filter->ip.do_max_ttl && filter->ip.max_ttl < ctx->iph6->hop_limit)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Min TTL length.
|
||||||
|
if (filter->ip.do_min_ttl && filter->ip.min_ttl > ctx->iph6->hop_limit)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check TCP matches.
|
||||||
|
if (filter->tcp.enabled)
|
||||||
|
{
|
||||||
|
if (!ctx->tcph)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source port checks.
|
||||||
|
if (filter->tcp.do_sport_min && ntohs(ctx->tcph->source) < filter->tcp.sport_min)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter->tcp.do_sport_max && ntohs(ctx->tcph->source) > filter->tcp.sport_max)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination port checks.
|
||||||
|
if (filter->tcp.do_dport_min && ntohs(ctx->tcph->dest) < filter->tcp.dport_min)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter->tcp.do_dport_max && ntohs(ctx->tcph->dest) > filter->tcp.dport_max)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// URG flag.
|
||||||
|
if (filter->tcp.do_urg && filter->tcp.urg != ctx->tcph->urg)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACK flag.
|
||||||
|
if (filter->tcp.do_ack && filter->tcp.ack != ctx->tcph->ack)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RST flag.
|
||||||
|
if (filter->tcp.do_rst && filter->tcp.rst != ctx->tcph->rst)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSH flag.
|
||||||
|
if (filter->tcp.do_psh && filter->tcp.psh != ctx->tcph->psh)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SYN flag.
|
||||||
|
if (filter->tcp.do_syn && filter->tcp.syn != ctx->tcph->syn)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIN flag.
|
||||||
|
if (filter->tcp.do_fin && filter->tcp.fin != ctx->tcph->fin)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ECE flag.
|
||||||
|
if (filter->tcp.do_ece && filter->tcp.ece != ctx->tcph->ece)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CWR flag.
|
||||||
|
if (filter->tcp.do_cwr && filter->tcp.cwr != ctx->tcph->cwr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check UDP matches.
|
||||||
|
else if (filter->udp.enabled)
|
||||||
|
{
|
||||||
|
if (!ctx->udph)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source port checks.
|
||||||
|
if (filter->udp.do_sport_min && ntohs(ctx->udph->source) < filter->udp.sport_min)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter->udp.do_sport_max && ntohs(ctx->udph->source) > filter->udp.sport_max)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination port checks.
|
||||||
|
if (filter->udp.do_dport_min && ntohs(ctx->udph->dest) < filter->udp.dport_min)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter->udp.do_dport_max && ntohs(ctx->udph->dest) > filter->udp.dport_max)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (filter->icmp.enabled)
|
||||||
|
{
|
||||||
|
if (ctx->icmph)
|
||||||
|
{
|
||||||
|
// Code.
|
||||||
|
if (filter->icmp.do_code && filter->icmp.code != ctx->icmph->code)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.
|
||||||
|
if (filter->icmp.do_type && filter->icmp.type != ctx->icmph->type)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
else if (ctx->icmph6)
|
||||||
|
{
|
||||||
|
// Code.
|
||||||
|
if (filter->icmp.do_code && filter->icmp.code != ctx->icmph6->icmp6_code)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.
|
||||||
|
if (filter->icmp.do_type && filter->icmp.type != ctx->icmph6->icmp6_type)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_FILTER_LOGGING
|
||||||
|
if (filter->log > 0)
|
||||||
|
{
|
||||||
|
log_filter_msg(ctx->iph, ctx->iph6, ctx->src_port, ctx->dst_port, ctx->protocol, ctx->now, ctx->ip_pps, ctx->ip_bps, ctx->flow_pps, ctx->flow_bps, ctx->pkt_len, idx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Matched.
|
||||||
|
ctx->matched = 1;
|
||||||
|
ctx->action = filter->action;
|
||||||
|
ctx->block_time = filter->block_time;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
51
src/xdp/utils/rule.h
Normal file
51
src/xdp/utils/rule.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common/all.h>
|
||||||
|
|
||||||
|
#include <xdp/utils/logging.h>
|
||||||
|
|
||||||
|
#include <xdp/utils/maps.h>
|
||||||
|
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/ipv6.h>
|
||||||
|
#include <linux/udp.h>
|
||||||
|
#include <linux/tcp.h>
|
||||||
|
#include <linux/icmp.h>
|
||||||
|
#include <linux/icmpv6.h>
|
||||||
|
|
||||||
|
struct rule_ctx
|
||||||
|
{
|
||||||
|
int matched;
|
||||||
|
int action;
|
||||||
|
u64 block_time;
|
||||||
|
|
||||||
|
u64 ip_pps;
|
||||||
|
u64 ip_bps;
|
||||||
|
|
||||||
|
u64 flow_pps;
|
||||||
|
u64 flow_bps;
|
||||||
|
|
||||||
|
u64 now;
|
||||||
|
int pkt_len;
|
||||||
|
u16 src_port;
|
||||||
|
u16 dst_port;
|
||||||
|
u8 protocol;
|
||||||
|
|
||||||
|
struct iphdr* iph;
|
||||||
|
struct ipv6hdr* iph6;
|
||||||
|
|
||||||
|
struct tcphdr* tcph;
|
||||||
|
struct udphdr* udph;
|
||||||
|
struct icmphdr* icmph;
|
||||||
|
|
||||||
|
struct icmp6hdr* icmph6;
|
||||||
|
} typedef rule_ctx_t;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FILTERS
|
||||||
|
static __always_inline long process_rule(u32 idx, void* data);
|
||||||
|
#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
|
||||||
|
#include "rule.c"
|
||||||
Reference in New Issue
Block a user