From 8596997b98eaef656cc21fabca3a0f8201dd4b79 Mon Sep 17 00:00:00 2001 From: Christian Deacon Date: Wed, 26 Feb 2025 11:13:59 -0500 Subject: [PATCH] Add filter logging. --- README.md | 6 +- src/common/config.h | 6 +- src/common/types.h | 15 +- src/loader/prog.c | 30 ++++ src/loader/utils/config.c | 297 +++++++++++++++++++------------------ src/loader/utils/config.h | 6 +- src/loader/utils/logging.c | 34 +++++ src/loader/utils/logging.h | 5 +- src/xdp/prog.c | 28 ++++ src/xdp/utils/maps.h | 10 +- 10 files changed, 285 insertions(+), 152 deletions(-) diff --git a/README.md b/README.md index 082815c..f33aeb7 100644 --- a/README.md +++ b/README.md @@ -129,8 +129,10 @@ The following table quickly explains the data types used within the configuratio ### Filter Object | Name | Type | Default | Description | | ---- | ---- | ------- | ----------- | -| enabled | bool | `false` | Whether the rule is enabled or not. | -| action | uint | `0` | The value of `0` drops or blocks the packet while `1` allows/passes the packet through. | +| enabled | bool | `true` | Whether the rule is enabled or not. | + +| action | uint | `1` | The value of `0` drops or blocks the packet while `1` allows/passes the packet through. | +| log | bool | `false` | Whether to log packets that are matched. | | block_time | uint | `1` | The amount of seconds to block the source IP for if matched. | | src_ip | string | `NULL` | The source IPv4 address to match (e.g. `10.50.0.3`). CIDRs are also supported (e.g. `10.50.0.0/24`)! | | dst_ip | string | `NULL` | The destination IPv4 address to match (e.g. `10.50.0.4`). CIDRs are also supported (e.g. `10.50.0.0/24`)! | diff --git a/src/common/config.h b/src/common/config.h index 0140b41..e5bd1d3 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -20,4 +20,8 @@ // If uncommented, rate limits for clients are determined using the source IP, port, and protocol instead of just the source IP. // This allows for more precise rate limits (connection-specific instead of a single source IP). // I decided not to include the destination IP/port because the source IP, port, and protocol should be represent a unique connection. -#define USE_FLOW_RL \ No newline at end of file +#define USE_FLOW_RL + +// Enables filter logging through XDP. +// If performance is a concerned, it is best to disable this feature by commenting out the below line with //. +#define ENABLE_FILTER_LOGGING \ No newline at end of file diff --git a/src/common/types.h b/src/common/types.h index da727ee..00a6e72 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -64,6 +64,8 @@ struct filter { u8 id; + unsigned int log : 1; + unsigned int enabled : 1; u8 action; @@ -131,4 +133,15 @@ struct flow6 u128 ip; u16 port; u8 protocol; -} typedef flow6_t; \ No newline at end of file +} typedef flow6_t; + +struct filter_log_event +{ + u64 ts; + int filter_id; + u32 src_ip; + u32 src_ip6[4]; + u16 src_port; + u64 pps; + u64 bps; +} typedef filter_log_event_t; \ No newline at end of file diff --git a/src/loader/prog.c b/src/loader/prog.c index f1eac1e..4f4e055 100644 --- a/src/loader/prog.c +++ b/src/loader/prog.c @@ -136,6 +136,22 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } +#ifdef ENABLE_FILTER_LOGGING + int filter_log_map = FindMapFd(prog, "filter_log_map"); + struct ring_buffer* rb = NULL; + + if (filter_log_map < 0) + { + LogMsg(&cfg, 1, 0, "[WARNING] Failed to find 'filter_log_map' BPF map. Filter logging will be disabled..."); + } + else + { + LogMsg(&cfg, 3, 0, "filter_log_map FD => %d.", filter_log_map); + + rb = ring_buffer__new(filter_log_map, HandleRbEvent, &cfg, NULL); + } +#endif + LogMsg(&cfg, 3, 0, "stats_map FD => %d.", stats_map); LogMsg(&cfg, 2, 0, "Updating filters..."); @@ -208,11 +224,25 @@ int main(int argc, char *argv[]) } } +#ifdef ENABLE_FILTER_LOGGING + if (rb) + { + ring_buffer__poll(rb, RB_TIMEOUT); + } +#endif + usleep(sleep_time); } fprintf(stdout, "\n"); +#ifdef ENABLE_FILTER_LOGGING + if (rb) + { + ring_buffer__free(rb); + } +#endif + // Detach XDP program. if (AttachXdp(prog, &mode_used, ifidx, 1, &cmd)) { diff --git a/src/loader/utils/config.c b/src/loader/utils/config.c index cab0bb3..83a0ff3 100644 --- a/src/loader/utils/config.c +++ b/src/loader/utils/config.c @@ -1,7 +1,5 @@ #include -#include - static FILE *file; /** @@ -55,60 +53,62 @@ void SetCfgDefaults(config__t *cfg) for (int i = 0; i < MAX_FILTERS; i++) { - cfg->filters[i].id = 0; - cfg->filters[i].enabled = 0; - cfg->filters[i].action = 0; - cfg->filters[i].src_ip = 0; - cfg->filters[i].dst_ip = 0; + filter_t* filter = &cfg->filters[i]; - for (int j = 0; j < 4; j++) - { - cfg->filters[i].src_ip6[j] = 0; - cfg->filters[i].dst_ip6[j] = 0; - } + filter->id = 0; + filter->enabled = 1; - cfg->filters[i].do_min_len = 0; - cfg->filters[i].min_len = 0; + filter->log = 0; - cfg->filters[i].do_max_len = 0; - cfg->filters[i].max_len = 65535; + filter->action = 1; + filter->src_ip = 0; + filter->dst_ip = 0; - cfg->filters[i].do_min_ttl = 0; - cfg->filters[i].min_ttl = 0; + memset(filter->src_ip6, 0, 4); + memset(filter->dst_ip6, 0, 4); - cfg->filters[i].do_max_ttl = 0; - cfg->filters[i].max_ttl = 255; + filter->do_min_len = 0; + filter->min_len = 0; - cfg->filters[i].do_tos = 0; - cfg->filters[i].tos = 0; + filter->do_max_len = 0; + filter->max_len = 65535; - cfg->filters[i].do_pps = 0; - cfg->filters[i].pps = 0; + 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; - cfg->filters[i].do_bps = 0; - cfg->filters[i].bps = 0; + filter->do_bps = 0; + filter->bps = 0; - cfg->filters[i].blocktime = 1; + filter->blocktime = 1; - cfg->filters[i].tcpopts.enabled = 0; - cfg->filters[i].tcpopts.do_dport = 0; - cfg->filters[i].tcpopts.do_dport = 0; - cfg->filters[i].tcpopts.do_urg = 0; - cfg->filters[i].tcpopts.do_ack = 0; - cfg->filters[i].tcpopts.do_rst = 0; - cfg->filters[i].tcpopts.do_psh = 0; - cfg->filters[i].tcpopts.do_syn = 0; - cfg->filters[i].tcpopts.do_fin = 0; - cfg->filters[i].tcpopts.do_ece = 0; - cfg->filters[i].tcpopts.do_cwr = 0; + 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; - cfg->filters[i].udpopts.enabled = 0; - cfg->filters[i].udpopts.do_sport = 0; - cfg->filters[i].udpopts.do_dport = 0; + filter->udpopts.enabled = 0; + filter->udpopts.do_sport = 0; + filter->udpopts.do_dport = 0; - cfg->filters[i].icmpopts.enabled = 0; - cfg->filters[i].icmpopts.do_code = 0; - cfg->filters[i].icmpopts.do_type = 0; + filter->icmpopts.enabled = 0; + filter->icmpopts.do_code = 0; + filter->icmpopts.do_type = 0; } } @@ -163,7 +163,7 @@ int ReadCfg(config__t *cfg) // 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)); + LogMsg(cfg, 0, 1, "Error from LibConfig when reading file - %s (Line %d)", config_error_text(&conf), config_error_line(&conf)); config_destroy(&conf); @@ -204,7 +204,7 @@ int ReadCfg(config__t *cfg) if (!config_lookup_string(&conf, "interface", &interface)) { - fprintf(stderr, "Error from LibConfig when reading 'interface' setting - %s\n\n", config_error_text(&conf)); + LogMsg(cfg, 0, 1, "Error from LibConfig when reading 'interface' setting - %s", config_error_text(&conf)); config_destroy(&conf); @@ -243,7 +243,7 @@ int ReadCfg(config__t *cfg) // 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)); + LogMsg(cfg, 0, 1, "Error from LibConfig when reading 'filters' array - %s.", config_error_text(&conf)); config_destroy(&conf); @@ -255,312 +255,318 @@ int ReadCfg(config__t *cfg) for (int i = 0; i < config_setting_length(setting); i++) { - config_setting_t* filter = config_setting_get_elem(setting, i); + filter_t* filter = &cfg->filters[i]; + + 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, "enabled", &enabled) == CONFIG_FALSE) + if (config_setting_lookup_bool(filter_cfg, "enabled", &enabled) == CONFIG_TRUE) { - // 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; + filter->enabled = enabled; } - cfg->filters[i].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, "action", &action) == CONFIG_FALSE) + if (config_setting_lookup_int(filter_cfg, "action", &action) == CONFIG_TRUE) { - 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; + filter->action = action; } - cfg->filters[i].action = action; - // Source IP (not required). const char *sip; - if (config_setting_lookup_string(filter, "src_ip", &sip)) + if (config_setting_lookup_string(filter_cfg, "src_ip", &sip) == CONFIG_TRUE) { ip_range_t ip = ParseIpCidr(sip); - cfg->filters[i].src_ip = ip.ip; - cfg->filters[i].src_cidr = ip.cidr; + filter->src_ip = ip.ip; + filter->src_cidr = ip.cidr; } // Destination IP (not required). const char *dip; - if (config_setting_lookup_string(filter, "dst_ip", &dip)) + if (config_setting_lookup_string(filter_cfg, "dst_ip", &dip) == CONFIG_TRUE) { ip_range_t ip = ParseIpCidr(dip); - cfg->filters[i].dst_ip = ip.ip; - cfg->filters[i].dst_cidr = ip.cidr; + filter->dst_ip = ip.ip; + filter->dst_cidr = ip.cidr; } // Source IP (IPv6) (not required). const char *sip6; - if (config_setting_lookup_string(filter, "src_ip6", &sip6)) + if (config_setting_lookup_string(filter_cfg, "src_ip6", &sip6) == CONFIG_TRUE) { struct in6_addr in; inet_pton(AF_INET6, sip6, &in); - memcpy(cfg->filters[i].src_ip6, in.__in6_u.__u6_addr32, 4); + memcpy(filter->src_ip6, in.__in6_u.__u6_addr32, 4); } // Destination IP (IPv6) (not required). const char *dip6; - if (config_setting_lookup_string(filter, "dst_ip6", &dip6)) + if (config_setting_lookup_string(filter_cfg, "dst_ip6", &dip6) == CONFIG_TRUE) { struct in6_addr in; inet_pton(AF_INET6, dip6, &in); - memcpy(cfg->filters[i].dst_ip6, in.__in6_u.__u6_addr32, 4); + memcpy(filter->dst_ip6, in.__in6_u.__u6_addr32, 4); } // Minimum TTL (not required). int min_ttl; - if (config_setting_lookup_int(filter, "min_ttl", &min_ttl)) + if (config_setting_lookup_int(filter_cfg, "min_ttl", &min_ttl) == CONFIG_TRUE) { - cfg->filters[i].min_ttl = (u8)min_ttl; - cfg->filters[i].do_min_ttl = 1; + filter->min_ttl = (u8)min_ttl; + filter->do_min_ttl = 1; } // Maximum TTL (not required). int max_ttl; - if (config_setting_lookup_int(filter, "max_ttl", &max_ttl)) + if (config_setting_lookup_int(filter_cfg, "max_ttl", &max_ttl) == CONFIG_TRUE) { - cfg->filters[i].max_ttl = (u8)max_ttl; - cfg->filters[i].do_max_ttl = 1; + filter->max_ttl = (u8)max_ttl; + filter->do_max_ttl = 1; } // Minimum length (not required). int min_len; - if (config_setting_lookup_int(filter, "min_len", &min_len)) + if (config_setting_lookup_int(filter_cfg, "min_len", &min_len) == CONFIG_TRUE) { - cfg->filters[i].min_len = min_len; - cfg->filters[i].do_min_len = 1; + filter->min_len = min_len; + filter->do_min_len = 1; } // Maximum length (not required). int max_len; - if (config_setting_lookup_int(filter, "max_len", &max_len)) + if (config_setting_lookup_int(filter_cfg, "max_len", &max_len) == CONFIG_TRUE) { - cfg->filters[i].max_len = max_len; - cfg->filters[i].do_max_len = 1; + filter->max_len = max_len; + filter->do_max_len = 1; } // TOS (not required). int tos; - if (config_setting_lookup_int(filter, "tos", &tos)) + if (config_setting_lookup_int(filter_cfg, "tos", &tos) == CONFIG_TRUE) { - cfg->filters[i].tos = (u8)tos; - cfg->filters[i].do_tos = 1; + filter->tos = (u8)tos; + filter->do_tos = 1; } // PPS (not required). long long pps; - if (config_setting_lookup_int64(filter, "pps", &pps)) + if (config_setting_lookup_int64(filter_cfg, "pps", &pps) == CONFIG_TRUE) { - cfg->filters[i].pps = pps; - cfg->filters[i].do_pps = 1; + filter->pps = pps; + filter->do_pps = 1; } // BPS (not required). long long bps; - if (config_setting_lookup_int64(filter, "bps", &bps)) + if (config_setting_lookup_int64(filter_cfg, "bps", &bps) == CONFIG_TRUE) { - cfg->filters[i].bps = bps; - cfg->filters[i].do_bps = 1; + filter->bps = bps; + filter->do_bps = 1; } // Block time (default 1). long long blocktime; - if (config_setting_lookup_int64(filter, "block_time", &blocktime)) + if (config_setting_lookup_int64(filter_cfg, "block_time", &blocktime) == CONFIG_TRUE) { - cfg->filters[i].blocktime = blocktime; + filter->blocktime = blocktime; } else { - cfg->filters[i].blocktime = 1; + filter->blocktime = 1; } /* TCP options */ // Enabled. int tcpenabled; - if (config_setting_lookup_bool(filter, "tcp_enabled", &tcpenabled)) + if (config_setting_lookup_bool(filter_cfg, "tcp_enabled", &tcpenabled) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.enabled = tcpenabled; + filter->tcpopts.enabled = tcpenabled; } // Source port. long long tcpsport; - if (config_setting_lookup_int64(filter, "tcp_sport", &tcpsport)) + if (config_setting_lookup_int64(filter_cfg, "tcp_sport", &tcpsport) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.sport = (u16)tcpsport; - cfg->filters[i].tcpopts.do_sport = 1; + filter->tcpopts.sport = (u16)tcpsport; + filter->tcpopts.do_sport = 1; } // Destination port. long long tcpdport; - if (config_setting_lookup_int64(filter, "tcp_dport", &tcpdport)) + if (config_setting_lookup_int64(filter_cfg, "tcp_dport", &tcpdport) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.dport = (u16)tcpdport; - cfg->filters[i].tcpopts.do_dport = 1; + filter->tcpopts.dport = (u16)tcpdport; + filter->tcpopts.do_dport = 1; } // URG flag. int tcpurg; - if (config_setting_lookup_bool(filter, "tcp_urg", &tcpurg)) + if (config_setting_lookup_bool(filter_cfg, "tcp_urg", &tcpurg) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.urg = tcpurg; - cfg->filters[i].tcpopts.do_urg = 1; + filter->tcpopts.urg = tcpurg; + filter->tcpopts.do_urg = 1; } // ACK flag. int tcpack; - if (config_setting_lookup_bool(filter, "tcp_ack", &tcpack)) + if (config_setting_lookup_bool(filter_cfg, "tcp_ack", &tcpack) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.ack = tcpack; - cfg->filters[i].tcpopts.do_ack = 1; + filter->tcpopts.ack = tcpack; + filter->tcpopts.do_ack = 1; } // RST flag. int tcprst; - if (config_setting_lookup_bool(filter, "tcp_rst", &tcprst)) + if (config_setting_lookup_bool(filter_cfg, "tcp_rst", &tcprst) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.rst = tcprst; - cfg->filters[i].tcpopts.do_rst = 1; + filter->tcpopts.rst = tcprst; + filter->tcpopts.do_rst = 1; } // PSH flag. int tcppsh; - if (config_setting_lookup_bool(filter, "tcp_psh", &tcppsh)) + if (config_setting_lookup_bool(filter_cfg, "tcp_psh", &tcppsh) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.psh = tcppsh; - cfg->filters[i].tcpopts.do_psh = 1; + filter->tcpopts.psh = tcppsh; + filter->tcpopts.do_psh = 1; } // SYN flag. int tcpsyn; - if (config_setting_lookup_bool(filter, "tcp_syn", &tcpsyn)) + if (config_setting_lookup_bool(filter_cfg, "tcp_syn", &tcpsyn) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.syn = tcpsyn; - cfg->filters[i].tcpopts.do_syn = 1; + filter->tcpopts.syn = tcpsyn; + filter->tcpopts.do_syn = 1; } // FIN flag. int tcpfin; - if (config_setting_lookup_bool(filter, "tcp_fin", &tcpfin)) + if (config_setting_lookup_bool(filter_cfg, "tcp_fin", &tcpfin) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.fin = tcpfin; - cfg->filters[i].tcpopts.do_fin = 1; + filter->tcpopts.fin = tcpfin; + filter->tcpopts.do_fin = 1; } // ECE flag. int tcpece; - if (config_setting_lookup_bool(filter, "tcp_ece", &tcpece)) + if (config_setting_lookup_bool(filter_cfg, "tcp_ece", &tcpece) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.ece = tcpece; - cfg->filters[i].tcpopts.do_ece = 1; + filter->tcpopts.ece = tcpece; + filter->tcpopts.do_ece = 1; } // CWR flag. int tcpcwr; - if (config_setting_lookup_bool(filter, "tcp_cwr", &tcpcwr)) + if (config_setting_lookup_bool(filter_cfg, "tcp_cwr", &tcpcwr) == CONFIG_TRUE) { - cfg->filters[i].tcpopts.cwr = tcpcwr; - cfg->filters[i].tcpopts.do_cwr = 1; + filter->tcpopts.cwr = tcpcwr; + filter->tcpopts.do_cwr = 1; } /* UDP options */ // Enabled. int udpenabled; - if (config_setting_lookup_bool(filter, "udp_enabled", &udpenabled)) + if (config_setting_lookup_bool(filter_cfg, "udp_enabled", &udpenabled) == CONFIG_TRUE) { - cfg->filters[i].udpopts.enabled = udpenabled; + filter->udpopts.enabled = udpenabled; } // Source port. long long udpsport; - if (config_setting_lookup_int64(filter, "udp_sport", &udpsport)) + if (config_setting_lookup_int64(filter_cfg, "udp_sport", &udpsport) == CONFIG_TRUE) { - cfg->filters[i].udpopts.sport = (u16)udpsport; - cfg->filters[i].udpopts.do_sport = 1; + filter->udpopts.sport = (u16)udpsport; + filter->udpopts.do_sport = 1; } // Destination port. long long udpdport; - if (config_setting_lookup_int64(filter, "udp_dport", &udpdport)) + if (config_setting_lookup_int64(filter_cfg, "udp_dport", &udpdport) == CONFIG_TRUE) { - cfg->filters[i].udpopts.dport = (u16)udpdport; - cfg->filters[i].udpopts.do_dport = 1; + filter->udpopts.dport = (u16)udpdport; + filter->udpopts.do_dport = 1; } /* ICMP options */ // Enabled. int icmpenabled; - if (config_setting_lookup_bool(filter, "icmp_enabled", &icmpenabled)) + if (config_setting_lookup_bool(filter_cfg, "icmp_enabled", &icmpenabled) == CONFIG_TRUE) { - cfg->filters[i].icmpopts.enabled = icmpenabled; + filter->icmpopts.enabled = icmpenabled; } // ICMP code. int icmpcode; - if (config_setting_lookup_int(filter, "icmp_code", &icmpcode)) + if (config_setting_lookup_int(filter_cfg, "icmp_code", &icmpcode) == CONFIG_TRUE) { - cfg->filters[i].icmpopts.code = (u8)icmpcode; - cfg->filters[i].icmpopts.do_code = 1; + filter->icmpopts.code = (u8)icmpcode; + filter->icmpopts.do_code = 1; } // ICMP type. int icmptype; - if (config_setting_lookup_int(filter, "icmp_type", &icmptype)) + if (config_setting_lookup_int(filter_cfg, "icmp_type", &icmptype) == CONFIG_TRUE) { - cfg->filters[i].icmpopts.type = (u8)icmptype; - cfg->filters[i].icmpopts.do_type = 1; + filter->icmpopts.type = (u8)icmptype; + filter->icmpopts.do_type = 1; } // Assign ID and increase filter count. - cfg->filters[i].id = ++filters; + filter->id = ++filters; } config_destroy(&conf); @@ -599,6 +605,7 @@ void PrintConfig(config__t* cfg) // Main. fprintf(stdout, "\t\t\tID => %d\n", filter->id); + fprintf(stdout, "\t\t\tLog => %d\n", filter->log); fprintf(stdout, "\t\t\tEnabled => %d\n", filter->enabled); fprintf(stdout, "\t\t\tAction => %d (0 = Block, 1 = Allow).\n\n", filter->action); diff --git a/src/loader/utils/config.h b/src/loader/utils/config.h index 174b9b0..6b4ba6c 100644 --- a/src/loader/utils/config.h +++ b/src/loader/utils/config.h @@ -9,6 +9,8 @@ #include +#include + #define CONFIG_DEFAULT_PATH "/etc/xdpfw/xdpfw.conf" struct config @@ -27,4 +29,6 @@ void SetCfgDefaults(config__t *cfg); void PrintConfig(config__t* cfg); int OpenCfg(const char *filename); -int ReadCfg(config__t *cfg); \ No newline at end of file +int ReadCfg(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 d45cafe..aa51ab9 100644 --- a/src/loader/utils/logging.c +++ b/src/loader/utils/logging.c @@ -93,4 +93,38 @@ void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...) LogMsgRaw(req_lvl, cfg->verbose, error, (const char*)cfg->log_file, msg, args); va_end(args); +} + +int HandleRbEvent(void* ctx, void* data, size_t sz) +{ + config__t* cfg = (config__t*)ctx; + filter_log_event_t* e = (filter_log_event_t*)data; + + filter_t* filter = &cfg->filters[e->filter_id]; + + if (filter == NULL) + { + return 1; + } + + char 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) + { + inet_ntop(AF_INET6, e->src_ip6, ip_str, sizeof(ip_str)); + } else + { + inet_ntop(AF_INET, &e->src_ip, ip_str, sizeof(ip_str)); + } + + char* action = "Dropped"; + + if (filter->action == 1) + { + action = "Passed"; + } + + LogMsg(cfg, 0, 0, "[FILTER %d] %s packet from '%s:%d' (PPS => %llu, BPS => %llu, Filter Block Time => %llu)...", e->filter_id, action, ip_str, e->src_port, e->pps, e->bps, filter->blocktime); + + return 0; } \ No newline at end of file diff --git a/src/loader/utils/logging.h b/src/loader/utils/logging.h index 9047191..d3dd611 100644 --- a/src/loader/utils/logging.h +++ b/src/loader/utils/logging.h @@ -12,4 +12,7 @@ #include -void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...); \ No newline at end of file +#define RB_TIMEOUT 100 + +void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...); +int HandleRbEvent(void* ctx, void* data, size_t sz); \ No newline at end of file diff --git a/src/xdp/prog.c b/src/xdp/prog.c index 4542a82..c8f7e9c 100644 --- a/src/xdp/prog.c +++ b/src/xdp/prog.c @@ -513,6 +513,34 @@ int xdp_prog_main(struct xdp_md *ctx) continue; } } + +#ifdef ENABLE_FILTER_LOGGING + if (filter->log > 0) + { + filter_log_event_t* e = bpf_ringbuf_reserve(&filter_log_map, sizeof(*e), 0); + + if (e) + { + e->ts = now; + e->filter_id = i; + + if (iph) + { + e->src_ip = iph->saddr; + } else if (iph6) + { + memcpy(&e->src_ip6, iph6->saddr.in6_u.u6_addr32, 4); + } + + e->src_port = src_port; + + e->pps = pps; + e->bps = bps; + + bpf_ringbuf_submit(e, 0); + } + } +#endif // Matched. action = filter->action; diff --git a/src/xdp/utils/maps.h b/src/xdp/utils/maps.h index c5478ba..fdb5475 100644 --- a/src/xdp/utils/maps.h +++ b/src/xdp/utils/maps.h @@ -59,4 +59,12 @@ struct __uint(max_entries, MAX_TRACK_IPS); __type(key, u128); __type(value, u64); -} ip6_blacklist_map SEC(".maps"); \ No newline at end of file +} ip6_blacklist_map SEC(".maps"); + +#ifdef ENABLE_FILTER_LOGGING +struct +{ + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 1 << 16); +} filter_log_map SEC(".maps"); +#endif \ No newline at end of file