Continue preparing Loader for new features.

This commit is contained in:
Christian Deacon
2025-03-01 10:39:11 -05:00
parent ff1ac4e817
commit 2019029a4d
5 changed files with 739 additions and 410 deletions

View File

@@ -22,16 +22,47 @@ int cont = 1;
int doing_stats = 0; int doing_stats = 0;
/** /**
* Unpins filter-specific BPF maps from file system. * Unpins required BPF maps from file system.
* *
* @param cfg A pointer to the config structure. * @param cfg A pointer to the config structure.
* @param obj A pointer to the BPF object. * @param obj A pointer to the BPF object.
* @param ignore_errors Whether to ignore errors. * @param ignore_errors Whether to ignore errors.
*/ */
static void UnpinFilterMaps(config__t* cfg, struct bpf_object* obj, int ignore_errors) static void UnpinNeededMaps(config__t* cfg, struct bpf_object* obj, int ignore_errors)
{ {
int ret; int ret;
// Unpin block map.
if ((ret = UnpinBpfMap(obj, XDP_MAP_PIN_DIR, "map_block")) != 0)
{
if (!ignore_errors)
{
LogMsg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_block' from file system (%d).", ret);
}
}
// Unpin block (IPv6) map.
if ((ret = UnpinBpfMap(obj, XDP_MAP_PIN_DIR, "map_block6")) != 0)
{
if (!ignore_errors)
{
LogMsg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_block6' from file system (%d).", ret);
}
}
#ifdef ENABLE_IP_RANGE_DROP
// Unpin IPv4 range drop map.
if ((ret = UnpinBpfMap(obj, XDP_MAP_PIN_DIR, "map_range_drop")) != 0)
{
if (!ignore_errors)
{
LogMsg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_range_drop' from file system (%d).", ret);
}
}
#endif
#ifdef ENABLE_FILTERS
// Unpin filters map.
if ((ret = UnpinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filters")) != 0) if ((ret = UnpinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filters")) != 0)
{ {
if (!ignore_errors) if (!ignore_errors)
@@ -40,6 +71,8 @@ static void UnpinFilterMaps(config__t* cfg, struct bpf_object* obj, int ignore_e
} }
} }
#ifdef ENABLE_FILTER_LOGGING
// Unpin filters log map.
if ((ret = UnpinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filter_log")) != 0) if ((ret = UnpinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filter_log")) != 0)
{ {
if (!ignore_errors) if (!ignore_errors)
@@ -47,6 +80,8 @@ static void UnpinFilterMaps(config__t* cfg, struct bpf_object* obj, int ignore_e
LogMsg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_filter_log' from file system (%d).", ret); LogMsg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_filter_log' from file system (%d).", ret);
} }
} }
#endif
#endif
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@@ -55,7 +90,7 @@ int main(int argc, char *argv[])
// Parse the command line. // Parse the command line.
cmdline_t cmd = {0}; cmdline_t cmd = {0};
cmd.cfgfile = CONFIG_DEFAULT_PATH; cmd.cfg_file = CONFIG_DEFAULT_PATH;
cmd.verbose = -1; cmd.verbose = -1;
cmd.pin_maps = -1; cmd.pin_maps = -1;
cmd.update_time = -1; cmd.update_time = -1;
@@ -90,9 +125,9 @@ int main(int argc, char *argv[])
cfg_overrides.stdout_update_time = cmd.stdout_update_time; cfg_overrides.stdout_update_time = cmd.stdout_update_time;
// Load config. // Load config.
if ((ret = LoadConfig(&cfg, cmd.cfgfile, &cfg_overrides)) != 0) if ((ret = LoadConfig(&cfg, cmd.cfg_file, &cfg_overrides)) != 0)
{ {
fprintf(stderr, "[ERROR] Failed to load config from file system (%s)(%d).\n", cmd.cfgfile, ret); fprintf(stderr, "[ERROR] Failed to load config from file system (%s)(%d).\n", cmd.cfg_file, ret);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -185,6 +220,16 @@ int main(int argc, char *argv[])
LogMsg(&cfg, 2, 0, "Retrieving BPF map FDs..."); LogMsg(&cfg, 2, 0, "Retrieving BPF map FDs...");
// Retrieve BPF maps. // Retrieve BPF maps.
int map_stats = FindMapFd(prog, "map_stats");
if (map_stats < 0)
{
LogMsg(&cfg, 0, 1, "[ERROR] Failed to find 'map_stats' BPF map.\n");
return EXIT_FAILURE;
}
#ifdef ENABLE_FILTERS
int map_filters = FindMapFd(prog, "map_filters"); int map_filters = FindMapFd(prog, "map_filters");
// Check for valid maps. // Check for valid maps.
@@ -197,17 +242,9 @@ int main(int argc, char *argv[])
LogMsg(&cfg, 3, 0, "map_filters FD => %d.", map_filters); LogMsg(&cfg, 3, 0, "map_filters FD => %d.", map_filters);
int map_stats = FindMapFd(prog, "map_stats");
if (map_stats < 0)
{
LogMsg(&cfg, 0, 1, "[ERROR] Failed to find 'map_stats' BPF map.\n");
return EXIT_FAILURE;
}
#ifdef ENABLE_FILTER_LOGGING #ifdef ENABLE_FILTER_LOGGING
int map_filter_log = FindMapFd(prog, "map_filter_log"); int map_filter_log = FindMapFd(prog, "map_filter_log");
struct ring_buffer* rb = NULL; struct ring_buffer* rb = NULL;
if (map_filter_log < 0) if (map_filter_log < 0)
@@ -221,6 +258,20 @@ int main(int argc, char *argv[])
rb = ring_buffer__new(map_filter_log, HandleRbEvent, &cfg, NULL); rb = ring_buffer__new(map_filter_log, HandleRbEvent, &cfg, NULL);
} }
#endif #endif
#endif
#ifdef ENABLE_IP_RANGE_DROP
int map_range_drop = FindMapFd(prog, "map_range_drop");
if (map_range_drop < 0)
{
LogMsg(&cfg, 1, 0, "[WARNING] Failed to find 'map_range_drop' BPF map. IP range drops will be disabled...");
}
else
{
LogMsg(&cfg, 3, 0, "map_range_drop FD => %d.", map_range_drop);
}
#endif
LogMsg(&cfg, 3, 0, "map_stats FD => %d.", map_stats); LogMsg(&cfg, 3, 0, "map_stats FD => %d.", map_stats);
@@ -233,8 +284,41 @@ int main(int argc, char *argv[])
// There are times where the BPF maps from the last run weren't cleaned up properly. // There are times where the BPF maps from the last run weren't cleaned up properly.
// 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.
UnpinFilterMaps(&cfg, obj, 1); UnpinNeededMaps(&cfg, obj, 1);
// Pin the block maps.
if ((ret = PinBpfMap(obj, XDP_MAP_PIN_DIR, "map_block")) != 0)
{
LogMsg(&cfg, 1, 0, "[WARNING] Failed to pin 'map_block' to file system (%d)...", ret);
}
else
{
LogMsg(&cfg, 3, 0, "BPF map 'map_block' pinned to '%s/map_block'.", XDP_MAP_PIN_DIR);
}
if ((ret = PinBpfMap(obj, XDP_MAP_PIN_DIR, "map_block6")) != 0)
{
LogMsg(&cfg, 1, 0, "[WARNING] Failed to pin 'map_block6' to file system (%d)...", ret);
}
else
{
LogMsg(&cfg, 3, 0, "BPF map 'map_block6' pinned to '%s/map_block6'.", XDP_MAP_PIN_DIR);
}
#ifdef ENABLE_IP_RANGE_DROP
// Pin the IPv4 range drop map.
if ((ret = PinBpfMap(obj, XDP_MAP_PIN_DIR, "map_range_drop")) != 0)
{
LogMsg(&cfg, 1, 0, "[WARNING] Failed to pin 'map_range_drop' to file system (%d)...", ret);
}
else
{
LogMsg(&cfg, 3, 0, "BPF map 'map_range_drop' pinned to '%s/map_range_drop'.", XDP_MAP_PIN_DIR);
}
#endif
#ifdef ENABLE_FILTERS
// Pin the filters map.
if ((ret = PinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filters")) != 0) if ((ret = PinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filters")) != 0)
{ {
LogMsg(&cfg, 1, 0, "[WARNING] Failed to pin 'map_filters' to file system (%d)...", ret); LogMsg(&cfg, 1, 0, "[WARNING] Failed to pin 'map_filters' to file system (%d)...", ret);
@@ -244,6 +328,8 @@ int main(int argc, char *argv[])
LogMsg(&cfg, 3, 0, "BPF map 'map_filters' pinned to '%s/map_filters'.", XDP_MAP_PIN_DIR); LogMsg(&cfg, 3, 0, "BPF map 'map_filters' pinned to '%s/map_filters'.", XDP_MAP_PIN_DIR);
} }
#ifdef ENABLE_FILTER_LOGGING
// Pin the filters log map.
if ((ret = PinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filter_log")) != 0) if ((ret = PinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filter_log")) != 0)
{ {
LogMsg(&cfg, 1, 0, "[WARNING] Failed to pin 'map_filter_log' to file system (%d)...", ret); LogMsg(&cfg, 1, 0, "[WARNING] Failed to pin 'map_filter_log' to file system (%d)...", ret);
@@ -252,12 +338,26 @@ int main(int argc, char *argv[])
{ {
LogMsg(&cfg, 3, 0, "BPF map 'map_filter_log' pinned to '%s/map_filter_log'.", XDP_MAP_PIN_DIR); LogMsg(&cfg, 3, 0, "BPF map 'map_filter_log' pinned to '%s/map_filter_log'.", XDP_MAP_PIN_DIR);
} }
#endif
#endif
} }
#ifdef ENABLE_FILTERS
LogMsg(&cfg, 2, 0, "Updating filters..."); LogMsg(&cfg, 2, 0, "Updating filters...");
// Update BPF maps. // Update filters.
UpdateFilters(map_filters, &cfg); UpdateFilters(map_filters, &cfg);
#endif
#ifdef ENABLE_IP_RANGE_DROP
if (map_range_drop > -1)
{
LogMsg(&cfg, 2, 0, "Updating IP drop ranges...");
// Update IP range drops.
UpdateRangeDrops(map_range_drop, &cfg);
}
#endif
// Signal. // Signal.
signal(SIGINT, SignalHndl); signal(SIGINT, SignalHndl);
@@ -299,17 +399,19 @@ int main(int argc, char *argv[])
if (cfg.update_time > 0 && (cur_time - last_update_check) > cfg.update_time) if (cfg.update_time > 0 && (cur_time - last_update_check) > cfg.update_time)
{ {
// Check if config file have been modified // Check if config file have been modified
if (stat(cmd.cfgfile, &conf_stat) == 0 && conf_stat.st_mtime > last_config_check) { if (stat(cmd.cfg_file, &conf_stat) == 0 && conf_stat.st_mtime > last_config_check) {
// Update config. // Reload config.
if ((ret = LoadConfig(&cfg, cmd.cfgfile, &cfg_overrides)) != 0) if ((ret = LoadConfig(&cfg, cmd.cfg_file, &cfg_overrides)) != 0)
{ {
LogMsg(&cfg, 1, 0, "[WARNING] Failed to load config after update check (%d)...\n", ret); LogMsg(&cfg, 1, 0, "[WARNING] Failed to load config after update check (%d)...\n", ret);
} }
// Update BPF maps. #ifdef ENABLE_FILTERS
// Update filters.
UpdateFilters(map_filters, &cfg); UpdateFilters(map_filters, &cfg);
#endif
// Update timer // Update last check timer
last_config_check = time(NULL); last_config_check = time(NULL);
// Make sure we set doing stats if needed. // Make sure we set doing stats if needed.
@@ -332,7 +434,7 @@ int main(int argc, char *argv[])
} }
} }
#ifdef ENABLE_FILTER_LOGGING #if defined(ENABLE_FILTERS) && defined(ENABLE_FILTER_LOGGING)
PollFiltersRb(rb); PollFiltersRb(rb);
#endif #endif
@@ -343,7 +445,7 @@ int main(int argc, char *argv[])
LogMsg(&cfg, 2, 0, "Cleaning up..."); LogMsg(&cfg, 2, 0, "Cleaning up...");
#ifdef ENABLE_FILTER_LOGGING #if defined(ENABLE_FILTERS) && defined(ENABLE_FILTER_LOGGING)
if (rb) if (rb)
{ {
ring_buffer__free(rb); ring_buffer__free(rb);
@@ -365,7 +467,7 @@ int main(int argc, char *argv[])
struct bpf_object* obj = GetBpfObj(prog); struct bpf_object* obj = GetBpfObj(prog);
UnpinFilterMaps(&cfg, obj, 0); UnpinNeededMaps(&cfg, obj, 0);
} }
// Lastly, close the XDP program. // Lastly, close the XDP program.

