Compare commits

..

10 Commits

Author SHA1 Message Date
Christian Deacon
496bdd0473 Add options and functionality for running with other XDP programs via xdp-loader. (#86)
Some checks failed
Build / build (push) Failing after 2m14s
Run / run (push) Failing after 2m0s
2025-12-28 15:56:35 -05:00
Christian Deacon
278ff71c59 Oops. 2025-10-14 22:43:04 -04:00
Christian Deacon
fd20b61cf2 Fix wrong setting name for interface(s). 2025-10-14 22:28:12 -04:00
AbdulOmar
c0543b2036 Unpin block IPv6 map only if IPV6 is enabled (#82)
There's no need to try to unpin the map if its not enabled at first. Just to prevent:

[WARNING] Failed to un-pin BPF map 'map_block6' from file system (1)
2025-10-07 18:32:17 -04:00
An Bool
a924233b46 Enable Pinning for map_stats (#78)
Co-authored-by: Christian Deacon <christianmdeacon@gmail.com>
2025-06-21 18:04:40 -04:00
Christian Deacon
2b570c2246 Update xdp-tools submodule. 2025-06-17 21:24:13 -04:00
Christian Deacon
82231f22ef Update README. 2025-05-05 13:30:01 -04:00
Christian Deacon
67a77ce659 Update README. 2025-05-02 21:05:29 -04:00
Christian Deacon
7dc351f352 Update README. 2025-03-28 22:25:36 -04:00
Christian Deacon
ec0b07eb37 Optimize XDP program when filter logging is disabled. 2025-03-28 22:21:31 -04:00
8 changed files with 59 additions and 18 deletions

View File

@@ -188,6 +188,7 @@ Here are more details on the layout of the runtime configuration.
| dst_ip6 | string | `NULL` | The destination IPv6 address to match (e.g. `fe80::ac21:14ff:fe4b:3a6d`). | | dst_ip6 | string | `NULL` | The destination IPv6 address to match (e.g. `fe80::ac21:14ff:fe4b:3a6d`). |
| min_ttl | int | `NULL` | The minimum TTL (time-to-live) to match. | | min_ttl | int | `NULL` | The minimum TTL (time-to-live) to match. |
| max_ttl | int | `NULL` | The maximum TTL (time-to-live) to match. | | max_ttl | int | `NULL` | The maximum TTL (time-to-live) to match. |
| min_len | int | `NULL` | The minimum packet length to match (includes the entire packet including the ethernet header and payload). |
| max_len | int | `NULL` | The maximum packet length to match (includes the entire packet including the ethernet header and payload). | | max_len | int | `NULL` | The maximum packet length to match (includes the entire packet including the ethernet header and payload). |
| tos | int | `NULL` | The ToS (type-of-service) to match. | | tos | int | `NULL` | The ToS (type-of-service) to match. |
@@ -306,9 +307,9 @@ The following CLI arguments are supported.
| --log | `--log 1` | Enables or disables logging for the dynamic filter. | | --log | `--log 1` | Enables or disables logging for the dynamic filter. |
| --block-time | `--block-time 60` | How long to block the source IP for if the packet is matched and the action is drop in the dynamic filter (0 = no time). | | --block-time | `--block-time 60` | How long to block the source IP for if the packet is matched and the action is drop in the dynamic filter (0 = no time). |
| --sip | `--sip 192.168.1.0/24` | The source IPv4 address/range to match with the dynamic filter. | | --sip | `--sip 192.168.1.0/24` | The source IPv4 address/range to match with the dynamic filter. |
| --dip | `--sip 10.90.0.0/24` | The destination IPv4 address/range to match with the dynamic filter. | | --dip | `--dip 10.90.0.0/24` | The destination IPv4 address/range to match with the dynamic filter. |
| --sip6 | `--sip 192.168.1.0/24` | The source IPv6 address to match with the dynamic filter. | | --sip6 | `--sip6 192.168.1.0/24` | The source IPv6 address to match with the dynamic filter. |
| --dip6 | `--sip 192.168.1.0/24` | The destination IPv6 address to match with the dynamic filter. | | --dip6 | `--dip6 192.168.1.0/24` | The destination IPv6 address to match with the dynamic filter. |
| --min-ttl | `--min-ttl 0` | The IP's minimum TTL to match with the dynamic filter. | | --min-ttl | `--min-ttl 0` | The IP's minimum TTL to match with the dynamic filter. |
| --max-ttl | `--max-ttl 6` | The IP's maximum TTL to match with the dynamic filter. | | --max-ttl | `--max-ttl 6` | The IP's maximum TTL to match with the dynamic filter. |
| --min-len | `--min-len 42` | The packet's mimimum length to match with the dynamic filter. | | --min-len | `--min-len 42` | The packet's mimimum length to match with the dynamic filter. |
@@ -386,6 +387,8 @@ This firewall supports both source **flow-based** (`flow_pps` and `flow_bps` set
The reason source IP-based rate limiting is disabled by default is because both methods require seperate calculations which isn't ideal if both methods aren't used inside of filter rules. I've found most users prefer flow-based rate limiting which is why I decided to only enable that by default. The reason source IP-based rate limiting is disabled by default is because both methods require seperate calculations which isn't ideal if both methods aren't used inside of filter rules. I've found most users prefer flow-based rate limiting which is why I decided to only enable that by default.
Additionally, if you're encountering a large amount of spoofed packets, it is **highly recommended** that you disable rate limiting entirely, at least temporarily until you stop receiving the spoofed packets. This is because a large amount of spoofed packets from different IPs and ports will cause the rate limit BPF maps to rapidly recycle entries and this can cause very high CPU usage depending on how many spoofed packets are being sent and the host's hardware.
### Filter Logging ### Filter Logging
This tool uses `bpf_ringbuf_reserve()` and `bpf_ringbuf_submit()` for filter match logging. At this time, there is no rate limit for the amount of log messages that may be sent. Therefore, if you're encountering a spoofed attack that is matching a filter rule with logging enabled, it will cause additional processing and disk load. This tool uses `bpf_ringbuf_reserve()` and `bpf_ringbuf_submit()` for filter match logging. At this time, there is no rate limit for the amount of log messages that may be sent. Therefore, if you're encountering a spoofed attack that is matching a filter rule with logging enabled, it will cause additional processing and disk load.

View File

@@ -58,3 +58,12 @@
// If enabled, uses a newer bpf_loop() function when choosing a source port for a new connection. // 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. // This allows for a much higher source port range. However, it requires a more recent kernel.
#define USE_NEW_LOOP #define USE_NEW_LOOP
// Whether to enable chaining multiple XDP programs with this tool (1 = enable. 0 = disable).
#define XDP_MULTIPROG_ENABLED 1
// The XDP program's run priority (used for running multiple XDP programs together).
#define XDP_MULTIPROG_PRIORITY 10
// The action that indicates it should go onto the next program (default XDP_PASS).
#define XDP_MULTIPROG_ACTION XDP_PASS

View File

@@ -32,6 +32,15 @@ static void unpin_needed_maps(config__t* cfg, struct bpf_object* obj, int ignore
{ {
int ret; int ret;
// Unpin stats map.
if ((ret = unpin_bpf_map(obj, XDP_MAP_PIN_DIR, "map_stats")) != 0)
{
if (!ignore_errors)
{
log_msg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_stats' from file system (%d).", ret);
}
}
// Unpin block map. // Unpin block map.
if ((ret = unpin_bpf_map(obj, XDP_MAP_PIN_DIR, "map_block")) != 0) if ((ret = unpin_bpf_map(obj, XDP_MAP_PIN_DIR, "map_block")) != 0)
{ {
@@ -40,7 +49,7 @@ static void unpin_needed_maps(config__t* cfg, struct bpf_object* obj, int ignore
log_msg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_block' from file system (%d).", ret); log_msg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_block' from file system (%d).", ret);
} }
} }
#ifdef ENABLE_IPV6
// Unpin block (IPv6) map. // Unpin block (IPv6) map.
if ((ret = unpin_bpf_map(obj, XDP_MAP_PIN_DIR, "map_block6")) != 0) if ((ret = unpin_bpf_map(obj, XDP_MAP_PIN_DIR, "map_block6")) != 0)
{ {
@@ -49,6 +58,7 @@ static void unpin_needed_maps(config__t* cfg, struct bpf_object* obj, int ignore
log_msg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_block6' from file system (%d).", ret); log_msg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_block6' from file system (%d).", ret);
} }
} }
#endif
#ifdef ENABLE_IP_RANGE_DROP #ifdef ENABLE_IP_RANGE_DROP
// Unpin IPv4 range drop map. // Unpin IPv4 range drop map.
@@ -312,6 +322,16 @@ int main(int argc, char *argv[])
// So it's best to attempt to unpin the maps before pinning while ignoring errors. // So it's best to attempt to unpin the maps before pinning while ignoring errors.
unpin_needed_maps(&cfg, obj, 1); unpin_needed_maps(&cfg, obj, 1);
// Pin the stats map.
if ((ret = pin_bpf_map(obj, XDP_MAP_PIN_DIR, "map_stats")) != 0)
{
log_msg(&cfg, 1, 0, "[WARNING] Failed to pin 'map_stats' to file system (%d)...", ret);
}
else
{
log_msg(&cfg, 3, 0, "BPF map 'map_stats' pinned to '%s/map_stats'.", XDP_MAP_PIN_DIR);
}
// Pin the block maps. // Pin the block maps.
if ((ret = pin_bpf_map(obj, XDP_MAP_PIN_DIR, "map_block")) != 0) if ((ret = pin_bpf_map(obj, XDP_MAP_PIN_DIR, "map_block")) != 0)
{ {

View File

@@ -808,7 +808,7 @@ int save_cfg(config__t* cfg, const char* file_path)
{ {
if (cfg->interfaces_cnt > 1) if (cfg->interfaces_cnt > 1)
{ {
setting = config_setting_add(root, "interfaces", CONFIG_TYPE_LIST); setting = config_setting_add(root, "interface", CONFIG_TYPE_LIST);
for (int i = 0; i < cfg->interfaces_cnt; i++) for (int i = 0; i < cfg->interfaces_cnt; i++)
{ {
@@ -829,7 +829,7 @@ int save_cfg(config__t* cfg, const char* file_path)
if (interface) if (interface)
{ {
setting = config_setting_add(root, "interfaces", CONFIG_TYPE_STRING); setting = config_setting_add(root, "interface", CONFIG_TYPE_STRING);
config_setting_set_string(setting, interface); config_setting_set_string(setting, interface);
} }
} }

View File

@@ -113,6 +113,10 @@ int attach_xdp(struct xdp_program *prog, char** mode, int ifidx, int detach, int
{ {
int err; int err;
// Before attaching, set chaining options.
xdp_program__set_run_prio(prog, XDP_MULTIPROG_PRIORITY);
xdp_program__set_chain_call_enabled(prog, XDP_MULTIPROG_ACTION, XDP_MULTIPROG_ENABLED);
u32 attach_mode = XDP_MODE_NATIVE; u32 attach_mode = XDP_MODE_NATIVE;
*mode = "DRV/native"; *mode = "DRV/native";

View File

@@ -338,19 +338,22 @@ int xdp_prog_main(struct xdp_md *ctx)
rule.flow_bps = flow_bps; rule.flow_bps = flow_bps;
rule.ip_pps = ip_pps; rule.ip_pps = ip_pps;
rule.ip_bps = ip_bps; rule.ip_bps = ip_bps;
rule.now = now;
rule.pkt_len = pkt_len; rule.pkt_len = pkt_len;
rule.src_port = src_port;
#ifdef ENABLE_FILTER_LOGGING #ifdef ENABLE_FILTER_LOGGING
rule.now = now;
rule.protocol = protocol;
rule.src_port = src_port;
rule.dst_port = dst_port; rule.dst_port = dst_port;
#endif #endif
rule.protocol = protocol;
rule.iph = iph; rule.iph = iph;
rule.iph6 = iph6;
rule.tcph = tcph; rule.tcph = tcph;
rule.udph = udph; rule.udph = udph;
rule.icmph = icmph; rule.icmph = icmph;
rule.iph6 = iph6;
rule.icmph6 = icmp6h; rule.icmph6 = icmp6h;
#ifdef USE_NEW_LOOP #ifdef USE_NEW_LOOP

View File

@@ -19,19 +19,21 @@ struct rule_ctx
int action; int action;
u64 block_time; u64 block_time;
int pkt_len;
u64 ip_pps; u64 ip_pps;
u64 ip_bps; u64 ip_bps;
u64 flow_pps; u64 flow_pps;
u64 flow_bps; u64 flow_bps;
u64 now;
int pkt_len;
u16 src_port;
#ifdef ENABLE_FILTER_LOGGING #ifdef ENABLE_FILTER_LOGGING
u64 now;
u8 protocol;
u16 src_port;
u16 dst_port; u16 dst_port;
#endif #endif
u8 protocol;
struct iphdr* iph; struct iphdr* iph;
struct ipv6hdr* iph6; struct ipv6hdr* iph6;