Add filter logging.
This commit is contained in:
@@ -129,8 +129,10 @@ The following table quickly explains the data types used within the configuratio
|
||||
### Filter Object
|
||||
| Name | Type | Default | Description |
|
||||
| ---- | ---- | ------- | ----------- |
|
||||
| enabled | bool | `false` | Whether the rule is enabled or not. |
|
||||
| action | uint | `0` | The value of `0` drops or blocks the packet while `1` allows/passes the packet through. |
|
||||
| enabled | bool | `true` | Whether the rule is enabled or not. |
|
||||
|
||||
| action | uint | `1` | The value of `0` drops or blocks the packet while `1` allows/passes the packet through. |
|
||||
| log | bool | `false` | Whether to log packets that are matched. |
|
||||
| block_time | uint | `1` | The amount of seconds to block the source IP for if matched. |
|
||||
| src_ip | string | `NULL` | The source IPv4 address to match (e.g. `10.50.0.3`). CIDRs are also supported (e.g. `10.50.0.0/24`)! |
|
||||
| dst_ip | string | `NULL` | The destination IPv4 address to match (e.g. `10.50.0.4`). CIDRs are also supported (e.g. `10.50.0.0/24`)! |
|
||||
|
||||
@@ -20,4 +20,8 @@
|
||||
// If uncommented, rate limits for clients are determined using the source IP, port, and protocol instead of just the source IP.
|
||||
// This allows for more precise rate limits (connection-specific instead of a single source IP).
|
||||
// I decided not to include the destination IP/port because the source IP, port, and protocol should be represent a unique connection.
|
||||
#define USE_FLOW_RL
|
||||
#define USE_FLOW_RL
|
||||
|
||||
// Enables filter logging through XDP.
|
||||
// If performance is a concerned, it is best to disable this feature by commenting out the below line with //.
|
||||
#define ENABLE_FILTER_LOGGING
|
||||
@@ -64,6 +64,8 @@ struct filter
|
||||
{
|
||||
u8 id;
|
||||
|
||||
unsigned int log : 1;
|
||||
|
||||
unsigned int enabled : 1;
|
||||
|
||||
u8 action;
|
||||
@@ -131,4 +133,15 @@ struct flow6
|
||||
u128 ip;
|
||||
u16 port;
|
||||
u8 protocol;
|
||||
} typedef flow6_t;
|
||||
} typedef flow6_t;
|
||||
|
||||
struct filter_log_event
|
||||
{
|
||||
u64 ts;
|
||||
int filter_id;
|
||||
u32 src_ip;
|
||||
u32 src_ip6[4];
|
||||
u16 src_port;
|
||||
u64 pps;
|
||||
u64 bps;
|
||||
} typedef filter_log_event_t;
|
||||
@@ -136,6 +136,22 @@ int main(int argc, char *argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FILTER_LOGGING
|
||||
int filter_log_map = FindMapFd(prog, "filter_log_map");
|
||||
struct ring_buffer* rb = NULL;
|
||||
|
||||
if (filter_log_map < 0)
|
||||
{
|
||||
LogMsg(&cfg, 1, 0, "[WARNING] Failed to find 'filter_log_map' BPF map. Filter logging will be disabled...");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMsg(&cfg, 3, 0, "filter_log_map FD => %d.", filter_log_map);
|
||||
|
||||
rb = ring_buffer__new(filter_log_map, HandleRbEvent, &cfg, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
LogMsg(&cfg, 3, 0, "stats_map FD => %d.", stats_map);
|
||||
|
||||
LogMsg(&cfg, 2, 0, "Updating filters...");
|
||||
@@ -208,11 +224,25 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FILTER_LOGGING
|
||||
if (rb)
|
||||
{
|
||||
ring_buffer__poll(rb, RB_TIMEOUT);
|
||||
}
|
||||
#endif
|
||||
|
||||
usleep(sleep_time);
|
||||
}
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
#ifdef ENABLE_FILTER_LOGGING
|
||||
if (rb)
|
||||
{
|
||||
ring_buffer__free(rb);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Detach XDP program.
|
||||
if (AttachXdp(prog, &mode_used, ifidx, 1, &cmd))
|
||||
{
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include <loader/utils/config.h>
|
||||
|
||||
#include <loader/utils/helpers.h>
|
||||
|
||||
static FILE *file;
|
||||
|
||||
/**
|
||||
@@ -55,60 +53,62 @@ void SetCfgDefaults(config__t *cfg)
|
||||
|
||||
for (int i = 0; i < MAX_FILTERS; i++)
|
||||
{
|
||||
cfg->filters[i].id = 0;
|
||||
cfg->filters[i].enabled = 0;
|
||||
cfg->filters[i].action = 0;
|
||||
cfg->filters[i].src_ip = 0;
|
||||
cfg->filters[i].dst_ip = 0;
|
||||
filter_t* filter = &cfg->filters[i];
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
cfg->filters[i].src_ip6[j] = 0;
|
||||
cfg->filters[i].dst_ip6[j] = 0;
|
||||
}
|
||||
filter->id = 0;
|
||||
filter->enabled = 1;
|
||||
|
||||
cfg->filters[i].do_min_len = 0;
|
||||
cfg->filters[i].min_len = 0;
|
||||
filter->log = 0;
|
||||
|
||||
cfg->filters[i].do_max_len = 0;
|
||||
cfg->filters[i].max_len = 65535;
|
||||
filter->action = 1;
|
||||
filter->src_ip = 0;
|
||||
filter->dst_ip = 0;
|
||||
|
||||
cfg->filters[i].do_min_ttl = 0;
|
||||
cfg->filters[i].min_ttl = 0;
|
||||
memset(filter->src_ip6, 0, 4);
|
||||
memset(filter->dst_ip6, 0, 4);
|
||||
|
||||
cfg->filters[i].do_max_ttl = 0;
|
||||
cfg->filters[i].max_ttl = 255;
|
||||
filter->do_min_len = 0;
|
||||
filter->min_len = 0;
|
||||
|
||||
cfg->filters[i].do_tos = 0;
|
||||
cfg->filters[i].tos = 0;
|
||||
filter->do_max_len = 0;
|
||||
filter->max_len = 65535;
|
||||
|
||||
cfg->filters[i].do_pps = 0;
|
||||
cfg->filters[i].pps = 0;
|
||||
filter->do_min_ttl = 0;
|
||||
filter->min_ttl = 0;
|
||||
|
||||
filter->do_max_ttl = 0;
|
||||
filter->max_ttl = 255;
|
||||
|
||||
filter->do_tos = 0;
|
||||
filter->tos = 0;
|
||||
|
||||
filter->do_pps = 0;
|
||||
filter->pps = 0;
|
||||
|
||||
cfg->filters[i].do_bps = 0;
|
||||
cfg->filters[i].bps = 0;
|
||||
filter->do_bps = 0;
|
||||
filter->bps = 0;
|
||||
|
||||
cfg->filters[i].blocktime = 1;
|
||||
filter->blocktime = 1;
|
||||
|
||||
cfg->filters[i].tcpopts.enabled = 0;
|
||||
cfg->filters[i].tcpopts.do_dport = 0;
|
||||
cfg->filters[i].tcpopts.do_dport = 0;
|
||||
cfg->filters[i].tcpopts.do_urg = 0;
|
||||
cfg->filters[i].tcpopts.do_ack = 0;
|
||||
cfg->filters[i].tcpopts.do_rst = 0;
|
||||
cfg->filters[i].tcpopts.do_psh = 0;
|
||||
cfg->filters[i].tcpopts.do_syn = 0;
|
||||
cfg->filters[i].tcpopts.do_fin = 0;
|
||||
cfg->filters[i].tcpopts.do_ece = 0;
|
||||
cfg->filters[i].tcpopts.do_cwr = 0;
|
||||
filter->tcpopts.enabled = 0;
|
||||
filter->tcpopts.do_dport = 0;
|
||||
filter->tcpopts.do_dport = 0;
|
||||
filter->tcpopts.do_urg = 0;
|
||||
filter->tcpopts.do_ack = 0;
|
||||
filter->tcpopts.do_rst = 0;
|
||||
filter->tcpopts.do_psh = 0;
|
||||
filter->tcpopts.do_syn = 0;
|
||||
filter->tcpopts.do_fin = 0;
|
||||
filter->tcpopts.do_ece = 0;
|
||||
filter->tcpopts.do_cwr = 0;
|
||||
|
||||
cfg->filters[i].udpopts.enabled = 0;
|
||||
cfg->filters[i].udpopts.do_sport = 0;
|
||||
cfg->filters[i].udpopts.do_dport = 0;
|
||||
filter->udpopts.enabled = 0;
|
||||
filter->udpopts.do_sport = 0;
|
||||
filter->udpopts.do_dport = 0;
|
||||
|
||||
cfg->filters[i].icmpopts.enabled = 0;
|
||||
cfg->filters[i].icmpopts.do_code = 0;
|
||||
cfg->filters[i].icmpopts.do_type = 0;
|
||||
filter->icmpopts.enabled = 0;
|
||||
filter->icmpopts.do_code = 0;
|
||||
filter->icmpopts.do_type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ int ReadCfg(config__t *cfg)
|
||||
// Attempt to read the config.
|
||||
if (config_read(&conf, file) == CONFIG_FALSE)
|
||||
{
|
||||
fprintf(stderr, "Error from LibConfig when reading file - %s (Line %d)\n\n", config_error_text(&conf), config_error_line(&conf));
|
||||
LogMsg(cfg, 0, 1, "Error from LibConfig when reading file - %s (Line %d)", config_error_text(&conf), config_error_line(&conf));
|
||||
|
||||
config_destroy(&conf);
|
||||
|
||||
@@ -204,7 +204,7 @@ int ReadCfg(config__t *cfg)
|
||||
|
||||
if (!config_lookup_string(&conf, "interface", &interface))
|
||||
{
|
||||
fprintf(stderr, "Error from LibConfig when reading 'interface' setting - %s\n\n", config_error_text(&conf));
|
||||
LogMsg(cfg, 0, 1, "Error from LibConfig when reading 'interface' setting - %s", config_error_text(&conf));
|
||||
|
||||
config_destroy(&conf);
|
||||
|
||||
@@ -243,7 +243,7 @@ int ReadCfg(config__t *cfg)
|
||||
// Check if filters map is valid. If not, not a biggie since they aren't required.
|
||||
if (setting == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error from LibConfig when reading 'filters' array - %s\n\n", config_error_text(&conf));
|
||||
LogMsg(cfg, 0, 1, "Error from LibConfig when reading 'filters' array - %s.", config_error_text(&conf));
|
||||
|
||||
config_destroy(&conf);
|
||||
|
||||
@@ -255,312 +255,318 @@ int ReadCfg(config__t *cfg)
|
||||
|
||||
for (int i = 0; i < config_setting_length(setting); i++)
|
||||
{
|
||||
config_setting_t* filter = config_setting_get_elem(setting, i);
|
||||
filter_t* filter = &cfg->filters[i];
|
||||
|
||||
config_setting_t* filter_cfg = config_setting_get_elem(setting, i);
|
||||
|
||||
if (filter == NULL || filter_cfg == NULL)
|
||||
{
|
||||
LogMsg(cfg, 0, 1, "[WARNING] Failed to read filter rule at index #%d. 'filter' or 'filter_cfg' is NULL (make sure you didn't exceed the maximum filters allowed!)...");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Enabled.
|
||||
int enabled;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "enabled", &enabled) == CONFIG_FALSE)
|
||||
if (config_setting_lookup_bool(filter_cfg, "enabled", &enabled) == CONFIG_TRUE)
|
||||
{
|
||||
// Print error and stop from existing this rule any further.
|
||||
fprintf(stderr, "Error from LibConfig when reading 'enabled' setting from filters array #%d. Error - %s\n\n", filters, config_error_text(&conf));
|
||||
|
||||
continue;
|
||||
filter->enabled = enabled;
|
||||
}
|
||||
|
||||
cfg->filters[i].enabled = enabled;
|
||||
// Log.
|
||||
int log;
|
||||
|
||||
if (config_setting_lookup_bool(filter_cfg, "log", &log) == CONFIG_TRUE)
|
||||
{
|
||||
filter->log = log;
|
||||
}
|
||||
|
||||
// Action (required).
|
||||
int action;
|
||||
|
||||
if (config_setting_lookup_int(filter, "action", &action) == CONFIG_FALSE)
|
||||
if (config_setting_lookup_int(filter_cfg, "action", &action) == CONFIG_TRUE)
|
||||
{
|
||||
fprintf(stderr, "Error from LibConfig when reading 'action' setting from filters array #%d. Error - %s\n\n", filters, config_error_text(&conf));
|
||||
|
||||
cfg->filters[i].enabled = 0;
|
||||
|
||||
continue;
|
||||
filter->action = action;
|
||||
}
|
||||
|
||||
cfg->filters[i].action = action;
|
||||
|
||||
// Source IP (not required).
|
||||
const char *sip;
|
||||
|
||||
if (config_setting_lookup_string(filter, "src_ip", &sip))
|
||||
if (config_setting_lookup_string(filter_cfg, "src_ip", &sip) == CONFIG_TRUE)
|
||||
{
|
||||
ip_range_t ip = ParseIpCidr(sip);
|
||||
|
||||
cfg->filters[i].src_ip = ip.ip;
|
||||
cfg->filters[i].src_cidr = ip.cidr;
|
||||
filter->src_ip = ip.ip;
|
||||
filter->src_cidr = ip.cidr;
|
||||
}
|
||||
|
||||
// Destination IP (not required).
|
||||
const char *dip;
|
||||
|
||||
if (config_setting_lookup_string(filter, "dst_ip", &dip))
|
||||
if (config_setting_lookup_string(filter_cfg, "dst_ip", &dip) == CONFIG_TRUE)
|
||||
{
|
||||
ip_range_t ip = ParseIpCidr(dip);
|
||||
|
||||
cfg->filters[i].dst_ip = ip.ip;
|
||||
cfg->filters[i].dst_cidr = ip.cidr;
|
||||
filter->dst_ip = ip.ip;
|
||||
filter->dst_cidr = ip.cidr;
|
||||
}
|
||||
|
||||
// Source IP (IPv6) (not required).
|
||||
const char *sip6;
|
||||
|
||||
if (config_setting_lookup_string(filter, "src_ip6", &sip6))
|
||||
if (config_setting_lookup_string(filter_cfg, "src_ip6", &sip6) == CONFIG_TRUE)
|
||||
{
|
||||
struct in6_addr in;
|
||||
|
||||
inet_pton(AF_INET6, sip6, &in);
|
||||
|
||||
memcpy(cfg->filters[i].src_ip6, in.__in6_u.__u6_addr32, 4);
|
||||
memcpy(filter->src_ip6, in.__in6_u.__u6_addr32, 4);
|
||||
}
|
||||
|
||||
// Destination IP (IPv6) (not required).
|
||||
const char *dip6;
|
||||
|
||||
if (config_setting_lookup_string(filter, "dst_ip6", &dip6))
|
||||
if (config_setting_lookup_string(filter_cfg, "dst_ip6", &dip6) == CONFIG_TRUE)
|
||||
{
|
||||
struct in6_addr in;
|
||||
|
||||
inet_pton(AF_INET6, dip6, &in);
|
||||
|
||||
memcpy(cfg->filters[i].dst_ip6, in.__in6_u.__u6_addr32, 4);
|
||||
memcpy(filter->dst_ip6, in.__in6_u.__u6_addr32, 4);
|
||||
}
|
||||
|
||||
// Minimum TTL (not required).
|
||||
int min_ttl;
|
||||
|
||||
if (config_setting_lookup_int(filter, "min_ttl", &min_ttl))
|
||||
if (config_setting_lookup_int(filter_cfg, "min_ttl", &min_ttl) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].min_ttl = (u8)min_ttl;
|
||||
cfg->filters[i].do_min_ttl = 1;
|
||||
filter->min_ttl = (u8)min_ttl;
|
||||
filter->do_min_ttl = 1;
|
||||
}
|
||||
|
||||
// Maximum TTL (not required).
|
||||
int max_ttl;
|
||||
|
||||
if (config_setting_lookup_int(filter, "max_ttl", &max_ttl))
|
||||
if (config_setting_lookup_int(filter_cfg, "max_ttl", &max_ttl) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].max_ttl = (u8)max_ttl;
|
||||
cfg->filters[i].do_max_ttl = 1;
|
||||
filter->max_ttl = (u8)max_ttl;
|
||||
filter->do_max_ttl = 1;
|
||||
}
|
||||
|
||||
// Minimum length (not required).
|
||||
int min_len;
|
||||
|
||||
if (config_setting_lookup_int(filter, "min_len", &min_len))
|
||||
if (config_setting_lookup_int(filter_cfg, "min_len", &min_len) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].min_len = min_len;
|
||||
cfg->filters[i].do_min_len = 1;
|
||||
filter->min_len = min_len;
|
||||
filter->do_min_len = 1;
|
||||
}
|
||||
|
||||
// Maximum length (not required).
|
||||
int max_len;
|
||||
|
||||
if (config_setting_lookup_int(filter, "max_len", &max_len))
|
||||
if (config_setting_lookup_int(filter_cfg, "max_len", &max_len) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].max_len = max_len;
|
||||
cfg->filters[i].do_max_len = 1;
|
||||
filter->max_len = max_len;
|
||||
filter->do_max_len = 1;
|
||||
}
|
||||
|
||||
// TOS (not required).
|
||||
int tos;
|
||||
|
||||
if (config_setting_lookup_int(filter, "tos", &tos))
|
||||
if (config_setting_lookup_int(filter_cfg, "tos", &tos) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tos = (u8)tos;
|
||||
cfg->filters[i].do_tos = 1;
|
||||
filter->tos = (u8)tos;
|
||||
filter->do_tos = 1;
|
||||
}
|
||||
|
||||
// PPS (not required).
|
||||
long long pps;
|
||||
|
||||
if (config_setting_lookup_int64(filter, "pps", &pps))
|
||||
if (config_setting_lookup_int64(filter_cfg, "pps", &pps) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].pps = pps;
|
||||
cfg->filters[i].do_pps = 1;
|
||||
filter->pps = pps;
|
||||
filter->do_pps = 1;
|
||||
}
|
||||
|
||||
// BPS (not required).
|
||||
long long bps;
|
||||
|
||||
if (config_setting_lookup_int64(filter, "bps", &bps))
|
||||
if (config_setting_lookup_int64(filter_cfg, "bps", &bps) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].bps = bps;
|
||||
cfg->filters[i].do_bps = 1;
|
||||
filter->bps = bps;
|
||||
filter->do_bps = 1;
|
||||
}
|
||||
|
||||
// Block time (default 1).
|
||||
long long blocktime;
|
||||
|
||||
if (config_setting_lookup_int64(filter, "block_time", &blocktime))
|
||||
if (config_setting_lookup_int64(filter_cfg, "block_time", &blocktime) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].blocktime = blocktime;
|
||||
filter->blocktime = blocktime;
|
||||
}
|
||||
else
|
||||
{
|
||||
cfg->filters[i].blocktime = 1;
|
||||
filter->blocktime = 1;
|
||||
}
|
||||
|
||||
/* TCP options */
|
||||
// Enabled.
|
||||
int tcpenabled;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "tcp_enabled", &tcpenabled))
|
||||
if (config_setting_lookup_bool(filter_cfg, "tcp_enabled", &tcpenabled) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.enabled = tcpenabled;
|
||||
filter->tcpopts.enabled = tcpenabled;
|
||||
}
|
||||
|
||||
// Source port.
|
||||
long long tcpsport;
|
||||
|
||||
if (config_setting_lookup_int64(filter, "tcp_sport", &tcpsport))
|
||||
if (config_setting_lookup_int64(filter_cfg, "tcp_sport", &tcpsport) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.sport = (u16)tcpsport;
|
||||
cfg->filters[i].tcpopts.do_sport = 1;
|
||||
filter->tcpopts.sport = (u16)tcpsport;
|
||||
filter->tcpopts.do_sport = 1;
|
||||
}
|
||||
|
||||
// Destination port.
|
||||
long long tcpdport;
|
||||
|
||||
if (config_setting_lookup_int64(filter, "tcp_dport", &tcpdport))
|
||||
if (config_setting_lookup_int64(filter_cfg, "tcp_dport", &tcpdport) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.dport = (u16)tcpdport;
|
||||
cfg->filters[i].tcpopts.do_dport = 1;
|
||||
filter->tcpopts.dport = (u16)tcpdport;
|
||||
filter->tcpopts.do_dport = 1;
|
||||
}
|
||||
|
||||
// URG flag.
|
||||
int tcpurg;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "tcp_urg", &tcpurg))
|
||||
if (config_setting_lookup_bool(filter_cfg, "tcp_urg", &tcpurg) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.urg = tcpurg;
|
||||
cfg->filters[i].tcpopts.do_urg = 1;
|
||||
filter->tcpopts.urg = tcpurg;
|
||||
filter->tcpopts.do_urg = 1;
|
||||
}
|
||||
|
||||
// ACK flag.
|
||||
int tcpack;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "tcp_ack", &tcpack))
|
||||
if (config_setting_lookup_bool(filter_cfg, "tcp_ack", &tcpack) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.ack = tcpack;
|
||||
cfg->filters[i].tcpopts.do_ack = 1;
|
||||
filter->tcpopts.ack = tcpack;
|
||||
filter->tcpopts.do_ack = 1;
|
||||
}
|
||||
|
||||
|
||||
// RST flag.
|
||||
int tcprst;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "tcp_rst", &tcprst))
|
||||
if (config_setting_lookup_bool(filter_cfg, "tcp_rst", &tcprst) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.rst = tcprst;
|
||||
cfg->filters[i].tcpopts.do_rst = 1;
|
||||
filter->tcpopts.rst = tcprst;
|
||||
filter->tcpopts.do_rst = 1;
|
||||
}
|
||||
|
||||
// PSH flag.
|
||||
int tcppsh;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "tcp_psh", &tcppsh))
|
||||
if (config_setting_lookup_bool(filter_cfg, "tcp_psh", &tcppsh) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.psh = tcppsh;
|
||||
cfg->filters[i].tcpopts.do_psh = 1;
|
||||
filter->tcpopts.psh = tcppsh;
|
||||
filter->tcpopts.do_psh = 1;
|
||||
}
|
||||
|
||||
// SYN flag.
|
||||
int tcpsyn;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "tcp_syn", &tcpsyn))
|
||||
if (config_setting_lookup_bool(filter_cfg, "tcp_syn", &tcpsyn) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.syn = tcpsyn;
|
||||
cfg->filters[i].tcpopts.do_syn = 1;
|
||||
filter->tcpopts.syn = tcpsyn;
|
||||
filter->tcpopts.do_syn = 1;
|
||||
}
|
||||
|
||||
// FIN flag.
|
||||
int tcpfin;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "tcp_fin", &tcpfin))
|
||||
if (config_setting_lookup_bool(filter_cfg, "tcp_fin", &tcpfin) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.fin = tcpfin;
|
||||
cfg->filters[i].tcpopts.do_fin = 1;
|
||||
filter->tcpopts.fin = tcpfin;
|
||||
filter->tcpopts.do_fin = 1;
|
||||
}
|
||||
|
||||
// ECE flag.
|
||||
int tcpece;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "tcp_ece", &tcpece))
|
||||
if (config_setting_lookup_bool(filter_cfg, "tcp_ece", &tcpece) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.ece = tcpece;
|
||||
cfg->filters[i].tcpopts.do_ece = 1;
|
||||
filter->tcpopts.ece = tcpece;
|
||||
filter->tcpopts.do_ece = 1;
|
||||
}
|
||||
|
||||
// CWR flag.
|
||||
int tcpcwr;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "tcp_cwr", &tcpcwr))
|
||||
if (config_setting_lookup_bool(filter_cfg, "tcp_cwr", &tcpcwr) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].tcpopts.cwr = tcpcwr;
|
||||
cfg->filters[i].tcpopts.do_cwr = 1;
|
||||
filter->tcpopts.cwr = tcpcwr;
|
||||
filter->tcpopts.do_cwr = 1;
|
||||
}
|
||||
|
||||
/* UDP options */
|
||||
// Enabled.
|
||||
int udpenabled;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "udp_enabled", &udpenabled))
|
||||
if (config_setting_lookup_bool(filter_cfg, "udp_enabled", &udpenabled) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].udpopts.enabled = udpenabled;
|
||||
filter->udpopts.enabled = udpenabled;
|
||||
}
|
||||
|
||||
// Source port.
|
||||
long long udpsport;
|
||||
|
||||
if (config_setting_lookup_int64(filter, "udp_sport", &udpsport))
|
||||
if (config_setting_lookup_int64(filter_cfg, "udp_sport", &udpsport) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].udpopts.sport = (u16)udpsport;
|
||||
cfg->filters[i].udpopts.do_sport = 1;
|
||||
filter->udpopts.sport = (u16)udpsport;
|
||||
filter->udpopts.do_sport = 1;
|
||||
}
|
||||
|
||||
// Destination port.
|
||||
long long udpdport;
|
||||
|
||||
if (config_setting_lookup_int64(filter, "udp_dport", &udpdport))
|
||||
if (config_setting_lookup_int64(filter_cfg, "udp_dport", &udpdport) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].udpopts.dport = (u16)udpdport;
|
||||
cfg->filters[i].udpopts.do_dport = 1;
|
||||
filter->udpopts.dport = (u16)udpdport;
|
||||
filter->udpopts.do_dport = 1;
|
||||
}
|
||||
|
||||
/* ICMP options */
|
||||
// Enabled.
|
||||
int icmpenabled;
|
||||
|
||||
if (config_setting_lookup_bool(filter, "icmp_enabled", &icmpenabled))
|
||||
if (config_setting_lookup_bool(filter_cfg, "icmp_enabled", &icmpenabled) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].icmpopts.enabled = icmpenabled;
|
||||
filter->icmpopts.enabled = icmpenabled;
|
||||
}
|
||||
|
||||
// ICMP code.
|
||||
int icmpcode;
|
||||
|
||||
if (config_setting_lookup_int(filter, "icmp_code", &icmpcode))
|
||||
if (config_setting_lookup_int(filter_cfg, "icmp_code", &icmpcode) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].icmpopts.code = (u8)icmpcode;
|
||||
cfg->filters[i].icmpopts.do_code = 1;
|
||||
filter->icmpopts.code = (u8)icmpcode;
|
||||
filter->icmpopts.do_code = 1;
|
||||
}
|
||||
|
||||
// ICMP type.
|
||||
int icmptype;
|
||||
|
||||
if (config_setting_lookup_int(filter, "icmp_type", &icmptype))
|
||||
if (config_setting_lookup_int(filter_cfg, "icmp_type", &icmptype) == CONFIG_TRUE)
|
||||
{
|
||||
cfg->filters[i].icmpopts.type = (u8)icmptype;
|
||||
cfg->filters[i].icmpopts.do_type = 1;
|
||||
filter->icmpopts.type = (u8)icmptype;
|
||||
filter->icmpopts.do_type = 1;
|
||||
}
|
||||
|
||||
// Assign ID and increase filter count.
|
||||
cfg->filters[i].id = ++filters;
|
||||
filter->id = ++filters;
|
||||
}
|
||||
|
||||
config_destroy(&conf);
|
||||
@@ -599,6 +605,7 @@ void PrintConfig(config__t* cfg)
|
||||
|
||||
// Main.
|
||||
fprintf(stdout, "\t\t\tID => %d\n", filter->id);
|
||||
fprintf(stdout, "\t\t\tLog => %d\n", filter->log);
|
||||
fprintf(stdout, "\t\t\tEnabled => %d\n", filter->enabled);
|
||||
fprintf(stdout, "\t\t\tAction => %d (0 = Block, 1 = Allow).\n\n", filter->action);
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <loader/utils/helpers.h>
|
||||
|
||||
#define CONFIG_DEFAULT_PATH "/etc/xdpfw/xdpfw.conf"
|
||||
|
||||
struct config
|
||||
@@ -27,4 +29,6 @@ void SetCfgDefaults(config__t *cfg);
|
||||
void PrintConfig(config__t* cfg);
|
||||
|
||||
int OpenCfg(const char *filename);
|
||||
int ReadCfg(config__t *cfg);
|
||||
int ReadCfg(config__t *cfg);
|
||||
|
||||
#include <loader/utils/logging.h>
|
||||
@@ -93,4 +93,38 @@ void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...)
|
||||
LogMsgRaw(req_lvl, cfg->verbose, error, (const char*)cfg->log_file, msg, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int HandleRbEvent(void* ctx, void* data, size_t sz)
|
||||
{
|
||||
config__t* cfg = (config__t*)ctx;
|
||||
filter_log_event_t* e = (filter_log_event_t*)data;
|
||||
|
||||
filter_t* filter = &cfg->filters[e->filter_id];
|
||||
|
||||
if (filter == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
char ip_str[INET6_ADDRSTRLEN];
|
||||
|
||||
if (memcmp(e->src_ip6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) != 0)
|
||||
{
|
||||
inet_ntop(AF_INET6, e->src_ip6, ip_str, sizeof(ip_str));
|
||||
} else
|
||||
{
|
||||
inet_ntop(AF_INET, &e->src_ip, ip_str, sizeof(ip_str));
|
||||
}
|
||||
|
||||
char* action = "Dropped";
|
||||
|
||||
if (filter->action == 1)
|
||||
{
|
||||
action = "Passed";
|
||||
}
|
||||
|
||||
LogMsg(cfg, 0, 0, "[FILTER %d] %s packet from '%s:%d' (PPS => %llu, BPS => %llu, Filter Block Time => %llu)...", e->filter_id, action, ip_str, e->src_port, e->pps, e->bps, filter->blocktime);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -12,4 +12,7 @@
|
||||
|
||||
#include <xdp/libxdp.h>
|
||||
|
||||
void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...);
|
||||
#define RB_TIMEOUT 100
|
||||
|
||||
void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...);
|
||||
int HandleRbEvent(void* ctx, void* data, size_t sz);
|
||||
@@ -513,6 +513,34 @@ int xdp_prog_main(struct xdp_md *ctx)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FILTER_LOGGING
|
||||
if (filter->log > 0)
|
||||
{
|
||||
filter_log_event_t* e = bpf_ringbuf_reserve(&filter_log_map, sizeof(*e), 0);
|
||||
|
||||
if (e)
|
||||
{
|
||||
e->ts = now;
|
||||
e->filter_id = i;
|
||||
|
||||
if (iph)
|
||||
{
|
||||
e->src_ip = iph->saddr;
|
||||
} else if (iph6)
|
||||
{
|
||||
memcpy(&e->src_ip6, iph6->saddr.in6_u.u6_addr32, 4);
|
||||
}
|
||||
|
||||
e->src_port = src_port;
|
||||
|
||||
e->pps = pps;
|
||||
e->bps = bps;
|
||||
|
||||
bpf_ringbuf_submit(e, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Matched.
|
||||
action = filter->action;
|
||||
|
||||
@@ -59,4 +59,12 @@ struct
|
||||
__uint(max_entries, MAX_TRACK_IPS);
|
||||
__type(key, u128);
|
||||
__type(value, u64);
|
||||
} ip6_blacklist_map SEC(".maps");
|
||||
} ip6_blacklist_map SEC(".maps");
|
||||
|
||||
#ifdef ENABLE_FILTER_LOGGING
|
||||
struct
|
||||
{
|
||||
__uint(type, BPF_MAP_TYPE_RINGBUF);
|
||||
__uint(max_entries, 1 << 16);
|
||||
} filter_log_map SEC(".maps");
|
||||
#endif
|
||||
Reference in New Issue
Block a user