View File

@@ -9,7 +9,7 @@
* *
* @return 0 on success or 1 on error. * @return 0 on success or 1 on error.
*/ */
int LoadConfig(config__t *cfg, char *cfg_file, config_overrides_t* overrides) int LoadConfig(config__t *cfg, const char* cfg_file, config_overrides_t* overrides)
{ {
int ret; int ret;
@@ -159,9 +159,9 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides)
int verbose; int verbose;
if (config_lookup_int(&conf, "verbose", &verbose) == CONFIG_TRUE || overrides->verbose > -1) if (config_lookup_int(&conf, "verbose", &verbose) == CONFIG_TRUE || (overrides && overrides->verbose > -1))
{ {
if (overrides->verbose > -1) if (overrides && overrides->verbose > -1)
{ {
cfg->verbose = overrides->verbose; cfg->verbose = overrides->verbose;
} }
@@ -182,7 +182,7 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides)
cfg->log_file = NULL; cfg->log_file = NULL;
} }
if (overrides->log_file != NULL) if (overrides && overrides->log_file != NULL)
{ {
if (strlen(overrides->log_file) > 0) if (strlen(overrides->log_file) > 0)
{ {
@@ -219,7 +219,7 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides)
cfg->interface = NULL; cfg->interface = NULL;
} }
if (overrides->interface != NULL) if (overrides && overrides->interface != NULL)
{ {
cfg->interface = strdup(overrides->interface); cfg->interface = strdup(overrides->interface);
} }
@@ -234,7 +234,7 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides)
if (config_lookup_bool(&conf, "pin_maps", &pin_maps) == CONFIG_TRUE || (overrides && overrides->pin_maps > -1)) if (config_lookup_bool(&conf, "pin_maps", &pin_maps) == CONFIG_TRUE || (overrides && overrides->pin_maps > -1))
{ {
if (overrides->pin_maps > -1) if (overrides && overrides->pin_maps > -1)
{ {
cfg->pin_maps = overrides->pin_maps; cfg->pin_maps = overrides->pin_maps;
} }
@@ -249,7 +249,7 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides)
if (config_lookup_int(&conf, "update_time", &update_time) == CONFIG_TRUE || (overrides && overrides->update_time > -1)) if (config_lookup_int(&conf, "update_time", &update_time) == CONFIG_TRUE || (overrides && overrides->update_time > -1))
{ {
if (overrides->update_time > -1) if (overrides && overrides->update_time > -1)
{ {
cfg->update_time = overrides->update_time; cfg->update_time = overrides->update_time;
} }
@@ -264,7 +264,7 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides)
if (config_lookup_bool(&conf, "no_stats", &no_stats) == CONFIG_TRUE || (overrides && overrides->no_stats > -1)) if (config_lookup_bool(&conf, "no_stats", &no_stats) == CONFIG_TRUE || (overrides && overrides->no_stats > -1))
{ {
if (overrides->no_stats > -1) if (overrides && overrides->no_stats > -1)
{ {
cfg->no_stats = overrides->no_stats; cfg->no_stats = overrides->no_stats;
} }
@@ -279,7 +279,7 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides)
if (config_lookup_bool(&conf, "stats_per_second", &stats_per_second) == CONFIG_TRUE || (overrides && overrides->stats_per_second > -1)) if (config_lookup_bool(&conf, "stats_per_second", &stats_per_second) == CONFIG_TRUE || (overrides && overrides->stats_per_second > -1))
{ {
if (overrides->stats_per_second > -1) if (overrides && overrides->stats_per_second > -1)
{ {
cfg->stats_per_second = overrides->stats_per_second; cfg->stats_per_second = overrides->stats_per_second;
} }
@@ -294,7 +294,7 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides)
if (config_lookup_int(&conf, "stdout_update_time", &stdout_update_time) == CONFIG_TRUE || (overrides && overrides->stdout_update_time > -1)) if (config_lookup_int(&conf, "stdout_update_time", &stdout_update_time) == CONFIG_TRUE || (overrides && overrides->stdout_update_time > -1))
{ {
if (overrides->stdout_update_time > -1) if (overrides && overrides->stdout_update_time > -1)
{ {
cfg->stdout_update_time = overrides->stdout_update_time; cfg->stdout_update_time = overrides->stdout_update_time;
} }
@@ -304,332 +304,349 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides)
} }
} }
// Read filters in map_filters structure. // Read filters.
setting = config_lookup(&conf, "filters"); setting = config_lookup(&conf, "filters");
// Check if filters map is valid. If not, not a biggie since they aren't required. if (setting && config_setting_is_list(setting))
if (setting == NULL)
{ {
LogMsg(cfg, 0, 1, "Error from LibConfig when reading 'filters' array - %s.", config_error_text(&conf)); for (int i = 0; i < config_setting_length(setting); i++)
{
config_destroy(&conf); filter_t* filter = &cfg->filters[i];
return 1; 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_cfg, "enabled", &enabled) == CONFIG_TRUE)
{
filter->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_cfg, "action", &action) == CONFIG_TRUE)
{
filter->action = action;
}
// Source IP (not required).
const char *sip;
if (config_setting_lookup_string(filter_cfg, "src_ip", &sip) == CONFIG_TRUE)
{
ip_range_t ip = ParseIpCidr(sip);
filter->src_ip = ip.ip;
filter->src_cidr = ip.cidr;
}
// Destination IP (not required).
const char *dip;
if (config_setting_lookup_string(filter_cfg, "dst_ip", &dip) == CONFIG_TRUE)
{
ip_range_t ip = ParseIpCidr(dip);
filter->dst_ip = ip.ip;
filter->dst_cidr = ip.cidr;
}
// Source IP (IPv6) (not required).
const char *sip6;
if (config_setting_lookup_string(filter_cfg, "src_ip6", &sip6) == CONFIG_TRUE)
{
struct in6_addr in;
inet_pton(AF_INET6, sip6, &in);
memcpy(filter->src_ip6, in.__in6_u.__u6_addr32, 4);
}
// Destination IP (IPv6) (not required).
const char *dip6;
if (config_setting_lookup_string(filter_cfg, "dst_ip6", &dip6) == CONFIG_TRUE)
{
struct in6_addr in;
inet_pton(AF_INET6, dip6, &in);
memcpy(filter->dst_ip6, in.__in6_u.__u6_addr32, 4);
}
// Minimum TTL (not required).
int min_ttl;
if (config_setting_lookup_int(filter_cfg, "min_ttl", &min_ttl) == CONFIG_TRUE)
{
filter->min_ttl = (u8)min_ttl;
filter->do_min_ttl = 1;
}
// Maximum TTL (not required).
int max_ttl;
if (config_setting_lookup_int(filter_cfg, "max_ttl", &max_ttl) == CONFIG_TRUE)
{
filter->max_ttl = (u8)max_ttl;
filter->do_max_ttl = 1;
}
// Minimum length (not required).
int min_len;
if (config_setting_lookup_int(filter_cfg, "min_len", &min_len) == CONFIG_TRUE)
{
filter->min_len = min_len;
filter->do_min_len = 1;
}
// Maximum length (not required).
int max_len;
if (config_setting_lookup_int(filter_cfg, "max_len", &max_len) == CONFIG_TRUE)
{
filter->max_len = max_len;
filter->do_max_len = 1;
}
// TOS (not required).
int tos;
if (config_setting_lookup_int(filter_cfg, "tos", &tos) == CONFIG_TRUE)
{
filter->tos = (u8)tos;
filter->do_tos = 1;
}
// PPS (not required).
long long pps;
if (config_setting_lookup_int64(filter_cfg, "pps", &pps) == CONFIG_TRUE)
{
filter->pps = pps;
filter->do_pps = 1;
}
// BPS (not required).
long long bps;
if (config_setting_lookup_int64(filter_cfg, "bps", &bps) == CONFIG_TRUE)
{
filter->bps = bps;
filter->do_bps = 1;
}
// Block time (default 1).
long long block_time;
if (config_setting_lookup_int64(filter_cfg, "block_time", &block_time) == CONFIG_TRUE)
{
filter->block_time = block_time;
}
else
{
filter->block_time = 1;
}
/* TCP options */
// Enabled.
int tcpenabled;
if (config_setting_lookup_bool(filter_cfg, "tcp_enabled", &tcpenabled) == CONFIG_TRUE)
{
filter->tcpopts.enabled = tcpenabled;
}
// Source port.
int tcpsport;
if (config_setting_lookup_int(filter_cfg, "tcp_sport", &tcpsport) == CONFIG_TRUE)
{
filter->tcpopts.sport = (u16)tcpsport;
filter->tcpopts.do_sport = 1;
}
// Destination port.
int tcpdport;
if (config_setting_lookup_int(filter_cfg, "tcp_dport", &tcpdport) == CONFIG_TRUE)
{
filter->tcpopts.dport = (u16)tcpdport;
filter->tcpopts.do_dport = 1;
}
// URG flag.
int tcpurg;
if (config_setting_lookup_bool(filter_cfg, "tcp_urg", &tcpurg) == CONFIG_TRUE)
{
filter->tcpopts.urg = tcpurg;
filter->tcpopts.do_urg = 1;
}
// ACK flag.
int tcpack;
if (config_setting_lookup_bool(filter_cfg, "tcp_ack", &tcpack) == CONFIG_TRUE)
{
filter->tcpopts.ack = tcpack;
filter->tcpopts.do_ack = 1;
}
// RST flag.
int tcprst;
if (config_setting_lookup_bool(filter_cfg, "tcp_rst", &tcprst) == CONFIG_TRUE)
{
filter->tcpopts.rst = tcprst;
filter->tcpopts.do_rst = 1;
}
// PSH flag.
int tcppsh;
if (config_setting_lookup_bool(filter_cfg, "tcp_psh", &tcppsh) == CONFIG_TRUE)
{
filter->tcpopts.psh = tcppsh;
filter->tcpopts.do_psh = 1;
}
// SYN flag.
int tcpsyn;
if (config_setting_lookup_bool(filter_cfg, "tcp_syn", &tcpsyn) == CONFIG_TRUE)
{
filter->tcpopts.syn = tcpsyn;
filter->tcpopts.do_syn = 1;
}
// FIN flag.
int tcpfin;
if (config_setting_lookup_bool(filter_cfg, "tcp_fin", &tcpfin) == CONFIG_TRUE)
{
filter->tcpopts.fin = tcpfin;
filter->tcpopts.do_fin = 1;
}
// ECE flag.
int tcpece;
if (config_setting_lookup_bool(filter_cfg, "tcp_ece", &tcpece) == CONFIG_TRUE)
{
filter->tcpopts.ece = tcpece;
filter->tcpopts.do_ece = 1;
}
// CWR flag.
int tcpcwr;
if (config_setting_lookup_bool(filter_cfg, "tcp_cwr", &tcpcwr) == CONFIG_TRUE)
{
filter->tcpopts.cwr = tcpcwr;
filter->tcpopts.do_cwr = 1;
}
/* UDP options */
// Enabled.
int udpenabled;
if (config_setting_lookup_bool(filter_cfg, "udp_enabled", &udpenabled) == CONFIG_TRUE)
{
filter->udpopts.enabled = udpenabled;
}
// Source port.
int udpsport;
if (config_setting_lookup_int(filter_cfg, "udp_sport", &udpsport) == CONFIG_TRUE)
{
filter->udpopts.sport = (u16)udpsport;
filter->udpopts.do_sport = 1;
}
// Destination port.
int udpdport;
if (config_setting_lookup_int(filter_cfg, "udp_dport", &udpdport) == CONFIG_TRUE)
{
filter->udpopts.dport = (u16)udpdport;
filter->udpopts.do_dport = 1;
}
/* ICMP options */
// Enabled.
int icmpenabled;
if (config_setting_lookup_bool(filter_cfg, "icmp_enabled", &icmpenabled) == CONFIG_TRUE)
{
filter->icmpopts.enabled = icmpenabled;
}
// ICMP code.
int icmpcode;
if (config_setting_lookup_int(filter_cfg, "icmp_code", &icmpcode) == CONFIG_TRUE)
{
filter->icmpopts.code = (u8)icmpcode;
filter->icmpopts.do_code = 1;
}
// ICMP type.
int icmptype;
if (config_setting_lookup_int(filter_cfg, "icmp_type", &icmptype) == CONFIG_TRUE)
{
filter->icmpopts.type = (u8)icmptype;
filter->icmpopts.do_type = 1;
}
// Make sure filter is set.
filter->set = 1;
}
} }
for (int i = 0; i < config_setting_length(setting); i++) // Read IP range drops.
setting = config_lookup(&conf, "ip_drop_ranges");
if (setting && config_setting_is_list(setting))
{ {
filter_t* filter = &cfg->filters[i]; for (int i = 0; i < config_setting_length(setting) && i < MAX_IP_RANGES; 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!)..."); const char* range = cfg->drop_ranges[i];
continue; if (cfg->drop_ranges[i])
{
free((void*)cfg->drop_ranges[i]);
cfg->drop_ranges[i] = NULL;
}
const char* new_range = config_setting_get_string_elem(setting, i);
if (new_range)
{
cfg->drop_ranges[i] = strdup(new_range);
}
} }
// Enabled.
int enabled;
if (config_setting_lookup_bool(filter_cfg, "enabled", &enabled) == CONFIG_TRUE)
{
filter->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_cfg, "action", &action) == CONFIG_TRUE)
{
filter->action = action;
}
// Source IP (not required).
const char *sip;
if (config_setting_lookup_string(filter_cfg, "src_ip", &sip) == CONFIG_TRUE)
{
ip_range_t ip = ParseIpCidr(sip);
filter->src_ip = ip.ip;
filter->src_cidr = ip.cidr;
}
// Destination IP (not required).
const char *dip;
if (config_setting_lookup_string(filter_cfg, "dst_ip", &dip) == CONFIG_TRUE)
{
ip_range_t ip = ParseIpCidr(dip);
filter->dst_ip = ip.ip;
filter->dst_cidr = ip.cidr;
}
// Source IP (IPv6) (not required).
const char *sip6;
if (config_setting_lookup_string(filter_cfg, "src_ip6", &sip6) == CONFIG_TRUE)
{
struct in6_addr in;
inet_pton(AF_INET6, sip6, &in);
memcpy(filter->src_ip6, in.__in6_u.__u6_addr32, 4);
}
// Destination IP (IPv6) (not required).
const char *dip6;
if (config_setting_lookup_string(filter_cfg, "dst_ip6", &dip6) == CONFIG_TRUE)
{
struct in6_addr in;
inet_pton(AF_INET6, dip6, &in);
memcpy(filter->dst_ip6, in.__in6_u.__u6_addr32, 4);
}
// Minimum TTL (not required).
int min_ttl;
if (config_setting_lookup_int(filter_cfg, "min_ttl", &min_ttl) == CONFIG_TRUE)
{
filter->min_ttl = (u8)min_ttl;
filter->do_min_ttl = 1;
}
// Maximum TTL (not required).
int max_ttl;
if (config_setting_lookup_int(filter_cfg, "max_ttl", &max_ttl) == CONFIG_TRUE)
{
filter->max_ttl = (u8)max_ttl;
filter->do_max_ttl = 1;
}
// Minimum length (not required).
int min_len;
if (config_setting_lookup_int(filter_cfg, "min_len", &min_len) == CONFIG_TRUE)
{
filter->min_len = min_len;
filter->do_min_len = 1;
}
// Maximum length (not required).
int max_len;
if (config_setting_lookup_int(filter_cfg, "max_len", &max_len) == CONFIG_TRUE)
{
filter->max_len = max_len;
filter->do_max_len = 1;
}
// TOS (not required).
int tos;
if (config_setting_lookup_int(filter_cfg, "tos", &tos) == CONFIG_TRUE)
{
filter->tos = (u8)tos;
filter->do_tos = 1;
}
// PPS (not required).
long long pps;
if (config_setting_lookup_int64(filter_cfg, "pps", &pps) == CONFIG_TRUE)
{
filter->pps = pps;
filter->do_pps = 1;
}
// BPS (not required).
long long bps;
if (config_setting_lookup_int64(filter_cfg, "bps", &bps) == CONFIG_TRUE)
{
filter->bps = bps;
filter->do_bps = 1;
}
// Block time (default 1).
long long block_time;
if (config_setting_lookup_int64(filter_cfg, "block_time", &block_time) == CONFIG_TRUE)
{
filter->block_time = block_time;
}
else
{
filter->block_time = 1;
}
/* TCP options */
// Enabled.
int tcpenabled;
if (config_setting_lookup_bool(filter_cfg, "tcp_enabled", &tcpenabled) == CONFIG_TRUE)
{
filter->tcpopts.enabled = tcpenabled;
}
// Source port.
int tcpsport;
if (config_setting_lookup_int(filter_cfg, "tcp_sport", &tcpsport) == CONFIG_TRUE)
{
filter->tcpopts.sport = (u16)tcpsport;
filter->tcpopts.do_sport = 1;
}
// Destination port.
int tcpdport;
if (config_setting_lookup_int(filter_cfg, "tcp_dport", &tcpdport) == CONFIG_TRUE)
{
filter->tcpopts.dport = (u16)tcpdport;
filter->tcpopts.do_dport = 1;
}
// URG flag.
int tcpurg;
if (config_setting_lookup_bool(filter_cfg, "tcp_urg", &tcpurg) == CONFIG_TRUE)
{
filter->tcpopts.urg = tcpurg;
filter->tcpopts.do_urg = 1;
}
// ACK flag.
int tcpack;
if (config_setting_lookup_bool(filter_cfg, "tcp_ack", &tcpack) == CONFIG_TRUE)
{
filter->tcpopts.ack = tcpack;
filter->tcpopts.do_ack = 1;
}
// RST flag.
int tcprst;
if (config_setting_lookup_bool(filter_cfg, "tcp_rst", &tcprst) == CONFIG_TRUE)
{
filter->tcpopts.rst = tcprst;
filter->tcpopts.do_rst = 1;
}
// PSH flag.
int tcppsh;
if (config_setting_lookup_bool(filter_cfg, "tcp_psh", &tcppsh) == CONFIG_TRUE)
{
filter->tcpopts.psh = tcppsh;
filter->tcpopts.do_psh = 1;
}
// SYN flag.
int tcpsyn;
if (config_setting_lookup_bool(filter_cfg, "tcp_syn", &tcpsyn) == CONFIG_TRUE)
{
filter->tcpopts.syn = tcpsyn;
filter->tcpopts.do_syn = 1;
}
// FIN flag.
int tcpfin;
if (config_setting_lookup_bool(filter_cfg, "tcp_fin", &tcpfin) == CONFIG_TRUE)
{
filter->tcpopts.fin = tcpfin;
filter->tcpopts.do_fin = 1;
}
// ECE flag.
int tcpece;
if (config_setting_lookup_bool(filter_cfg, "tcp_ece", &tcpece) == CONFIG_TRUE)
{
filter->tcpopts.ece = tcpece;
filter->tcpopts.do_ece = 1;
}
// CWR flag.
int tcpcwr;
if (config_setting_lookup_bool(filter_cfg, "tcp_cwr", &tcpcwr) == CONFIG_TRUE)
{
filter->tcpopts.cwr = tcpcwr;
filter->tcpopts.do_cwr = 1;
}
/* UDP options */
// Enabled.
int udpenabled;
if (config_setting_lookup_bool(filter_cfg, "udp_enabled", &udpenabled) == CONFIG_TRUE)
{
filter->udpopts.enabled = udpenabled;
}
// Source port.
int udpsport;
if (config_setting_lookup_int(filter_cfg, "udp_sport", &udpsport) == CONFIG_TRUE)
{
filter->udpopts.sport = (u16)udpsport;
filter->udpopts.do_sport = 1;
}
// Destination port.
int udpdport;
if (config_setting_lookup_int(filter_cfg, "udp_dport", &udpdport) == CONFIG_TRUE)
{
filter->udpopts.dport = (u16)udpdport;
filter->udpopts.do_dport = 1;
}
/* ICMP options */
// Enabled.
int icmpenabled;
if (config_setting_lookup_bool(filter_cfg, "icmp_enabled", &icmpenabled) == CONFIG_TRUE)
{
filter->icmpopts.enabled = icmpenabled;
}
// ICMP code.
int icmpcode;
if (config_setting_lookup_int(filter_cfg, "icmp_code", &icmpcode) == CONFIG_TRUE)
{
filter->icmpopts.code = (u8)icmpcode;
filter->icmpopts.do_code = 1;
}
// ICMP type.
int icmptype;
if (config_setting_lookup_int(filter_cfg, "icmp_type", &icmptype) == CONFIG_TRUE)
{
filter->icmpopts.type = (u8)icmptype;
filter->icmpopts.do_type = 1;
}
// Make sure filter is set.
filter->set = 1;
} }
config_destroy(&conf); config_destroy(&conf);
@@ -882,6 +899,27 @@ int SaveCfg(config__t* cfg, const char* file_path)
} }
} }
// Add IP ranges.
config_setting_t* ip_drop_ranges = config_setting_add(root, "ip_drop_ranges", CONFIG_TYPE_LIST);
if (ip_drop_ranges)
{
for (int i = 0; i < MAX_IP_RANGES; i++)
{
const char* range = cfg->drop_ranges[i];
if (range)
{
config_setting_t* elem = config_setting_add(ip_drop_ranges, NULL, CONFIG_TYPE_STRING);
if (elem)
{
config_setting_set_string(elem, range);
}
}
}
}
// Write config to file. // Write config to file.
file = fopen(file_path, "w"); file = fopen(file_path, "w");
@@ -900,14 +938,79 @@ int SaveCfg(config__t* cfg, const char* file_path)
return 0; return 0;
} }
/**
* Sets the default values for a filter.
*
* @param filter A pointer to the filter.
*
* @return void
*/
void SetFilterDefaults(filter_t* filter)
{
filter->set = 0;
filter->enabled = 1;
filter->log = 0;
filter->action = 1;
filter->src_ip = 0;
filter->dst_ip = 0;
memset(filter->src_ip6, 0, 4);
memset(filter->dst_ip6, 0, 4);
filter->do_min_len = 0;
filter->min_len = 0;
filter->do_max_len = 0;
filter->max_len = 65535;
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;
filter->do_bps = 0;
filter->bps = 0;
filter->block_time = 1;
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;
filter->udpopts.enabled = 0;
filter->udpopts.do_sport = 0;
filter->udpopts.do_dport = 0;
filter->icmpopts.enabled = 0;
filter->icmpopts.do_code = 0;
filter->icmpopts.do_type = 0;
}
/** /**
* Sets the config structure's default values. * Sets the config structure's default values.
* *
* @param cfg A pointer to the config structure. * @param cfg A pointer to the config structure.
* *
* @return Void * @return void
*/ */
void SetCfgDefaults(config__t *cfg) void SetCfgDefaults(config__t* cfg)
{ {
cfg->verbose = 2; cfg->verbose = 2;
cfg->log_file = strdup("/var/log/xdpfw.log"); cfg->log_file = strdup("/var/log/xdpfw.log");
@@ -922,61 +1025,10 @@ void SetCfgDefaults(config__t *cfg)
{ {
filter_t* filter = &cfg->filters[i]; filter_t* filter = &cfg->filters[i];
filter->set = 0; SetFilterDefaults(filter);
filter->enabled = 1;
filter->log = 0;
filter->action = 1;
filter->src_ip = 0;
filter->dst_ip = 0;
memset(filter->src_ip6, 0, 4);
memset(filter->dst_ip6, 0, 4);
filter->do_min_len = 0;
filter->min_len = 0;
filter->do_max_len = 0;
filter->max_len = 65535;
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;
filter->do_bps = 0;
filter->bps = 0;
filter->block_time = 1;
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;
filter->udpopts.enabled = 0;
filter->udpopts.do_sport = 0;
filter->udpopts.do_dport = 0;
filter->icmpopts.enabled = 0;
filter->icmpopts.do_code = 0;
filter->icmpopts.do_type = 0;
} }
memset(cfg->drop_ranges, 0, sizeof(cfg->drop_ranges));
} }
/** /**
@@ -1111,6 +1163,20 @@ void PrintConfig(config__t* cfg)
printf("\n\n"); printf("\n\n");
} }
printf("\n");
printf("IP Drop Ranges\n");
for (int i = 0; i < MAX_IP_RANGES; i++)
{
const char* range = cfg->drop_ranges[i];
if (range)
{
printf("\t- %s\n", range);
}
}
} }
/** /**
@@ -1134,5 +1200,29 @@ int GetNextAvailableFilterIndex(config__t* cfg)
return i; return i;
} }
return -1;
}
/**
* Retrieves the next available IP drop range index.
*
* @param cfg A pointer to the config structure.
*
* @return The next available index or -1 if there are no available indexes.
*/
int GetNextAvailableIpDropRangeIndex(config__t* cfg)
{
for (int i = 0; i < MAX_IP_RANGES; i++)
{
const char* range = cfg->drop_ranges[i];
if (range)
{
continue;
}
return i;
}
return -1; return -1;
} }

