diff --git a/src/loader/prog.c b/src/loader/prog.c index 38e2e2e..4d86c06 100644 --- a/src/loader/prog.c +++ b/src/loader/prog.c @@ -21,6 +21,34 @@ int cont = 1; int doing_stats = 0; +/** + * Unpins filter-specific 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) +{ + int ret; + + if ((ret = UnpinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filters")) != 0) + { + if (!ignore_errors) + { + LogMsg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_filters' from file system (%d).", ret); + } + } + + if ((ret = UnpinBpfMap(obj, XDP_MAP_PIN_DIR, "map_filter_log")) != 0) + { + if (!ignore_errors) + { + LogMsg(cfg, 1, 0, "[WARNING] Failed to un-pin BPF map 'map_filter_log' from file system (%d).", ret); + } + } +} + int main(int argc, char *argv[]) { int ret; @@ -29,6 +57,7 @@ int main(int argc, char *argv[]) cmdline_t cmd = {0}; cmd.cfgfile = CONFIG_DEFAULT_PATH; cmd.verbose = -1; + cmd.pin_maps = -1; cmd.update_time = -1; cmd.no_stats = -1; cmd.stats_per_second = -1; @@ -54,6 +83,7 @@ int main(int argc, char *argv[]) cfg_overrides.verbose = cmd.verbose; cfg_overrides.log_file = cmd.log_file; cfg_overrides.interface = cmd.interface; + cfg_overrides.pin_maps = cmd.pin_maps; cfg_overrides.update_time = cmd.update_time; cfg_overrides.no_stats = cmd.no_stats; cfg_overrides.stats_per_second = cmd.stats_per_second; @@ -140,7 +170,7 @@ int main(int argc, char *argv[]) // Attach XDP program. char *mode_used = NULL; - if ((ret = AttachXdp(prog, &mode_used, ifidx, 0, &cmd)) != 0) + if ((ret = AttachXdp(prog, &mode_used, ifidx, 0, cmd.skb, cmd.offload)) != 0) { LogMsg(&cfg, 0, 1, "[ERROR] Failed to attach XDP program to interface '%s' using available modes (%d).\n", cfg.interface, ret); @@ -194,6 +224,36 @@ int main(int argc, char *argv[]) LogMsg(&cfg, 3, 0, "map_stats FD => %d.", map_stats); + // Pin BPF maps to file system if we need to. + if (cfg.pin_maps) + { + LogMsg(&cfg, 2, 0, "Pinning BPF maps..."); + + struct bpf_object* obj = GetBpfObj(prog); + + // 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); + + 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); + } + else + { + LogMsg(&cfg, 3, 0, "BPF map 'map_filters' pinned to '%s/map_filters'.", XDP_MAP_PIN_DIR); + } + + 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); + } + else + { + LogMsg(&cfg, 3, 0, "BPF map 'map_filter_log' pinned to '%s/map_filter_log'.", XDP_MAP_PIN_DIR); + } + } + LogMsg(&cfg, 2, 0, "Updating filters..."); // Update BPF maps. @@ -281,6 +341,8 @@ int main(int argc, char *argv[]) fprintf(stdout, "\n"); + LogMsg(&cfg, 2, 0, "Cleaning up..."); + #ifdef ENABLE_FILTER_LOGGING if (rb) { @@ -289,14 +351,27 @@ int main(int argc, char *argv[]) #endif // Detach XDP program. - if (AttachXdp(prog, &mode_used, ifidx, 1, &cmd)) + if (AttachXdp(prog, &mode_used, ifidx, 1, cmd.skb, cmd.offload)) { LogMsg(&cfg, 0, 1, "[ERROR] Failed to detach XDP program from interface '%s'.\n", cfg.interface); return EXIT_FAILURE; } - LogMsg(&cfg, 1, 0, "Cleaned up and exiting...\n"); + // Unpin maps from file system. + if (cfg.pin_maps) + { + LogMsg(&cfg, 2, 0, "Un-pinning BPF maps from file system..."); + + struct bpf_object* obj = GetBpfObj(prog); + + UnpinFilterMaps(&cfg, obj, 0); + } + + // Lastly, close the XDP program. + xdp_program__close(prog); + + LogMsg(&cfg, 1, 0, "Exiting.\n"); // Exit program successfully. return EXIT_SUCCESS; diff --git a/src/loader/utils/cmdline.h b/src/loader/utils/cmdline.h index 9207efc..ac1a0b9 100644 --- a/src/loader/utils/cmdline.h +++ b/src/loader/utils/cmdline.h @@ -16,6 +16,7 @@ struct cmdline int verbose; char* log_file; char* interface; + int pin_maps; int update_time; int no_stats; int stats_per_second; diff --git a/src/loader/utils/config.c b/src/loader/utils/config.c index eb0ce74..8cabc11 100644 --- a/src/loader/utils/config.c +++ b/src/loader/utils/config.c @@ -1,7 +1,5 @@ #include -static FILE *file; - /** * Loads the config from the file system. * @@ -13,107 +11,56 @@ static FILE *file; */ int LoadConfig(config__t *cfg, char *cfg_file, config_overrides_t* overrides) { + int ret; + + FILE *file = NULL; + // Open config file. - if (OpenCfg(cfg_file) != 0) + if ((ret = OpenCfg(&file, cfg_file)) != 0 || file == NULL) { fprintf(stderr, "Error opening config file.\n"); - return EXIT_FAILURE; + return ret; } SetCfgDefaults(cfg); memset(cfg->filters, 0, sizeof(cfg->filters)); - // Read config and check for errors. - if (ReadCfg(cfg, overrides) != 0) + char* buffer = NULL; + + // Read config. + if ((ret = ReadCfg(file, &buffer)) != 0) { fprintf(stderr, "Error reading config file.\n"); - return EXIT_FAILURE; + CloseCfg(file); + + return ret; + } + + // Parse config. + if ((ret = ParseCfg(cfg, buffer, overrides)) != 0) + { + fprintf(stderr, "Error parsing config file.\n"); + + CloseCfg(file); + + return ret; + } + + free(buffer); + + if ((ret = CloseCfg(file)) != 0) + { + fprintf(stderr, "Error closing config file.\n"); + + return ret; } return EXIT_SUCCESS; } -/** - * Sets the config structure's default values. - * - * @param cfg A pointer to the config structure. - * - * @return Void - */ -void SetCfgDefaults(config__t *cfg) -{ - cfg->verbose = 2; - cfg->log_file = strdup("/var/log/xdpfw.log"); - cfg->update_time = 0; - cfg->interface = NULL; - cfg->no_stats = 0; - cfg->stats_per_second = 0; - cfg->stdout_update_time = 1000; - - for (int i = 0; i < MAX_FILTERS; i++) - { - 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; - } -} - /** * Opens the config file. * @@ -121,19 +68,19 @@ void SetCfgDefaults(config__t *cfg) * * @return 0 on success or 1 on error. */ -int OpenCfg(const char *file_name) +int OpenCfg(FILE** file, const char *file_name) { // Close any existing files. - if (file != NULL) + if (*file != NULL) { - fclose(file); + fclose(*file); - file = NULL; + *file = NULL; } - file = fopen(file_name, "r"); + *file = fopen(file_name, "r"); - if (file == NULL) + if (*file == NULL) { return 1; } @@ -141,22 +88,59 @@ int OpenCfg(const char *file_name) 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 CloseCfg(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 ReadCfg(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 ReadCfg(config__t *cfg, config_overrides_t* overrides) +int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides) { - // Not sure why this would be set to NULL after checking for it in OpenConfig(), but just for safety. - if (file == NULL) - { - return -1; - } - // Initialize config. config_t conf; config_setting_t *setting; @@ -164,7 +148,7 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) config_init(&conf); // Attempt to read the config. - if (config_read(&conf, file) == CONFIG_FALSE) + if (config_read_string(&conf, data) == CONFIG_FALSE) { LogMsg(cfg, 0, 1, "Error from LibConfig when reading file - %s (Line %d)", config_error_text(&conf), config_error_line(&conf)); @@ -189,7 +173,7 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) const char* log_file; - if (config_lookup_string(&conf, "log_file", &log_file) == CONFIG_TRUE || overrides->log_file != NULL) + 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) @@ -226,7 +210,7 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) // Get interface. const char *interface; - if (config_lookup_string(&conf, "interface", &interface) == CONFIG_TRUE || overrides->interface != NULL) + 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) @@ -245,10 +229,25 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) } } + // Pin BPF maps. + int pin_maps; + + if (config_lookup_bool(&conf, "pin_maps", &pin_maps) == CONFIG_TRUE || (overrides && overrides->pin_maps > -1)) + { + if (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->update_time > -1) + if (config_lookup_int(&conf, "update_time", &update_time) == CONFIG_TRUE || (overrides && overrides->update_time > -1)) { if (overrides->update_time > -1) { @@ -263,7 +262,7 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) // Get no stats. int no_stats; - if (config_lookup_bool(&conf, "no_stats", &no_stats) == CONFIG_TRUE || 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) { @@ -278,7 +277,7 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) // Stats per second. int stats_per_second; - if (config_lookup_bool(&conf, "stats_per_second", &stats_per_second) == CONFIG_TRUE || 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) { @@ -293,7 +292,7 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) // Get stdout update time. int stdout_update_time; - if (config_lookup_int(&conf, "stdout_update_time", &stdout_update_time) == CONFIG_TRUE || 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) { @@ -486,18 +485,18 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) } // Source port. - long long tcpsport; + int tcpsport; - if (config_setting_lookup_int64(filter_cfg, "tcp_sport", &tcpsport) == CONFIG_TRUE) + if (config_setting_lookup_int(filter_cfg, "tcp_sport", &tcpsport) == CONFIG_TRUE) { filter->tcpopts.sport = (u16)tcpsport; filter->tcpopts.do_sport = 1; } // Destination port. - long long tcpdport; + int tcpdport; - if (config_setting_lookup_int64(filter_cfg, "tcp_dport", &tcpdport) == CONFIG_TRUE) + if (config_setting_lookup_int(filter_cfg, "tcp_dport", &tcpdport) == CONFIG_TRUE) { filter->tcpopts.dport = (u16)tcpdport; filter->tcpopts.do_dport = 1; @@ -521,7 +520,6 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) filter->tcpopts.do_ack = 1; } - // RST flag. int tcprst; @@ -586,18 +584,18 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) } // Source port. - long long udpsport; + int udpsport; - if (config_setting_lookup_int64(filter_cfg, "udp_sport", &udpsport) == CONFIG_TRUE) + if (config_setting_lookup_int(filter_cfg, "udp_sport", &udpsport) == CONFIG_TRUE) { filter->udpopts.sport = (u16)udpsport; filter->udpopts.do_sport = 1; } // Destination port. - long long udpdport; + int udpdport; - if (config_setting_lookup_int64(filter_cfg, "udp_dport", &udpdport) == CONFIG_TRUE) + if (config_setting_lookup_int(filter_cfg, "udp_dport", &udpdport) == CONFIG_TRUE) { filter->udpopts.dport = (u16)udpdport; filter->udpopts.do_dport = 1; @@ -639,6 +637,430 @@ int ReadCfg(config__t *cfg, config_overrides_t* overrides) 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 SaveCfg(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_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. + config_setting_t* enabled = config_setting_add(filter_cfg, "enabled", CONFIG_TYPE_BOOL); + config_setting_set_bool(enabled, filter->enabled); + + // Add log setting. + config_setting_t* log = config_setting_add(filter_cfg, "log", CONFIG_TYPE_BOOL); + config_setting_set_bool(log, filter->log); + + // Add action setting. + config_setting_t* action = config_setting_add(filter_cfg, "action", CONFIG_TYPE_INT); + config_setting_set_int(action, filter->action); + + // Add source IPv4. + if (filter->src_ip > 0) + { + char ip_str[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, &filter->src_ip, ip_str, sizeof(ip_str)); + + char full_ip[INET_ADDRSTRLEN + 6]; + snprintf(full_ip, sizeof(full_ip), "%s/%d", ip_str, filter->src_cidr); + + config_setting_t* src_ip = config_setting_add(filter_cfg, "src_ip", CONFIG_TYPE_STRING); + config_setting_set_string(src_ip, full_ip); + } + + // Add destination IPv4. + if (filter->dst_ip > 0) + { + char ip_str[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, &filter->dst_ip, ip_str, sizeof(ip_str)); + + char full_ip[INET_ADDRSTRLEN + 6]; + snprintf(full_ip, sizeof(full_ip), "%s/%d", ip_str, filter->src_cidr); + + config_setting_t* dst_ip = config_setting_add(filter_cfg, "dst_ip", CONFIG_TYPE_STRING); + config_setting_set_string(dst_ip, full_ip); + } + + // Add source IPv6. + if (memcmp(filter->src_ip6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) != 0) + { + char ip_str[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET, filter->src_ip6, ip_str, sizeof(ip_str)); + + //char full_ip[INET6_ADDRSTRLEN + 6]; + //snprintf(full_ip, sizeof(full_ip), "%s/%d", ip_str, filter->src_cidr6); + + config_setting_t* src_ip6 = config_setting_add(filter_cfg, "src_ip6", CONFIG_TYPE_STRING); + config_setting_set_string(src_ip6, ip_str); + } + + // Add source IPv6. + if (memcmp(filter->dst_ip6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) != 0) + { + char ip_str[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET, filter->dst_ip6, ip_str, sizeof(ip_str)); + + //char full_ip[INET6_ADDRSTRLEN + 6]; + //snprintf(full_ip, sizeof(full_ip), "%s/%d", ip_str, filter->src_cidr6); + + config_setting_t* dst_ip6 = config_setting_add(filter_cfg, "dst_ip6", CONFIG_TYPE_STRING); + config_setting_set_string(dst_ip6, ip_str); + } + + // Add minimum TTL. + config_setting_t* min_ttl = config_setting_add(filter_cfg, "min_ttl", CONFIG_TYPE_INT); + config_setting_set_int(min_ttl, filter->min_ttl); + + // Add maximum TTL. + config_setting_t* max_ttl = config_setting_add(filter_cfg, "max_ttl", CONFIG_TYPE_INT); + config_setting_set_int(max_ttl, filter->max_ttl); + + // Add minimum length. + config_setting_t* min_len = config_setting_add(filter_cfg, "min_len", CONFIG_TYPE_INT); + config_setting_set_int(min_len, filter->min_len); + + // Add maximum length. + config_setting_t* max_len = config_setting_add(filter_cfg, "max_len", CONFIG_TYPE_INT); + config_setting_set_int(max_len, filter->max_len); + + // Add ToS. + config_setting_t* tos = config_setting_add(filter_cfg, "tos", CONFIG_TYPE_INT); + config_setting_set_int(tos, filter->tos); + + // Add PPS. + config_setting_t* pps = config_setting_add(filter_cfg, "pps", CONFIG_TYPE_INT64); + config_setting_set_int64(pps, filter->pps); + + // Add BPS. + config_setting_t* bps = config_setting_add(filter_cfg, "bps", CONFIG_TYPE_INT64); + config_setting_set_int64(bps, filter->bps); + + // Add block time. + 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 TCP enabled. + config_setting_t* tcp_enabled = config_setting_add(filter_cfg, "tcp_enabled", CONFIG_TYPE_BOOL); + config_setting_set_bool(tcp_enabled, filter->tcpopts.enabled); + + // Add TCP source port. + config_setting_t* tcp_sport = config_setting_add(filter_cfg, "tcp_sport", CONFIG_TYPE_INT); + config_setting_set_int(tcp_sport, filter->tcpopts.sport); + + // Add TCP destination port. + config_setting_t* tcp_dport = config_setting_add(filter_cfg, "tcp_dport", CONFIG_TYPE_INT); + config_setting_set_int(tcp_dport, filter->tcpopts.dport); + + // Add TCP URG flag. + config_setting_t* tcp_urg = config_setting_add(filter_cfg, "tcp_urg", CONFIG_TYPE_BOOL); + config_setting_set_bool(tcp_urg, filter->tcpopts.urg); + + // Add TCP ACK flag. + config_setting_t* tcp_ack = config_setting_add(filter_cfg, "tcp_ack", CONFIG_TYPE_BOOL); + config_setting_set_bool(tcp_ack, filter->tcpopts.ack); + + // Add TCP RST flag. + config_setting_t* tcp_rst = config_setting_add(filter_cfg, "tcp_rst", CONFIG_TYPE_BOOL); + config_setting_set_bool(tcp_rst, filter->tcpopts.rst); + + // Add TCP PSH flag. + config_setting_t* tcp_psh = config_setting_add(filter_cfg, "tcp_psh", CONFIG_TYPE_BOOL); + config_setting_set_bool(tcp_psh, filter->tcpopts.psh); + + // Add TCP SYN flag. + config_setting_t* tcp_syn = config_setting_add(filter_cfg, "tcp_syn", CONFIG_TYPE_BOOL); + config_setting_set_bool(tcp_syn, filter->tcpopts.syn); + + // Add TCP FIN flag. + config_setting_t* tcp_fin = config_setting_add(filter_cfg, "tcp_fin", CONFIG_TYPE_BOOL); + config_setting_set_bool(tcp_fin, filter->tcpopts.fin); + + // Add TCP ECE flag. + config_setting_t* tcp_ece = config_setting_add(filter_cfg, "tcp_ece", CONFIG_TYPE_BOOL); + config_setting_set_bool(tcp_ece, filter->tcpopts.ece); + + // Add TCP CWR flag. + config_setting_t* tcp_cwr = config_setting_add(filter_cfg, "tcp_cwr", CONFIG_TYPE_BOOL); + config_setting_set_bool(tcp_cwr, filter->tcpopts.cwr); + + // Add UDP enabled. + config_setting_t* udp_enabled = config_setting_add(filter_cfg, "udp_enabled", CONFIG_TYPE_BOOL); + config_setting_set_bool(udp_enabled, filter->udpopts.enabled); + + // Add UDP source port. + config_setting_t* udp_sport = config_setting_add(filter_cfg, "udp_sport", CONFIG_TYPE_INT); + config_setting_set_int(udp_sport, filter->udpopts.sport); + + // Add UDP destination port. + config_setting_t* udp_dport = config_setting_add(filter_cfg, "udp_dport", CONFIG_TYPE_INT); + config_setting_set_int(udp_dport, filter->udpopts.dport); + + // Add ICMP enabled. + config_setting_t* icmp_enabled = config_setting_add(filter_cfg, "icmp_enabled", CONFIG_TYPE_BOOL); + config_setting_set_bool(icmp_enabled, filter->icmpopts.enabled); + + // Add ICMP code. + config_setting_t* icmp_code = config_setting_add(filter_cfg, "icmp_code", CONFIG_TYPE_INT); + config_setting_set_int(icmp_code, filter->icmpopts.code); + + // Add ICMP type. + config_setting_t* icmp_type = config_setting_add(filter_cfg, "icmp_type", CONFIG_TYPE_INT); + config_setting_set_int(icmp_type, filter->icmpopts.type); + } + } + } + + // 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 config structure's default values. + * + * @param cfg A pointer to the config structure. + * + * @return Void + */ +void SetCfgDefaults(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_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; + } +} + +/** + * Prints a filter rule. + * + * @param filter A pointer to the filter rule. + * @param idx The current index. + * + * @return void + */ +void PrintFilter(filter_t* filter, int idx) +{ + printf("\tFilter #%d\n", idx); + printf("\t\tEnabled => %d\n", filter->enabled); + printf("\t\tAction => %d (0 = Block, 1 = Allow).\n", filter->action); + printf("\t\tLog => %d\n\n", filter->log); + + // IP Options. + printf("\t\tIP Options\n"); + + // IP addresses require additional code for string printing. + struct sockaddr_in sin; + sin.sin_addr.s_addr = filter->src_ip; + printf("\t\t\tSource IPv4 => %s\n", inet_ntoa(sin.sin_addr)); + printf("\t\t\tSource CIDR => %d\n", filter->src_cidr); + + struct sockaddr_in din; + din.sin_addr.s_addr = filter->dst_ip; + printf("\t\t\tDestination IPv4 => %s\n", inet_ntoa(din.sin_addr)); + printf("\t\t\tDestination CIDR => %d\n", filter->dst_cidr); + + struct in6_addr sin6; + memcpy(&sin6, &filter->src_ip6, sizeof(sin6)); + + char srcipv6[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &sin6, srcipv6, sizeof(srcipv6)); + + printf("\t\t\tSource IPv6 => %s\n", srcipv6); + + struct in6_addr din6; + memcpy(&din6, &filter->dst_ip6, sizeof(din6)); + + char dstipv6[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &din6, dstipv6, sizeof(dstipv6)); + + printf("\t\t\tDestination IPv6 => %s\n", dstipv6); + + // Other IP header information. + printf("\t\t\tMax Length => %d\n", filter->max_len); + printf("\t\t\tMin Length => %d\n", filter->min_len); + printf("\t\t\tMax TTL => %d\n", filter->max_ttl); + printf("\t\t\tMin TTL => %d\n", filter->min_ttl); + printf("\t\t\tTOS => %d\n", filter->tos); + printf("\t\t\tPPS => %llu\n", filter->pps); + printf("\t\t\tBPS => %llu\n", filter->bps); + printf("\t\t\tBlock Time => %llu\n\n", filter->block_time); + + // TCP Options. + printf("\t\tTCP Options\n"); + printf("\t\t\tTCP Enabled => %d\n", filter->tcpopts.enabled); + printf("\t\t\tTCP Source Port => %d\n", filter->tcpopts.sport); + printf("\t\t\tTCP Destination Port => %d\n", filter->tcpopts.dport); + printf("\t\t\tTCP URG Flag => %d\n", filter->tcpopts.urg); + printf("\t\t\tTCP ACK Flag => %d\n", filter->tcpopts.ack); + printf("\t\t\tTCP RST Flag => %d\n", filter->tcpopts.rst); + printf("\t\t\tTCP PSH Flag => %d\n", filter->tcpopts.psh); + printf("\t\t\tTCP SYN Flag => %d\n", filter->tcpopts.syn); + printf("\t\t\tTCP FIN Flag => %d\n", filter->tcpopts.fin); + printf("\t\t\tTCP ECE Flag => %d\n", filter->tcpopts.ece); + printf("\t\t\tTCP CWR Flag => %d\n\n", filter->tcpopts.cwr); + + // UDP Options. + printf("\t\tUDP Options\n"); + printf("\t\t\tUDP Enabled => %d\n", filter->udpopts.enabled); + printf("\t\t\tUDP Source Port => %d\n", filter->udpopts.sport); + printf("\t\t\tUDP Destination Port => %d\n\n", filter->udpopts.dport); + + // ICMP Options. + printf("\t\tICMP Options\n"); + printf("\t\t\tICMP Enabled => %d\n", filter->icmpopts.enabled); + printf("\t\t\tICMP Code => %d\n", filter->icmpopts.code); + printf("\t\t\tICMP Type => %d\n", filter->icmpopts.type); +} + /** * Prints config settings. * @@ -663,17 +1085,18 @@ void PrintConfig(config__t* cfg) } printf("Printing config...\n"); - printf("\tGeneral Settings\n"); + printf("General Settings\n"); - printf("\t\tVerbose => %d\n", cfg->verbose); - printf("\t\tLog File => %s\n", log_file); - printf("\t\tInterface Name => %s\n", interface); - printf("\t\tUpdate Time => %d\n", cfg->update_time); - printf("\t\tNo Stats => %d\n", cfg->no_stats); - printf("\t\tStats Per Second => %d\n", cfg->stats_per_second); - printf("\t\tStdout Update Time => %d\n\n", cfg->stdout_update_time); + 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("\tFilters\n"); + printf("Filters\n"); for (int i = 0; i < MAX_FILTERS; i++) { @@ -684,79 +1107,32 @@ void PrintConfig(config__t* cfg) break; } - printf("\t\tFilter #%d:\n", (i + 1)); - - // Main. - printf("\t\t\tEnabled => %d\n", filter->enabled); - printf("\t\t\tAction => %d (0 = Block, 1 = Allow).\n", filter->action); - printf("\t\t\tLog => %d\n\n", filter->log); - - // IP Options. - printf("\t\t\tIP Options\n"); - - // IP addresses require additional code for string printing. - struct sockaddr_in sin; - sin.sin_addr.s_addr = filter->src_ip; - printf("\t\t\t\tSource IPv4 => %s\n", inet_ntoa(sin.sin_addr)); - printf("\t\t\t\tSource CIDR => %d\n", filter->src_cidr); - - struct sockaddr_in din; - din.sin_addr.s_addr = filter->dst_ip; - printf("\t\t\t\tDestination IPv4 => %s\n", inet_ntoa(din.sin_addr)); - printf("\t\t\t\tDestination CIDR => %d\n", filter->dst_cidr); - - struct in6_addr sin6; - memcpy(&sin6, &filter->src_ip6, sizeof(sin6)); - - char srcipv6[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &sin6, srcipv6, sizeof(srcipv6)); - - printf("\t\t\t\tSource IPv6 => %s\n", srcipv6); - - struct in6_addr din6; - memcpy(&din6, &filter->dst_ip6, sizeof(din6)); - - char dstipv6[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &din6, dstipv6, sizeof(dstipv6)); - - printf("\t\t\t\tDestination IPv6 => %s\n", dstipv6); - - // Other IP header information. - printf("\t\t\t\tMax Length => %d\n", filter->max_len); - printf("\t\t\t\tMin Length => %d\n", filter->min_len); - printf("\t\t\t\tMax TTL => %d\n", filter->max_ttl); - printf("\t\t\t\tMin TTL => %d\n", filter->min_ttl); - printf("\t\t\t\tTOS => %d\n", filter->tos); - printf("\t\t\t\tPPS => %llu\n", filter->pps); - printf("\t\t\t\tBPS => %llu\n", filter->bps); - printf("\t\t\t\tBlock Time => %llu\n\n", filter->block_time); - - // TCP Options. - printf("\t\t\tTCP Options\n"); - printf("\t\t\t\tTCP Enabled => %d\n", filter->tcpopts.enabled); - printf("\t\t\t\tTCP Source Port => %d\n", filter->tcpopts.sport); - printf("\t\t\t\tTCP Destination Port => %d\n", filter->tcpopts.dport); - printf("\t\t\t\tTCP URG Flag => %d\n", filter->tcpopts.urg); - printf("\t\t\t\tTCP ACK Flag => %d\n", filter->tcpopts.ack); - printf("\t\t\t\tTCP RST Flag => %d\n", filter->tcpopts.rst); - printf("\t\t\t\tTCP PSH Flag => %d\n", filter->tcpopts.psh); - printf("\t\t\t\tTCP SYN Flag => %d\n", filter->tcpopts.syn); - printf("\t\t\t\tTCP FIN Flag => %d\n", filter->tcpopts.fin); - printf("\t\t\t\tTCP ECE Flag => %d\n", filter->tcpopts.ece); - printf("\t\t\t\tTCP CWR Flag => %d\n\n", filter->tcpopts.cwr); - - // UDP Options. - printf("\t\t\tUDP Options\n"); - printf("\t\t\t\tUDP Enabled => %d\n", filter->udpopts.enabled); - printf("\t\t\t\tUDP Source Port => %d\n", filter->udpopts.sport); - printf("\t\t\t\tUDP Destination Port => %d\n\n", filter->udpopts.dport); - - // ICMP Options. - printf("\t\t\tICMP Options\n"); - printf("\t\t\t\tICMP Enabled => %d\n", filter->icmpopts.enabled); - printf("\t\t\t\tICMP Code => %d\n", filter->icmpopts.code); - printf("\t\t\t\tICMP Type => %d\n", filter->icmpopts.type); + PrintFilter(filter, i + 1); printf("\n\n"); } +} + +/** + * 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 GetNextAvailableFilterIndex(config__t* cfg) +{ + for (int i = 0; i < MAX_FILTERS; i++) + { + filter_t* filter = &cfg->filters[i]; + + if (filter->set) + { + 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 a1ea302..c2ad130 100644 --- a/src/loader/utils/config.h +++ b/src/loader/utils/config.h @@ -18,6 +18,7 @@ struct config int verbose; char *log_file; char *interface; + unsigned int pin_maps : 1; int update_time; unsigned int no_stats : 1; unsigned int stats_per_second : 1; @@ -30,6 +31,7 @@ struct config_overrides int verbose; const char* log_file; const char* interface; + int pin_maps; int update_time; int no_stats; int stats_per_second; @@ -37,11 +39,19 @@ struct config_overrides } typedef config_overrides_t; -int LoadConfig(config__t *cfg, char *cfg_file, config_overrides_t* overrides); void SetCfgDefaults(config__t *cfg); + +void PrintFilter(filter_t* filter, int idx); void PrintConfig(config__t* cfg); -int OpenCfg(const char *filename); -int ReadCfg(config__t *cfg, config_overrides_t* overrides); +int LoadConfig(config__t *cfg, char *cfg_file, config_overrides_t* overrides); +int SaveCfg(config__t* cfg, const char* file_path); + +int OpenCfg(FILE** file, const char *file_name); +int CloseCfg(FILE* file); +int ReadCfg(FILE* file, char** buffer); +int ParseCfg(config__t *cfg, const char* data, config_overrides_t* overrides); + +int GetNextAvailableFilterIndex(config__t* cfg); #include \ No newline at end of file diff --git a/src/loader/utils/logging.c b/src/loader/utils/logging.c index 8b06284..eb35304 100644 --- a/src/loader/utils/logging.c +++ b/src/loader/utils/logging.c @@ -74,7 +74,6 @@ static void LogMsgRaw(int req_lvl, int cur_lvl, int error, const char* log_path, return; } - char log_file_msg[len + 22 + 1]; snprintf(log_file_msg, sizeof(log_file_msg), "[%02d-%02d-%02d %02d:%02d:%02d]%s", tm_val->tm_year % 100, tm_val->tm_mon + 1, tm_val->tm_mday, @@ -143,7 +142,7 @@ int HandleRbEvent(void* ctx, void* data, size_t sz) } char src_ip_str[INET6_ADDRSTRLEN]; - char dst_ip_str[INET_ADDRSTRLEN]; + char dst_ip_str[INET6_ADDRSTRLEN]; if (memcmp(e->src_ip6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) != 0) { diff --git a/src/loader/utils/stats.c b/src/loader/utils/stats.c index c62fdbb..a37cb47 100644 --- a/src/loader/utils/stats.c +++ b/src/loader/utils/stats.c @@ -53,7 +53,8 @@ int CalculateStats(int map_stats, int cpus, int per_second) if (per_second) { struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); // Get precise time + clock_gettime(CLOCK_MONOTONIC, &now); + double elapsed_time = (now.tv_sec - last_update_time.tv_sec) + (now.tv_nsec - last_update_time.tv_nsec) / 1e9; diff --git a/src/loader/utils/stats.h b/src/loader/utils/stats.h index 25d4112..9281db9 100644 --- a/src/loader/utils/stats.h +++ b/src/loader/utils/stats.h @@ -4,7 +4,6 @@ #include -#include #include #include diff --git a/src/loader/utils/xdp.c b/src/loader/utils/xdp.c index c9bc935..96da61b 100644 --- a/src/loader/utils/xdp.c +++ b/src/loader/utils/xdp.c @@ -85,6 +85,18 @@ struct xdp_program *LoadBpfObj(const char *file_name) return prog; } +/** + * Retrieves BPF object from XDP program. + * + * @param prog A pointer to the XDP program. + * + * @return The BPF object. + */ +struct bpf_object* GetBpfObj(struct xdp_program* prog) +{ + return xdp_program__bpf_obj(prog); +} + /** * Attempts to attach or detach (progfd = -1) a BPF/XDP program to an interface. * @@ -92,11 +104,12 @@ struct xdp_program *LoadBpfObj(const char *file_name) * @param mode_used The mode being used. * @param ifidx The index to the interface to attach to. * @param detach If above 0, attempts to detach XDP program. - * @param cmd A pointer to a cmdline struct that includes command line arguments (mostly checking for offload/HW mode set). + * @param force_skb If set, forces the XDP program to run in SKB mode. + * @param force_offload If set, forces the XDP program to run in offload mode. * * @return 0 on success and 1 on error. */ -int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, u8 detach, cmdline_t *cmd) +int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, int detach, int force_skb, int force_offload) { int err; @@ -104,13 +117,13 @@ int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, u8 detach, cmdli *mode = "DRV/native"; - if (cmd->offload) + if (force_offload) { *mode = "HW/offload"; attach_mode = XDP_MODE_HW; } - else if (cmd->skb) + else if (force_skb) { *mode = "SKB/generic"; @@ -176,6 +189,58 @@ int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, u8 detach, cmdli return EXIT_SUCCESS; } +/** + * Deletes a filter. + * + * @param map_filters The filters BPF map FD. + * @param idx The filter index to delete. + * + * @return 0 on success or the error value of bpf_map_delete_elem(). + */ +int DeleteFilter(int map_filters, u32 idx) +{ + return bpf_map_delete_elem(map_filters, &idx); +} + +/** + * Deletes all filters. + * + * @param map_filters The filters BPF map FD. + * + * @return void + */ +void DeleteFilters(int map_filters) +{ + for (int i = 0; i < MAX_FILTERS; i++) + { + DeleteFilter(map_filters, i); + } +} + +/** + * Updates a filter rule. + * + * @param map_filters The filters BPF map FD. + * @param filter A pointer to the filter. + * @param idx The filter index to insert or update. + * + * @return 0 on success or error value of bpf_map_update_elem(). + */ +int UpdateFilter(int map_filters, filter_t* filter, int idx) +{ + int ret; + + filter_t filter_cpus[MAX_CPUS]; + memset(filter_cpus, 0, sizeof(filter_cpus)); + + for (int j = 0; j < MAX_CPUS; j++) + { + filter_cpus[j] = *filter; + } + + return bpf_map_update_elem(map_filters, &idx, &filter_cpus, BPF_ANY); +} + /** * Updates the filter's BPF map with current config settings. * @@ -192,13 +257,11 @@ void UpdateFilters(int map_filters, config__t *cfg) // Add a filter to the filter maps. for (int i = 0; i < MAX_FILTERS; i++) { - filter_t* filter = &cfg->filters[i]; - // Delete previous rule from BPF map. // We do this in the case rules were edited and were put out of order since the key doesn't uniquely map to a specific rule. - u32 key = i; + DeleteFilter(map_filters, i); - bpf_map_delete_elem(map_filters, &key); + filter_t* filter = &cfg->filters[i]; // Only insert set and enabled filters. if (!filter->set || !filter->enabled) @@ -206,21 +269,78 @@ void UpdateFilters(int map_filters, config__t *cfg) continue; } - // Create value array (max CPUs in size) since we're using a per CPU map. - filter_t filter_cpus[MAX_CPUS]; - memset(filter_cpus, 0, sizeof(filter_cpus)); - - for (int j = 0; j < MAX_CPUS; j++) + // Attempt to update filter. + if ((ret = UpdateFilter(map_filters, filter, cur_idx)) != 0) { - filter_cpus[j] = *filter; - } + fprintf(stderr, "[WARNING] Failed to update filter #%d due to BPF update error (%d)...\n", cur_idx, ret); - // Attempt to update BPF map. - if ((ret = bpf_map_update_elem(map_filters, &cur_idx, &filter_cpus, BPF_ANY)) != 0) - { - fprintf(stderr, "[WARNING] Failed to update filter #%d due to BPF update error (%d)...\n", i, ret); + continue; } cur_idx++; } +} + +/** + * Pins a BPF map to the file system. + * + * @param obj A pointer to the BPF object. + * @param pin_dir The pin directory. + * @param map_name The map name. + * + * @return 0 on success or value of bpf_map__pin() on error. + */ +int PinBpfMap(struct bpf_object* obj, const char* pin_dir, const char* map_name) +{ + struct bpf_map* map = bpf_object__find_map_by_name(obj, map_name); + + if (!map) + { + return -1; + } + + char full_path[255]; + snprintf(full_path, sizeof(full_path), "%s/%s", XDP_MAP_PIN_DIR, map_name); + + return bpf_map__pin(map, full_path); +} + +/** + * Unpins a BPF map from the file system. + * + * @param obj A pointer to the BPF object. + * @param pin_dir The pin directory. + * @param map_name The map name. + * + * @return + */ +int UnpinBpfMap(struct bpf_object* obj, const char* pin_dir, const char* map_name) +{ + struct bpf_map* map = bpf_object__find_map_by_name(obj, map_name); + + if (!map) + { + return 1; + } + + char full_path[255]; + snprintf(full_path, sizeof(full_path), "%s/%s", XDP_MAP_PIN_DIR, map_name); + + return bpf_map__unpin(map, full_path); +} + +/** + * Retrieves a map FD on the file system (pinned). + * + * @param pin_dir The pin directory. + * @param map_name The map name. + * + * @return The map FD or -1 on error. + */ +int GetMapPinFd(const char* pin_dir, const char* map_name) +{ + char full_path[255]; + snprintf(full_path, sizeof(full_path), "%s/%s", pin_dir, map_name); + + return bpf_obj_get(full_path); } \ No newline at end of file diff --git a/src/loader/utils/xdp.h b/src/loader/utils/xdp.h index 77d46ff..6561da3 100644 --- a/src/loader/utils/xdp.h +++ b/src/loader/utils/xdp.h @@ -4,14 +4,26 @@ #include -#include #include #include #define XDP_OBJ_PATH "/etc/xdpfw/xdp_prog.o" +#define XDP_MAP_PIN_DIR "/sys/fs/bpf/xdpfw" int FindMapFd(struct xdp_program *prog, const char *map_name); void SetLibBPFLogMode(int silent); + struct xdp_program *LoadBpfObj(const char *file_name); -int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, u8 detach, cmdline_t *cmd); -void UpdateFilters(int map_filters, config__t *cfg); \ No newline at end of file +struct bpf_object* GetBpfObj(struct xdp_program* prog); + +int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, int detach, int force_skb, int force_offload); + +int DeleteFilter(int map_filters, u32 idx); +void DeleteFilters(int map_filters); + +int UpdateFilter(int map_filters, filter_t* filter, int idx); +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