Redid XDP prgoram.

This commit is contained in:
Christian Deacon
2020-05-05 23:58:48 +00:00
parent f88a52f792
commit e4632530ed

View File

@@ -58,6 +58,14 @@ struct bpf_map_def SEC("maps") count_map =
.max_entries = 1 .max_entries = 1
}; };
struct bpf_map_def SEC("maps") stats_map =
{
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(uint32_t),
.value_size = sizeof(struct xdpfw_stats),
.max_entries = 1
};
SEC("xdp_prog") SEC("xdp_prog")
int xdp_prog_main(struct xdp_md *ctx) int xdp_prog_main(struct xdp_md *ctx)
{ {
@@ -73,6 +81,18 @@ int xdp_prog_main(struct xdp_md *ctx)
return XDP_ABORTED; return XDP_ABORTED;
} }
// Filter count.
uint8_t filterCount;
if (*filters > MAX_FILTERS)
{
filterCount = MAX_FILTERS;
}
else
{
filterCount = *filters;
}
// Initialize data. // Initialize data.
void *data_end = (void *)(long)ctx->data_end; void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data; void *data = (void *)(long)ctx->data;
@@ -91,8 +111,9 @@ int xdp_prog_main(struct xdp_md *ctx)
// Let's get the filters we need. // Let's get the filters we need.
struct filter *filter[MAX_FILTERS]; struct filter *filter[MAX_FILTERS];
//struct filter *(*p)[] = &filter;
for (uint16_t i = 0; i < *filters; i++) for (uint8_t i = 0; i < MAX_FILTERS; i++)
{ {
uint32_t key = i; uint32_t key = i;
@@ -111,11 +132,70 @@ int xdp_prog_main(struct xdp_md *ctx)
return XDP_PASS; return XDP_PASS;
} }
// Let's match IP-header level filtering. // Check IP header protocols.
for (uint16_t i = 0; i < *filters; i++) if (unlikely(iph->protocol != IPPROTO_UDP && iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_ICMP))
{ {
// Check if enabled. return XDP_PASS;
if (filter[i]->enabled == 0) }
struct tcphdr *tcph;
struct udphdr *udph;
struct icmphdr *icmph;
uint16_t l4headerLen = 0;
// 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++)
{
if (!filter[i] || filter[i]->id < 1)
{
break;
}
if (!filter[i]->enabled)
{ {
continue; continue;
} }
@@ -133,247 +213,146 @@ int xdp_prog_main(struct xdp_md *ctx)
} }
// Max TTL length. // Max TTL length.
if (filter[i]->max_ttl > iph->ttl) if (filter[i]->do_max_ttl && filter[i]->max_ttl > iph->ttl)
{ {
continue; continue;
} }
// Min TTL length. // Min TTL length.
if (filter[i]->min_ttl < iph->ttl) if (filter[i]->do_min_ttl && filter[i]->min_ttl < iph->ttl)
{ {
continue; continue;
} }
// Max packet length. // Max packet length.
if (filter[i]->max_len > (ntohs(iph->tot_len) + sizeof(struct ethhdr))) if (filter[i]->do_max_len && filter[i]->max_len > (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
{ {
continue; continue;
} }
// Min packet length. // Min packet length.
if (filter[i]->min_len < (ntohs(iph->tot_len) + sizeof(struct ethhdr))) if (filter[i]->do_min_len && filter[i]->min_len < (ntohs(iph->tot_len) + sizeof(struct ethhdr)))
{ {
continue; continue;
} }
// TOS. // TOS.
if (filter[i]->tos != 0 && filter[i]->tos == iph->tos) if (filter[i]->do_tos && filter[i]->tos != iph->tos)
{ {
continue; continue;
} }
// Matched. // Do TCP options.
matched = 1; if (iph->protocol == IPPROTO_TCP && filter[i]->tcpopts.enabled)
action = filter[i]->action;
break;
}
uint16_t l4headerLen = 0;
// Check protocol.
if (iph->protocol == IPPROTO_TCP)
{
// Scan TCP header.
struct tcphdr *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);
// Time to loop through each filtering rule and look for TCP options.
for (uint16_t i = 0; i < *filters; i++)
{
// Enabled.
if (filter[i]->tcpopts.enabled == 0)
{
continue;
}
// Source port. // Source port.
if (filter[i]->tcpopts.sport != 0 && htons(filter[i]->tcpopts.sport) != tcph->source) if (filter[i]->tcpopts.do_sport && htons(filter[i]->tcpopts.sport) != tcph->source)
{ {
continue; continue;
} }
// Destination port. // Destination port.
if (filter[i]->tcpopts.dport != 0 && htons(filter[i]->tcpopts.dport) != tcph->dest) if (filter[i]->tcpopts.do_dport && htons(filter[i]->tcpopts.dport) != tcph->dest)
{ {
continue; continue;
} }
// URG flag. // URG flag.
if (filter[i]->tcpopts.urg != tcph->urg) if (filter[i]->tcpopts.do_urg && filter[i]->tcpopts.urg != tcph->urg)
{ {
continue; continue;
} }
// ACK flag. // ACK flag.
if (filter[i]->tcpopts.ack != tcph->ack) if (filter[i]->tcpopts.do_ack && filter[i]->tcpopts.ack != tcph->ack)
{ {
continue; continue;
} }
// RST flag. // RST flag.
if (filter[i]->tcpopts.rst != tcph->rst) if (filter[i]->tcpopts.do_rst && filter[i]->tcpopts.rst != tcph->rst)
{ {
continue; continue;
} }
// PSH flag. // PSH flag.
if (filter[i]->tcpopts.psh != tcph->psh) if (filter[i]->tcpopts.do_psh && filter[i]->tcpopts.psh != tcph->psh)
{ {
continue; continue;
} }
// SYN flag. // SYN flag.
if (filter[i]->tcpopts.syn != tcph->syn) if (filter[i]->tcpopts.do_syn && filter[i]->tcpopts.syn != tcph->syn)
{ {
continue; continue;
} }
// FIN flag. // FIN flag.
if (filter[i]->tcpopts.fin != tcph->fin) if (filter[i]->tcpopts.do_fin && filter[i]->tcpopts.fin != tcph->fin)
{ {
continue; continue;
} }
matched = 1;
action = filter[i]->action;
break;
} }
} else if (iph->protocol == IPPROTO_UDP && filter[i]->udpopts.enabled)
else if (iph->protocol == IPPROTO_UDP)
{
// Scan UDP header.
struct udphdr *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);
// Time to loop through each filtering rule and look for TCP options.
for (uint16_t i = 0; i < *filters; i++)
{
// Enabled.
if (filter[i]->udpopts.enabled == 0)
{
continue;
}
// Source port. // Source port.
if (filter[i]->udpopts.sport != 0 && htons(filter[i]->udpopts.sport) != udph->source) if (filter[i]->udpopts.do_sport && htons(filter[i]->udpopts.sport) != udph->source)
{ {
continue; continue;
} }
// Destination port. // Destination port.
if (filter[i]->udpopts.dport != 0 && htons(filter[i]->udpopts.dport) != udph->dest) if (filter[i]->udpopts.do_dport && htons(filter[i]->udpopts.dport) != udph->dest)
{ {
continue; continue;
} }
matched = 1;
action = filter[i]->action;
break;
} }
} else if (iph->protocol == IPPROTO_ICMP && filter[i]->icmpopts.enabled)
else if (iph->protocol == IPPROTO_ICMP)
{
// Scan UDP header.
struct icmphdr *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);
// Time to loop through each filtering rule and look for TCP options.
for (uint16_t i = 0; i < *filters; i++)
{
// Enabled.
if (filter[i]->icmpopts.enabled == 0)
{
continue;
}
// Code. // Code.
if (filter[i]->icmpopts.code != icmph->code) if (filter[i]->icmpopts.do_code && filter[i]->icmpopts.code != icmph->code)
{ {
continue; continue;
} }
// Type. // Type.
if (filter[i]->icmpopts.type != icmph->type) if (filter[i]->icmpopts.do_type && filter[i]->icmpopts.type != icmph->type)
{
continue;
}
}
if (filter[i]->payloadLen > 0)
{
uint8_t *pcktData = (data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4headerLen);
// Now check packet data and ensure we have enough to match.
if (pcktData + (filter[i]->payloadLen + 1) > (uint8_t *)data_end)
{ {
continue; continue;
} }
matched = 1; for (uint16_t j = 0; j < filter[i]->payloadLen; j++)
action = filter[i]->action;
break;
}
}
// Finally, perform match against payload data.
unsigned char *pcktData = (data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4headerLen);
// Check packet data.
for (uint16_t i = 0; i < *filters; i++)
{
// Check if payload is set.
if (filter[i]->payloadLen < 1)
{
continue;
}
// Now check packet data and ensure we have enough to match.
if (pcktData + (filter[i]->payloadLen) + 1 > (unsigned char *)data_end)
{
continue;
}
uint8_t found = 1;
for (uint16_t j = 0; i < filter[i]->payloadLen; i++)
{
if (*pcktData == filter[i]->payloadMatch[j])
{ {
pcktData++; if ((*pcktData++) == filter[i]->payloadMatch[j])
{
continue;
}
continue; break;
} }
found = 0;
break;
} }
if (found) // Matched.
{ #ifdef DEBUG
matched = 1; bpf_printk("Matched rule ID #%" PRIu8 "\n", filter[i]->id);
action = filter[i]->action; #endif
}
matched = 1;
action = filter[i]->action;
break;
} }
} }
if (matched && action == 0) if (matched && action == 0)