View File

@@ -23,7 +23,9 @@ struct config
unsigned int no_stats : 1; unsigned int no_stats : 1;
unsigned int stats_per_second : 1; unsigned int stats_per_second : 1;
int stdout_update_time; int stdout_update_time;
filter_t filters[MAX_FILTERS]; filter_t filters[MAX_FILTERS];
const char* drop_ranges[MAX_IP_RANGES];
} typedef config__t; // config_t is taken by libconfig -.- } typedef config__t; // config_t is taken by libconfig -.-
struct config_overrides struct config_overrides
@@ -36,15 +38,15 @@ struct config_overrides
int no_stats; int no_stats;
int stats_per_second; int stats_per_second;
int stdout_update_time; int stdout_update_time;
} typedef config_overrides_t; } typedef config_overrides_t;
void SetCfgDefaults(config__t *cfg); void SetCfgDefaults(config__t *cfg);
void SetFilterDefaults(filter_t* filter);
void PrintFilter(filter_t* filter, int idx);
void PrintConfig(config__t* cfg); void PrintConfig(config__t* cfg);
void PrintFilter(filter_t* filter, int idx);
int LoadConfig(config__t *cfg, char *cfg_file, config_overrides_t* overrides); int LoadConfig(config__t *cfg, const char* cfg_file, config_overrides_t* overrides);
int SaveCfg(config__t* cfg, const char* file_path); int SaveCfg(config__t* cfg, const char* file_path);
int OpenCfg(FILE** file, const char *file_name); int OpenCfg(FILE** file, const char *file_name);
@@ -53,5 +55,6 @@ int ReadCfg(FILE* file, char** buffer);
int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides); int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides);
int GetNextAvailableFilterIndex(config__t* cfg); int GetNextAvailableFilterIndex(config__t* cfg);
int GetNextAvailableIpDropRangeIndex(config__t* cfg);
#include <loader/utils/logging.h> #include <loader/utils/logging.h>

