Add IPv6 support, rewrite program to improve performance, and update README.
This commit is contained in:
36
src/config.c
36
src/config.c
@@ -24,6 +24,12 @@ void SetConfigDefaults(struct config_map *cfg)
|
||||
cfg->filters[i].srcIP = 0;
|
||||
cfg->filters[i].dstIP = 0;
|
||||
|
||||
for (uint8_t j = 0; j < 4; j++)
|
||||
{
|
||||
cfg->filters[i].srcIP6[j] = 0;
|
||||
cfg->filters[i].dstIP6[j] = 0;
|
||||
}
|
||||
|
||||
cfg->filters[i].do_min_len = 0;
|
||||
cfg->filters[i].min_len = 0;
|
||||
|
||||
@@ -210,6 +216,36 @@ int ReadConfig(struct config_map *cfg)
|
||||
cfg->filters[i].dstIP = inet_addr(dIP);
|
||||
}
|
||||
|
||||
// Source IP (IPv6) (not required).
|
||||
const char *sIP6;
|
||||
|
||||
if (config_setting_lookup_string(filter, "srcip6", &sIP6))
|
||||
{
|
||||
struct in6_addr in;
|
||||
|
||||
inet_pton(AF_INET6, sIP6, &in);
|
||||
|
||||
for (uint8_t j = 0; j < 4; j++)
|
||||
{
|
||||
cfg->filters[i].srcIP6[j] = in.__in6_u.__u6_addr32[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Destination IP (IPv6) (not required).
|
||||
const char *dIP6;
|
||||
|
||||
if (config_setting_lookup_string(filter, "dstip6", &dIP6))
|
||||
{
|
||||
struct in6_addr in;
|
||||
|
||||
inet_pton(AF_INET6, dIP6, &in);
|
||||
|
||||
for (uint8_t j = 0; j < 4; j++)
|
||||
{
|
||||
cfg->filters[i].dstIP6[j] = in.__in6_u.__u6_addr32[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Minimum TTL (not required).
|
||||
int min_ttl;
|
||||
|
||||
|
||||
@@ -70,6 +70,9 @@ struct filter
|
||||
uint32_t srcIP;
|
||||
uint32_t dstIP;
|
||||
|
||||
uint32_t srcIP6[4];
|
||||
uint32_t dstIP6[4];
|
||||
|
||||
unsigned int do_min_ttl : 1;
|
||||
uint8_t min_ttl;
|
||||
|
||||
|
||||
527
src/xdpfw_kern.c
527
src/xdpfw_kern.c
@@ -1,8 +1,10 @@
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/in.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
@@ -16,7 +18,9 @@
|
||||
#include "include/xdpfw.h"
|
||||
|
||||
//#define DEBUG
|
||||
#define DOSTATSONBLOCKMAP // Feel free to comment this out if you don't want the `blocked` entry on the stats map to be incremented every single time a packet is dropped from the source IP being on the blocked map. Commenting this line out should increase performance when blocking malicious traffic.
|
||||
//#define DOSTATSONBLOCKMAP // Feel free to comment this out if you don't want the `blocked` entry on the stats map to be incremented every single time a packet is dropped from the source IP being on the blocked map. Commenting this line out should increase performance when blocking malicious traffic.
|
||||
|
||||
#define ALLOWSINGLEIPV4V6 // When this is defined, a check will occur inside the IPv4 and IPv6 filters. For IPv6 packets, if no IPv6 source/destination IP addresses are set, but there is an IPv4 address, it will ignore the filter. The same goes for IPv4, if there is no IPv4 source/destination IP addresses set, if an IPv6 address is set, it will ignore the filter.
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
@@ -43,6 +47,8 @@
|
||||
#define ntohl(x) (x)
|
||||
#endif
|
||||
|
||||
#define uint128_t __uint128_t
|
||||
|
||||
struct bpf_map_def SEC("maps") filters_map =
|
||||
{
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
@@ -75,9 +81,25 @@ struct bpf_map_def SEC("maps") ip_blacklist_map =
|
||||
.max_entries = MAX_TRACK_IPS
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") ip6_stats_map =
|
||||
{
|
||||
.type = BPF_MAP_TYPE_LRU_HASH,
|
||||
.key_size = sizeof(uint128_t),
|
||||
.value_size = sizeof(struct xdpfw_ip_stats),
|
||||
.max_entries = MAX_TRACK_IPS
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") ip6_blacklist_map =
|
||||
{
|
||||
.type = BPF_MAP_TYPE_LRU_HASH,
|
||||
.key_size = sizeof(uint128_t),
|
||||
.value_size = sizeof(uint64_t),
|
||||
.max_entries = MAX_TRACK_IPS
|
||||
};
|
||||
|
||||
SEC("xdp_prog")
|
||||
int xdp_prog_main(struct xdp_md *ctx)
|
||||
{
|
||||
{
|
||||
// Initialize data.
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
void *data = (void *)(long)ctx->data;
|
||||
@@ -92,40 +114,67 @@ int xdp_prog_main(struct xdp_md *ctx)
|
||||
}
|
||||
|
||||
// Check Ethernet protocol.
|
||||
if (unlikely(ethhdr->h_proto != htons(ETH_P_IP)))
|
||||
if (unlikely(ethhdr->h_proto != htons(ETH_P_IP) && ethhdr->h_proto != htons(ETH_P_IPV6)))
|
||||
{
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
uint8_t matched = 0;
|
||||
uint8_t action = 0;
|
||||
uint64_t blocktime = 1;
|
||||
|
||||
// Scan IP header.
|
||||
struct iphdr *iph = data + sizeof(struct ethhdr);
|
||||
// Initialize IP headers.
|
||||
struct iphdr *iph;
|
||||
struct ipv6hdr *iph6;
|
||||
uint128_t srcip6 = 0;
|
||||
|
||||
// Check if the IP header is valid.
|
||||
if (unlikely(iph + 1 > (struct iphdr *)data_end))
|
||||
// Set IPv4 and IPv6 common variables.
|
||||
if (ethhdr->h_proto == htons(ETH_P_IPV6))
|
||||
{
|
||||
return XDP_DROP;
|
||||
iph6 = (data + sizeof(struct ethhdr));
|
||||
|
||||
if (unlikely(iph6 + 1 > (struct ipv6hdr *)data_end))
|
||||
{
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
srcip6 |= (uint128_t) iph6->saddr.in6_u.u6_addr32[0] << 0;
|
||||
srcip6 |= (uint128_t) iph6->saddr.in6_u.u6_addr32[1] << 16;
|
||||
srcip6 |= (uint128_t) iph6->saddr.in6_u.u6_addr32[2] << 32;
|
||||
srcip6 |= (uint128_t) iph6->saddr.in6_u.u6_addr32[3] << 48;
|
||||
}
|
||||
else
|
||||
{
|
||||
iph = (data + sizeof(struct ethhdr));
|
||||
|
||||
if (unlikely(iph + 1 > (struct iphdr *)data_end))
|
||||
{
|
||||
return XDP_DROP;
|
||||
}
|
||||
}
|
||||
|
||||
// Check IP header protocols.
|
||||
if (unlikely(iph->protocol != IPPROTO_UDP && iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_ICMP))
|
||||
if ((ethhdr->h_proto == htons(ETH_P_IPV6) && iph6->nexthdr != IPPROTO_UDP && iph6->nexthdr != IPPROTO_TCP && iph6->nexthdr != IPPROTO_ICMP) && (ethhdr->h_proto == htons(ETH_P_IP) && iph->protocol != IPPROTO_UDP && iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_ICMP))
|
||||
{
|
||||
return XDP_DROP;
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
// Get stats map.
|
||||
uint32_t key = 0;
|
||||
struct xdpfw_stats *stats;
|
||||
|
||||
stats = bpf_map_lookup_elem(&stats_map, &key);
|
||||
struct xdpfw_stats *stats = bpf_map_lookup_elem(&stats_map, &key);
|
||||
|
||||
uint64_t now = bpf_ktime_get_ns();
|
||||
|
||||
// Check blacklist map.
|
||||
uint64_t *blocked = bpf_map_lookup_elem(&ip_blacklist_map, &iph->saddr);
|
||||
uint64_t *blocked = NULL;
|
||||
|
||||
if (ethhdr->h_proto == htons(ETH_P_IPV6))
|
||||
{
|
||||
blocked = bpf_map_lookup_elem(&ip6_blacklist_map, &srcip6);
|
||||
}
|
||||
else
|
||||
{
|
||||
blocked = bpf_map_lookup_elem(&ip_blacklist_map, &iph->saddr);
|
||||
}
|
||||
|
||||
if (blocked != NULL && *blocked > 0)
|
||||
{
|
||||
@@ -136,7 +185,14 @@ int xdp_prog_main(struct xdp_md *ctx)
|
||||
if (now > *blocked)
|
||||
{
|
||||
// Remove element from map.
|
||||
bpf_map_delete_elem(&ip_blacklist_map, &iph->saddr);
|
||||
if (ethhdr->h_proto == htons(ETH_P_IPV6))
|
||||
{
|
||||
bpf_map_delete_elem(&ip6_blacklist_map, &srcip6);
|
||||
}
|
||||
else
|
||||
{
|
||||
bpf_map_delete_elem(&ip_blacklist_map, &iph->saddr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -157,8 +213,17 @@ int xdp_prog_main(struct xdp_md *ctx)
|
||||
uint64_t pps = 0;
|
||||
uint64_t bps = 0;
|
||||
|
||||
struct xdpfw_ip_stats *ip_stats = bpf_map_lookup_elem(&ip_stats_map, &iph->saddr);
|
||||
|
||||
struct xdpfw_ip_stats *ip_stats = NULL;
|
||||
|
||||
if (ethhdr->h_proto == htons(ETH_P_IPV6))
|
||||
{
|
||||
ip_stats = bpf_map_lookup_elem(&ip6_stats_map, &srcip6);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip_stats = bpf_map_lookup_elem(&ip_stats_map, &iph->saddr);
|
||||
}
|
||||
|
||||
if (ip_stats)
|
||||
{
|
||||
// Check for reset.
|
||||
@@ -188,264 +253,404 @@ int xdp_prog_main(struct xdp_md *ctx)
|
||||
pps = new.pps;
|
||||
bps = new.bps;
|
||||
|
||||
bpf_map_update_elem(&ip_stats_map, &iph->saddr, &new, BPF_ANY);
|
||||
if (ethhdr->h_proto == htons(ETH_P_IPV6))
|
||||
{
|
||||
bpf_map_update_elem(&ip6_stats_map, &srcip6, &new, BPF_ANY);
|
||||
}
|
||||
else
|
||||
{
|
||||
bpf_map_update_elem(&ip_stats_map, &iph->saddr, &new, BPF_ANY);
|
||||
}
|
||||
}
|
||||
|
||||
// Let's get the filters we need.
|
||||
struct filter *filter[MAX_FILTERS];
|
||||
struct tcphdr *tcph = NULL;
|
||||
struct udphdr *udph = NULL;
|
||||
struct icmphdr *icmph = NULL;
|
||||
struct icmp6hdr *icmp6h = NULL;
|
||||
|
||||
// Check protocol.
|
||||
if (ethhdr->h_proto == htons(ETH_P_IPV6))
|
||||
{
|
||||
switch (iph6->nexthdr)
|
||||
{
|
||||
case IPPROTO_TCP:
|
||||
// Scan TCP header.
|
||||
tcph = (data + sizeof(struct ethhdr) + sizeof(struct ipv6hdr));
|
||||
|
||||
// Check TCP header.
|
||||
if (tcph + 1 > (struct tcphdr *)data_end)
|
||||
{
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
// Scan UDP header.
|
||||
udph = (data + sizeof(struct ethhdr) + sizeof(struct ipv6hdr));
|
||||
|
||||
// Check TCP header.
|
||||
if (udph + 1 > (struct udphdr *)data_end)
|
||||
{
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IPPROTO_ICMPV6:
|
||||
// Scan ICMPv6 header.
|
||||
icmp6h = (data + sizeof(struct ethhdr) + sizeof(struct ipv6hdr));
|
||||
|
||||
// Check ICMPv6 header.
|
||||
if (icmp6h + 1 > (struct icmp6hdr *)data_end)
|
||||
{
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (iph->protocol)
|
||||
{
|
||||
case IPPROTO_TCP:
|
||||
// Scan TCP header.
|
||||
tcph = (data + sizeof(struct ethhdr) + (iph->ihl * 4));
|
||||
|
||||
// Check TCP header.
|
||||
if (tcph + 1 > (struct tcphdr *)data_end)
|
||||
{
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
// Scan UDP header.
|
||||
udph = (data + sizeof(struct ethhdr) + (iph->ihl * 4));
|
||||
|
||||
// Check TCP header.
|
||||
if (udph + 1 > (struct udphdr *)data_end)
|
||||
{
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IPPROTO_ICMP:
|
||||
// Scan ICMP header.
|
||||
icmph = (data + sizeof(struct ethhdr) + (iph->ihl * 4));
|
||||
|
||||
// Check ICMP header.
|
||||
if (icmph + 1 > (struct icmphdr *)data_end)
|
||||
{
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < MAX_FILTERS; i++)
|
||||
{
|
||||
uint32_t key = i;
|
||||
|
||||
filter[i] = bpf_map_lookup_elem(&filters_map, &key);
|
||||
}
|
||||
|
||||
struct tcphdr *tcph;
|
||||
struct udphdr *udph;
|
||||
struct icmphdr *icmph;
|
||||
|
||||
uint16_t l4headerLen = 0;
|
||||
struct filter *filter = bpf_map_lookup_elem(&filters_map, &key);
|
||||
|
||||
// Check protocol.
|
||||
if (iph->protocol == IPPROTO_TCP)
|
||||
{
|
||||
// Scan TCP header.
|
||||
tcph = (data + sizeof(struct ethhdr) + (iph->ihl * 4));
|
||||
|
||||
// Check TCP header.
|
||||
if (tcph + 1 > (struct tcphdr *)data_end)
|
||||
{
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
// Set L4 Header length.
|
||||
l4headerLen = sizeof(struct tcphdr);
|
||||
}
|
||||
else if (iph->protocol == IPPROTO_UDP)
|
||||
{
|
||||
// Scan UDP header.
|
||||
udph = (data + sizeof(struct ethhdr) + (iph->ihl * 4));
|
||||
|
||||
// Check TCP header.
|
||||
if (udph + 1 > (struct udphdr *)data_end)
|
||||
{
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
// Set L4 Header length.
|
||||
l4headerLen = sizeof(struct udphdr);
|
||||
}
|
||||
else if (iph->protocol == IPPROTO_ICMP)
|
||||
{
|
||||
// Scan UDP header.
|
||||
icmph = (data + sizeof(struct ethhdr) + (iph->ihl * 4));
|
||||
|
||||
// Check TCP header.
|
||||
if (icmph + 1 > (struct icmphdr *)data_end)
|
||||
{
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
// Set L4 Header length.
|
||||
l4headerLen = sizeof(struct icmphdr);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < MAX_FILTERS; i++)
|
||||
{
|
||||
// Check if ID is above 0 (if 0, it's an invalid rule).
|
||||
if (!filter[i] || filter[i]->id < 1)
|
||||
if (!filter || filter->id < 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if the rule is enabled.
|
||||
if (!filter[i]->enabled)
|
||||
if (!filter->enabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Source address.
|
||||
if (filter[i]->srcIP != 0 && iph->saddr != filter[i]->srcIP)
|
||||
// Do specific IPv6.
|
||||
if (ethhdr->h_proto == htons(ETH_P_IPV6))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (iph6 + 1 > (struct ipv6hdr *)data_end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Destination address.
|
||||
if (filter[i]->dstIP != 0 && iph->daddr != filter[i]->dstIP)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 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]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Max TTL length.
|
||||
if (filter[i]->do_max_ttl && filter[i]->max_ttl > iph->ttl)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 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]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Min TTL length.
|
||||
if (filter[i]->do_min_ttl && filter[i]->min_ttl < iph->ttl)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#ifdef ALLOWSINGLEIPV4V6
|
||||
if (filter->srcIP != 0 || filter->dstIP != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Max packet length.
|
||||
if (filter[i]->do_max_len && filter[i]->max_len > (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Max TTL length.
|
||||
if (filter->do_max_ttl && filter->max_ttl > iph6->hop_limit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Min packet length.
|
||||
if (filter[i]->do_min_len && filter[i]->min_len < (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Min TTL length.
|
||||
if (filter->do_min_ttl && filter->min_ttl < iph6->hop_limit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TOS.
|
||||
if (filter[i]->do_tos && filter[i]->tos != iph->tos)
|
||||
// Max packet length.
|
||||
if (filter->do_max_len && filter->max_len > (ntohs(iph6->payload_len) + sizeof(struct ethhdr)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Min packet length.
|
||||
if (filter->do_min_len && filter->min_len < (ntohs(iph6->payload_len) + sizeof(struct ethhdr)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
// Source address.
|
||||
if (filter->srcIP != 0 && iph->saddr != filter->srcIP)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Destination address.
|
||||
if (filter->dstIP != 0 && iph->daddr != filter->dstIP)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#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))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TOS.
|
||||
if (filter->do_tos && filter->tos != iph->tos)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Max TTL length.
|
||||
if (filter->do_max_ttl && filter->max_ttl > iph->ttl)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Min TTL length.
|
||||
if (filter->do_min_ttl && filter->min_ttl < iph->ttl)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Max packet length.
|
||||
if (filter->do_max_len && filter->max_len > (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Min packet length.
|
||||
if (filter->do_min_len && filter->min_len < (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// PPS.
|
||||
if (filter[i]->do_pps && pps <= filter[i]->pps)
|
||||
if (filter->do_pps && pps <= filter->pps)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// BPS.
|
||||
if (filter[i]->do_bps && bps <= filter[i]->bps)
|
||||
if (filter->do_bps && bps <= filter->bps)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Do TCP options.
|
||||
if (iph->protocol == IPPROTO_TCP && filter[i]->tcpopts.enabled)
|
||||
if (filter->tcpopts.enabled)
|
||||
{
|
||||
if (!tcph)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Source port.
|
||||
if (filter[i]->tcpopts.do_sport && htons(filter[i]->tcpopts.sport) != tcph->source)
|
||||
if (filter->tcpopts.do_sport && htons(filter->tcpopts.sport) != tcph->source)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Destination port.
|
||||
if (filter[i]->tcpopts.do_dport && htons(filter[i]->tcpopts.dport) != tcph->dest)
|
||||
if (filter->tcpopts.do_dport && htons(filter->tcpopts.dport) != tcph->dest)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// URG flag.
|
||||
if (filter[i]->tcpopts.do_urg && filter[i]->tcpopts.urg != tcph->urg)
|
||||
if (filter->tcpopts.do_urg && filter->tcpopts.urg != tcph->urg)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// ACK flag.
|
||||
if (filter[i]->tcpopts.do_ack && filter[i]->tcpopts.ack != tcph->ack)
|
||||
if (filter->tcpopts.do_ack && filter->tcpopts.ack != tcph->ack)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// RST flag.
|
||||
if (filter[i]->tcpopts.do_rst && filter[i]->tcpopts.rst != tcph->rst)
|
||||
if (filter->tcpopts.do_rst && filter->tcpopts.rst != tcph->rst)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// PSH flag.
|
||||
if (filter[i]->tcpopts.do_psh && filter[i]->tcpopts.psh != tcph->psh)
|
||||
if (filter->tcpopts.do_psh && filter->tcpopts.psh != tcph->psh)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// SYN flag.
|
||||
if (filter[i]->tcpopts.do_syn && filter[i]->tcpopts.syn != tcph->syn)
|
||||
if (filter->tcpopts.do_syn && filter->tcpopts.syn != tcph->syn)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIN flag.
|
||||
if (filter[i]->tcpopts.do_fin && filter[i]->tcpopts.fin != tcph->fin)
|
||||
if (filter->tcpopts.do_fin && filter->tcpopts.fin != tcph->fin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (iph->protocol == IPPROTO_UDP && filter[i]->udpopts.enabled)
|
||||
else if (filter->udpopts.enabled)
|
||||
{
|
||||
if (!udph)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Source port.
|
||||
if (filter[i]->udpopts.do_sport && htons(filter[i]->udpopts.sport) != udph->source)
|
||||
if (filter->udpopts.do_sport && htons(filter->udpopts.sport) != udph->source)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Destination port.
|
||||
if (filter[i]->udpopts.do_dport && htons(filter[i]->udpopts.dport) != udph->dest)
|
||||
if (filter->udpopts.do_dport && htons(filter->udpopts.dport) != udph->dest)
|
||||
{
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (iph->protocol == IPPROTO_ICMP && filter[i]->icmpopts.enabled)
|
||||
else if (filter->icmpopts.enabled)
|
||||
{
|
||||
if (!icmph)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Code.
|
||||
if (filter[i]->icmpopts.do_code && filter[i]->icmpopts.code != icmph->code)
|
||||
if (filter->icmpopts.do_code && filter->icmpopts.code != icmph->code)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Type.
|
||||
if (filter[i]->icmpopts.do_type && filter[i]->icmpopts.type != icmph->type)
|
||||
if (filter->icmpopts.do_type && filter->icmpopts.type != icmph->type)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (icmp6h && filter->icmpopts.enabled)
|
||||
{
|
||||
if (!icmp6h)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Code.
|
||||
if (filter->icmpopts.do_code && filter->icmpopts.code != icmp6h->icmp6_code)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Type.
|
||||
if (filter->icmpopts.do_type && filter->icmpopts.type != icmp6h->icmp6_type)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Matched.
|
||||
#ifdef DEBUG
|
||||
bpf_printk("Matched rule ID #%" PRIu8 ".\n", filter[i]->id);
|
||||
bpf_printk("Matched rule ID #%" PRIu8 ".\n", filter->id);
|
||||
#endif
|
||||
|
||||
action = filter->action;
|
||||
blocktime = filter->blockTime;
|
||||
|
||||
matched = 1;
|
||||
action = filter[i]->action;
|
||||
blocktime = filter[i]->blockTime;
|
||||
|
||||
break;
|
||||
goto matched;
|
||||
}
|
||||
|
||||
return XDP_PASS;
|
||||
|
||||
if (matched)
|
||||
{
|
||||
// Increase allowed or blocked entries on stats map.
|
||||
if (stats)
|
||||
matched:
|
||||
if (action == 0)
|
||||
{
|
||||
// Update stats map.
|
||||
if (action == 0)
|
||||
#ifdef DEBUG
|
||||
//bpf_printk("Matched with protocol %" PRIu8 " and sAddr %" PRIu32 ".\n", iph->protocol, iph->saddr);
|
||||
#endif
|
||||
|
||||
// Before dropping, update the blacklist map.
|
||||
if (blocktime > 0)
|
||||
{
|
||||
uint64_t newTime = now + (blocktime * 1000000000);
|
||||
|
||||
if (ethhdr->h_proto == htons(ETH_P_IPV6))
|
||||
{
|
||||
bpf_map_update_elem(&ip6_blacklist_map, &srcip6, &newTime, BPF_ANY);
|
||||
}
|
||||
else
|
||||
{
|
||||
bpf_map_update_elem(&ip_blacklist_map, &iph->saddr, &newTime, BPF_ANY);
|
||||
}
|
||||
}
|
||||
|
||||
if (stats)
|
||||
{
|
||||
__sync_fetch_and_add(&stats->blocked, 1);
|
||||
}
|
||||
else
|
||||
|
||||
return XDP_DROP;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stats)
|
||||
{
|
||||
__sync_fetch_and_add(&stats->allowed, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
//bpf_printk("Matched with protocol %" PRIu8 " and sAddr %" PRIu32 ".\n", iph->protocol, iph->saddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((matched) && action == 0)
|
||||
{
|
||||
// Before dropping, update the blacklist map.
|
||||
if (blocktime > 0)
|
||||
{
|
||||
uint64_t newTime = now + (blocktime * 1000000000);
|
||||
|
||||
bpf_map_update_elem(&ip_blacklist_map, &iph->saddr, &newTime, BPF_ANY);
|
||||
}
|
||||
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
return XDP_PASS;
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
Reference in New Issue
Block a user