diff --git a/src/config.c b/src/config.c index 8e199ec..1f0ff32 100644 --- a/src/config.c +++ b/src/config.c @@ -38,6 +38,12 @@ void SetConfigDefaults(struct config_map *cfg) cfg->filters[i].do_tos = 0; cfg->filters[i].tos = 0; + + cfg->filters[i].do_pps = 0; + cfg->filters[i].pps = 0; + + cfg->filters[i].do_bps = 0; + cfg->filters[i].bps = 0; cfg->filters[i].tcpopts.enabled = 0; cfg->filters[i].tcpopts.do_dport = 0; @@ -124,7 +130,6 @@ int ReadConfig(struct config_map *cfg) cfg->interface = strdup(interface); - // Get auto update time. int updateTime; @@ -255,6 +260,24 @@ int ReadConfig(struct config_map *cfg) cfg->filters[i].do_tos = 1; } + // PPS (not required). + long long pps; + + if (config_setting_lookup_int64(filter, "pps", &pps)) + { + cfg->filters[i].pps = pps; + cfg->filters[i].do_pps = 1; + } + + // BPS (not required). + long long bps; + + if (config_setting_lookup_int64(filter, "bps", &bps)) + { + cfg->filters[i].bps = bps; + cfg->filters[i].do_bps = 1; + } + // Payload match. const char *payload; diff --git a/src/include/xdpfw.h b/src/include/xdpfw.h index 0d52ebc..3a09f5f 100644 --- a/src/include/xdpfw.h +++ b/src/include/xdpfw.h @@ -5,6 +5,8 @@ #define MAX_PCKT_LENGTH 65535 #define MAX_FILTERS 50 +#define MAX_CPUS 128 +#define LRU_MAP_SIZE 16384 struct tcpopts { @@ -84,6 +86,12 @@ struct filter unsigned int do_tos : 1; int8_t tos; + unsigned int do_pps : 1; + uint64_t pps; + + unsigned int do_bps : 1; + uint64_t bps; + uint8_t payloadMatch[MAX_PCKT_LENGTH]; uint16_t payloadLen; @@ -98,5 +106,11 @@ struct xdpfw_stats uint64_t blocked; }; +struct xdpfw_ip_stats +{ + uint64_t pps; + uint64_t bps; + uint64_t tracking; +}; #endif \ No newline at end of file diff --git a/src/xdpfw_kern.c b/src/xdpfw_kern.c index 6c1ce1c..fdc6dcd 100644 --- a/src/xdpfw_kern.c +++ b/src/xdpfw_kern.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -6,15 +5,17 @@ #include #include #include - -#include "../libbpf/src/bpf_helpers.h" - #include #include +#include +#include + +#include "../libbpf/src/bpf_helpers.h" + #include "include/xdpfw.h" -//#define DEBUG +#define DEBUG #ifdef DEBUG @@ -27,7 +28,6 @@ #endif -#define SEC(NAME) __attribute__((section(NAME), used)) #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ @@ -58,6 +58,14 @@ struct bpf_map_def SEC("maps") stats_map = .max_entries = 1 }; +struct bpf_map_def SEC("maps") ip_stats_map = +{ + .type = BPF_MAP_TYPE_PERCPU_HASH, + .key_size = sizeof(uint32_t), + .value_size = sizeof(struct xdpfw_ip_stats), + .max_entries = LRU_MAP_SIZE +}; + SEC("xdp_prog") int xdp_prog_main(struct xdp_md *ctx) { @@ -105,6 +113,44 @@ int xdp_prog_main(struct xdp_md *ctx) return XDP_PASS; } + // Update IP stats (PPS/BPS). + uint64_t pps = 0; + uint64_t bps = 0; + uint64_t now = bpf_ktime_get_ns(); + + struct xdpfw_ip_stats *ip_stats = bpf_map_lookup_elem(&ip_stats_map, &iph->saddr); + + if (ip_stats) + { + // Check for reset. + if ((now - ip_stats->tracking) > 1e9) + { + ip_stats->pps = 0; + ip_stats->bps = 0; + ip_stats->tracking = now; + } + + ip_stats->pps++; + ip_stats->bps += ctx->data_end - ctx->data; + + pps = ip_stats->pps; + bps = ip_stats->bps; + } + else + { + // Create new entry. + struct xdpfw_ip_stats new; + + new.pps = 1; + new.bps = ctx->data_end - ctx->data; + new.tracking = now; + + pps = new.pps; + bps = new.bps; + + bpf_map_update_elem(&ip_stats_map, &iph->saddr, &new, BPF_ANY); + } + struct tcphdr *tcph; struct udphdr *udph; struct icmphdr *icmph; @@ -211,24 +257,40 @@ int xdp_prog_main(struct xdp_md *ctx) continue; } + // PPS. + if (filter[i]->do_pps && pps <= filter[i]->pps) + { + continue; + } + + // BPS. + if (filter[i]->do_bps && bps <= filter[i]->bps) + { + continue; + } + // Payload match. /* if (filter[i]->payloadLen > 0) { uint8_t found = 1; - uint16_t len = filter[i]->payloadLen; // Initialize packet data. - uint8_t *pcktData = (data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4headerLen); - - if (pcktData + len > (uint8_t *)data_end) + for (uint16_t j = 0; j < MAX_PCKT_LENGTH; j++) { - continue; - } + if ((j + 1) > filter[i]->payloadLen) + { + break; + } - for (uint16_t j = 0; j < filter[i]->payloadLen; j++) - { - if ((*pcktData++) == filter[i]->payloadMatch[j]) + uint8_t *byte = (data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4headerLen + j); + + if (byte + 1 > (uint8_t *)data_end) + { + break; + } + + if (*byte == filter[i]->payloadMatch[j]) { continue; } @@ -341,7 +403,7 @@ int xdp_prog_main(struct xdp_md *ctx) // Matched. #ifdef DEBUG - bpf_printk("Matched rule ID #%" PRIu8 "\n", filter[i]->id); + bpf_printk("Matched rule ID #%" PRIu8 ".\n", filter[i]->id); #endif matched = 1; @@ -376,7 +438,7 @@ int xdp_prog_main(struct xdp_md *ctx) } #ifdef DEBUG - bpf_printk("Matched with protocol %" PRIu8 " and sAddr %" PRIu32 "\n", iph->protocol, iph->saddr); + //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 bba4422..8d21d40 100644 --- a/src/xdpfw_loader.c +++ b/src/xdpfw_loader.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -330,7 +331,9 @@ int main(int argc, char *argv[]) fprintf(stdout, "Min Length => %" PRIu16 "\n", conf->filters[i].min_len); fprintf(stdout, "Max TTL => %" PRIu8 "\n", conf->filters[i].max_ttl); fprintf(stdout, "Min TTL => %" PRIu8 "\n", conf->filters[i].min_ttl); - fprintf(stdout, "TOS => %" PRIu8 "\n\n", conf->filters[i].tos); + fprintf(stdout, "TOS => %" PRIu8 "\n", conf->filters[i].tos); + fprintf(stdout, "PPS => %" PRIu64 "\n", conf->filters[i].pps); + fprintf(stdout, "BPS => %" PRIu64 "\n\n", conf->filters[i].bps); // TCP Options. fprintf(stdout, "TCP Enabled => %" PRIu8 "\n", conf->filters[i].tcpopts.enabled);