View File

@@ -343,4 +343,128 @@ int GetMapPinFd(const char* pin_dir, const char* map_name)
snprintf(full_path, sizeof(full_path), "%s/%s", pin_dir, map_name); snprintf(full_path, sizeof(full_path), "%s/%s", pin_dir, map_name);
return bpf_obj_get(full_path); return bpf_obj_get(full_path);
}
/**
* Deletes IPv4 address from block map.
*
* @param map_block The block map's FD.
* @param ip The IP address to remove.
*
* @return 0 on success or error value of bpf_map_delete_elem().
*/
int DeleteBlock(int map_block, u32 ip)
{
return bpf_map_delete_elem(map_block, &ip);
}
/**
* Adds an IPv4 address to the block map.
*
* @param map_block The block map's FD.
* @param ip The IP address to add.
* @param expires When the block expires (nanoseconds since system boot).
*
* @return 0 on success or error value of bpf_map_update_elem().
*/
int AddBlock(int map_block, u32 ip, u64 expires)
{
return bpf_map_update_elem(map_block, &ip, &expires, BPF_ANY);
}
/**
* Deletes IPv6 address from block map.
*
* @param map_block6 The block map's FD.
* @param ip The IP address to remove.
*
* @return 0 on success or error value of bpf_map_delete_elem().
*/
int DeleteBlock6(int map_block6, u128 ip)
{
return bpf_map_delete_elem(map_block6, &ip);
}
/**
* Adds an IPv6 address to the block map.
*
* @param map_block6 The block map's FD.
* @param ip The IP address to add.
* @param expires When the block expires (nanoseconds since system boot).
*
* @return 0 on success or error value of bpf_map_update_elem().
*/
int AddBlock6(int map_block6, u128 ip, u64 expires)
{
return bpf_map_update_elem(map_block6, &ip, &expires, BPF_ANY);
}
/**
* Deletes an IPv4 range from the drop map.
*
* @param map_range_drop The IPv4 range drop map's FD.
* @param net The network IP.
* @param cidr The network's CIDR.
*
* @return 0 on success or error value of bpf_map_delete_elem().
*/
int DeleteRangeDrop(int map_range_drop, u32 net, u8 cidr)
{
u32 bit_mask = ( ~( (1 << (32 - cidr) ) - 1) );
u32 start = net & bit_mask;
LpmTrieKey key = {0};
key.prefix_len = cidr;
key.data = start;
return bpf_map_delete_elem(map_range_drop, &key);
}
/**
* Adds an IPv4 range to the drop map.
*
* @param map_range_drop The IPv4 range drop map's FD.
* @param net The network IP.
* @param cidr The network's CIDR.
*
* @return 0 on success or error value of bpf_map_update_elem().
*/
int AddRangeDrop(int map_range_drop, u32 net, u8 cidr)
{
u32 bit_mask = ( ~( (1 << (32 - cidr) ) - 1) );
u32 start = net & bit_mask;
LpmTrieKey key = {0};
key.prefix_len = cidr;
key.data = start;
u64 val = ( (u64)bit_mask << 32 ) | start;
return bpf_map_update_elem(map_range_drop, &key, &val, BPF_ANY);
}
/**
* Updates IP ranges from config file.
*
* @param map_range_drop The IPv4 range drop map's FD.
* @param cfg A pointer to the config file
*
* @return void
*/
void UpdateRangeDrops(int map_range_drop, config__t* cfg)
{
for (int i = 0; i < MAX_IP_RANGES; i++)
{
const char* range = cfg->drop_ranges[i];
if (!range)
{
continue;
}
// Parse IP range string and return network IP and CIDR.
ip_range_t t = ParseIpCidr(range);
AddRangeDrop(map_range_drop, t.ip, t.cidr);
}
} }

View File

@@ -26,4 +26,14 @@ void UpdateFilters(int map_filters, config__t *cfg);
int PinBpfMap(struct bpf_object* obj, const char* pin_dir, const char* map_name); int PinBpfMap(struct bpf_object* obj, const char* pin_dir, const char* map_name);
int UnpinBpfMap(struct bpf_object* obj, const char* pin_dir, const char* map_name); int UnpinBpfMap(struct bpf_object* obj, const char* pin_dir, const char* map_name);
int GetMapPinFd(const char* pin_dir, const char* map_name); int GetMapPinFd(const char* pin_dir, const char* map_name);
int DeleteBlock(int map_block, u32 ip);
int AddBlock(int map_block, u32 ip, u64 expires);
int DeleteBlock6(int map_block6, u128 ip);
int AddBlock6(int map_block6, u128 ip, u64 expires);
int DeleteRangeDrop(int map_range_drop, u32 net, u8 cidr);
int AddRangeDrop(int map_range_drop, u32 net, u8 cidr);
void UpdateRangeDrops(int map_range_drop, config__t* cfg);