Merge pull request #59 from gamemann/20250226-logging
Logging System Overhaul
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
xdpfw
|
xdpfw
|
||||||
xdpfw.s
|
xdpfw.s
|
||||||
xdpfw.conf
|
xdpfw.conf
|
||||||
|
*.log
|
||||||
13
Makefile
13
Makefile
@@ -13,6 +13,7 @@ LOADER_DIR = $(SRC_DIR)/loader
|
|||||||
XDP_DIR = $(SRC_DIR)/xdp
|
XDP_DIR = $(SRC_DIR)/xdp
|
||||||
|
|
||||||
ETC_DIR = /etc/xdpfw
|
ETC_DIR = /etc/xdpfw
|
||||||
|
LOG_DIR = /var/log/xdpfw
|
||||||
|
|
||||||
# Additional build directories.
|
# Additional build directories.
|
||||||
BUILD_LOADER_DIR = $(BUILD_DIR)/loader
|
BUILD_LOADER_DIR = $(BUILD_DIR)/loader
|
||||||
@@ -52,6 +53,9 @@ LOADER_UTILS_CMDLINE_OBJ = cmdline.o
|
|||||||
LOADER_UTILS_XDP_SRC = xdp.c
|
LOADER_UTILS_XDP_SRC = xdp.c
|
||||||
LOADER_UTILS_XDP_OBJ = xdp.o
|
LOADER_UTILS_XDP_OBJ = xdp.o
|
||||||
|
|
||||||
|
LOADER_UTILS_LOGGING_SRC = logging.c
|
||||||
|
LOADER_UTILS_LOGGING_OBJ = logging.o
|
||||||
|
|
||||||
LOADER_UTILS_STATS_SRC = stats.c
|
LOADER_UTILS_STATS_SRC = stats.c
|
||||||
LOADER_UTILS_STATS_OBJ = stats.o
|
LOADER_UTILS_STATS_OBJ = stats.o
|
||||||
|
|
||||||
@@ -59,7 +63,7 @@ LOADER_UTILS_HELPERS_SRC = helpers.c
|
|||||||
LOADER_UTILS_HELPERS_OBJ = helpers.o
|
LOADER_UTILS_HELPERS_OBJ = helpers.o
|
||||||
|
|
||||||
# Loader objects.
|
# Loader objects.
|
||||||
LOADER_OBJS = $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CMDLINE_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_XDP_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_STATS_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_HELPERS_OBJ)
|
LOADER_OBJS = $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CMDLINE_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_XDP_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_LOGGING_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_STATS_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_HELPERS_OBJ)
|
||||||
|
|
||||||
ifeq ($(LIBXDP_STATIC), 1)
|
ifeq ($(LIBXDP_STATIC), 1)
|
||||||
LOADER_OBJS := $(LIBBPF_OBJS) $(LIBXDP_OBJS) $(LOADER_OBJS)
|
LOADER_OBJS := $(LIBBPF_OBJS) $(LIBXDP_OBJS) $(LOADER_OBJS)
|
||||||
@@ -93,7 +97,7 @@ all: loader xdp
|
|||||||
loader: loader_utils
|
loader: loader_utils
|
||||||
$(CC) $(INCS) $(FLAGS) $(FLAGS_LOADER) -o $(BUILD_LOADER_DIR)/$(LOADER_OUT) $(LOADER_OBJS) $(LOADER_DIR)/$(LOADER_SRC)
|
$(CC) $(INCS) $(FLAGS) $(FLAGS_LOADER) -o $(BUILD_LOADER_DIR)/$(LOADER_OUT) $(LOADER_OBJS) $(LOADER_DIR)/$(LOADER_SRC)
|
||||||
|
|
||||||
loader_utils: loader_utils_config loader_utils_cmdline loader_utils_helpers loader_utils_xdp loader_utils_stats
|
loader_utils: loader_utils_config loader_utils_cmdline loader_utils_helpers loader_utils_xdp loader_utils_logging loader_utils_stats
|
||||||
|
|
||||||
loader_utils_config:
|
loader_utils_config:
|
||||||
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_CONFIG_SRC)
|
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_CONFIG_SRC)
|
||||||
@@ -104,6 +108,9 @@ loader_utils_cmdline:
|
|||||||
loader_utils_xdp:
|
loader_utils_xdp:
|
||||||
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_XDP_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_XDP_SRC)
|
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_XDP_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_XDP_SRC)
|
||||||
|
|
||||||
|
loader_utils_logging:
|
||||||
|
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_LOGGING_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_LOGGING_SRC)
|
||||||
|
|
||||||
loader_utils_stats:
|
loader_utils_stats:
|
||||||
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_STATS_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_STATS_SRC)
|
$(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_STATS_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_STATS_SRC)
|
||||||
|
|
||||||
@@ -128,6 +135,8 @@ libxdp_clean:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
mkdir -p $(ETC_DIR)
|
mkdir -p $(ETC_DIR)
|
||||||
|
mkdir -p $(LOG_DIR)
|
||||||
|
|
||||||
cp -n xdpfw.conf.example $(ETC_DIR)/xdpfw.conf
|
cp -n xdpfw.conf.example $(ETC_DIR)/xdpfw.conf
|
||||||
|
|
||||||
cp -n other/xdpfw.service /etc/systemd/system/
|
cp -n other/xdpfw.service /etc/systemd/system/
|
||||||
|
|||||||
31
README.md
31
README.md
@@ -12,7 +12,7 @@ With that said, reasons for a host's network configuration not supporting XDP's
|
|||||||
|
|
||||||
I hope this project helps existing network engineers/programmers interested in utilizing XDP or anybody interested in getting into those fields! (D)DoS mitigation/prevention is such an important part of Cyber Security and understanding the concept of networking and packet flow on a low-medium level would certainly help those who are pursuing a career in the field 🙂
|
I hope this project helps existing network engineers/programmers interested in utilizing XDP or anybody interested in getting into those fields! (D)DoS mitigation/prevention is such an important part of Cyber Security and understanding the concept of networking and packet flow on a low-medium level would certainly help those who are pursuing a career in the field 🙂
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Building & Installing
|
## Building & Installing
|
||||||
Before building, ensure the following packages are installed. These packages can be installed with `apt` on Debian-based systems (e.g. Ubuntu, etc.), but there should be similar package names in other package managers.
|
Before building, ensure the following packages are installed. These packages can be installed with `apt` on Debian-based systems (e.g. Ubuntu, etc.), but there should be similar package names in other package managers.
|
||||||
@@ -59,7 +59,9 @@ Additionally, here is a list of flags you may pass to this script.
|
|||||||
| --no-install | Build the tool and/or LibXDP without installing them. |
|
| --no-install | Build the tool and/or LibXDP without installing them. |
|
||||||
| --clean | Remove build files for the tool and LibXDP. |
|
| --clean | Remove build files for the tool and LibXDP. |
|
||||||
| --no-static | Do *not* statically link LibXDP and LibBPF object files when building the tool. This makes the build process faster, but you may need to alter your `LD_LIBRARY_PATH` env variable before running the tool and requires LibXDP to be installed on your system already. |
|
| --no-static | Do *not* statically link LibXDP and LibBPF object files when building the tool. This makes the build process faster, but you may need to alter your `LD_LIBRARY_PATH` env variable before running the tool and requires LibXDP to be installed on your system already. |
|
||||||
| --help | Displays help message. |
|
| --help | Displays help message. |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### Without Bash Script
|
### Without Bash Script
|
||||||
If you do not want to use the Bash script above, you may use `make` to build and install this tool instead.
|
If you do not want to use the Bash script above, you may use `make` to build and install this tool instead.
|
||||||
@@ -80,6 +82,8 @@ make
|
|||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Command Line Usage
|
## Command Line Usage
|
||||||
The following command line arguments are supported.
|
The following command line arguments are supported.
|
||||||
|
|
||||||
@@ -118,6 +122,8 @@ The following table quickly explains the data types used within the configuratio
|
|||||||
### Main
|
### Main
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ---- | ---- | ------- | ----------- |
|
| ---- | ---- | ------- | ----------- |
|
||||||
|
| verbose | int | `2` | The verbose level for logging (0 - 5 supported so far). |
|
||||||
|
| log_file | string | `/var/log/xdpfw/xdpfw.log` | The log file location. If the string is empty (`""`), the log file is disabled. |
|
||||||
| interface | string | `NULL` | The network interface name to attach the XDP program to (usually retrieved with `ip a` or `ifconfig`). |
|
| interface | string | `NULL` | The network interface name to attach the XDP program to (usually retrieved with `ip a` or `ifconfig`). |
|
||||||
| update_time | uint | `0` | How often to update the config and filtering rules from the file system in seconds (0 disables). |
|
| update_time | uint | `0` | How often to update the config and filtering rules from the file system in seconds (0 disables). |
|
||||||
| no_stats | bool | `false` | Whether to enable or disable packet counters. Disabling packet counters will improve performance, but result in less visibility on what the XDP Firewall is doing. |
|
| no_stats | bool | `false` | Whether to enable or disable packet counters. Disabling packet counters will improve performance, but result in less visibility on what the XDP Firewall is doing. |
|
||||||
@@ -127,8 +133,9 @@ The following table quickly explains the data types used within the configuratio
|
|||||||
### Filter Object
|
### Filter Object
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ---- | ---- | ------- | ----------- |
|
| ---- | ---- | ------- | ----------- |
|
||||||
| enabled | bool | `false` | Whether the rule is enabled or not. |
|
| enabled | bool | `true` | 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. |
|
| log | bool | `false` | Whether to log packets that are matched. |
|
||||||
|
| action | uint | `1` | The value of `0` drops or blocks the packet while `1` allows/passes the packet through. |
|
||||||
| block_time | uint | `1` | The amount of seconds to block the source IP for if 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`)! |
|
| 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`)! |
|
| 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`)! |
|
||||||
@@ -301,6 +308,22 @@ export LD_LIBRARY_PATH=/usr/local/lib
|
|||||||
sudo xdpfw
|
sudo xdpfw
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Filter Logging
|
||||||
|
This tool uses `bpf_ringbuf_reserve()` and `bpf_ringbuf_submit()` for filter match logging. At this time, there is no rate limit for the amount of log messages that may be sent. Therefore, if you're encountering a spoofed attack that is matching a filter rule with logging enabled, it will cause additional processing and disk load.
|
||||||
|
|
||||||
|
I recommend only enabling filter logging at this time for debugging. If you'd like to disable filter logging entirely (which will improve performance slightly), you may comment out the `ENABLE_FILTER_LOGGING` line [here](https://github.com/gamemann/XDP-Firewall/blob/master/src/common/config.h#L27).
|
||||||
|
|
||||||
|
```C
|
||||||
|
//#define ENABLE_FILTER_LOGGING
|
||||||
|
```
|
||||||
|
|
||||||
|
I will most likely implement functionality to rate limit log messages from XDP in the future.
|
||||||
|
|
||||||
|
### LibBPF Logging
|
||||||
|
When loading the BPF/XDP program through LibXDP/LibBPF, logging is disabled unless if the `verbose` log setting is set to `5` or higher.
|
||||||
|
|
||||||
|
If the tool fails to load or attach the XDP program, it is recommended you set `verbose` to 5 or above so LibXDP outputs specific warnings and errors.
|
||||||
|
|
||||||
## My Other XDP Projects
|
## My Other XDP Projects
|
||||||
I just wanted to share other open source projects I've made which also utilize XDP (or AF_XDP sockets) for those interested. I hope code from these other projects help programmers trying to utilize XDP in their own projects!
|
I just wanted to share other open source projects I've made which also utilize XDP (or AF_XDP sockets) for those interested. I hope code from these other projects help programmers trying to utilize XDP in their own projects!
|
||||||
|
|
||||||
|
|||||||
BIN
images/build_make.gif
Normal file
BIN
images/build_make.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
images/build_script.gif
Normal file
BIN
images/build_script.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
images/demo.gif
BIN
images/demo.gif
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 MiB |
BIN
images/run.gif
Normal file
BIN
images/run.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 482 KiB |
@@ -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.
|
// 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).
|
// 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.
|
// 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
|
#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
|
||||||
@@ -64,6 +64,8 @@ struct filter
|
|||||||
{
|
{
|
||||||
u8 id;
|
u8 id;
|
||||||
|
|
||||||
|
unsigned int log : 1;
|
||||||
|
|
||||||
unsigned int enabled : 1;
|
unsigned int enabled : 1;
|
||||||
|
|
||||||
u8 action;
|
u8 action;
|
||||||
@@ -131,4 +133,25 @@ struct flow6
|
|||||||
u128 ip;
|
u128 ip;
|
||||||
u16 port;
|
u16 port;
|
||||||
u8 protocol;
|
u8 protocol;
|
||||||
} typedef flow6_t;
|
} typedef flow6_t;
|
||||||
|
|
||||||
|
struct filter_log_event
|
||||||
|
{
|
||||||
|
u64 ts;
|
||||||
|
int filter_id;
|
||||||
|
|
||||||
|
u32 src_ip;
|
||||||
|
u32 src_ip6[4];
|
||||||
|
|
||||||
|
u16 src_port;
|
||||||
|
|
||||||
|
u32 dst_ip;
|
||||||
|
u32 dst_ip6[4];
|
||||||
|
|
||||||
|
u16 dst_port;
|
||||||
|
|
||||||
|
u8 protocol;
|
||||||
|
|
||||||
|
u64 pps;
|
||||||
|
u64 bps;
|
||||||
|
} typedef filter_log_event_t;
|
||||||
@@ -14,10 +14,12 @@
|
|||||||
#include <loader/utils/cmdline.h>
|
#include <loader/utils/cmdline.h>
|
||||||
#include <loader/utils/config.h>
|
#include <loader/utils/config.h>
|
||||||
#include <loader/utils/xdp.h>
|
#include <loader/utils/xdp.h>
|
||||||
|
#include <loader/utils/logging.h>
|
||||||
#include <loader/utils/stats.h>
|
#include <loader/utils/stats.h>
|
||||||
#include <loader/utils/helpers.h>
|
#include <loader/utils/helpers.h>
|
||||||
|
|
||||||
int cont = 1;
|
int cont = 1;
|
||||||
|
int doing_stats = 0;
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@@ -37,16 +39,6 @@ int main(int argc, char *argv[])
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raise RLimit.
|
|
||||||
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
|
|
||||||
|
|
||||||
if (setrlimit(RLIMIT_MEMLOCK, &rl))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "[ERROR] Failed to raise rlimit. Please make sure this program is ran as root!\n");
|
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize config.
|
// Initialize config.
|
||||||
config__t cfg = {0};
|
config__t cfg = {0};
|
||||||
|
|
||||||
@@ -68,54 +60,119 @@ int main(int argc, char *argv[])
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print tool info.
|
||||||
|
if (cfg.verbose > 0)
|
||||||
|
{
|
||||||
|
PrintToolInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
LogMsg(&cfg, 2, 0, "Raising RLimit...");
|
||||||
|
|
||||||
|
// Raise RLimit.
|
||||||
|
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
|
||||||
|
|
||||||
|
if (setrlimit(RLIMIT_MEMLOCK, &rl))
|
||||||
|
{
|
||||||
|
LogMsg(&cfg, 0, 1, "[ERROR] Failed to raise rlimit. Please make sure this program is ran as root!\n");
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogMsg(&cfg, 2, 0, "Retrieving interface index for '%s'...", cfg.interface);
|
||||||
|
|
||||||
// Get interface index.
|
// Get interface index.
|
||||||
int ifidx = if_nametoindex(cfg.interface);
|
int ifidx = if_nametoindex(cfg.interface);
|
||||||
|
|
||||||
if (ifidx < 0)
|
if (ifidx < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[ERROR] Failed to retrieve index of network interface '%s'.\n", cfg.interface);
|
LogMsg(&cfg, 0, 1, "[ERROR] Failed to retrieve index of network interface '%s'.\n", cfg.interface);
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogMsg(&cfg, 2, 0, "Loading XDP/BPF program at '%s'...", XDP_OBJ_PATH);
|
||||||
|
|
||||||
|
// Determine custom LibBPF log level.
|
||||||
|
int silent = 1;
|
||||||
|
|
||||||
|
if (cfg.verbose > 4)
|
||||||
|
{
|
||||||
|
silent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetLibBPFLogMode(silent);
|
||||||
|
|
||||||
// Load BPF object.
|
// Load BPF object.
|
||||||
struct xdp_program *prog = LoadBpfObj(XDP_OBJ_PATH);
|
struct xdp_program *prog = LoadBpfObj(XDP_OBJ_PATH);
|
||||||
|
|
||||||
if (prog == NULL)
|
if (prog == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[ERROR] Failed to load eBPF object file. Object path => %s.\n", XDP_OBJ_PATH);
|
LogMsg(&cfg, 0, 1, "[ERROR] Failed to load eBPF object file. Object path => %s.\n", XDP_OBJ_PATH);
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogMsg(&cfg, 2, 0, "Attaching XDP program to interface '%s'...", cfg.interface);
|
||||||
|
|
||||||
// Attach XDP program.
|
// Attach XDP program.
|
||||||
if ((ret = AttachXdp(prog, ifidx, 0, &cmd)) != 0)
|
char *mode_used = NULL;
|
||||||
|
|
||||||
|
if ((ret = AttachXdp(prog, &mode_used, ifidx, 0, &cmd)) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[ERROR] Failed to attach XDP program to interface '%s' (%d).\n", cfg.interface, ret);
|
LogMsg(&cfg, 0, 1, "[ERROR] Failed to attach XDP program to interface '%s' using available modes (%d).\n", cfg.interface, ret);
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode_used != NULL)
|
||||||
|
{
|
||||||
|
LogMsg(&cfg, 1, 0, "Attached XDP program using mode '%s'...", mode_used);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogMsg(&cfg, 2, 0, "Retrieving BPF map FDs...");
|
||||||
|
|
||||||
// Retrieve BPF maps.
|
// Retrieve BPF maps.
|
||||||
int filters_map = FindMapFd(prog, "filters_map");
|
int filters_map = FindMapFd(prog, "filters_map");
|
||||||
|
|
||||||
// Check for valid maps.
|
// Check for valid maps.
|
||||||
if (filters_map < 0)
|
if (filters_map < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[ERROR] Failed to find 'filters_map' BPF map.\n");
|
LogMsg(&cfg, 0, 1, "[ERROR] Failed to find 'filters_map' BPF map.\n");
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogMsg(&cfg, 3, 0, "filters_map FD => %d.", filters_map);
|
||||||
|
|
||||||
int stats_map = FindMapFd(prog, "stats_map");
|
int stats_map = FindMapFd(prog, "stats_map");
|
||||||
|
|
||||||
if (stats_map < 0)
|
if (stats_map < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[ERROR] Failed to find 'stats_map' BPF map.\n");
|
LogMsg(&cfg, 0, 1, "[ERROR] Failed to find 'stats_map' BPF map.\n");
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
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...");
|
||||||
|
|
||||||
// Update BPF maps.
|
// Update BPF maps.
|
||||||
UpdateFilters(filters_map, &cfg);
|
UpdateFilters(filters_map, &cfg);
|
||||||
|
|
||||||
@@ -126,6 +183,8 @@ int main(int argc, char *argv[])
|
|||||||
// Receive CPU count for stats map parsing.
|
// Receive CPU count for stats map parsing.
|
||||||
int cpus = get_nprocs_conf();
|
int cpus = get_nprocs_conf();
|
||||||
|
|
||||||
|
LogMsg(&cfg, 4, 0, "Retrieved %d CPUs on host.", cpus);
|
||||||
|
|
||||||
unsigned int end_time = (cmd.time > 0) ? time(NULL) + cmd.time : 0;
|
unsigned int end_time = (cmd.time > 0) ? time(NULL) + cmd.time : 0;
|
||||||
|
|
||||||
// Create last updated variables.
|
// Create last updated variables.
|
||||||
@@ -136,6 +195,12 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
struct stat conf_stat;
|
struct stat conf_stat;
|
||||||
|
|
||||||
|
// Check if we're doing stats.
|
||||||
|
if (!cfg.nostats)
|
||||||
|
{
|
||||||
|
doing_stats = 1;
|
||||||
|
}
|
||||||
|
|
||||||
while (cont)
|
while (cont)
|
||||||
{
|
{
|
||||||
// Get current time.
|
// Get current time.
|
||||||
@@ -159,7 +224,7 @@ int main(int argc, char *argv[])
|
|||||||
// Update config.
|
// Update config.
|
||||||
if ((ret = LoadConfig(&cfg, cmd.cfgfile)) != 0)
|
if ((ret = LoadConfig(&cfg, cmd.cfgfile)) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[WARNING] Failed to load config after update check (%d)...\n", ret);
|
LogMsg(&cfg, 1, 0, "[WARNING] Failed to load config after update check (%d)...\n", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update BPF maps.
|
// Update BPF maps.
|
||||||
@@ -167,6 +232,12 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// Update timer
|
// Update timer
|
||||||
last_config_check = time(NULL);
|
last_config_check = time(NULL);
|
||||||
|
|
||||||
|
// Make sure we set doing stats if needed.
|
||||||
|
if (!cfg.nostats && !doing_stats)
|
||||||
|
{
|
||||||
|
doing_stats = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update last updated variable.
|
// Update last updated variable.
|
||||||
@@ -178,24 +249,38 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
if (CalculateStats(stats_map, cpus))
|
if (CalculateStats(stats_map, cpus))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[WARNING] Failed to calculate packet stats. Stats map FD => %d...\n", stats_map);
|
LogMsg(&cfg, 1, 0, "[WARNING] Failed to calculate packet stats. Stats map FD => %d...\n", stats_map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_FILTER_LOGGING
|
||||||
|
if (rb)
|
||||||
|
{
|
||||||
|
ring_buffer__poll(rb, RB_TIMEOUT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
usleep(sleep_time);
|
usleep(sleep_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stdout, "\n");
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
// Detach XDP program.
|
#ifdef ENABLE_FILTER_LOGGING
|
||||||
if (AttachXdp(prog, ifidx, 1, &cmd))
|
if (rb)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[ERROR] Failed to detach XDP program from interface '%s'.\n", cfg.interface);
|
ring_buffer__free(rb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Detach XDP program.
|
||||||
|
if (AttachXdp(prog, &mode_used, ifidx, 1, &cmd))
|
||||||
|
{
|
||||||
|
LogMsg(&cfg, 0, 1, "[ERROR] Failed to detach XDP program from interface '%s'.\n", cfg.interface);
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stdout, "Cleaned up and exiting...\n");
|
LogMsg(&cfg, 1, 0, "Cleaned up and exiting...\n");
|
||||||
|
|
||||||
// Exit program successfully.
|
// Exit program successfully.
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#include <loader/utils/config.h>
|
#include <loader/utils/config.h>
|
||||||
|
|
||||||
#include <loader/utils/helpers.h>
|
|
||||||
|
|
||||||
static FILE *file;
|
static FILE *file;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,6 +44,8 @@ int LoadConfig(config__t *cfg, char *cfg_file)
|
|||||||
*/
|
*/
|
||||||
void SetCfgDefaults(config__t *cfg)
|
void SetCfgDefaults(config__t *cfg)
|
||||||
{
|
{
|
||||||
|
cfg->verbose = 2;
|
||||||
|
cfg->log_file = strdup("/var/log/xdpfw/xdpfw.log");
|
||||||
cfg->updatetime = 0;
|
cfg->updatetime = 0;
|
||||||
cfg->interface = NULL;
|
cfg->interface = NULL;
|
||||||
cfg->nostats = 0;
|
cfg->nostats = 0;
|
||||||
@@ -53,60 +53,62 @@ void SetCfgDefaults(config__t *cfg)
|
|||||||
|
|
||||||
for (int i = 0; i < MAX_FILTERS; i++)
|
for (int i = 0; i < MAX_FILTERS; i++)
|
||||||
{
|
{
|
||||||
cfg->filters[i].id = 0;
|
filter_t* filter = &cfg->filters[i];
|
||||||
cfg->filters[i].enabled = 0;
|
|
||||||
cfg->filters[i].action = 0;
|
|
||||||
cfg->filters[i].src_ip = 0;
|
|
||||||
cfg->filters[i].dst_ip = 0;
|
|
||||||
|
|
||||||
for (int j = 0; j < 4; j++)
|
filter->id = 0;
|
||||||
{
|
filter->enabled = 1;
|
||||||
cfg->filters[i].src_ip6[j] = 0;
|
|
||||||
cfg->filters[i].dst_ip6[j] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg->filters[i].do_min_len = 0;
|
filter->log = 0;
|
||||||
cfg->filters[i].min_len = 0;
|
|
||||||
|
|
||||||
cfg->filters[i].do_max_len = 0;
|
filter->action = 1;
|
||||||
cfg->filters[i].max_len = 65535;
|
filter->src_ip = 0;
|
||||||
|
filter->dst_ip = 0;
|
||||||
|
|
||||||
cfg->filters[i].do_min_ttl = 0;
|
memset(filter->src_ip6, 0, 4);
|
||||||
cfg->filters[i].min_ttl = 0;
|
memset(filter->dst_ip6, 0, 4);
|
||||||
|
|
||||||
cfg->filters[i].do_max_ttl = 0;
|
filter->do_min_len = 0;
|
||||||
cfg->filters[i].max_ttl = 255;
|
filter->min_len = 0;
|
||||||
|
|
||||||
cfg->filters[i].do_tos = 0;
|
filter->do_max_len = 0;
|
||||||
cfg->filters[i].tos = 0;
|
filter->max_len = 65535;
|
||||||
|
|
||||||
cfg->filters[i].do_pps = 0;
|
filter->do_min_ttl = 0;
|
||||||
cfg->filters[i].pps = 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;
|
filter->do_bps = 0;
|
||||||
cfg->filters[i].bps = 0;
|
filter->bps = 0;
|
||||||
|
|
||||||
cfg->filters[i].blocktime = 1;
|
filter->blocktime = 1;
|
||||||
|
|
||||||
cfg->filters[i].tcpopts.enabled = 0;
|
filter->tcpopts.enabled = 0;
|
||||||
cfg->filters[i].tcpopts.do_dport = 0;
|
filter->tcpopts.do_dport = 0;
|
||||||
cfg->filters[i].tcpopts.do_dport = 0;
|
filter->tcpopts.do_dport = 0;
|
||||||
cfg->filters[i].tcpopts.do_urg = 0;
|
filter->tcpopts.do_urg = 0;
|
||||||
cfg->filters[i].tcpopts.do_ack = 0;
|
filter->tcpopts.do_ack = 0;
|
||||||
cfg->filters[i].tcpopts.do_rst = 0;
|
filter->tcpopts.do_rst = 0;
|
||||||
cfg->filters[i].tcpopts.do_psh = 0;
|
filter->tcpopts.do_psh = 0;
|
||||||
cfg->filters[i].tcpopts.do_syn = 0;
|
filter->tcpopts.do_syn = 0;
|
||||||
cfg->filters[i].tcpopts.do_fin = 0;
|
filter->tcpopts.do_fin = 0;
|
||||||
cfg->filters[i].tcpopts.do_ece = 0;
|
filter->tcpopts.do_ece = 0;
|
||||||
cfg->filters[i].tcpopts.do_cwr = 0;
|
filter->tcpopts.do_cwr = 0;
|
||||||
|
|
||||||
cfg->filters[i].udpopts.enabled = 0;
|
filter->udpopts.enabled = 0;
|
||||||
cfg->filters[i].udpopts.do_sport = 0;
|
filter->udpopts.do_sport = 0;
|
||||||
cfg->filters[i].udpopts.do_dport = 0;
|
filter->udpopts.do_dport = 0;
|
||||||
|
|
||||||
cfg->filters[i].icmpopts.enabled = 0;
|
filter->icmpopts.enabled = 0;
|
||||||
cfg->filters[i].icmpopts.do_code = 0;
|
filter->icmpopts.do_code = 0;
|
||||||
cfg->filters[i].icmpopts.do_type = 0;
|
filter->icmpopts.do_type = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,19 +163,48 @@ int ReadCfg(config__t *cfg)
|
|||||||
// Attempt to read the config.
|
// Attempt to read the config.
|
||||||
if (config_read(&conf, file) == CONFIG_FALSE)
|
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);
|
config_destroy(&conf);
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int verbose;
|
||||||
|
|
||||||
|
if (config_lookup_int(&conf, "verbose", &verbose) == CONFIG_TRUE)
|
||||||
|
{
|
||||||
|
cfg->verbose = verbose;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* log_file;
|
||||||
|
|
||||||
|
if (config_lookup_string(&conf, "log_file", &log_file) == CONFIG_TRUE)
|
||||||
|
{
|
||||||
|
// We must free previous value to prevent memory leak.
|
||||||
|
if (cfg->log_file != NULL)
|
||||||
|
{
|
||||||
|
free(cfg->log_file);
|
||||||
|
cfg->log_file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(log_file) > 0)
|
||||||
|
{
|
||||||
|
cfg->log_file = strdup(log_file);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cfg->log_file = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get interface.
|
// Get interface.
|
||||||
const char *interface;
|
const char *interface;
|
||||||
|
|
||||||
if (!config_lookup_string(&conf, "interface", &interface))
|
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);
|
config_destroy(&conf);
|
||||||
|
|
||||||
@@ -212,7 +243,7 @@ int ReadCfg(config__t *cfg)
|
|||||||
// Check if filters map is valid. If not, not a biggie since they aren't required.
|
// Check if filters map is valid. If not, not a biggie since they aren't required.
|
||||||
if (setting == NULL)
|
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);
|
config_destroy(&conf);
|
||||||
|
|
||||||
@@ -224,312 +255,318 @@ int ReadCfg(config__t *cfg)
|
|||||||
|
|
||||||
for (int i = 0; i < config_setting_length(setting); i++)
|
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.
|
// Enabled.
|
||||||
int 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.
|
filter->enabled = enabled;
|
||||||
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;
|
// Log.
|
||||||
|
int log;
|
||||||
|
|
||||||
|
if (config_setting_lookup_bool(filter_cfg, "log", &log) == CONFIG_TRUE)
|
||||||
|
{
|
||||||
|
filter->log = log;
|
||||||
|
}
|
||||||
|
|
||||||
// Action (required).
|
// Action (required).
|
||||||
int action;
|
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));
|
filter->action = action;
|
||||||
|
|
||||||
cfg->filters[i].enabled = 0;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg->filters[i].action = action;
|
|
||||||
|
|
||||||
// Source IP (not required).
|
// Source IP (not required).
|
||||||
const char *sip;
|
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);
|
ip_range_t ip = ParseIpCidr(sip);
|
||||||
|
|
||||||
cfg->filters[i].src_ip = ip.ip;
|
filter->src_ip = ip.ip;
|
||||||
cfg->filters[i].src_cidr = ip.cidr;
|
filter->src_cidr = ip.cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination IP (not required).
|
// Destination IP (not required).
|
||||||
const char *dip;
|
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);
|
ip_range_t ip = ParseIpCidr(dip);
|
||||||
|
|
||||||
cfg->filters[i].dst_ip = ip.ip;
|
filter->dst_ip = ip.ip;
|
||||||
cfg->filters[i].dst_cidr = ip.cidr;
|
filter->dst_cidr = ip.cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source IP (IPv6) (not required).
|
// Source IP (IPv6) (not required).
|
||||||
const char *sip6;
|
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;
|
struct in6_addr in;
|
||||||
|
|
||||||
inet_pton(AF_INET6, sip6, &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).
|
// Destination IP (IPv6) (not required).
|
||||||
const char *dip6;
|
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;
|
struct in6_addr in;
|
||||||
|
|
||||||
inet_pton(AF_INET6, dip6, &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).
|
// Minimum TTL (not required).
|
||||||
int min_ttl;
|
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;
|
filter->min_ttl = (u8)min_ttl;
|
||||||
cfg->filters[i].do_min_ttl = 1;
|
filter->do_min_ttl = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maximum TTL (not required).
|
// Maximum TTL (not required).
|
||||||
int max_ttl;
|
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;
|
filter->max_ttl = (u8)max_ttl;
|
||||||
cfg->filters[i].do_max_ttl = 1;
|
filter->do_max_ttl = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Minimum length (not required).
|
// Minimum length (not required).
|
||||||
int min_len;
|
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;
|
filter->min_len = min_len;
|
||||||
cfg->filters[i].do_min_len = 1;
|
filter->do_min_len = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maximum length (not required).
|
// Maximum length (not required).
|
||||||
int max_len;
|
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;
|
filter->max_len = max_len;
|
||||||
cfg->filters[i].do_max_len = 1;
|
filter->do_max_len = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TOS (not required).
|
// TOS (not required).
|
||||||
int tos;
|
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;
|
filter->tos = (u8)tos;
|
||||||
cfg->filters[i].do_tos = 1;
|
filter->do_tos = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PPS (not required).
|
// PPS (not required).
|
||||||
long long pps;
|
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;
|
filter->pps = pps;
|
||||||
cfg->filters[i].do_pps = 1;
|
filter->do_pps = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BPS (not required).
|
// BPS (not required).
|
||||||
long long bps;
|
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;
|
filter->bps = bps;
|
||||||
cfg->filters[i].do_bps = 1;
|
filter->do_bps = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block time (default 1).
|
// Block time (default 1).
|
||||||
long long blocktime;
|
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
|
else
|
||||||
{
|
{
|
||||||
cfg->filters[i].blocktime = 1;
|
filter->blocktime = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TCP options */
|
/* TCP options */
|
||||||
// Enabled.
|
// Enabled.
|
||||||
int tcpenabled;
|
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.
|
// Source port.
|
||||||
long long tcpsport;
|
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;
|
filter->tcpopts.sport = (u16)tcpsport;
|
||||||
cfg->filters[i].tcpopts.do_sport = 1;
|
filter->tcpopts.do_sport = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination port.
|
// Destination port.
|
||||||
long long tcpdport;
|
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;
|
filter->tcpopts.dport = (u16)tcpdport;
|
||||||
cfg->filters[i].tcpopts.do_dport = 1;
|
filter->tcpopts.do_dport = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// URG flag.
|
// URG flag.
|
||||||
int tcpurg;
|
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;
|
filter->tcpopts.urg = tcpurg;
|
||||||
cfg->filters[i].tcpopts.do_urg = 1;
|
filter->tcpopts.do_urg = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACK flag.
|
// ACK flag.
|
||||||
int tcpack;
|
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;
|
filter->tcpopts.ack = tcpack;
|
||||||
cfg->filters[i].tcpopts.do_ack = 1;
|
filter->tcpopts.do_ack = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// RST flag.
|
// RST flag.
|
||||||
int tcprst;
|
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;
|
filter->tcpopts.rst = tcprst;
|
||||||
cfg->filters[i].tcpopts.do_rst = 1;
|
filter->tcpopts.do_rst = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PSH flag.
|
// PSH flag.
|
||||||
int tcppsh;
|
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;
|
filter->tcpopts.psh = tcppsh;
|
||||||
cfg->filters[i].tcpopts.do_psh = 1;
|
filter->tcpopts.do_psh = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SYN flag.
|
// SYN flag.
|
||||||
int tcpsyn;
|
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;
|
filter->tcpopts.syn = tcpsyn;
|
||||||
cfg->filters[i].tcpopts.do_syn = 1;
|
filter->tcpopts.do_syn = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIN flag.
|
// FIN flag.
|
||||||
int tcpfin;
|
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;
|
filter->tcpopts.fin = tcpfin;
|
||||||
cfg->filters[i].tcpopts.do_fin = 1;
|
filter->tcpopts.do_fin = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ECE flag.
|
// ECE flag.
|
||||||
int tcpece;
|
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;
|
filter->tcpopts.ece = tcpece;
|
||||||
cfg->filters[i].tcpopts.do_ece = 1;
|
filter->tcpopts.do_ece = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CWR flag.
|
// CWR flag.
|
||||||
int tcpcwr;
|
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;
|
filter->tcpopts.cwr = tcpcwr;
|
||||||
cfg->filters[i].tcpopts.do_cwr = 1;
|
filter->tcpopts.do_cwr = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* UDP options */
|
/* UDP options */
|
||||||
// Enabled.
|
// Enabled.
|
||||||
int udpenabled;
|
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.
|
// Source port.
|
||||||
long long udpsport;
|
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;
|
filter->udpopts.sport = (u16)udpsport;
|
||||||
cfg->filters[i].udpopts.do_sport = 1;
|
filter->udpopts.do_sport = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination port.
|
// Destination port.
|
||||||
long long udpdport;
|
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;
|
filter->udpopts.dport = (u16)udpdport;
|
||||||
cfg->filters[i].udpopts.do_dport = 1;
|
filter->udpopts.do_dport = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ICMP options */
|
/* ICMP options */
|
||||||
// Enabled.
|
// Enabled.
|
||||||
int icmpenabled;
|
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.
|
// ICMP code.
|
||||||
int icmpcode;
|
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;
|
filter->icmpopts.code = (u8)icmpcode;
|
||||||
cfg->filters[i].icmpopts.do_code = 1;
|
filter->icmpopts.do_code = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ICMP type.
|
// ICMP type.
|
||||||
int icmptype;
|
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;
|
filter->icmpopts.type = (u8)icmptype;
|
||||||
cfg->filters[i].icmpopts.do_type = 1;
|
filter->icmpopts.do_type = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign ID and increase filter count.
|
// Assign ID and increase filter count.
|
||||||
cfg->filters[i].id = ++filters;
|
filter->id = ++filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
config_destroy(&conf);
|
config_destroy(&conf);
|
||||||
@@ -568,6 +605,7 @@ void PrintConfig(config__t* cfg)
|
|||||||
|
|
||||||
// Main.
|
// Main.
|
||||||
fprintf(stdout, "\t\t\tID => %d\n", filter->id);
|
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\tEnabled => %d\n", filter->enabled);
|
||||||
fprintf(stdout, "\t\t\tAction => %d (0 = Block, 1 = Allow).\n\n", filter->action);
|
fprintf(stdout, "\t\t\tAction => %d (0 = Block, 1 = Allow).\n\n", filter->action);
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,14 @@
|
|||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <loader/utils/helpers.h>
|
||||||
|
|
||||||
#define CONFIG_DEFAULT_PATH "/etc/xdpfw/xdpfw.conf"
|
#define CONFIG_DEFAULT_PATH "/etc/xdpfw/xdpfw.conf"
|
||||||
|
|
||||||
struct config
|
struct config
|
||||||
{
|
{
|
||||||
|
int verbose;
|
||||||
|
char *log_file;
|
||||||
char *interface;
|
char *interface;
|
||||||
u16 updatetime;
|
u16 updatetime;
|
||||||
unsigned int nostats : 1;
|
unsigned int nostats : 1;
|
||||||
@@ -25,4 +29,6 @@ void SetCfgDefaults(config__t *cfg);
|
|||||||
void PrintConfig(config__t* cfg);
|
void PrintConfig(config__t* cfg);
|
||||||
|
|
||||||
int OpenCfg(const char *filename);
|
int OpenCfg(const char *filename);
|
||||||
int ReadCfg(config__t *cfg);
|
int ReadCfg(config__t *cfg);
|
||||||
|
|
||||||
|
#include <loader/utils/logging.h>
|
||||||
@@ -55,4 +55,45 @@ ip_range_t ParseIpCidr(const char *ip)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves protocol name by ID.
|
||||||
|
*
|
||||||
|
* @param id The protocol ID
|
||||||
|
*
|
||||||
|
* @return The protocol string.
|
||||||
|
*/
|
||||||
|
const char* GetProtocolStrById(int id)
|
||||||
|
{
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
return "TCP";
|
||||||
|
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
return "UDP";
|
||||||
|
|
||||||
|
case IPPROTO_ICMP:
|
||||||
|
return "ICMP";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints tool name and author.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void PrintToolInfo()
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
" __ ______ ____ _____ _ _ _ \n"
|
||||||
|
" \\ \\/ / _ \\| _ \\ | ___(_)_ __ _____ ____ _| | |\n"
|
||||||
|
" \\ /| | | | |_) | | |_ | | '__/ _ \\ \\ /\\ / / _` | | |\n"
|
||||||
|
" / \\| |_| | __/ | _| | | | | __/\\ V V / (_| | | |\n"
|
||||||
|
" /_/\\_\\____/|_| |_| |_|_| \\___| \\_/\\_/ \\__,_|_|_|\n"
|
||||||
|
"\n\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -17,4 +17,6 @@ extern int cont;
|
|||||||
|
|
||||||
void PrintHelpMenu();
|
void PrintHelpMenu();
|
||||||
void SignalHndl(int code);
|
void SignalHndl(int code);
|
||||||
ip_range_t ParseIpCidr(const char* ip);
|
ip_range_t ParseIpCidr(const char* ip);
|
||||||
|
const char* GetProtocolStrById(int id);
|
||||||
|
void PrintToolInfo();
|
||||||
152
src/loader/utils/logging.c
Normal file
152
src/loader/utils/logging.c
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
#include <loader/utils/logging.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a log message to stdout/stderr along with a file if specified.
|
||||||
|
*
|
||||||
|
* @param req_lvl The required level for this message.
|
||||||
|
* @param cur_lvl The current verbose level.
|
||||||
|
* @param error If 1, sets pipe to stderr instead of stdout.
|
||||||
|
* @param msg The log message.
|
||||||
|
* @param args A VA list of arguments for the message.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
static void LogMsgRaw(int req_lvl, int cur_lvl, int error, const char* log_path, const char* msg, va_list args)
|
||||||
|
{
|
||||||
|
if (cur_lvl < req_lvl)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* pipe = stdout;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
pipe = stderr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to format the message.
|
||||||
|
va_list args_copy;
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
int len = vsnprintf(NULL, 0, msg, args_copy);
|
||||||
|
va_end(args_copy);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char f_msg[len + 1];
|
||||||
|
vsnprintf(f_msg, sizeof(f_msg), msg, args);
|
||||||
|
|
||||||
|
char full_msg[len + 6 + 1];
|
||||||
|
snprintf(full_msg, sizeof(full_msg), "[%d] %s", req_lvl, f_msg);
|
||||||
|
|
||||||
|
// If we're calculating stats, we need to prepend a new line.
|
||||||
|
if (doing_stats)
|
||||||
|
{
|
||||||
|
fprintf(pipe, "\n%s\n", full_msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(pipe, "%s\n", full_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log_path != NULL)
|
||||||
|
{
|
||||||
|
FILE* log_file = fopen(log_path, "a");
|
||||||
|
|
||||||
|
if (!log_file)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm* tm_val = localtime(&now);
|
||||||
|
|
||||||
|
if (!tm_val)
|
||||||
|
{
|
||||||
|
fclose(log_file);
|
||||||
|
|
||||||
|
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,
|
||||||
|
tm_val->tm_hour, tm_val->tm_min, tm_val->tm_sec, full_msg);
|
||||||
|
|
||||||
|
fprintf(log_file, "%s\n", log_file_msg);
|
||||||
|
|
||||||
|
fclose(log_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a log message using LogMsgRaw().
|
||||||
|
*
|
||||||
|
* @param cfg A pointer to the config structure.
|
||||||
|
* @param req_lvl The required level for this message.
|
||||||
|
* @param error Whether this is an error.
|
||||||
|
* @param msg The log message with format support.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
|
||||||
|
LogMsgRaw(req_lvl, cfg->verbose, error, (const char*)cfg->log_file, msg, args);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for BPF ringbuffer event (filter logging).
|
||||||
|
*
|
||||||
|
* @param ctx The context (should be config__t*).
|
||||||
|
* @param data The event data (should be filter_log_event_t*).
|
||||||
|
* @param sz The event data size.
|
||||||
|
*
|
||||||
|
* @return 0 on success or 1 on failure.
|
||||||
|
*/
|
||||||
|
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 src_ip_str[INET6_ADDRSTRLEN];
|
||||||
|
char dst_ip_str[INET_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, src_ip_str, sizeof(src_ip_str));
|
||||||
|
inet_ntop(AF_INET6, e->dst_ip6, dst_ip_str, sizeof(dst_ip_str));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
inet_ntop(AF_INET, &e->src_ip, src_ip_str, sizeof(src_ip_str));
|
||||||
|
inet_ntop(AF_INET, &e->dst_ip, dst_ip_str, sizeof(dst_ip_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
char* action = "Dropped";
|
||||||
|
|
||||||
|
if (filter->action == 1)
|
||||||
|
{
|
||||||
|
action = "Passed";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* protocol_str = GetProtocolStrById(e->protocol);
|
||||||
|
|
||||||
|
LogMsg(cfg, 0, 0, "[FILTER %d] %s %s packet '%s:%d' => '%s:%d' (PPS => %llu, BPS => %llu, Filter Block Time => %llu)...", e->filter_id, action, protocol_str, src_ip_str, htons(e->src_port), dst_ip_str, htons(e->dst_port), e->pps, e->bps, filter->blocktime);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
20
src/loader/utils/logging.h
Normal file
20
src/loader/utils/logging.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <common/all.h>
|
||||||
|
|
||||||
|
#include <loader/utils/config.h>
|
||||||
|
|
||||||
|
#include <xdp/libxdp.h>
|
||||||
|
|
||||||
|
#define RB_TIMEOUT 100
|
||||||
|
|
||||||
|
extern int doing_stats;
|
||||||
|
|
||||||
|
void LogMsg(config__t* cfg, int req_lvl, int error, const char* msg, ...);
|
||||||
|
int HandleRbEvent(void* ctx, void* data, size_t sz);
|
||||||
@@ -40,9 +40,12 @@ int CalculateStats(int stats_map, int cpus)
|
|||||||
dropped += stats[i].dropped;
|
dropped += stats[i].dropped;
|
||||||
passed += stats[i].passed;
|
passed += stats[i].passed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("\r\033[1;32mAllowed:\033[0m %llu | ", allowed);
|
||||||
|
printf("\033[1;31mDropped:\033[0m %llu | ", dropped);
|
||||||
|
printf("\033[1;34mPassed:\033[0m %llu", passed);
|
||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fprintf(stdout, "\rAllowed: %llu | Dropped: %llu | Passed: %llu", allowed, dropped, passed);
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,35 @@ int FindMapFd(struct xdp_program *prog, const char *map_name)
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom print function for LibBPF that doesn't print anything (silent mode).
|
||||||
|
*
|
||||||
|
* @param level The current LibBPF log level.
|
||||||
|
* @param format The message format.
|
||||||
|
* @param args Format arguments for the message.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
static int LibBPFSilent(enum libbpf_print_level level, const char *format, va_list args)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets custom LibBPF log mode.
|
||||||
|
*
|
||||||
|
* @param silent If 1, disables LibBPF logging entirely.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void SetLibBPFLogMode(int silent)
|
||||||
|
{
|
||||||
|
if (silent)
|
||||||
|
{
|
||||||
|
libbpf_set_print(LibBPFSilent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a BPF object file.
|
* Loads a BPF object file.
|
||||||
*
|
*
|
||||||
@@ -60,31 +89,32 @@ struct xdp_program *LoadBpfObj(const char *file_name)
|
|||||||
* Attempts to attach or detach (progfd = -1) a BPF/XDP program to an interface.
|
* Attempts to attach or detach (progfd = -1) a BPF/XDP program to an interface.
|
||||||
*
|
*
|
||||||
* @param prog A pointer to the XDP program structure.
|
* @param prog A pointer to the XDP program structure.
|
||||||
|
* @param mode_used The mode being used.
|
||||||
* @param ifidx The index to the interface to attach to.
|
* @param ifidx The index to the interface to attach to.
|
||||||
* @param detach If above 0, attempts to detach XDP program.
|
* @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 cmd A pointer to a cmdline struct that includes command line arguments (mostly checking for offload/HW mode set).
|
||||||
*
|
*
|
||||||
* @return 0 on success and 1 on error.
|
* @return 0 on success and 1 on error.
|
||||||
*/
|
*/
|
||||||
int AttachXdp(struct xdp_program *prog, int ifidx, u8 detach, cmdline_t *cmd)
|
int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, u8 detach, cmdline_t *cmd)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
u32 mode = XDP_MODE_NATIVE;
|
u32 attach_mode = XDP_MODE_NATIVE;
|
||||||
char *smode;
|
|
||||||
|
|
||||||
smode = "DRV/native";
|
*mode = "DRV/native";
|
||||||
|
|
||||||
if (cmd->offload)
|
if (cmd->offload)
|
||||||
{
|
{
|
||||||
smode = "HW/offload";
|
*mode = "HW/offload";
|
||||||
|
|
||||||
mode = XDP_MODE_HW;
|
attach_mode = XDP_MODE_HW;
|
||||||
}
|
}
|
||||||
else if (cmd->skb)
|
else if (cmd->skb)
|
||||||
{
|
{
|
||||||
smode = "SKB/generic";
|
*mode = "SKB/generic";
|
||||||
mode = XDP_MODE_SKB;
|
|
||||||
|
attach_mode = XDP_MODE_SKB;
|
||||||
}
|
}
|
||||||
|
|
||||||
int exit = 0;
|
int exit = 0;
|
||||||
@@ -96,39 +126,35 @@ int AttachXdp(struct xdp_program *prog, int ifidx, u8 detach, cmdline_t *cmd)
|
|||||||
|
|
||||||
if (detach)
|
if (detach)
|
||||||
{
|
{
|
||||||
err = xdp_program__detach(prog, ifidx, mode, 0);
|
err = xdp_program__detach(prog, ifidx, attach_mode, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = xdp_program__attach(prog, ifidx, mode, 0);
|
err = xdp_program__attach(prog, ifidx, attach_mode, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Could not attach with mode %s (%s) (%d).\n", smode, strerror(-err), -err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrease mode.
|
// Decrease mode.
|
||||||
switch (mode)
|
switch (attach_mode)
|
||||||
{
|
{
|
||||||
case XDP_MODE_HW:
|
case XDP_MODE_HW:
|
||||||
mode = XDP_MODE_NATIVE;
|
attach_mode = XDP_MODE_NATIVE;
|
||||||
smode = "DRV/native";
|
*mode = "DRV/native";
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XDP_MODE_NATIVE:
|
case XDP_MODE_NATIVE:
|
||||||
mode = XDP_MODE_SKB;
|
attach_mode = XDP_MODE_SKB;
|
||||||
smode = "SKB/generic";
|
*mode = "SKB/generic";
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XDP_MODE_SKB:
|
case XDP_MODE_SKB:
|
||||||
// Exit loop.
|
// Exit loop.
|
||||||
exit = 1;
|
exit = 1;
|
||||||
smode = NULL;
|
|
||||||
|
*mode = NULL;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -142,16 +168,11 @@ int AttachXdp(struct xdp_program *prog, int ifidx, u8 detach, cmdline_t *cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If exit is set to 1 or smode is NULL, it indicates full failure.
|
// If exit is set to 1 or smode is NULL, it indicates full failure.
|
||||||
if (exit || smode == NULL)
|
if (exit || *mode == NULL)
|
||||||
{
|
{
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (detach < 1)
|
|
||||||
{
|
|
||||||
fprintf(stdout, "Loaded XDP program on mode %s...\n", smode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#define XDP_OBJ_PATH "/etc/xdpfw/xdp_prog.o"
|
#define XDP_OBJ_PATH "/etc/xdpfw/xdp_prog.o"
|
||||||
|
|
||||||
int FindMapFd(struct xdp_program *prog, const char *map_name);
|
int FindMapFd(struct xdp_program *prog, const char *map_name);
|
||||||
|
void SetLibBPFLogMode(int silent);
|
||||||
struct xdp_program *LoadBpfObj(const char *file_name);
|
struct xdp_program *LoadBpfObj(const char *file_name);
|
||||||
int AttachXdp(struct xdp_program *prog, int ifidx, u8 detach, cmdline_t *cmd);
|
int AttachXdp(struct xdp_program *prog, char** mode, int ifidx, u8 detach, cmdline_t *cmd);
|
||||||
void UpdateFilters(int filters_map, config__t *cfg);
|
void UpdateFilters(int filters_map, config__t *cfg);
|
||||||
@@ -136,6 +136,11 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
struct icmp6hdr *icmp6h = NULL;
|
struct icmp6hdr *icmp6h = NULL;
|
||||||
|
|
||||||
u16 src_port = 0;
|
u16 src_port = 0;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FILTER_LOGGING
|
||||||
|
u16 dst_port = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
u8 protocol = 0;
|
u8 protocol = 0;
|
||||||
|
|
||||||
if (iph6)
|
if (iph6)
|
||||||
@@ -156,6 +161,10 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
|
|
||||||
src_port = tcph->source;
|
src_port = tcph->source;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FILTER_LOGGING
|
||||||
|
dst_port = tcph->dest;
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPPROTO_UDP:
|
case IPPROTO_UDP:
|
||||||
@@ -170,6 +179,10 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
|
|
||||||
src_port = udph->source;
|
src_port = udph->source;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FILTER_LOGGING
|
||||||
|
dst_port = udph->dest;
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPPROTO_ICMPV6:
|
case IPPROTO_ICMPV6:
|
||||||
@@ -203,6 +216,10 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
|
|
||||||
src_port = tcph->source;
|
src_port = tcph->source;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FILTER_LOGGING
|
||||||
|
dst_port = tcph->dest;
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPPROTO_UDP:
|
case IPPROTO_UDP:
|
||||||
@@ -217,6 +234,10 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
|
|
||||||
src_port = udph->source;
|
src_port = udph->source;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FILTER_LOGGING
|
||||||
|
dst_port = udph->dest;
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPPROTO_ICMP:
|
case IPPROTO_ICMP:
|
||||||
@@ -513,6 +534,39 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
continue;
|
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;
|
||||||
|
e->dst_ip = iph->daddr;
|
||||||
|
} else if (iph6)
|
||||||
|
{
|
||||||
|
memcpy(&e->src_ip6, iph6->saddr.in6_u.u6_addr32, 4);
|
||||||
|
memcpy(&e->dst_ip6, iph6->daddr.in6_u.u6_addr32, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
e->src_port = src_port;
|
||||||
|
e->dst_port = dst_port;
|
||||||
|
|
||||||
|
e->protocol = protocol;
|
||||||
|
|
||||||
|
e->pps = pps;
|
||||||
|
e->bps = bps;
|
||||||
|
|
||||||
|
bpf_ringbuf_submit(e, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Matched.
|
// Matched.
|
||||||
action = filter->action;
|
action = filter->action;
|
||||||
|
|||||||
@@ -59,4 +59,12 @@ struct
|
|||||||
__uint(max_entries, MAX_TRACK_IPS);
|
__uint(max_entries, MAX_TRACK_IPS);
|
||||||
__type(key, u128);
|
__type(key, u128);
|
||||||
__type(value, u64);
|
__type(value, u64);
|
||||||
} ip6_blacklist_map SEC(".maps");
|
} 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
|
||||||
Reference in New Issue
Block a user