diff --git a/src/loader/prog.c b/src/loader/prog.c index 4d86c06..f35b598 100644 --- a/src/loader/prog.c +++ b/src/loader/prog.c @@ -22,16 +22,47 @@ int cont = 1; 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 obj A pointer to the BPF object. * @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; + // 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 (!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 (!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); } } +#endif +#endif } int main(int argc, char *argv[]) @@ -55,7 +90,7 @@ int main(int argc, char *argv[]) // Parse the command line. cmdline_t cmd = {0}; - cmd.cfgfile = CONFIG_DEFAULT_PATH; + cmd.cfg_file = CONFIG_DEFAULT_PATH; cmd.verbose = -1; cmd.pin_maps = -1; cmd.update_time = -1; @@ -90,9 +125,9 @@ int main(int argc, char *argv[]) cfg_overrides.stdout_update_time = cmd.stdout_update_time; // 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; } @@ -185,6 +220,16 @@ int main(int argc, char *argv[]) LogMsg(&cfg, 2, 0, "Retrieving BPF map FDs..."); // 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"); // Check for valid maps. @@ -197,17 +242,9 @@ int main(int argc, char *argv[]) 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 int map_filter_log = FindMapFd(prog, "map_filter_log"); + struct ring_buffer* rb = NULL; 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); } #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); @@ -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. // 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) { 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); } +#ifdef ENABLE_FILTER_LOGGING + // Pin the filters log map. 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); @@ -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); } +#endif +#endif } +#ifdef ENABLE_FILTERS LogMsg(&cfg, 2, 0, "Updating filters..."); - // Update BPF maps. + // Update filters. 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(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) { // Check if config file have been modified - if (stat(cmd.cfgfile, &conf_stat) == 0 && conf_stat.st_mtime > last_config_check) { - // Update config. - if ((ret = LoadConfig(&cfg, cmd.cfgfile, &cfg_overrides)) != 0) + if (stat(cmd.cfg_file, &conf_stat) == 0 && conf_stat.st_mtime > last_config_check) { + // Reload config. + 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); } - // Update BPF maps. +#ifdef ENABLE_FILTERS + // Update filters. UpdateFilters(map_filters, &cfg); +#endif - // Update timer + // Update last check timer last_config_check = time(NULL); // 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); #endif @@ -343,7 +445,7 @@ int main(int argc, char *argv[]) LogMsg(&cfg, 2, 0, "Cleaning up..."); -#ifdef ENABLE_FILTER_LOGGING +#if defined(ENABLE_FILTERS) && defined(ENABLE_FILTER_LOGGING) if (rb) { ring_buffer__free(rb); @@ -365,7 +467,7 @@ int main(int argc, char *argv[]) struct bpf_object* obj = GetBpfObj(prog); - UnpinFilterMaps(&cfg, obj, 0); + UnpinNeededMaps(&cfg, obj, 0); } // Lastly, close the XDP program. diff --git a/src/loader/utils/config.c b/src/loader/utils/config.c index 8cabc11..2c2cc03 100644 --- a/src/loader/utils/config.c +++ b/src/loader/utils/config.c @@ -9,7 +9,7 @@ * * @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; @@ -159,9 +159,9 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides) 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; } @@ -182,7 +182,7 @@ int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides) cfg->log_file = NULL; } - if (overrides->log_file != NULL) + if (overrides && overrides->log_file != NULL) { 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; } - if (overrides->interface != NULL) + if (overrides && overrides->interface != NULL) { 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 (overrides->pin_maps > -1) + if (overrides && overrides->pin_maps > -1) { 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 (overrides->update_time > -1) + if (overrides && overrides->update_time > -1) { 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 (overrides->no_stats > -1) + if (overrides && overrides->no_stats > -1) { 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 (overrides->stats_per_second > -1) + if (overrides && overrides->stats_per_second > -1) { 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 (overrides->stdout_update_time > -1) + if (overrides && overrides->stdout_update_time > -1) { 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"); - // Check if filters map is valid. If not, not a biggie since they aren't required. - if (setting == NULL) + if (setting && config_setting_is_list(setting)) { - LogMsg(cfg, 0, 1, "Error from LibConfig when reading 'filters' array - %s.", config_error_text(&conf)); - - config_destroy(&conf); + for (int i = 0; i < config_setting_length(setting); i++) + { + 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]; - - config_setting_t* filter_cfg = config_setting_get_elem(setting, i); - - if (filter == NULL || filter_cfg == NULL) + for (int i = 0; i < config_setting_length(setting) && i < MAX_IP_RANGES; i++) { - 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); @@ -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. file = fopen(file_path, "w"); @@ -900,14 +938,79 @@ int SaveCfg(config__t* cfg, const char* file_path) 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. * * @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->log_file = strdup("/var/log/xdpfw.log"); @@ -922,61 +1025,10 @@ void SetCfgDefaults(config__t *cfg) { filter_t* filter = &cfg->filters[i]; - 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; + SetFilterDefaults(filter); } + + memset(cfg->drop_ranges, 0, sizeof(cfg->drop_ranges)); } /** @@ -1111,6 +1163,20 @@ void PrintConfig(config__t* cfg) 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 -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; } \ No newline at end of file diff --git a/src/loader/utils/config.h b/src/loader/utils/config.h index c2ad130..4cc57c9 100644 --- a/src/loader/utils/config.h +++ b/src/loader/utils/config.h @@ -23,7 +23,9 @@ struct config unsigned int no_stats : 1; unsigned int stats_per_second : 1; int stdout_update_time; + filter_t filters[MAX_FILTERS]; + const char* drop_ranges[MAX_IP_RANGES]; } typedef config__t; // config_t is taken by libconfig -.- struct config_overrides @@ -36,15 +38,15 @@ struct config_overrides int no_stats; int stats_per_second; int stdout_update_time; - } typedef config_overrides_t; void SetCfgDefaults(config__t *cfg); +void SetFilterDefaults(filter_t* filter); -void PrintFilter(filter_t* filter, int idx); 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 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 GetNextAvailableFilterIndex(config__t* cfg); +int GetNextAvailableIpDropRangeIndex(config__t* cfg); #include \ No newline at end of file diff --git a/src/loader/utils/xdp.c b/src/loader/utils/xdp.c index 96da61b..425971f 100644 --- a/src/loader/utils/xdp.c +++ b/src/loader/utils/xdp.c @@ -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); 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); + } } \ No newline at end of file diff --git a/src/loader/utils/xdp.h b/src/loader/utils/xdp.h index 6561da3..08d1c49 100644 --- a/src/loader/utils/xdp.h +++ b/src/loader/utils/xdp.h @@ -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 UnpinBpfMap(struct bpf_object* obj, const char* pin_dir, const char* map_name); -int GetMapPinFd(const char* pin_dir, const char* map_name); \ No newline at end of file +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); \ No newline at end of file