Files
XDP-Firewall/src/loader/utils/config.c
2025-03-06 15:49:14 -05:00

1275 lines
34 KiB
C

#include <loader/utils/config.h>
/**
* Loads the config from the file system.
*
* @param cfg A pointer to the config structure.
* @param cfg_file The path to the config file.
* @param overrides Overrides to use instead of config values.
*
* @return 0 on success or 1 on error.
*/
int load_cfg(config__t *cfg, const char* cfg_file, config_overrides_t* overrides)
{
int ret;
FILE *file = NULL;
// Open config file.
if ((ret = open_cfg(&file, cfg_file)) != 0 || file == NULL)
{
fprintf(stderr, "Error opening config file.\n");
return ret;
}
set_cfg_defaults(cfg);
char* buffer = NULL;
// Read config.
if ((ret = read_cfg(file, &buffer)) != 0)
{
fprintf(stderr, "Error reading config file.\n");
close_cfg(file);
return ret;
}
// Parse config.
if ((ret = parse_cfg(cfg, buffer, overrides)) != 0)
{
fprintf(stderr, "Error parsing config file.\n");
close_cfg(file);
return ret;
}
free(buffer);
if ((ret = close_cfg(file)) != 0)
{
fprintf(stderr, "Error closing config file.\n");
return ret;
}
return EXIT_SUCCESS;
}
/**
* Opens the config file.
*
* @param file_name Path to config file.
*
* @return 0 on success or 1 on error.
*/
int open_cfg(FILE** file, const char *file_name)
{
// Close any existing files.
if (*file != NULL)
{
fclose(*file);
*file = NULL;
}
*file = fopen(file_name, "r");
if (*file == NULL)
{
return 1;
}
return 0;
}
/**
* Close config file.
*
* @param file A pointer to the file to close.
*
* @param return 0 on success or error value of fclose().
*/
int close_cfg(FILE* file)
{
return fclose(file);
}
/**
* Reads contents from the config file.
*
* @param file The file pointer.
* @param buffer The buffer to store the data in (manually allocated).
*/
int read_cfg(FILE* file, char** buffer)
{
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
rewind(file);
if (file_size <= 0)
{
return 1;
}
*buffer = malloc(file_size + 1);
if (*buffer == NULL)
{
return 1;
}
size_t read = fread(*buffer, 1, file_size, file);
(*buffer)[read] = '\0';
return 0;
}
/**
* Read the config file and stores values in config structure.
*
* @param cfg A pointer to the config structure.
* @param data The config data.
* @param overrides Overrides to use instead of config values.
*
* @return 0 on success or 1/-1 on error.
*/
int parse_cfg(config__t *cfg, const char* data, config_overrides_t* overrides)
{
// Initialize config.
config_t conf;
config_setting_t *setting;
config_init(&conf);
// Attempt to read the config.
if (config_read_string(&conf, data) == CONFIG_FALSE)
{
log_msg(cfg, 0, 1, "Error from LibConfig when reading file - %s (Line %d)", config_error_text(&conf), config_error_line(&conf));
config_destroy(&conf);
return EXIT_FAILURE;
}
int verbose;
if (config_lookup_int(&conf, "verbose", &verbose) == CONFIG_TRUE || (overrides && overrides->verbose > -1))
{
if (overrides && overrides->verbose > -1)
{
cfg->verbose = overrides->verbose;
}
else
{
cfg->verbose = verbose;
}
}
const char* log_file;
if (config_lookup_string(&conf, "log_file", &log_file) == CONFIG_TRUE || (overrides && overrides->log_file != NULL))
{
// We must free previous value to prevent memory leak.
if (cfg->log_file != NULL)
{
free(cfg->log_file);
cfg->log_file = NULL;
}
if (overrides && overrides->log_file != NULL)
{
if (strlen(overrides->log_file) > 0)
{
cfg->log_file = strdup(overrides->log_file);
}
else
{
cfg->log_file = NULL;
}
}
else
{
if (strlen(log_file) > 0)
{
cfg->log_file = strdup(log_file);
}
else
{
cfg->log_file = NULL;
}
}
}
// Get interface.
const char *interface;
if (config_lookup_string(&conf, "interface", &interface) == CONFIG_TRUE || (overrides && overrides->interface != NULL))
{
// We must free previous value to prevent memory leak.
if (cfg->interface != NULL)
{
free(cfg->interface);
cfg->interface = NULL;
}
if (overrides && overrides->interface != NULL)
{
cfg->interface = strdup(overrides->interface);
}
else
{
cfg->interface = strdup(interface);
}
}
// Pin BPF maps.
int pin_maps;
if (config_lookup_bool(&conf, "pin_maps", &pin_maps) == CONFIG_TRUE || (overrides && overrides->pin_maps > -1))
{
if (overrides && overrides->pin_maps > -1)
{
cfg->pin_maps = overrides->pin_maps;
}
else
{
cfg->pin_maps = pin_maps;
}
}
// Get auto update time.
int update_time;
if (config_lookup_int(&conf, "update_time", &update_time) == CONFIG_TRUE || (overrides && overrides->update_time > -1))
{
if (overrides && overrides->update_time > -1)
{
cfg->update_time = overrides->update_time;
}
else
{
cfg->update_time = update_time;
}
}
// Get no stats.
int no_stats;
if (config_lookup_bool(&conf, "no_stats", &no_stats) == CONFIG_TRUE || (overrides && overrides->no_stats > -1))
{
if (overrides && overrides->no_stats > -1)
{
cfg->no_stats = overrides->no_stats;
}
else
{
cfg->no_stats = no_stats;
}
}
// Stats per second.
int stats_per_second;
if (config_lookup_bool(&conf, "stats_per_second", &stats_per_second) == CONFIG_TRUE || (overrides && overrides->stats_per_second > -1))
{
if (overrides && overrides->stats_per_second > -1)
{
cfg->stats_per_second = overrides->stats_per_second;
}
else
{
cfg->stats_per_second = stats_per_second;
}
}
// Get stdout update time.
int stdout_update_time;
if (config_lookup_int(&conf, "stdout_update_time", &stdout_update_time) == CONFIG_TRUE || (overrides && overrides->stdout_update_time > -1))
{
if (overrides && overrides->stdout_update_time > -1)
{
cfg->stdout_update_time = overrides->stdout_update_time;
}
else
{
cfg->stdout_update_time = stdout_update_time;
}
}
// Read filters.
setting = config_lookup(&conf, "filters");
if (setting && config_setting_is_list(setting))
{
for (int i = 0; i < config_setting_length(setting); i++)
{
filter_rule_cfg_t* filter = &cfg->filters[i];
config_setting_t* filter_cfg = config_setting_get_elem(setting, i);
if (filter == NULL || filter_cfg == NULL)
{
log_msg(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;
}
// Make sure filter is set.
filter->set = 1;
// 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;
}
// Block time (default 1).
int block_time;
if (config_setting_lookup_int(filter_cfg, "block_time", &block_time) == CONFIG_TRUE)
{
filter->block_time = block_time;
}
// PPS (not required).
s64 pps;
if (config_setting_lookup_int64(filter_cfg, "pps", &pps) == CONFIG_TRUE)
{
filter->pps = pps;
}
// BPS (not required).
s64 bps;
if (config_setting_lookup_int64(filter_cfg, "bps", &bps) == CONFIG_TRUE)
{
filter->bps = bps;
}
/* IP Options */
// Source IP (not required).
const char *sip;
if (config_setting_lookup_string(filter_cfg, "src_ip", &sip) == CONFIG_TRUE)
{
filter->ip.src_ip = strdup(sip);
}
// Destination IP (not required).
const char *dip;
if (config_setting_lookup_string(filter_cfg, "dst_ip", &dip) == CONFIG_TRUE)
{
filter->ip.dst_ip = strdup(dip);
}
// Source IP (IPv6) (not required).
const char *sip6;
if (config_setting_lookup_string(filter_cfg, "src_ip6", &sip6) == CONFIG_TRUE)
{
filter->ip.src_ip6 = strdup(sip6);
}
// Destination IP (IPv6) (not required).
const char *dip6;
if (config_setting_lookup_string(filter_cfg, "dst_ip6", &dip6) == CONFIG_TRUE)
{
filter->ip.dst_ip6 = strdup(dip6);
}
// Minimum TTL (not required).
int min_ttl;
if (config_setting_lookup_int(filter_cfg, "min_ttl", &min_ttl) == CONFIG_TRUE)
{
filter->ip.min_ttl = min_ttl;
}
// Maximum TTL (not required).
int max_ttl;
if (config_setting_lookup_int(filter_cfg, "max_ttl", &max_ttl) == CONFIG_TRUE)
{
filter->ip.max_ttl = max_ttl;
}
// Minimum length (not required).
int min_len;
if (config_setting_lookup_int(filter_cfg, "min_len", &min_len) == CONFIG_TRUE)
{
filter->ip.min_len = min_len;
}
// Maximum length (not required).
int max_len;
if (config_setting_lookup_int(filter_cfg, "max_len", &max_len) == CONFIG_TRUE)
{
filter->ip.max_len = max_len;
}
// TOS (not required).
int tos;
if (config_setting_lookup_int(filter_cfg, "tos", &tos) == CONFIG_TRUE)
{
filter->ip.tos = tos;
}
/* TCP options */
// Enabled.
int tcp_enabled;
if (config_setting_lookup_bool(filter_cfg, "tcp_enabled", &tcp_enabled) == CONFIG_TRUE)
{
filter->tcp.enabled = tcp_enabled;
}
// Source port.
int tcp_sport;
if (config_setting_lookup_int(filter_cfg, "tcp_sport", &tcp_sport) == CONFIG_TRUE)
{
filter->tcp.sport = tcp_sport;
}
// Destination port.
int tcp_dport;
if (config_setting_lookup_int(filter_cfg, "tcp_dport", &tcp_dport) == CONFIG_TRUE)
{
filter->tcp.dport = tcp_dport;
}
// URG flag.
int tcp_urg;
if (config_setting_lookup_bool(filter_cfg, "tcp_urg", &tcp_urg) == CONFIG_TRUE)
{
filter->tcp.urg = tcp_urg;
}
// ACK flag.
int tcp_ack;
if (config_setting_lookup_bool(filter_cfg, "tcp_ack", &tcp_ack) == CONFIG_TRUE)
{
filter->tcp.ack = tcp_ack;
}
// RST flag.
int tcp_rst;
if (config_setting_lookup_bool(filter_cfg, "tcp_rst", &tcp_rst) == CONFIG_TRUE)
{
filter->tcp.rst = tcp_rst;
}
// PSH flag.
int tcp_psh;
if (config_setting_lookup_bool(filter_cfg, "tcp_psh", &tcp_psh) == CONFIG_TRUE)
{
filter->tcp.psh = tcp_psh;
}
// SYN flag.
int tcp_syn;
if (config_setting_lookup_bool(filter_cfg, "tcp_syn", &tcp_syn) == CONFIG_TRUE)
{
filter->tcp.syn = tcp_syn;
}
// FIN flag.
int tcp_fin;
if (config_setting_lookup_bool(filter_cfg, "tcp_fin", &tcp_fin) == CONFIG_TRUE)
{
filter->tcp.fin = tcp_fin;
}
// ECE flag.
int tcp_ece;
if (config_setting_lookup_bool(filter_cfg, "tcp_ece", &tcp_ece) == CONFIG_TRUE)
{
filter->tcp.ece = tcp_ece;
}
// CWR flag.
int tcp_cwr;
if (config_setting_lookup_bool(filter_cfg, "tcp_cwr", &tcp_cwr) == CONFIG_TRUE)
{
filter->tcp.cwr = tcp_cwr;
}
/* UDP options */
// Enabled.
int udp_enabled;
if (config_setting_lookup_bool(filter_cfg, "udp_enabled", &udp_enabled) == CONFIG_TRUE)
{
filter->udp.enabled = udp_enabled;
}
// Source port.
int udp_sport;
if (config_setting_lookup_int(filter_cfg, "udp_sport", &udp_sport) == CONFIG_TRUE)
{
filter->udp.sport = udp_sport;
}
// Destination port.
int udp_dport;
if (config_setting_lookup_int(filter_cfg, "udp_dport", &udp_dport) == CONFIG_TRUE)
{
filter->udp.dport = udp_dport;
}
/* ICMP options */
// Enabled.
int icmp_enabled;
if (config_setting_lookup_bool(filter_cfg, "icmp_enabled", &icmp_enabled) == CONFIG_TRUE)
{
filter->icmp.enabled = icmp_enabled;
}
// ICMP code.
int icmp_code;
if (config_setting_lookup_int(filter_cfg, "icmp_code", &icmp_code) == CONFIG_TRUE)
{
filter->icmp.code = icmp_code;
}
// ICMP type.
int icmp_type;
if (config_setting_lookup_int(filter_cfg, "icmp_type", &icmp_type) == CONFIG_TRUE)
{
filter->icmp.type = icmp_type;
}
}
}
// Read IP range drops.
setting = config_lookup(&conf, "ip_drop_ranges");
if (setting && config_setting_is_list(setting))
{
for (int i = 0; i < config_setting_length(setting) && i < MAX_IP_RANGES; i++)
{
const char* range = cfg->drop_ranges[i];
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);
}
}
}
config_destroy(&conf);
return EXIT_SUCCESS;
}
/**
* Saves config to file system.
*
* @param cfg A pointer to the config.
* @param file_path The file path to store the config into.
*
* @param return 0 on success or 1 on failure.
*/
int save_cfg(config__t* cfg, const char* file_path)
{
config_t conf;
config_setting_t *root, *setting;
FILE* file;
config_init(&conf);
root = config_root_setting(&conf);
// Add verbose.
setting = config_setting_add(root, "verbose", CONFIG_TYPE_INT);
config_setting_set_int(setting, cfg->verbose);
// Add log file.
if (cfg->log_file)
{
setting = config_setting_add(root, "log_file", CONFIG_TYPE_STRING);
config_setting_set_string(setting, cfg->log_file);
}
// Add interface.
if (cfg->interface)
{
setting = config_setting_add(root, "interface", CONFIG_TYPE_STRING);
config_setting_set_string(setting, cfg->interface);
}
// Add pin maps.
setting = config_setting_add(root, "pin_maps", CONFIG_TYPE_BOOL);
config_setting_set_bool(setting, cfg->pin_maps);
// Add update time.
setting = config_setting_add(root, "update_time", CONFIG_TYPE_INT);
config_setting_set_int(setting, cfg->update_time);
// Add no stats.
setting = config_setting_add(root, "no_stats", CONFIG_TYPE_BOOL);
config_setting_set_bool(setting, cfg->no_stats);
// Add stats per second.
setting = config_setting_add(root, "stats_per_second", CONFIG_TYPE_BOOL);
config_setting_set_bool(setting, cfg->stats_per_second);
// Add stdout update time.
setting = config_setting_add(root, "stdout_update_time", CONFIG_TYPE_INT);
config_setting_set_int(setting, cfg->stdout_update_time);
// Add filters.
config_setting_t* filters = config_setting_add(root, "filters", CONFIG_TYPE_LIST);
if (filters)
{
for (int i = 0; i < MAX_FILTERS; i++)
{
filter_rule_cfg_t* filter = &cfg->filters[i];
if (!filter->set)
{
continue;
}
config_setting_t* filter_cfg = config_setting_add(filters, NULL, CONFIG_TYPE_GROUP);
if (filter_cfg)
{
// Add enabled setting.
if (filter->enabled > -1)
{
config_setting_t* enabled = config_setting_add(filter_cfg, "enabled", CONFIG_TYPE_BOOL);
config_setting_set_bool(enabled, filter->enabled);
}
// Add log setting.
if (filter->log > -1)
{
config_setting_t* log = config_setting_add(filter_cfg, "log", CONFIG_TYPE_BOOL);
config_setting_set_bool(log, filter->log);
}
// Add action setting.
if (filter->action > -1)
{
config_setting_t* action = config_setting_add(filter_cfg, "action", CONFIG_TYPE_INT);
config_setting_set_int(action, filter->action);
}
// Add block time.
if (filter->block_time > -1)
{
config_setting_t* block_time = config_setting_add(filter_cfg, "block_time", CONFIG_TYPE_INT64);
config_setting_set_int64(block_time, filter->block_time);
}
// Add PPS.
if (filter->pps > -1)
{
config_setting_t* pps = config_setting_add(filter_cfg, "pps", CONFIG_TYPE_INT64);
config_setting_set_int64(pps, filter->pps);
}
// Add BPS.
if (filter->bps > -1)
{
config_setting_t* bps = config_setting_add(filter_cfg, "bps", CONFIG_TYPE_INT64);
config_setting_set_int64(bps, filter->bps);
}
// Add source IPv4.
if (filter->ip.src_ip)
{
config_setting_t* src_ip = config_setting_add(filter_cfg, "src_ip", CONFIG_TYPE_STRING);
config_setting_set_string(src_ip, filter->ip.src_ip);
}
// Add destination IPv4.
if (filter->ip.dst_ip)
{
config_setting_t* dst_ip = config_setting_add(filter_cfg, "dst_ip", CONFIG_TYPE_STRING);
config_setting_set_string(dst_ip, filter->ip.dst_ip);
}
// Add source IPv6.
if (filter->ip.src_ip6)
{
config_setting_t* src_ip6 = config_setting_add(filter_cfg, "src_ip6", CONFIG_TYPE_STRING);
config_setting_set_string(src_ip6, filter->ip.src_ip6);
}
// Add source IPv6.
if (filter->ip.dst_ip6)
{
config_setting_t* dst_ip6 = config_setting_add(filter_cfg, "dst_ip6", CONFIG_TYPE_STRING);
config_setting_set_string(dst_ip6, filter->ip.dst_ip6);
}
// Add minimum TTL.
if (filter->ip.min_ttl > -1)
{
config_setting_t* min_ttl = config_setting_add(filter_cfg, "min_ttl", CONFIG_TYPE_INT);
config_setting_set_int(min_ttl, filter->ip.min_ttl);
}
// Add maximum TTL.
if (filter->ip.max_ttl > -1)
{
config_setting_t* max_ttl = config_setting_add(filter_cfg, "max_ttl", CONFIG_TYPE_INT);
config_setting_set_int(max_ttl, filter->ip.max_ttl);
}
// Add minimum length.
if (filter->ip.min_len > -1)
{
config_setting_t* min_len = config_setting_add(filter_cfg, "min_len", CONFIG_TYPE_INT);
config_setting_set_int(min_len, filter->ip.min_len);
}
// Add maximum length.
if (filter->ip.max_len > -1)
{
config_setting_t* max_len = config_setting_add(filter_cfg, "max_len", CONFIG_TYPE_INT);
config_setting_set_int(max_len, filter->ip.max_len);
}
// Add ToS.
if (filter->ip.tos > -1)
{
config_setting_t* tos = config_setting_add(filter_cfg, "tos", CONFIG_TYPE_INT);
config_setting_set_int(tos, filter->ip.tos);
}
// Add TCP enabled.
if (filter->tcp.enabled > -1)
{
config_setting_t* tcp_enabled = config_setting_add(filter_cfg, "tcp_enabled", CONFIG_TYPE_BOOL);
config_setting_set_bool(tcp_enabled, filter->tcp.enabled);
}
// Add TCP source port.
if (filter->tcp.sport > -1)
{
config_setting_t* tcp_sport = config_setting_add(filter_cfg, "tcp_sport", CONFIG_TYPE_INT);
config_setting_set_int(tcp_sport, filter->tcp.sport);
}
// Add TCP destination port.
if (filter->tcp.dport > -1)
{
config_setting_t* tcp_dport = config_setting_add(filter_cfg, "tcp_dport", CONFIG_TYPE_INT);
config_setting_set_int(tcp_dport, filter->tcp.dport);
}
// Add TCP URG flag.
if (filter->tcp.urg > -1)
{
config_setting_t* tcp_urg = config_setting_add(filter_cfg, "tcp_urg", CONFIG_TYPE_BOOL);
config_setting_set_bool(tcp_urg, filter->tcp.urg);
}
// Add TCP ACK flag.
if (filter->tcp.ack > -1)
{
config_setting_t* tcp_ack = config_setting_add(filter_cfg, "tcp_ack", CONFIG_TYPE_BOOL);
config_setting_set_bool(tcp_ack, filter->tcp.ack);
}
// Add TCP RST flag.
if (filter->tcp.rst > -1)
{
config_setting_t* tcp_rst = config_setting_add(filter_cfg, "tcp_rst", CONFIG_TYPE_BOOL);
config_setting_set_bool(tcp_rst, filter->tcp.rst);
}
// Add TCP PSH flag.
if (filter->tcp.psh > -1)
{
config_setting_t* tcp_psh = config_setting_add(filter_cfg, "tcp_psh", CONFIG_TYPE_BOOL);
config_setting_set_bool(tcp_psh, filter->tcp.psh);
}
// Add TCP SYN flag.
if (filter->tcp.syn > -1)
{
config_setting_t* tcp_syn = config_setting_add(filter_cfg, "tcp_syn", CONFIG_TYPE_BOOL);
config_setting_set_bool(tcp_syn, filter->tcp.syn);
}
// Add TCP FIN flag.
if (filter->tcp.fin > -1)
{
config_setting_t* tcp_fin = config_setting_add(filter_cfg, "tcp_fin", CONFIG_TYPE_BOOL);
config_setting_set_bool(tcp_fin, filter->tcp.fin);
}
// Add TCP ECE flag.
if (filter->tcp.ece > -1)
{
config_setting_t* tcp_ece = config_setting_add(filter_cfg, "tcp_ece", CONFIG_TYPE_BOOL);
config_setting_set_bool(tcp_ece, filter->tcp.ece);
}
// Add TCP CWR flag.
if (filter->tcp.cwr > -1)
{
config_setting_t* tcp_cwr = config_setting_add(filter_cfg, "tcp_cwr", CONFIG_TYPE_BOOL);
config_setting_set_bool(tcp_cwr, filter->tcp.cwr);
}
// Add UDP enabled.
if (filter->udp.enabled > -1)
{
config_setting_t* udp_enabled = config_setting_add(filter_cfg, "udp_enabled", CONFIG_TYPE_BOOL);
config_setting_set_bool(udp_enabled, filter->udp.enabled);
}
// Add UDP source port.
if (filter->udp.sport > -1)
{
config_setting_t* udp_sport = config_setting_add(filter_cfg, "udp_sport", CONFIG_TYPE_INT);
config_setting_set_int(udp_sport, filter->udp.sport);
}
// Add UDP destination port.
if (filter->udp.dport > -1)
{
config_setting_t* udp_dport = config_setting_add(filter_cfg, "udp_dport", CONFIG_TYPE_INT);
config_setting_set_int(udp_dport, filter->udp.dport);
}
// Add ICMP enabled.
if (filter->icmp.enabled > -1)
{
config_setting_t* icmp_enabled = config_setting_add(filter_cfg, "icmp_enabled", CONFIG_TYPE_BOOL);
config_setting_set_bool(icmp_enabled, filter->icmp.enabled);
}
// Add ICMP code.
if (filter->icmp.code > -1)
{
config_setting_t* icmp_code = config_setting_add(filter_cfg, "icmp_code", CONFIG_TYPE_INT);
config_setting_set_int(icmp_code, filter->icmp.code);
}
// Add ICMP type.
if (filter->icmp.type > -1)
{
config_setting_t* icmp_type = config_setting_add(filter_cfg, "icmp_type", CONFIG_TYPE_INT);
config_setting_set_int(icmp_type, filter->icmp.type);
}
}
}
}
// 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.
file = fopen(file_path, "w");
if (!file)
{
config_destroy(&conf);
return 1;
}
config_write(&conf, file);
fclose(file);
config_destroy(&conf);
return 0;
}
/**
* Sets the default values for a filter.
*
* @param filter A pointer to the filter.
*
* @return void
*/
void set_filter_defaults(filter_rule_cfg_t* filter)
{
filter->set = 0;
filter->enabled = 1;
filter->log = 0;
filter->action = 1;
filter->block_time = 1;
filter->pps = -1;
filter->bps = -1;
if (filter->ip.src_ip)
{
free((void*)filter->ip.src_ip);
filter->ip.src_ip = NULL;
}
if (filter->ip.dst_ip)
{
free((void*)filter->ip.dst_ip);
filter->ip.dst_ip = NULL;
}
if (filter->ip.src_ip6)
{
free((void*)filter->ip.src_ip6);
filter->ip.src_ip6 = NULL;
}
if (filter->ip.dst_ip6)
{
free((void*)filter->ip.dst_ip6);
filter->ip.dst_ip6 = NULL;
}
filter->ip.min_ttl = -1;
filter->ip.max_ttl = -1;
filter->ip.min_len = -1;
filter->ip.max_len = -1;
filter->ip.tos = -1;
filter->tcp.enabled = -1;
filter->tcp.sport = -1;
filter->tcp.dport = -1;
filter->tcp.urg = -1;
filter->tcp.ack = -1;
filter->tcp.rst = -1;
filter->tcp.psh = -1;
filter->tcp.syn = -1;
filter->tcp.fin = -1;
filter->tcp.ece = -1;
filter->tcp.cwr = -1;
filter->udp.enabled = -1;
filter->udp.sport = -1;
filter->udp.dport = -1;
filter->icmp.enabled = -1;
filter->icmp.code = -1;
filter->icmp.type = -1;
}
/**
* Sets the config structure's default values.
*
* @param cfg A pointer to the config structure.
*
* @return void
*/
void set_cfg_defaults(config__t* cfg)
{
cfg->verbose = 2;
cfg->log_file = strdup("/var/log/xdpfw.log");
cfg->update_time = 0;
cfg->interface = NULL;
cfg->pin_maps = 1;
cfg->no_stats = 0;
cfg->stats_per_second = 0;
cfg->stdout_update_time = 1000;
for (int i = 0; i < MAX_FILTERS; i++)
{
filter_rule_cfg_t* filter = &cfg->filters[i];
set_filter_defaults(filter);
}
memset(cfg->drop_ranges, 0, sizeof(cfg->drop_ranges));
}
/**
* Prints a filter rule.
*
* @param filter A pointer to the filter rule.
* @param idx The current index.
*
* @return void
*/
void print_filter(filter_rule_cfg_t* filter, int idx)
{
printf("\tFilter #%d\n", idx);
printf("\t\tEnabled => %d\n", filter->enabled);
printf("\t\tLog => %d\n\n", filter->log);
printf("\t\tAction => %d (0 = Block, 1 = Allow).\n", filter->action);
printf("\t\t\tBlock Time => %d\n\n", filter->block_time);
printf("\t\t\tPPS => %lld\n", filter->pps);
printf("\t\t\tBPS => %lld\n\n", filter->bps);
// IP Options.
printf("\t\tIP Options\n");
// IP addresses require additional code for string printing.
const char* src_ip = "N/A";
if (filter->ip.src_ip)
{
src_ip = filter->ip.src_ip;
}
printf("\t\t\tSource IPv4 => %s\n", src_ip);
const char* dst_ip = "N/A";
if (filter->ip.dst_ip)
{
dst_ip = filter->ip.dst_ip;
}
printf("\t\t\tDestination IPv4 => %s\n", dst_ip);
const char* src_ip6 = "N/A";
if (filter->ip.src_ip6)
{
src_ip6 = filter->ip.src_ip6;
}
printf("\t\t\tSource IPv6 => %s\n", src_ip6);
const char* dst_ip6 = "N/A";
if (filter->ip.dst_ip6)
{
dst_ip6 = filter->ip.dst_ip6;
}
printf("\t\t\tDestination IPv6 => %s\n", dst_ip6);
printf("\t\t\tMin TTL => %d\n", filter->ip.min_ttl);
printf("\t\t\tMax TTL => %d\n", filter->ip.max_ttl);
printf("\t\t\tMin Length => %d\n", filter->ip.min_len);
printf("\t\t\tMax Length => %d\n", filter->ip.max_len);
printf("\t\t\tTOS => %d\n\n", filter->ip.tos);
// TCP Options.
printf("\t\tTCP Options\n");
printf("\t\t\tTCP Enabled => %d\n", filter->tcp.enabled);
printf("\t\t\tTCP Source Port => %d\n", filter->tcp.sport);
printf("\t\t\tTCP Destination Port => %d\n", filter->tcp.dport);
printf("\t\t\tTCP URG Flag => %d\n", filter->tcp.urg);
printf("\t\t\tTCP ACK Flag => %d\n", filter->tcp.ack);
printf("\t\t\tTCP RST Flag => %d\n", filter->tcp.rst);
printf("\t\t\tTCP PSH Flag => %d\n", filter->tcp.psh);
printf("\t\t\tTCP SYN Flag => %d\n", filter->tcp.syn);
printf("\t\t\tTCP FIN Flag => %d\n", filter->tcp.fin);
printf("\t\t\tTCP ECE Flag => %d\n", filter->tcp.ece);
printf("\t\t\tTCP CWR Flag => %d\n\n", filter->tcp.cwr);
// UDP Options.
printf("\t\tUDP Options\n");
printf("\t\t\tUDP Enabled => %d\n", filter->udp.enabled);
printf("\t\t\tUDP Source Port => %d\n", filter->udp.sport);
printf("\t\t\tUDP Destination Port => %d\n\n", filter->udp.dport);
// ICMP Options.
printf("\t\tICMP Options\n");
printf("\t\t\tICMP Enabled => %d\n", filter->icmp.enabled);
printf("\t\t\tICMP Code => %d\n", filter->icmp.code);
printf("\t\t\tICMP Type => %d\n", filter->icmp.type);
}
/**
* Prints config settings.
*
* @param cfg A pointer to the config structure.
*
* @return void
*/
void print_cfg(config__t* cfg)
{
char* interface = "N/A";
if (cfg->interface != NULL)
{
interface = cfg->interface;
}
char* log_file = "N/A";
if (cfg->log_file != NULL)
{
log_file = cfg->log_file;
}
printf("Printing config...\n");
printf("General Settings\n");
printf("\tVerbose => %d\n", cfg->verbose);
printf("\tLog File => %s\n", log_file);
printf("\tInterface Name => %s\n", interface);
printf("\tPin BPF Maps => %d\n", cfg->pin_maps);
printf("\tUpdate Time => %d\n", cfg->update_time);
printf("\tNo Stats => %d\n", cfg->no_stats);
printf("\tStats Per Second => %d\n", cfg->stats_per_second);
printf("\tStdout Update Time => %d\n\n", cfg->stdout_update_time);
printf("Filters\n");
for (int i = 0; i < MAX_FILTERS; i++)
{
filter_rule_cfg_t *filter = &cfg->filters[i];
if (!filter->set)
{
break;
}
print_filter(filter, i + 1);
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);
}
}
}
/**
* Retrieves next available filter index.
*
* @param cfg A pointer to the config structure.
*
* @return The next available index or -1 if there are no available indexes.
*/
int get_next_filter_idx(config__t* cfg)
{
for (int i = 0; i < MAX_FILTERS; i++)
{
filter_rule_cfg_t* filter = &cfg->filters[i];
if (filter->set)
{
continue;
}
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 get_next_ip_drop_range_idx(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;
}