Added blocktime filter option and optimized code.
This commit is contained in:
19
README.md
19
README.md
@@ -22,14 +22,17 @@ Config option `filters` is an array. Each filter includes the following options:
|
|||||||
|
|
||||||
* `enabled` => If true, this rule is enabled.
|
* `enabled` => If true, this rule is enabled.
|
||||||
* `action` => What action to perform against the packet if matched. 0 = Block. 1 = Allow.
|
* `action` => What action to perform against the packet if matched. 0 = Block. 1 = Allow.
|
||||||
* `srcip` => The source IP to match (e.g. 10.50.0.3).
|
* `srcip` => The source IP the packet must have to match (e.g. 10.50.0.3).
|
||||||
* `dstip` => The destination IP to match (e.g. 10.50.0.4).
|
* `dstip` => The destination IP the packet must have to match (e.g. 10.50.0.4).
|
||||||
* `min_ttl` => The minimum TTL (time to live) the packet has to match.
|
* `min_ttl` => The minimum TTL (time to live) the packet must have to match.
|
||||||
* `max_ttl` => The maximum TTL (time to live) the packet has to match.
|
* `max_ttl` => The maximum TTL (time to live) the packet must have to match.
|
||||||
* `max_len` => The maximum packet length the packet has to match. This includes the entire frame (ethernet header, IP header, L4 header, and data).
|
* `max_len` => The maximum packet length the packet must have to match. This includes the entire frame (ethernet header, IP header, L4 header, and data).
|
||||||
* `min_len` => The minimum packet length the packet has to match. This includes the entire frame (ethernet header, IP header, L4 header, and data).
|
* `min_len` => The minimum packet length the packet must have to match. This includes the entire frame (ethernet header, IP header, L4 header, and data).
|
||||||
* `tos` => The TOS (type of service) the packet has to match.
|
* `tos` => The TOS (type of service) the packet must have to match.
|
||||||
* `payloadmatch` => The payload (L4 data) the packet has to match. The format is in hexadecimal and each byte is separated by a space. An example includes: `FF FF FF FF 59`.
|
* `pps` => The maximum packets per second a source IP can send before matching.
|
||||||
|
* `bps` => The maximum amount of bytes per second a source IP can send before matching.
|
||||||
|
* `blocktime` => The maximum of time in seconds to block the source IP if the rule matches and the action is block (0). Default value is `1`.
|
||||||
|
* `payloadmatch` => The payload (L4 data) the packet must have to match. The format is in hexadecimal and each byte is separated by a space. An example includes: `FF FF FF FF 59`.
|
||||||
|
|
||||||
#### TCP Options
|
#### TCP Options
|
||||||
The config option `tcpopts` within a filter is an array including TCP options. This should only be one array per filter. Options include:
|
The config option `tcpopts` within a filter is an array including TCP options. This should only be one array per filter. Options include:
|
||||||
|
|||||||
12
src/config.c
12
src/config.c
@@ -278,6 +278,18 @@ int ReadConfig(struct config_map *cfg)
|
|||||||
cfg->filters[i].do_bps = 1;
|
cfg->filters[i].do_bps = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Block time (default 1).
|
||||||
|
int blocktime;
|
||||||
|
|
||||||
|
if (config_setting_lookup_int(filter, "blocktime", &blocktime))
|
||||||
|
{
|
||||||
|
cfg->filters[i].blockTime = blocktime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cfg->filters[i].blockTime = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Payload match.
|
// Payload match.
|
||||||
const char *payload;
|
const char *payload;
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ struct filter
|
|||||||
unsigned int do_bps : 1;
|
unsigned int do_bps : 1;
|
||||||
uint64_t bps;
|
uint64_t bps;
|
||||||
|
|
||||||
|
uint16_t blockTime;
|
||||||
|
|
||||||
uint8_t payloadMatch[MAX_PCKT_LENGTH];
|
uint8_t payloadMatch[MAX_PCKT_LENGTH];
|
||||||
uint16_t payloadLen;
|
uint16_t payloadLen;
|
||||||
|
|
||||||
|
|||||||
679
src/xdpfw_kern.c
679
src/xdpfw_kern.c
@@ -66,6 +66,14 @@ struct bpf_map_def SEC("maps") ip_stats_map =
|
|||||||
.max_entries = MAX_TRACK_IPS
|
.max_entries = MAX_TRACK_IPS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bpf_map_def SEC("maps") ip_blacklist_map =
|
||||||
|
{
|
||||||
|
.type = BPF_MAP_TYPE_LRU_PERCPU_HASH,
|
||||||
|
.key_size = sizeof(uint32_t),
|
||||||
|
.value_size = sizeof(uint64_t),
|
||||||
|
.max_entries = MAX_TRACK_IPS
|
||||||
|
};
|
||||||
|
|
||||||
SEC("xdp_prog")
|
SEC("xdp_prog")
|
||||||
int xdp_prog_main(struct xdp_md *ctx)
|
int xdp_prog_main(struct xdp_md *ctx)
|
||||||
{
|
{
|
||||||
@@ -82,6 +90,91 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
return XDP_DROP;
|
return XDP_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check Ethernet protocol.
|
||||||
|
if (unlikely(ethhdr->h_proto != htons(ETH_P_IP)))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Check if the IP header is valid.
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
return XDP_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t now = bpf_ktime_get_ns();
|
||||||
|
|
||||||
|
// Check blacklist map.
|
||||||
|
uint64_t *blocked = bpf_map_lookup_elem(&ip_blacklist_map, &iph->saddr);
|
||||||
|
|
||||||
|
if (blocked != NULL && *blocked > 0)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
bpf_printk("Checking for blocked packet... Block time %" PRIu64 "\n", *blocked);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (now > *blocked)
|
||||||
|
{
|
||||||
|
// Remove element from map.
|
||||||
|
bpf_map_delete_elem(&ip_blacklist_map, &iph->saddr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// They're still blocked. Drop the packet.
|
||||||
|
return XDP_DROP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update IP stats (PPS/BPS).
|
||||||
|
uint64_t pps = 0;
|
||||||
|
uint64_t bps = 0;
|
||||||
|
|
||||||
|
struct xdpfw_ip_stats *ip_stats = bpf_map_lookup_elem(&ip_stats_map, &iph->saddr);
|
||||||
|
|
||||||
|
if (ip_stats)
|
||||||
|
{
|
||||||
|
// Check for reset.
|
||||||
|
if ((now - ip_stats->tracking) > 1000000000)
|
||||||
|
{
|
||||||
|
ip_stats->pps = 0;
|
||||||
|
ip_stats->bps = 0;
|
||||||
|
ip_stats->tracking = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_stats->pps++;
|
||||||
|
ip_stats->bps += ctx->data_end - ctx->data;
|
||||||
|
|
||||||
|
pps = ip_stats->pps;
|
||||||
|
bps = ip_stats->bps;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create new entry.
|
||||||
|
struct xdpfw_ip_stats new;
|
||||||
|
|
||||||
|
new.pps = 1;
|
||||||
|
new.bps = ctx->data_end - ctx->data;
|
||||||
|
new.tracking = now;
|
||||||
|
|
||||||
|
pps = new.pps;
|
||||||
|
bps = new.bps;
|
||||||
|
|
||||||
|
bpf_map_update_elem(&ip_stats_map, &iph->saddr, &new, BPF_ANY);
|
||||||
|
}
|
||||||
|
|
||||||
// Let's get the filters we need.
|
// Let's get the filters we need.
|
||||||
struct filter *filter[MAX_FILTERS];
|
struct filter *filter[MAX_FILTERS];
|
||||||
|
|
||||||
@@ -92,359 +185,305 @@ int xdp_prog_main(struct xdp_md *ctx)
|
|||||||
filter[i] = bpf_map_lookup_elem(&filters_map, &key);
|
filter[i] = bpf_map_lookup_elem(&filters_map, &key);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t matched = 0;
|
struct tcphdr *tcph;
|
||||||
uint8_t action = 0;
|
struct udphdr *udph;
|
||||||
|
struct icmphdr *icmph;
|
||||||
|
|
||||||
|
uint16_t l4headerLen = 0;
|
||||||
|
|
||||||
// Check Ethernet protocol and ensure it's IP.
|
// Check protocol.
|
||||||
if (likely(ethhdr->h_proto == htons(ETH_P_IP)))
|
if (iph->protocol == IPPROTO_TCP)
|
||||||
{
|
{
|
||||||
// Scan IP header.
|
// Scan TCP header.
|
||||||
struct iphdr *iph = data + sizeof(struct ethhdr);
|
tcph = (data + sizeof(struct ethhdr) + (iph->ihl * 4));
|
||||||
|
|
||||||
// Check if the IP header is valid.
|
// Check TCP header.
|
||||||
if (unlikely(iph + 1 > (struct iphdr *)data_end))
|
if (tcph + 1 > (struct tcphdr *)data_end)
|
||||||
{
|
|
||||||
return XDP_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check IP header protocols.
|
|
||||||
if (unlikely(iph->protocol != IPPROTO_UDP && iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_ICMP))
|
|
||||||
{
|
{
|
||||||
return XDP_PASS;
|
return XDP_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update IP stats (PPS/BPS).
|
// Set L4 Header length.
|
||||||
uint64_t pps = 0;
|
l4headerLen = sizeof(struct tcphdr);
|
||||||
uint64_t bps = 0;
|
}
|
||||||
uint64_t now = bpf_ktime_get_ns();
|
else if (iph->protocol == IPPROTO_UDP)
|
||||||
|
{
|
||||||
|
// Scan UDP header.
|
||||||
|
udph = (data + sizeof(struct ethhdr) + (iph->ihl * 4));
|
||||||
|
|
||||||
struct xdpfw_ip_stats *ip_stats = bpf_map_lookup_elem(&ip_stats_map, &iph->saddr);
|
// Check TCP header.
|
||||||
|
if (udph + 1 > (struct udphdr *)data_end)
|
||||||
if (ip_stats)
|
|
||||||
{
|
{
|
||||||
// Check for reset.
|
return XDP_PASS;
|
||||||
if ((now - ip_stats->tracking) > 1e9)
|
|
||||||
{
|
|
||||||
ip_stats->pps = 0;
|
|
||||||
ip_stats->bps = 0;
|
|
||||||
ip_stats->tracking = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
ip_stats->pps++;
|
|
||||||
ip_stats->bps += ctx->data_end - ctx->data;
|
|
||||||
|
|
||||||
pps = ip_stats->pps;
|
|
||||||
bps = ip_stats->bps;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Create new entry.
|
|
||||||
struct xdpfw_ip_stats new;
|
|
||||||
|
|
||||||
new.pps = 1;
|
|
||||||
new.bps = ctx->data_end - ctx->data;
|
|
||||||
new.tracking = now;
|
|
||||||
|
|
||||||
pps = new.pps;
|
|
||||||
bps = new.bps;
|
|
||||||
|
|
||||||
bpf_map_update_elem(&ip_stats_map, &iph->saddr, &new, BPF_ANY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tcphdr *tcph;
|
// Set L4 Header length.
|
||||||
struct udphdr *udph;
|
l4headerLen = sizeof(struct udphdr);
|
||||||
struct icmphdr *icmph;
|
}
|
||||||
|
else if (iph->protocol == IPPROTO_ICMP)
|
||||||
uint16_t l4headerLen = 0;
|
{
|
||||||
|
// Scan UDP header.
|
||||||
|
icmph = (data + sizeof(struct ethhdr) + (iph->ihl * 4));
|
||||||
|
|
||||||
// Check protocol.
|
// Check TCP header.
|
||||||
if (iph->protocol == IPPROTO_TCP)
|
if (icmph + 1 > (struct icmphdr *)data_end)
|
||||||
{
|
{
|
||||||
// Scan TCP header.
|
return XDP_PASS;
|
||||||
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)
|
|
||||||
|
// 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)
|
||||||
{
|
{
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the rule is enabled.
|
|
||||||
if (!filter[i]->enabled)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source address.
|
|
||||||
if (filter[i]->srcIP != 0 && iph->saddr != filter[i]->srcIP)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destination address.
|
|
||||||
if (filter[i]->dstIP != 0 && iph->daddr != filter[i]->dstIP)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max TTL length.
|
|
||||||
if (filter[i]->do_max_ttl && filter[i]->max_ttl > iph->ttl)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Min TTL length.
|
|
||||||
if (filter[i]->do_min_ttl && filter[i]->min_ttl < iph->ttl)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max packet length.
|
|
||||||
if (filter[i]->do_max_len && filter[i]->max_len > (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Min packet length.
|
|
||||||
if (filter[i]->do_min_len && filter[i]->min_len < (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TOS.
|
|
||||||
if (filter[i]->do_tos && filter[i]->tos != iph->tos)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PPS.
|
|
||||||
if (filter[i]->do_pps && pps <= filter[i]->pps)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BPS.
|
|
||||||
if (filter[i]->do_bps && bps <= filter[i]->bps)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Payload match.
|
|
||||||
/*
|
|
||||||
if (filter[i]->payloadLen > 0)
|
|
||||||
{
|
|
||||||
uint8_t found = 1;
|
|
||||||
|
|
||||||
// Initialize packet data.
|
|
||||||
for (uint16_t j = 0; j < MAX_PCKT_LENGTH; j++)
|
|
||||||
{
|
|
||||||
if ((j + 1) > filter[i]->payloadLen)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *byte = (data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4headerLen + j);
|
|
||||||
|
|
||||||
if (byte + 1 > (uint8_t *)data_end)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*byte == filter[i]->payloadMatch[j])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = 0;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Check layer 4 filters.
|
|
||||||
if (iph->protocol == IPPROTO_TCP && !filter[i]->tcpopts.enabled)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (iph->protocol == IPPROTO_UDP && !filter[i]->udpopts.enabled)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (iph->protocol == IPPROTO_ICMP && !filter[i]->icmpopts.enabled)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do TCP options.
|
|
||||||
if (iph->protocol == IPPROTO_TCP && filter[i]->tcpopts.enabled)
|
|
||||||
{
|
|
||||||
// Source port.
|
|
||||||
if (filter[i]->tcpopts.do_sport && htons(filter[i]->tcpopts.sport) != tcph->source)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destination port.
|
|
||||||
if (filter[i]->tcpopts.do_dport && htons(filter[i]->tcpopts.dport) != tcph->dest)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// URG flag.
|
|
||||||
if (filter[i]->tcpopts.do_urg && filter[i]->tcpopts.urg != tcph->urg)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ACK flag.
|
|
||||||
if (filter[i]->tcpopts.do_ack && filter[i]->tcpopts.ack != tcph->ack)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// RST flag.
|
|
||||||
if (filter[i]->tcpopts.do_rst && filter[i]->tcpopts.rst != tcph->rst)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PSH flag.
|
|
||||||
if (filter[i]->tcpopts.do_psh && filter[i]->tcpopts.psh != tcph->psh)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SYN flag.
|
|
||||||
if (filter[i]->tcpopts.do_syn && filter[i]->tcpopts.syn != tcph->syn)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIN flag.
|
|
||||||
if (filter[i]->tcpopts.do_fin && filter[i]->tcpopts.fin != tcph->fin)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (iph->protocol == IPPROTO_UDP && filter[i]->udpopts.enabled)
|
|
||||||
{
|
|
||||||
// Source port.
|
|
||||||
if (filter[i]->udpopts.do_sport && htons(filter[i]->udpopts.sport) != udph->source)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destination port.
|
|
||||||
if (filter[i]->udpopts.do_dport && htons(filter[i]->udpopts.dport) != udph->dest)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (iph->protocol == IPPROTO_ICMP && filter[i]->icmpopts.enabled)
|
|
||||||
{
|
|
||||||
// Code.
|
|
||||||
if (filter[i]->icmpopts.do_code && filter[i]->icmpopts.code != icmph->code)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type.
|
|
||||||
if (filter[i]->icmpopts.do_type && filter[i]->icmpopts.type != icmph->type)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matched.
|
|
||||||
#ifdef DEBUG
|
|
||||||
bpf_printk("Matched rule ID #%" PRIu8 ".\n", filter[i]->id);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
matched = 1;
|
|
||||||
action = filter[i]->action;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matched)
|
// Check if the rule is enabled.
|
||||||
|
if (!filter[i]->enabled)
|
||||||
{
|
{
|
||||||
// Get stats map.
|
continue;
|
||||||
uint32_t key = 0;
|
}
|
||||||
struct xdpfw_stats *stats;
|
|
||||||
|
|
||||||
stats = bpf_map_lookup_elem(&stats_map, &key);
|
// Source address.
|
||||||
|
if (filter[i]->srcIP != 0 && iph->saddr != filter[i]->srcIP)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (stats)
|
// Destination address.
|
||||||
|
if (filter[i]->dstIP != 0 && iph->daddr != filter[i]->dstIP)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max TTL length.
|
||||||
|
if (filter[i]->do_max_ttl && filter[i]->max_ttl > iph->ttl)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Min TTL length.
|
||||||
|
if (filter[i]->do_min_ttl && filter[i]->min_ttl < iph->ttl)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max packet length.
|
||||||
|
if (filter[i]->do_max_len && filter[i]->max_len > (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Min packet length.
|
||||||
|
if (filter[i]->do_min_len && filter[i]->min_len < (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOS.
|
||||||
|
if (filter[i]->do_tos && filter[i]->tos != iph->tos)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PPS.
|
||||||
|
if (filter[i]->do_pps && pps <= filter[i]->pps)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BPS.
|
||||||
|
if (filter[i]->do_bps && bps <= filter[i]->bps)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payload match.
|
||||||
|
/*
|
||||||
|
if (filter[i]->payloadLen > 0)
|
||||||
|
{
|
||||||
|
uint8_t found = 1;
|
||||||
|
|
||||||
|
// Initialize packet data.
|
||||||
|
for (uint16_t j = 0; j < MAX_PCKT_LENGTH; j++)
|
||||||
{
|
{
|
||||||
// Update stats map.
|
if ((j + 1) > filter[i]->payloadLen)
|
||||||
if (action == 0)
|
|
||||||
{
|
{
|
||||||
stats->blocked++;
|
break;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stats->allowed++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
key = 0;
|
uint8_t *byte = (data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4headerLen + j);
|
||||||
|
|
||||||
bpf_map_update_elem(&stats_map, &key, stats, BPF_ANY);
|
if (byte + 1 > (uint8_t *)data_end)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*byte == filter[i]->payloadMatch[j])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
if (!found)
|
||||||
//bpf_printk("Matched with protocol %" PRIu8 " and sAddr %" PRIu32 ".\n", iph->protocol, iph->saddr);
|
{
|
||||||
#endif
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Check layer 4 filters.
|
||||||
|
if (iph->protocol == IPPROTO_TCP && !filter[i]->tcpopts.enabled)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (iph->protocol == IPPROTO_UDP && !filter[i]->udpopts.enabled)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (iph->protocol == IPPROTO_ICMP && !filter[i]->icmpopts.enabled)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do TCP options.
|
||||||
|
if (iph->protocol == IPPROTO_TCP && filter[i]->tcpopts.enabled)
|
||||||
|
{
|
||||||
|
// Source port.
|
||||||
|
if (filter[i]->tcpopts.do_sport && htons(filter[i]->tcpopts.sport) != tcph->source)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination port.
|
||||||
|
if (filter[i]->tcpopts.do_dport && htons(filter[i]->tcpopts.dport) != tcph->dest)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// URG flag.
|
||||||
|
if (filter[i]->tcpopts.do_urg && filter[i]->tcpopts.urg != tcph->urg)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACK flag.
|
||||||
|
if (filter[i]->tcpopts.do_ack && filter[i]->tcpopts.ack != tcph->ack)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RST flag.
|
||||||
|
if (filter[i]->tcpopts.do_rst && filter[i]->tcpopts.rst != tcph->rst)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSH flag.
|
||||||
|
if (filter[i]->tcpopts.do_psh && filter[i]->tcpopts.psh != tcph->psh)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SYN flag.
|
||||||
|
if (filter[i]->tcpopts.do_syn && filter[i]->tcpopts.syn != tcph->syn)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIN flag.
|
||||||
|
if (filter[i]->tcpopts.do_fin && filter[i]->tcpopts.fin != tcph->fin)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (iph->protocol == IPPROTO_UDP && filter[i]->udpopts.enabled)
|
||||||
|
{
|
||||||
|
// Source port.
|
||||||
|
if (filter[i]->udpopts.do_sport && htons(filter[i]->udpopts.sport) != udph->source)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination port.
|
||||||
|
if (filter[i]->udpopts.do_dport && htons(filter[i]->udpopts.dport) != udph->dest)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (iph->protocol == IPPROTO_ICMP && filter[i]->icmpopts.enabled)
|
||||||
|
{
|
||||||
|
// Code.
|
||||||
|
if (filter[i]->icmpopts.do_code && filter[i]->icmpopts.code != icmph->code)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.
|
||||||
|
if (filter[i]->icmpopts.do_type && filter[i]->icmpopts.type != icmph->type)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matched.
|
||||||
|
#ifdef DEBUG
|
||||||
|
bpf_printk("Matched rule ID #%" PRIu8 ".\n", filter[i]->id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
matched = 1;
|
||||||
|
action = filter[i]->action;
|
||||||
|
blocktime = filter[i]->blockTime;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched)
|
||||||
|
{
|
||||||
|
// Get stats map.
|
||||||
|
uint32_t key = 0;
|
||||||
|
struct xdpfw_stats *stats;
|
||||||
|
|
||||||
|
stats = bpf_map_lookup_elem(&stats_map, &key);
|
||||||
|
|
||||||
|
if (stats)
|
||||||
|
{
|
||||||
|
// Update stats map.
|
||||||
|
if (action == 0)
|
||||||
|
{
|
||||||
|
stats->blocked++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stats->allowed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = 0;
|
||||||
|
|
||||||
|
bpf_map_update_elem(&stats_map, &key, stats, BPF_ANY);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
//bpf_printk("Matched with protocol %" PRIu8 " and sAddr %" PRIu32 ".\n", iph->protocol, iph->saddr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matched && action == 0)
|
if (matched && action == 0)
|
||||||
{
|
{
|
||||||
|
// Before dropping, update the blacklist map.
|
||||||
|
uint64_t newTime = now + (blocktime * 1000000000);
|
||||||
|
|
||||||
|
bpf_map_update_elem(&ip_blacklist_map, &iph->saddr, &newTime, BPF_ANY);
|
||||||
|
|
||||||
return XDP_DROP;
|
return XDP_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -344,6 +344,7 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stdout, "TOS => %" PRIu8 "\n", conf->filters[i].tos);
|
fprintf(stdout, "TOS => %" PRIu8 "\n", conf->filters[i].tos);
|
||||||
fprintf(stdout, "PPS => %" PRIu64 "\n", conf->filters[i].pps);
|
fprintf(stdout, "PPS => %" PRIu64 "\n", conf->filters[i].pps);
|
||||||
fprintf(stdout, "BPS => %" PRIu64 "\n\n", conf->filters[i].bps);
|
fprintf(stdout, "BPS => %" PRIu64 "\n\n", conf->filters[i].bps);
|
||||||
|
fprintf(stdout, "Block Time => %" PRIu16 "\n\n", conf->filters[i].blockTime);
|
||||||
|
|
||||||
// TCP Options.
|
// TCP Options.
|
||||||
fprintf(stdout, "TCP Enabled => %" PRIu8 "\n", conf->filters[i].tcpopts.enabled);
|
fprintf(stdout, "TCP Enabled => %" PRIu8 "\n", conf->filters[i].tcpopts.enabled);
|
||||||
|
|||||||
Reference in New Issue
Block a user