diff --git a/src/config.c b/src/config.c index e69de29..8c82f5b 100644 --- a/src/config.c +++ b/src/config.c @@ -0,0 +1,410 @@ +#include +#include +#include +#include + +#include + +#include "include/xdpfw.h" +#include "include/config.h" + +FILE *file; + +void SetConfigDefaults(struct config_map *cfg) +{ + cfg->updateTime = 0; + cfg->interface = "eth0"; + + for (uint16_t i = 0; i < MAX_FILTERS; i++) + { + cfg->filters[i].enabled = 0; + cfg->filters[i].action = 0; + cfg->filters[i].srcIP = 0; + cfg->filters[i].dstIP = 0; + cfg->filters[i].min_id = 0; + cfg->filters[i].max_id = 4294967295; + cfg->filters[i].min_len = 0; + cfg->filters[i].max_len = 65535; + cfg->filters[i].min_ttl = 0; + cfg->filters[i].max_ttl = 255; + cfg->filters[i].tos = 0; + cfg->filters[i].protocol = 0; + + cfg->filters[i].tcpopts.enabled = 0; + cfg->filters[i].udpopts.enabled = 0; + cfg->filters[i].icmpopts.enabled = 0; + + for (uint16_t j = 0; i < MAX_PCKT_LENGTH; i++) + { + cfg->filters[i].payloadMatch[j] = 0; + } + + cfg->filters[i].payloadLen = 0; + } +} + +int OpenConfig(const char *FileName) +{ + // Close any existing files. + if (file != NULL) + { + fclose(file); + + file = NULL; + } + + file = fopen(FileName, "r"); + + if (file == NULL) + { + return 1; + } + + return 0; +} + +int ReadConfig(struct config_map *cfg) +{ + // 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; + + config_init(&conf); + + // Attempt to read the config. + if (config_read(&conf, file) == CONFIG_FALSE) + { + fprintf(stderr, "Error from LibConfig when reading file - %s (Line %d)\n\n", config_error_text(&conf), config_error_line(&conf)); + + config_destroy(&conf); + + return 1; + } + + // Get interface. + const char *interface; + + if (!config_lookup_string(&conf, "interface", &interface)) + { + fprintf(stderr, "Error from LibConfig when reading 'interface' setting - %s\n\n", config_error_text(&conf)); + + config_destroy(&conf); + + return 1; + } + + cfg->interface = strdup(interface); + + + // Get auto update time. + int updateTime; + + if (!config_lookup_bool(&conf, "updatetime", &updateTime)) + { + fprintf(stderr, "Error from LibConfig when reading 'updatetime' setting - %s\n\n", config_error_text(&conf)); + + config_destroy(&conf); + + return 1; + } + + cfg->updateTime = updateTime; + + // Read filters in filters_map structure. + setting = config_lookup(&conf, "filters"); + + // Check if filters map is valid. If not, not a biggie since they aren't required. + if (setting == NULL) + { + fprintf(stderr, "Error from LibConfig when reading 'filters' array - %s\n\n", config_error_text(&conf)); + + config_destroy(&conf); + + return 1; + } + + // Set filter count. + int filters = 0; + + for (uint8_t i = 0; i < config_setting_length(setting); i++) + { + config_setting_t* filter = config_setting_get_elem(setting, i); + + // Enabled. + int enabled; + + if (config_setting_lookup_bool(filter, "enabled", &enabled) != 0) + { + // Print error and stop from existing this rule any further. + fprintf(stderr, "Error from LibConfig when reading 'enabled' setting from filters array #%d. Error - %s\n\n", filters, config_error_text(&conf)); + + continue; + } + + cfg->filters[i].enabled = enabled; + + // Action (required). + int action; + + if (config_setting_lookup_int(filter, "action", &action) != 0) + { + fprintf(stderr, "Error from LibConfig when reading 'action' setting from filters array #%d. Error - %s\n\n", filters, config_error_text(&conf)); + + cfg->filters[i].enabled = 0; + + continue; + } + + cfg->filters[i].action = action; + + // Source IP (not required). + const char *sIP; + + if (config_setting_lookup_string(filter, "srcip", &sIP)) + { + cfg->filters[i].srcIP = inet_addr(sIP); + } + + // Destination IP (not required). + const char *dIP; + + if (config_setting_lookup_string(filter, "dstip", &dIP)) + { + cfg->filters[i].dstIP = inet_addr(dIP); + } + + // Protocol (required). + int protocol; + + if (!config_setting_lookup_int(filter, "protocol", &protocol)) + { + fprintf(stderr, "Error from LibConfig when reading 'protocol' setting from filters array #%d. Error - %s\n\n", filters, config_error_text(&conf)); + + cfg->filters[i].enabled = 0; + + continue; + } + + cfg->filters[i].protocol = protocol; + + // Minimum TTL (not required). + int min_ttl; + + if (config_setting_lookup_int(filter, "min_ttl", &min_ttl)) + { + cfg->filters[i].min_ttl = min_ttl; + } + + // Maximum TTL (not required). + int max_ttl; + + if (config_setting_lookup_int(filter, "max_ttl", &max_ttl)) + { + cfg->filters[i].max_ttl = max_ttl; + } + + // Minimum length (not required). + int min_len; + + if (config_setting_lookup_int(filter, "min_len", &min_len)) + { + cfg->filters[i].min_len = min_len; + } + + // Maximum length (not required). + int max_len; + + if (config_setting_lookup_int(filter, "max_len", &max_len)) + { + cfg->filters[i].max_len = max_len; + } + + // TOS (not required). + int tos; + + if (config_setting_lookup_int(filter, "tos", &tos)) + { + cfg->filters[i].tos = tos; + } + + // Payload match. + const char *payload; + + if (config_setting_lookup_string(filter, "payloadmatch", &payload)) + { + // We need to split the string and scan everything into the uint8_t payload. + char *split; + + char *str = malloc((strlen(payload) + 1) * sizeof(char)); + strcpy(str, payload); + + split = strtok(str, " "); + + while (split != NULL) + { + sscanf(split, "%2hhx", &cfg->filters[i].payloadMatch[cfg->filters[i].payloadLen]); + + cfg->filters[i].payloadLen++; + + split = strtok(NULL, " "); + } + } + + // Check for TCP options. + config_setting_t* tcpopts = config_setting_lookup(filter, "tcpopts"); + + // Check TCP options. + if (tcpopts != NULL) + { + // Enabled. + int enabled; + + if (config_setting_lookup_bool(tcpopts, "enabled", &enabled)) + { + cfg->filters[i].tcpopts.enabled = enabled; + } + + // Source port. + long long sport; + + if (config_setting_lookup_int64(tcpopts, "sport", &sport)) + { + cfg->filters[i].tcpopts.sport = (uint16_t)sport; + } + + // Destination port. + long long dport; + + if (config_setting_lookup_int64(tcpopts, "dport", &dport)) + { + cfg->filters[i].tcpopts.dport = (uint16_t)dport; + } + + // URG flag. + int urg; + + if (config_setting_lookup_bool(tcpopts, "urg", &urg)) + { + cfg->filters[i].tcpopts.urg = urg; + } + + // ACK flag. + int ack; + + if (config_setting_lookup_bool(tcpopts, "ack", &ack)) + { + cfg->filters[i].tcpopts.ack = ack; + } + + // RST flag. + int rst; + + if (config_setting_lookup_bool(tcpopts, "rst", &rst)) + { + cfg->filters[i].tcpopts.rst = rst; + } + + // PSH flag. + int psh; + + if (config_setting_lookup_bool(tcpopts, "psh", &psh)) + { + cfg->filters[i].tcpopts.psh = psh; + } + + // SYN flag. + int syn; + + if (config_setting_lookup_bool(tcpopts, "syn", &syn)) + { + cfg->filters[i].tcpopts.syn = syn; + } + + // FIN flag. + int fin; + + if (config_setting_lookup_bool(tcpopts, "fin", &fin)) + { + cfg->filters[i].tcpopts.fin = fin; + } + } + + // Check for UDP options. + config_setting_t* udpopts = config_setting_lookup(filter, "udpopts"); + + // Check UDP options. + if (udpopts != NULL) + { + // Enabled. + int enabled; + + if (config_setting_lookup_bool(udpopts, "enabled", &enabled)) + { + cfg->filters[i].udpopts.enabled = enabled; + } + + // Source port. + long long sport; + + if (config_setting_lookup_int64(udpopts, "sport", &sport)) + { + cfg->filters[i].udpopts.sport = (uint16_t)sport; + } + + // Destination port. + long long dport; + + if (config_setting_lookup_int64(udpopts, "dport", &dport)) + { + cfg->filters[i].udpopts.dport = (uint16_t)dport; + } + } + + // Check for ICMP options. + config_setting_t* icmpopts = config_setting_lookup(filter, "icmpopts"); + + // Check UDP options. + if (icmpopts != NULL) + { + // Enabled. + int enabled; + + if (config_setting_lookup_bool(icmpopts, "enabled", &enabled)) + { + cfg->filters[i].icmpopts.enabled = enabled; + } + + // ICMP code. + int code; + + if (config_setting_lookup_int(icmpopts, "code", &code)) + { + cfg->filters[i].icmpopts.code = code; + } + + // ICMP type. + int type; + + if (config_setting_lookup_int(icmpopts, "type", &type)) + { + cfg->filters[i].icmpopts.type = type; + } + } + + // Increase filter count. + filters++; + } + + // Assign filter count to config. + cfg->filterCount = filters; + + config_destroy(&conf); + + return 0; +} \ No newline at end of file diff --git a/src/include/config.h b/src/include/config.h index e69de29..53ca9a3 100644 --- a/src/include/config.h +++ b/src/include/config.h @@ -0,0 +1,18 @@ +#ifndef CONFIG_HEADER +#define CONFIG_HEADER + +#include "xdpfw.h" + +struct config_map +{ + char *interface; + uint16_t updateTime; + uint16_t filterCount; + struct filter filters[MAX_FILTERS]; +}; + +void SetConfigDefaults(struct config_map *cfg); +int OpenConfig(const char *FileName); +int ReadConfig(struct config_map *cfg); + +#endif \ No newline at end of file diff --git a/src/include/xdpfw.h b/src/include/xdpfw.h index e69de29..74c1dcd 100644 --- a/src/include/xdpfw.h +++ b/src/include/xdpfw.h @@ -0,0 +1,70 @@ +#ifndef XDPFW_Header +#define XDPFW_Header + +#include + +#define MAX_PCKT_LENGTH 65535 +#define MAX_FILTERS 255 + +struct tcpopts +{ + unsigned int enabled : 1; + + uint16_t sport; + uint16_t dport; + + // TCP flags. + unsigned int urg : 1; + unsigned int ack : 1; + unsigned int rst : 1; + unsigned int psh : 1; + unsigned int syn : 1; + unsigned int fin : 1; +}; + +struct udpopts +{ + unsigned int enabled : 1; + + uint16_t sport; + uint16_t dport; +}; + +struct icmpopts +{ + unsigned int enabled : 1; + + uint8_t code; + uint8_t type; +}; + +struct filter +{ + unsigned int enabled : 1; + + uint8_t action; + + uint32_t srcIP; + uint32_t dstIP; + uint8_t protocol; + + uint8_t min_ttl; + uint8_t max_ttl; + + uint16_t min_len; + uint16_t max_len; + + uint32_t min_id; + uint32_t max_id; + + int8_t tos; + + uint8_t payloadMatch[MAX_PCKT_LENGTH]; + uint16_t payloadLen; + + struct tcpopts tcpopts; + struct udpopts udpopts; + struct icmpopts icmpopts; +}; + +#endif \ No newline at end of file