Add IPv4 CIDR support and clean up code.
This commit is contained in:
@@ -58,8 +58,8 @@ The following table quickly explains the data types used within the configuratio
|
|||||||
| enabled | bool | `false` | Whether the rule is enabled or not. |
|
| 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. |
|
| action | uint | `0` | 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`). |
|
| 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`) |
|
| 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`)! |
|
||||||
| src_ip6 | string | `NULL` | The source IPv6 address to match (e.g. `fe80::18c4:dfff:fe70:d8a6`). |
|
| src_ip6 | string | `NULL` | The source IPv6 address to match (e.g. `fe80::18c4:dfff:fe70:d8a6`). |
|
||||||
| dst_ip6 | string | `NULL` | The destination IPv6 address to match (e.g. `fe80::ac21:14ff:fe4b:3a6d`). |
|
| dst_ip6 | string | `NULL` | The destination IPv6 address to match (e.g. `fe80::ac21:14ff:fe4b:3a6d`). |
|
||||||
| min_ttl | byte | `NULL` | The minimum TTL (time-to-live) to match. |
|
| min_ttl | byte | `NULL` | The minimum TTL (time-to-live) to match. |
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const struct option opts[] =
|
|||||||
*
|
*
|
||||||
* @return Void
|
* @return Void
|
||||||
*/
|
*/
|
||||||
void parsecommandline(struct cmdline *cmd, int argc, char *argv[])
|
void ParseCommandLine(struct cmdline *cmd, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ struct cmdline
|
|||||||
unsigned int help : 1;
|
unsigned int help : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
void parsecommandline(struct cmdline *cmd, int argc, char *argv[]);
|
void ParseCommandLine(struct cmdline *cmd, int argc, char *argv[]);
|
||||||
29
src/config.c
29
src/config.c
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "xdpfw.h"
|
#include "xdpfw.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ FILE *file;
|
|||||||
*
|
*
|
||||||
* @return Void
|
* @return Void
|
||||||
*/
|
*/
|
||||||
void setcfgdefaults(struct config *cfg)
|
void SetCfgDefaults(struct config *cfg)
|
||||||
{
|
{
|
||||||
cfg->updatetime = 0;
|
cfg->updatetime = 0;
|
||||||
cfg->interface = NULL;
|
cfg->interface = NULL;
|
||||||
@@ -30,13 +31,13 @@ void setcfgdefaults(struct config *cfg)
|
|||||||
cfg->filters[i].id = 0;
|
cfg->filters[i].id = 0;
|
||||||
cfg->filters[i].enabled = 0;
|
cfg->filters[i].enabled = 0;
|
||||||
cfg->filters[i].action = 0;
|
cfg->filters[i].action = 0;
|
||||||
cfg->filters[i].srcip = 0;
|
cfg->filters[i].src_ip = 0;
|
||||||
cfg->filters[i].dstip = 0;
|
cfg->filters[i].dst_ip = 0;
|
||||||
|
|
||||||
for (__u8 j = 0; j < 4; j++)
|
for (__u8 j = 0; j < 4; j++)
|
||||||
{
|
{
|
||||||
cfg->filters[i].srcip6[j] = 0;
|
cfg->filters[i].src_ip6[j] = 0;
|
||||||
cfg->filters[i].dstip6[j] = 0;
|
cfg->filters[i].dst_ip6[j] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg->filters[i].do_min_len = 0;
|
cfg->filters[i].do_min_len = 0;
|
||||||
@@ -91,7 +92,7 @@ void setcfgdefaults(struct config *cfg)
|
|||||||
*
|
*
|
||||||
* @return 0 on success or 1 on error.
|
* @return 0 on success or 1 on error.
|
||||||
*/
|
*/
|
||||||
int opencfg(const char *filename)
|
int OpenCfg(const char *filename)
|
||||||
{
|
{
|
||||||
// Close any existing files.
|
// Close any existing files.
|
||||||
if (file != NULL)
|
if (file != NULL)
|
||||||
@@ -118,7 +119,7 @@ int opencfg(const char *filename)
|
|||||||
*
|
*
|
||||||
* @return 0 on success or 1/-1 on error.
|
* @return 0 on success or 1/-1 on error.
|
||||||
*/
|
*/
|
||||||
int readcfg(struct config *cfg)
|
int ReadCfg(struct config *cfg)
|
||||||
{
|
{
|
||||||
// Not sure why this would be set to NULL after checking for it in OpenConfig(), but just for safety.
|
// Not sure why this would be set to NULL after checking for it in OpenConfig(), but just for safety.
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
@@ -232,7 +233,10 @@ int readcfg(struct config *cfg)
|
|||||||
|
|
||||||
if (config_setting_lookup_string(filter, "src_ip", &sip))
|
if (config_setting_lookup_string(filter, "src_ip", &sip))
|
||||||
{
|
{
|
||||||
cfg->filters[i].srcip = inet_addr(sip);
|
struct ip ip = ParseIp(sip);
|
||||||
|
|
||||||
|
cfg->filters[i].src_ip = ip.ip;
|
||||||
|
cfg->filters[i].src_cidr = ip.cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination IP (not required).
|
// Destination IP (not required).
|
||||||
@@ -240,7 +244,10 @@ int readcfg(struct config *cfg)
|
|||||||
|
|
||||||
if (config_setting_lookup_string(filter, "dst_ip", &dip))
|
if (config_setting_lookup_string(filter, "dst_ip", &dip))
|
||||||
{
|
{
|
||||||
cfg->filters[i].dstip = inet_addr(dip);
|
struct ip ip = ParseIp(dip);
|
||||||
|
|
||||||
|
cfg->filters[i].dst_ip = ip.ip;
|
||||||
|
cfg->filters[i].dst_cidr = ip.cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source IP (IPv6) (not required).
|
// Source IP (IPv6) (not required).
|
||||||
@@ -254,7 +261,7 @@ int readcfg(struct config *cfg)
|
|||||||
|
|
||||||
for (__u8 j = 0; j < 4; j++)
|
for (__u8 j = 0; j < 4; j++)
|
||||||
{
|
{
|
||||||
cfg->filters[i].srcip6[j] = in.__in6_u.__u6_addr32[j];
|
cfg->filters[i].src_ip6[j] = in.__in6_u.__u6_addr32[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +276,7 @@ int readcfg(struct config *cfg)
|
|||||||
|
|
||||||
for (__u8 j = 0; j < 4; j++)
|
for (__u8 j = 0; j < 4; j++)
|
||||||
{
|
{
|
||||||
cfg->filters[i].dstip6[j] = in.__in6_u.__u6_addr32[j];
|
cfg->filters[i].dst_ip6[j] = in.__in6_u.__u6_addr32[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ struct config
|
|||||||
struct filter filters[MAX_FILTERS];
|
struct filter filters[MAX_FILTERS];
|
||||||
};
|
};
|
||||||
|
|
||||||
void setcfgdefaults(struct config *cfg);
|
void SetCfgDefaults(struct config *cfg);
|
||||||
int opencfg(const char *filename);
|
int OpenCfg(const char *filename);
|
||||||
int readcfg(struct config *cfg);
|
int ReadCfg(struct config *cfg);
|
||||||
42
src/utils.h
Normal file
42
src/utils.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct ip
|
||||||
|
{
|
||||||
|
__u32 ip;
|
||||||
|
__u32 cidr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an IP string with CIDR support. Stores IP in network byte order in ip.ip and CIDR in ip.cidr.
|
||||||
|
*
|
||||||
|
* @param ip The IP string.
|
||||||
|
*
|
||||||
|
* @return Returns an IP structure with IP and CIDR.
|
||||||
|
*/
|
||||||
|
struct ip ParseIp(const char *ip)
|
||||||
|
{
|
||||||
|
struct ip ret = {0};
|
||||||
|
ret.cidr = 32;
|
||||||
|
|
||||||
|
char *token = strtok((char *) ip, "/");
|
||||||
|
|
||||||
|
if (token)
|
||||||
|
{
|
||||||
|
ret.ip = inet_addr(token);
|
||||||
|
|
||||||
|
token = strtok(NULL, "/");
|
||||||
|
|
||||||
|
if (token)
|
||||||
|
{
|
||||||
|
ret.cidr = (unsigned int) strtoul(token, NULL, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
17
src/xdp_utils.h
Normal file
17
src/xdp_utils.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "xdpfw.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an IP is within a specific CIDR range.
|
||||||
|
*
|
||||||
|
* @param src_ip The source/main IP to check against.
|
||||||
|
* @param net_ip The network IP.
|
||||||
|
* @param cidr The CIDR range.
|
||||||
|
*
|
||||||
|
* @return 1 on yes, 0 on no.
|
||||||
|
*/
|
||||||
|
static __always_inline __u8 IsIpInRange(__u32 src_ip, __u32 net_ip, __u8 cidr)
|
||||||
|
{
|
||||||
|
return !((src_ip ^ net_ip) & htonl(0xFFFFFFFFu << (32 - cidr)));
|
||||||
|
}
|
||||||
116
src/xdpfw.c
116
src/xdpfw.c
@@ -23,13 +23,14 @@
|
|||||||
#include "xdpfw.h"
|
#include "xdpfw.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "cmdline.h"
|
#include "cmdline.h"
|
||||||
|
#include "xdp_utils.h"
|
||||||
|
|
||||||
// Other variables.
|
// Other variables.
|
||||||
static __u8 cont = 1;
|
static __u8 cont = 1;
|
||||||
static int filtersmap = -1;
|
static int filtersmap = -1;
|
||||||
static int statsmap = -1;
|
static int statsmap = -1;
|
||||||
|
|
||||||
void signalHndl(int tmp)
|
void SignalHndl(int tmp)
|
||||||
{
|
{
|
||||||
cont = 0;
|
cont = 0;
|
||||||
}
|
}
|
||||||
@@ -41,7 +42,7 @@ void signalHndl(int tmp)
|
|||||||
*
|
*
|
||||||
* @return Void
|
* @return Void
|
||||||
*/
|
*/
|
||||||
void updatefilters(struct config *cfg)
|
void UpdateFilters(struct config *cfg)
|
||||||
{
|
{
|
||||||
// Loop through all filters and delete the map. We do this in the case rules were edited and were put out of order since the key doesn't uniquely map to a specific rule.
|
// Loop through all filters and delete the map. We do this in the case rules were edited and were put out of order since the key doesn't uniquely map to a specific rule.
|
||||||
for (__u8 i = 0; i < MAX_FILTERS; i++)
|
for (__u8 i = 0; i < MAX_FILTERS; i++)
|
||||||
@@ -84,17 +85,17 @@ void updatefilters(struct config *cfg)
|
|||||||
*
|
*
|
||||||
* @return 0 on success or -1 on error.
|
* @return 0 on success or -1 on error.
|
||||||
*/
|
*/
|
||||||
int updateconfig(struct config *cfg, char *cfgfile)
|
int UpdateConfig(struct config *cfg, char *cfgfile)
|
||||||
{
|
{
|
||||||
// Open config file.
|
// Open config file.
|
||||||
if (opencfg(cfgfile) != 0)
|
if (OpenCfg(cfgfile) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error opening filters file: %s\n", cfgfile);
|
fprintf(stderr, "Error opening filters file: %s\n", cfgfile);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
setcfgdefaults(cfg);
|
SetCfgDefaults(cfg);
|
||||||
|
|
||||||
for (__u16 i = 0; i < MAX_FILTERS; i++)
|
for (__u16 i = 0; i < MAX_FILTERS; i++)
|
||||||
{
|
{
|
||||||
@@ -102,7 +103,7 @@ int updateconfig(struct config *cfg, char *cfgfile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read config and check for errors.
|
// Read config and check for errors.
|
||||||
if (readcfg(cfg) != 0)
|
if (ReadCfg(cfg) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error reading filters file.\n");
|
fprintf(stderr, "Error reading filters file.\n");
|
||||||
|
|
||||||
@@ -120,7 +121,7 @@ int updateconfig(struct config *cfg, char *cfgfile)
|
|||||||
*
|
*
|
||||||
* @return The map's FD.
|
* @return The map's FD.
|
||||||
*/
|
*/
|
||||||
int findmapfd(struct xdp_program *prog, const char *mapname)
|
int FindMapFd(struct xdp_program *prog, const char *mapname)
|
||||||
{
|
{
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
|
||||||
@@ -155,7 +156,7 @@ int findmapfd(struct xdp_program *prog, const char *mapname)
|
|||||||
*
|
*
|
||||||
* @return XDP program structure (pointer) or NULL.
|
* @return XDP program structure (pointer) or NULL.
|
||||||
*/
|
*/
|
||||||
struct xdp_program *loadbpfobj(const char *filename)
|
struct xdp_program *LoadBpfObj(const char *filename)
|
||||||
{
|
{
|
||||||
struct xdp_program *prog = xdp_program__open_file(filename, "xdp_prog", NULL);
|
struct xdp_program *prog = xdp_program__open_file(filename, "xdp_prog", NULL);
|
||||||
|
|
||||||
@@ -178,7 +179,7 @@ struct xdp_program *loadbpfobj(const char *filename)
|
|||||||
*
|
*
|
||||||
* @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, struct cmdline *cmd)
|
int AttachXdp(struct xdp_program *prog, int ifidx, __u8 detach, struct cmdline *cmd)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -267,6 +268,7 @@ int attachxdp(struct xdp_program *prog, int ifidx, __u8 detach, struct cmdline *
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct stat conf_stat;
|
struct stat conf_stat;
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
// Parse the command line.
|
// Parse the command line.
|
||||||
@@ -278,7 +280,7 @@ int main(int argc, char *argv[])
|
|||||||
.offload = 0
|
.offload = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
parsecommandline(&cmd, argc, argv);
|
ParseCommandLine(&cmd, argc, argv);
|
||||||
|
|
||||||
// Check for help menu.
|
// Check for help menu.
|
||||||
if (cmd.help)
|
if (cmd.help)
|
||||||
@@ -314,10 +316,10 @@ int main(int argc, char *argv[])
|
|||||||
// Initialize config.
|
// Initialize config.
|
||||||
struct config cfg = {0};
|
struct config cfg = {0};
|
||||||
|
|
||||||
setcfgdefaults(&cfg);
|
SetCfgDefaults(&cfg);
|
||||||
|
|
||||||
// Update config.
|
// Update config.
|
||||||
updateconfig(&cfg, cmd.cfgfile);
|
UpdateConfig(&cfg, cmd.cfgfile);
|
||||||
|
|
||||||
// Check for list option.
|
// Check for list option.
|
||||||
if (cmd.list)
|
if (cmd.list)
|
||||||
@@ -329,7 +331,9 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
for (uint16_t i = 0; i < MAX_FILTERS; i++)
|
for (uint16_t i = 0; i < MAX_FILTERS; i++)
|
||||||
{
|
{
|
||||||
if (cfg.filters[i].id < 1)
|
struct filter *filter = &cfg.filters[i];
|
||||||
|
|
||||||
|
if (filter->id < 1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -337,24 +341,26 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stdout, "Filter #%d:\n", (i + 1));
|
fprintf(stdout, "Filter #%d:\n", (i + 1));
|
||||||
|
|
||||||
// Main.
|
// Main.
|
||||||
fprintf(stdout, "\tID => %d\n", cfg.filters[i].id);
|
fprintf(stdout, "\tID => %d\n", filter->id);
|
||||||
fprintf(stdout, "\tEnabled => %d\n", cfg.filters[i].enabled);
|
fprintf(stdout, "\tEnabled => %d\n", filter->enabled);
|
||||||
fprintf(stdout, "\tAction => %d (0 = Block, 1 = Allow).\n\n", cfg.filters[i].action);
|
fprintf(stdout, "\tAction => %d (0 = Block, 1 = Allow).\n\n", filter->action);
|
||||||
|
|
||||||
// IP Options.
|
// IP Options.
|
||||||
fprintf(stdout, "\tIP Options\n");
|
fprintf(stdout, "\tIP Options\n");
|
||||||
|
|
||||||
// IP addresses require additional code for string printing.
|
// IP addresses require additional code for string printing.
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
sin.sin_addr.s_addr = cfg.filters[i].srcip;
|
sin.sin_addr.s_addr = filter->src_ip;
|
||||||
fprintf(stdout, "\t\tSource IPv4 => %s\n", inet_ntoa(sin.sin_addr));
|
fprintf(stdout, "\t\tSource IPv4 => %s\n", inet_ntoa(sin.sin_addr));
|
||||||
|
fprintf(stdout, "\t\tSource CIDR => %d\n", filter->src_cidr);
|
||||||
|
|
||||||
struct sockaddr_in din;
|
struct sockaddr_in din;
|
||||||
din.sin_addr.s_addr = cfg.filters[i].dstip;
|
din.sin_addr.s_addr = filter->dst_ip;
|
||||||
fprintf(stdout, "\t\tDestination IPv4 => %s\n", inet_ntoa(din.sin_addr));
|
fprintf(stdout, "\t\tDestination IPv4 => %s\n", inet_ntoa(din.sin_addr));
|
||||||
|
fprintf(stdout, "\t\tDestination CIDR => %d\n", filter->dst_cidr);
|
||||||
|
|
||||||
struct in6_addr sin6;
|
struct in6_addr sin6;
|
||||||
memcpy(&sin6, &cfg.filters[i].srcip6, sizeof(sin6));
|
memcpy(&sin6, &filter->src_ip6, sizeof(sin6));
|
||||||
|
|
||||||
char srcipv6[INET6_ADDRSTRLEN];
|
char srcipv6[INET6_ADDRSTRLEN];
|
||||||
inet_ntop(AF_INET6, &sin6, srcipv6, sizeof(srcipv6));
|
inet_ntop(AF_INET6, &sin6, srcipv6, sizeof(srcipv6));
|
||||||
@@ -362,7 +368,7 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stdout, "\t\tSource IPv6 => %s\n", srcipv6);
|
fprintf(stdout, "\t\tSource IPv6 => %s\n", srcipv6);
|
||||||
|
|
||||||
struct in6_addr din6;
|
struct in6_addr din6;
|
||||||
memcpy(&din6, &cfg.filters[i].dstip6, sizeof(din6));
|
memcpy(&din6, &filter->dst_ip6, sizeof(din6));
|
||||||
|
|
||||||
char dstipv6[INET6_ADDRSTRLEN];
|
char dstipv6[INET6_ADDRSTRLEN];
|
||||||
inet_ntop(AF_INET6, &din6, dstipv6, sizeof(dstipv6));
|
inet_ntop(AF_INET6, &din6, dstipv6, sizeof(dstipv6));
|
||||||
@@ -370,40 +376,40 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stdout, "\t\tDestination IPv6 => %s\n", dstipv6);
|
fprintf(stdout, "\t\tDestination IPv6 => %s\n", dstipv6);
|
||||||
|
|
||||||
// Other IP header information.
|
// Other IP header information.
|
||||||
fprintf(stdout, "\t\tMax Length => %d\n", cfg.filters[i].max_len);
|
fprintf(stdout, "\t\tMax Length => %d\n", filter->max_len);
|
||||||
fprintf(stdout, "\t\tMin Length => %d\n", cfg.filters[i].min_len);
|
fprintf(stdout, "\t\tMin Length => %d\n", filter->min_len);
|
||||||
fprintf(stdout, "\t\tMax TTL => %d\n", cfg.filters[i].max_ttl);
|
fprintf(stdout, "\t\tMax TTL => %d\n", filter->max_ttl);
|
||||||
fprintf(stdout, "\t\tMin TTL => %d\n", cfg.filters[i].min_ttl);
|
fprintf(stdout, "\t\tMin TTL => %d\n", filter->min_ttl);
|
||||||
fprintf(stdout, "\t\tTOS => %d\n", cfg.filters[i].tos);
|
fprintf(stdout, "\t\tTOS => %d\n", filter->tos);
|
||||||
fprintf(stdout, "\t\tPPS => %llu\n", cfg.filters[i].pps);
|
fprintf(stdout, "\t\tPPS => %llu\n", filter->pps);
|
||||||
fprintf(stdout, "\t\tBPS => %llu\n", cfg.filters[i].bps);
|
fprintf(stdout, "\t\tBPS => %llu\n", filter->bps);
|
||||||
fprintf(stdout, "\t\tBlock Time => %llu\n\n", cfg.filters[i].blocktime);
|
fprintf(stdout, "\t\tBlock Time => %llu\n\n", filter->blocktime);
|
||||||
|
|
||||||
// TCP Options.
|
// TCP Options.
|
||||||
fprintf(stdout, "\tTCP Options\n");
|
fprintf(stdout, "\tTCP Options\n");
|
||||||
fprintf(stdout, "\t\tTCP Enabled => %d\n", cfg.filters[i].tcpopts.enabled);
|
fprintf(stdout, "\t\tTCP Enabled => %d\n", filter->tcpopts.enabled);
|
||||||
fprintf(stdout, "\t\tTCP Source Port => %d\n", cfg.filters[i].tcpopts.sport);
|
fprintf(stdout, "\t\tTCP Source Port => %d\n", filter->tcpopts.sport);
|
||||||
fprintf(stdout, "\t\tTCP Destination Port => %d\n", cfg.filters[i].tcpopts.dport);
|
fprintf(stdout, "\t\tTCP Destination Port => %d\n", filter->tcpopts.dport);
|
||||||
fprintf(stdout, "\t\tTCP URG Flag => %d\n", cfg.filters[i].tcpopts.urg);
|
fprintf(stdout, "\t\tTCP URG Flag => %d\n", filter->tcpopts.urg);
|
||||||
fprintf(stdout, "\t\tTCP ACK Flag => %d\n", cfg.filters[i].tcpopts.ack);
|
fprintf(stdout, "\t\tTCP ACK Flag => %d\n", filter->tcpopts.ack);
|
||||||
fprintf(stdout, "\t\tTCP RST Flag => %d\n", cfg.filters[i].tcpopts.rst);
|
fprintf(stdout, "\t\tTCP RST Flag => %d\n", filter->tcpopts.rst);
|
||||||
fprintf(stdout, "\t\tTCP PSH Flag => %d\n", cfg.filters[i].tcpopts.psh);
|
fprintf(stdout, "\t\tTCP PSH Flag => %d\n", filter->tcpopts.psh);
|
||||||
fprintf(stdout, "\t\tTCP SYN Flag => %d\n", cfg.filters[i].tcpopts.syn);
|
fprintf(stdout, "\t\tTCP SYN Flag => %d\n", filter->tcpopts.syn);
|
||||||
fprintf(stdout, "\t\tTCP FIN Flag => %d\n", cfg.filters[i].tcpopts.fin);
|
fprintf(stdout, "\t\tTCP FIN Flag => %d\n", filter->tcpopts.fin);
|
||||||
fprintf(stdout, "\t\tTCP ECE Flag => %d\n", cfg.filters[i].tcpopts.ece);
|
fprintf(stdout, "\t\tTCP ECE Flag => %d\n", filter->tcpopts.ece);
|
||||||
fprintf(stdout, "\t\tTCP CWR Flag => %d\n\n", cfg.filters[i].tcpopts.cwr);
|
fprintf(stdout, "\t\tTCP CWR Flag => %d\n\n", filter->tcpopts.cwr);
|
||||||
|
|
||||||
// UDP Options.
|
// UDP Options.
|
||||||
fprintf(stdout, "\tUDP Options\n");
|
fprintf(stdout, "\tUDP Options\n");
|
||||||
fprintf(stdout, "\t\tUDP Enabled => %d\n", cfg.filters[i].udpopts.enabled);
|
fprintf(stdout, "\t\tUDP Enabled => %d\n", filter->udpopts.enabled);
|
||||||
fprintf(stdout, "\t\tUDP Source Port => %d\n", cfg.filters[i].udpopts.sport);
|
fprintf(stdout, "\t\tUDP Source Port => %d\n", filter->udpopts.sport);
|
||||||
fprintf(stdout, "\t\tUDP Destination Port => %d\n\n", cfg.filters[i].udpopts.dport);
|
fprintf(stdout, "\t\tUDP Destination Port => %d\n\n", filter->udpopts.dport);
|
||||||
|
|
||||||
// ICMP Options.
|
// ICMP Options.
|
||||||
fprintf(stdout, "\tICMP Options\n");
|
fprintf(stdout, "\tICMP Options\n");
|
||||||
fprintf(stdout, "\t\tICMP Enabled => %d\n", cfg.filters[i].icmpopts.enabled);
|
fprintf(stdout, "\t\tICMP Enabled => %d\n", filter->icmpopts.enabled);
|
||||||
fprintf(stdout, "\t\tICMP Code => %d\n", cfg.filters[i].icmpopts.code);
|
fprintf(stdout, "\t\tICMP Code => %d\n", filter->icmpopts.code);
|
||||||
fprintf(stdout, "\t\tICMP Type => %d\n", cfg.filters[i].icmpopts.type);
|
fprintf(stdout, "\t\tICMP Type => %d\n", filter->icmpopts.type);
|
||||||
|
|
||||||
fprintf(stdout, "\n\n");
|
fprintf(stdout, "\n\n");
|
||||||
}
|
}
|
||||||
@@ -425,7 +431,7 @@ int main(int argc, char *argv[])
|
|||||||
const char *filename = "/etc/xdpfw/xdpfw_kern.o";
|
const char *filename = "/etc/xdpfw/xdpfw_kern.o";
|
||||||
|
|
||||||
// Load BPF object.
|
// Load BPF object.
|
||||||
struct xdp_program *prog = loadbpfobj(filename);
|
struct xdp_program *prog = LoadBpfObj(filename);
|
||||||
|
|
||||||
if (prog == NULL)
|
if (prog == NULL)
|
||||||
{
|
{
|
||||||
@@ -435,14 +441,14 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attach XDP program.
|
// Attach XDP program.
|
||||||
if (attachxdp(prog, ifidx, 0, &cmd))
|
if (AttachXdp(prog, ifidx, 0, &cmd))
|
||||||
{
|
{
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve BPF maps.
|
// Retrieve BPF maps.
|
||||||
filtersmap = findmapfd(prog, "filters_map");
|
filtersmap = FindMapFd(prog, "filters_map");
|
||||||
statsmap = findmapfd(prog, "stats_map");
|
statsmap = FindMapFd(prog, "stats_map");
|
||||||
|
|
||||||
// Check for valid maps.
|
// Check for valid maps.
|
||||||
if (filtersmap < 0)
|
if (filtersmap < 0)
|
||||||
@@ -460,10 +466,10 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update BPF maps.
|
// Update BPF maps.
|
||||||
updatefilters(&cfg);
|
UpdateFilters(&cfg);
|
||||||
|
|
||||||
// Signal.
|
// Signal.
|
||||||
signal(SIGINT, signalHndl);
|
signal(SIGINT, SignalHndl);
|
||||||
|
|
||||||
// Receive CPU count for stats map parsing.
|
// Receive CPU count for stats map parsing.
|
||||||
int cpus = get_nprocs_conf();
|
int cpus = get_nprocs_conf();
|
||||||
@@ -492,15 +498,15 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
// Check if config file have been modified
|
// Check if config file have been modified
|
||||||
if (stat(cmd.cfgfile, &conf_stat) == 0 && conf_stat.st_mtime > lastupdated) {
|
if (stat(cmd.cfgfile, &conf_stat) == 0 && conf_stat.st_mtime > lastupdated) {
|
||||||
// Memleak fix for strdup() in updateconfig()
|
// Memleak fix for strdup() in UpdateConfig()
|
||||||
// Before updating it again, we need to free the old return value
|
// Before updating it again, we need to free the old return value
|
||||||
free(cfg.interface);
|
free(cfg.interface);
|
||||||
|
|
||||||
// Update config.
|
// Update config.
|
||||||
updateconfig(&cfg, cmd.cfgfile);
|
UpdateConfig(&cfg, cmd.cfgfile);
|
||||||
|
|
||||||
// Update BPF maps.
|
// Update BPF maps.
|
||||||
updatefilters(&cfg);
|
UpdateFilters(&cfg);
|
||||||
|
|
||||||
// Update timer
|
// Update timer
|
||||||
lastupdated = time(NULL);
|
lastupdated = time(NULL);
|
||||||
@@ -553,7 +559,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Detach XDP program.
|
// Detach XDP program.
|
||||||
attachxdp(prog, ifidx, 1, &cmd);
|
AttachXdp(prog, ifidx, 1, &cmd);
|
||||||
|
|
||||||
// Add spacing.
|
// Add spacing.
|
||||||
fprintf(stdout, "\n");
|
fprintf(stdout, "\n");
|
||||||
|
|||||||
11
src/xdpfw.h
11
src/xdpfw.h
@@ -101,11 +101,14 @@ struct filter
|
|||||||
|
|
||||||
__u8 action;
|
__u8 action;
|
||||||
|
|
||||||
__u32 srcip;
|
__u32 src_ip;
|
||||||
__u32 dstip;
|
__u8 src_cidr;
|
||||||
|
|
||||||
__u32 srcip6[4];
|
__u32 dst_ip;
|
||||||
__u32 dstip6[4];
|
__u8 dst_cidr;
|
||||||
|
|
||||||
|
__u32 src_ip6[4];
|
||||||
|
__u32 dst_ip6[4];
|
||||||
|
|
||||||
unsigned int do_min_ttl : 1;
|
unsigned int do_min_ttl : 1;
|
||||||
__u8 min_ttl;
|
__u8 min_ttl;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <xdp/prog_dispatcher.h>
|
#include <xdp/prog_dispatcher.h>
|
||||||
|
|
||||||
#include "xdpfw.h"
|
#include "xdpfw.h"
|
||||||
|
#include "xdp_utils.h"
|
||||||
|
|
||||||
#ifndef memcpy
|
#ifndef memcpy
|
||||||
#define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n))
|
#define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n))
|
||||||
@@ -103,7 +104,7 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
// Initialize IP headers.
|
// Initialize IP headers.
|
||||||
struct iphdr *iph = NULL;
|
struct iphdr *iph = NULL;
|
||||||
struct ipv6hdr *iph6 = NULL;
|
struct ipv6hdr *iph6 = NULL;
|
||||||
__u128 srcip6 = 0;
|
__u128 src_ip6 = 0;
|
||||||
|
|
||||||
// Set IPv4 and IPv6 common variables.
|
// Set IPv4 and IPv6 common variables.
|
||||||
if (eth->h_proto == htons(ETH_P_IPV6))
|
if (eth->h_proto == htons(ETH_P_IPV6))
|
||||||
@@ -115,7 +116,7 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
return XDP_DROP;
|
return XDP_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&srcip6, &iph6->saddr.in6_u.u6_addr32, sizeof(srcip6));
|
memcpy(&src_ip6, &iph6->saddr.in6_u.u6_addr32, sizeof(src_ip6));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -144,7 +145,7 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
|
|
||||||
if (iph6)
|
if (iph6)
|
||||||
{
|
{
|
||||||
blocked = bpf_map_lookup_elem(&ip6_blacklist_map, &srcip6);
|
blocked = bpf_map_lookup_elem(&ip6_blacklist_map, &src_ip6);
|
||||||
}
|
}
|
||||||
else if (iph)
|
else if (iph)
|
||||||
{
|
{
|
||||||
@@ -162,7 +163,7 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
// Remove element from map.
|
// Remove element from map.
|
||||||
if (iph6)
|
if (iph6)
|
||||||
{
|
{
|
||||||
bpf_map_delete_elem(&ip6_blacklist_map, &srcip6);
|
bpf_map_delete_elem(&ip6_blacklist_map, &src_ip6);
|
||||||
}
|
}
|
||||||
else if (iph)
|
else if (iph)
|
||||||
{
|
{
|
||||||
@@ -192,7 +193,7 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
|
|
||||||
if (iph6)
|
if (iph6)
|
||||||
{
|
{
|
||||||
ip_stats = bpf_map_lookup_elem(&ip6_stats_map, &srcip6);
|
ip_stats = bpf_map_lookup_elem(&ip6_stats_map, &src_ip6);
|
||||||
}
|
}
|
||||||
else if (iph)
|
else if (iph)
|
||||||
{
|
{
|
||||||
@@ -234,7 +235,7 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
|
|
||||||
if (iph6)
|
if (iph6)
|
||||||
{
|
{
|
||||||
bpf_map_update_elem(&ip6_stats_map, &srcip6, &new, BPF_ANY);
|
bpf_map_update_elem(&ip6_stats_map, &src_ip6, &new, BPF_ANY);
|
||||||
}
|
}
|
||||||
else if (iph)
|
else if (iph)
|
||||||
{
|
{
|
||||||
@@ -353,19 +354,19 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
if (iph6)
|
if (iph6)
|
||||||
{
|
{
|
||||||
// Source address.
|
// Source address.
|
||||||
if (filter->srcip6[0] != 0 && (iph6->saddr.in6_u.u6_addr32[0] != filter->srcip6[0] || iph6->saddr.in6_u.u6_addr32[1] != filter->srcip6[1] || iph6->saddr.in6_u.u6_addr32[2] != filter->srcip6[2] || iph6->saddr.in6_u.u6_addr32[3] != filter->srcip6[3]))
|
if (filter->src_ip6[0] != 0 && (iph6->saddr.in6_u.u6_addr32[0] != filter->src_ip6[0] || iph6->saddr.in6_u.u6_addr32[1] != filter->src_ip6[1] || iph6->saddr.in6_u.u6_addr32[2] != filter->src_ip6[2] || iph6->saddr.in6_u.u6_addr32[3] != filter->src_ip6[3]))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination address.
|
// Destination address.
|
||||||
if (filter->dstip6[0] != 0 && (iph6->daddr.in6_u.u6_addr32[0] != filter->dstip6[0] || iph6->daddr.in6_u.u6_addr32[1] != filter->dstip6[1] || iph6->daddr.in6_u.u6_addr32[2] != filter->dstip6[2] || iph6->daddr.in6_u.u6_addr32[3] != filter->dstip6[3]))
|
if (filter->dst_ip6[0] != 0 && (iph6->daddr.in6_u.u6_addr32[0] != filter->dst_ip6[0] || iph6->daddr.in6_u.u6_addr32[1] != filter->dst_ip6[1] || iph6->daddr.in6_u.u6_addr32[2] != filter->dst_ip6[2] || iph6->daddr.in6_u.u6_addr32[3] != filter->dst_ip6[3]))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ALLOWSINGLEIPV4V6
|
#ifdef ALLOWSINGLEIPV4V6
|
||||||
if (filter->srcip != 0 || filter->dstip != 0)
|
if (filter->src_ip != 0 || filter->dst_ip != 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -398,19 +399,35 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
else if (iph)
|
else if (iph)
|
||||||
{
|
{
|
||||||
// Source address.
|
// Source address.
|
||||||
if (filter->srcip && iph->saddr != filter->srcip)
|
if (filter->src_ip)
|
||||||
{
|
{
|
||||||
continue;
|
if (filter->src_cidr == 32 && iph->saddr != filter->src_ip)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsIpInRange(iph->saddr, filter->src_ip, filter->src_cidr))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination address.
|
// Destination address.
|
||||||
if (filter->dstip != 0 && iph->daddr != filter->dstip)
|
if (filter->dst_ip)
|
||||||
{
|
{
|
||||||
continue;
|
if (filter->dst_cidr == 32 && iph->daddr != filter->dst_ip)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsIpInRange(iph->daddr, filter->dst_ip, filter->dst_cidr))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ALLOWSINGLEIPV4V6
|
#ifdef ALLOWSINGLEIPV4V6
|
||||||
if ((filter->srcip6[0] != 0 || filter->srcip6[1] != 0 || filter->srcip6[2] != 0 || filter->srcip6[3] != 0) || (filter->dstip6[0] != 0 || filter->dstip6[1] != 0 || filter->dstip6[2] != 0 || filter->dstip6[3] != 0))
|
if ((filter->src_ip6[0] != 0 || filter->src_ip6[1] != 0 || filter->src_ip6[2] != 0 || filter->src_ip6[3] != 0) || (filter->dst_ip6[0] != 0 || filter->dst_ip6[1] != 0 || filter->dst_ip6[2] != 0 || filter->dst_ip6[3] != 0))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -615,7 +632,7 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
|
|
||||||
if (iph6)
|
if (iph6)
|
||||||
{
|
{
|
||||||
bpf_map_update_elem(&ip6_blacklist_map, &srcip6, &newTime, BPF_ANY);
|
bpf_map_update_elem(&ip6_blacklist_map, &src_ip6, &newTime, BPF_ANY);
|
||||||
}
|
}
|
||||||
else if (iph)
|
else if (iph)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user