diff --git a/src/config.c b/src/config.c index c014e9b..8e199ec 100644 --- a/src/config.c +++ b/src/config.c @@ -14,6 +14,7 @@ void SetConfigDefaults(struct config_map *cfg) { cfg->updateTime = 0; cfg->interface = "eth0"; + cfg->nostats = 0; for (uint16_t i = 0; i < MAX_FILTERS; i++) { @@ -138,6 +139,14 @@ int ReadConfig(struct config_map *cfg) cfg->updateTime = updateTime; + // Get no stats. + int nostats; + + if (config_lookup_bool(&conf, "nostats", &nostats) == CONFIG_TRUE) + { + cfg->nostats = nostats; + } + // Read filters in filters_map structure. setting = config_lookup(&conf, "filters"); @@ -444,9 +453,6 @@ int ReadConfig(struct config_map *cfg) filters++; } - // Assign filter count to config. - cfg->filterCount = filters; - config_destroy(&conf); return 0; diff --git a/src/include/config.h b/src/include/config.h index 53ca9a3..41c528e 100644 --- a/src/include/config.h +++ b/src/include/config.h @@ -7,7 +7,7 @@ struct config_map { char *interface; uint16_t updateTime; - uint16_t filterCount; + unsigned int nostats : 1; struct filter filters[MAX_FILTERS]; }; diff --git a/src/xdpfw_kern.c b/src/xdpfw_kern.c index e9c14f8..f0baf46 100644 --- a/src/xdpfw_kern.c +++ b/src/xdpfw_kern.c @@ -50,14 +50,6 @@ struct bpf_map_def SEC("maps") filters_map = .max_entries = MAX_FILTERS }; -struct bpf_map_def SEC("maps") count_map = -{ - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(uint32_t), - .value_size = sizeof(uint8_t), - .max_entries = 1 -}; - struct bpf_map_def SEC("maps") stats_map = { .type = BPF_MAP_TYPE_ARRAY, @@ -68,31 +60,7 @@ struct bpf_map_def SEC("maps") stats_map = SEC("xdp_prog") int xdp_prog_main(struct xdp_md *ctx) -{ - // Check for count map. - uint32_t key = 0; - uint16_t *filters; - - filters = bpf_map_lookup_elem(&count_map, &key); - - // Check if the count map value is valid. - if (filters == NULL) - { - return XDP_ABORTED; - } - - // Filter count. - uint8_t filterCount; - - if (*filters > MAX_FILTERS) - { - filterCount = MAX_FILTERS; - } - else - { - filterCount = *filters; - } - +{ // Initialize data. void *data_end = (void *)(long)ctx->data_end; void *data = (void *)(long)ctx->data; @@ -189,11 +157,13 @@ int xdp_prog_main(struct xdp_md *ctx) for (uint8_t i = 0; i < MAX_FILTERS; i++) { + // Check if ID is above 0 (if 0, it's an invalid rule). if (!filter[i] || filter[i]->id < 1) { break; } + // Check if the rule is enabled. if (!filter[i]->enabled) { continue; @@ -241,17 +211,20 @@ int xdp_prog_main(struct xdp_md *ctx) continue; } - // Custom payload. + // Payload match. if (filter[i]->payloadLen > 0) { + // Initialize packet data. uint8_t *pcktData = (data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4headerLen); // Now check packet data and ensure we have enough to match. - if (pcktData + (filter[i]->payloadLen + 1) > (uint8_t *)data_end) + if (pcktData + (filter[i]->payloadLen) > (uint8_t *)data_end) { continue; } + uint8_t found = 1; + for (uint16_t j = 0; j < filter[i]->payloadLen; j++) { if ((*pcktData++) == filter[i]->payloadMatch[j]) @@ -259,8 +232,15 @@ int xdp_prog_main(struct xdp_md *ctx) continue; } + found = 0; + break; } + + if (!found) + { + continue; + } } // Check layer 4 filters. @@ -370,7 +350,32 @@ int xdp_prog_main(struct xdp_md *ctx) if (matched) { - bpf_printk("Matched with protocol %" PRIu8 " and sAddr %" PRIu32 "\n", iph->protocol, iph->saddr); + // Get stats map. + uint32_t key = 0; + struct xdpfw_stats *stats; + + stats = bpf_map_lookup_elem(&stats_map, &key); + + if (stats) + { + // Update stats map. + if (action == 0) + { + stats->blocked++; + } + else + { + stats->allowed++; + } + + key = 0; + + bpf_map_update_elem(&stats_map, &key, stats, BPF_ANY); + } + + #ifdef DEBUG + bpf_printk("Matched with protocol %" PRIu8 " and sAddr %" PRIu32 "\n", iph->protocol, iph->saddr); + #endif } } diff --git a/src/xdpfw_loader.c b/src/xdpfw_loader.c index 82d2997..bba4422 100644 --- a/src/xdpfw_loader.c +++ b/src/xdpfw_loader.c @@ -34,7 +34,6 @@ const struct option opts[] = // Other variables. static uint8_t cont = 1; static int filter_map_fd = -1; -static int count_map_fd = -1; static int stats_map_fd = -1; void signalHndl(int tmp) @@ -87,8 +86,15 @@ void update_BPF(struct config_map *conf) } // Add a filter to the filter maps. - for (uint32_t i = 0; i < conf->filterCount; i++) + for (uint32_t i = 0; i < MAX_FILTERS; i++) { + // Check if we have a valid ID. + if (conf->filters[i].id < 1) + { + break; + } + + // Attempt to update BPF map. if (bpf_map_update_elem(filter_map_fd, &i, &conf->filters[i], BPF_ANY) == -1) { fprintf(stderr, "Error updating BPF item #%d\n", i); @@ -161,7 +167,6 @@ int load_bpf_object_file__simple(const char *filename) } filter_map_fd = find_map_fd(obj, "filters_map"); - count_map_fd = find_map_fd(obj, "count_map"); stats_map_fd = find_map_fd(obj, "stats_map"); return first_prog_fd; @@ -296,10 +301,14 @@ int main(int argc, char *argv[]) fprintf(stdout, "Details:\n"); fprintf(stdout, "Interface Name => %s\n", conf->interface); fprintf(stdout, "Update Time => %" PRIu16 "\n", conf->updateTime); - fprintf(stdout, "Filters Count => %" PRIu16 "\n\n", conf->filterCount); - for (uint16_t i = 0; i < conf->filterCount; i++) + for (uint16_t i = 0; i < MAX_FILTERS; i++) { + if (conf->filters[i].id < 1) + { + break; + } + fprintf(stdout, "Filter #%" PRIu16 ":\n", (i + 1)); // Main. @@ -344,6 +353,19 @@ int main(int argc, char *argv[]) fprintf(stdout, "ICMP Code => %" PRIu8 "\n", conf->filters[i].icmpopts.code); fprintf(stdout, "ICMP Type => %" PRIu8 "\n", conf->filters[i].icmpopts.type); + // Payload. + if (conf->filters[i].payloadLen > 0) + { + fprintf(stdout, "\nPayload (%d) => ", conf->filters[i].payloadLen); + + for(uint16_t j = 0; j < conf->filters[i].payloadLen; j++) + { + fprintf(stdout, "%2hhx ", conf->filters[i].payloadMatch[j]); + } + + fprintf(stdout, "\n"); + } + fprintf(stdout, "\n\n"); } @@ -391,13 +413,6 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - if (count_map_fd < 0) - { - fprintf(stderr, "Error finding 'count_map' BPF map.\n"); - - return EXIT_FAILURE; - } - if (stats_map_fd < 0) { fprintf(stderr, "Error finding 'stats_map' BPF map.\n"); @@ -430,20 +445,17 @@ int main(int argc, char *argv[]) } // Update stats. - if ((curTime - statsLastUpdated) > 5) + if ((curTime - statsLastUpdated) > 2 && !conf->nostats) { - uint16_t key = 0; - struct xdpfw_stats *stats; + uint32_t key = 0; + struct xdpfw_stats stats; - bpf_map_lookup_elem(stats_map_fd, &key, stats); + bpf_map_lookup_elem(stats_map_fd, &key, &stats); - if (stats != NULL) - { - fprintf(stdout, "\rPackets allowed: %" PRIu64 "\n", stats->allowed); - fprintf(stdout, "\rPackets blocked: %" PRIu64 "\n", stats->blocked); - - fflush(stdout); - } + fflush(stdout); + fprintf(stdout, "\rPackets Allowed: %" PRIu64 " | Packets Blocked: %" PRIu64, stats.allowed, stats.blocked); + + statsLastUpdated = time(NULL); } sleep(1); @@ -460,6 +472,9 @@ int main(int argc, char *argv[]) // Free config. free(conf); + // Add spacing. + fprintf(stdout, "\n"); + // Exit program successfully. return EXIT_SUCCESS; } \ No newline at end of file