Mitigator BPF API
Functions and types programs can use to filter packets.
Data Structures | Macros | Typedefs | Enumerations | Functions
mitigator_bpf.h File Reference
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

Go to the source code of this file.

Data Structures

struct  EtherAddr
 Ethernet address (MAC address). More...
 
struct  EtherHeader
 Ethernet header (802.1). More...
 
struct  VlanHeader
 VLAN header (802.1q). More...
 
struct  IpHeader
 IPv4 header. More...
 
struct  UdpHeader
 UDP header. More...
 
struct  TcpHeader
 TCP header. More...
 
struct  Flow
 Packet flow information. More...
 
struct  TableRecord
 Record in the program-wide table. More...
 

Macros

#define PROGRAM_DISPLAY_ID(id)
 Mandatory program identifier for display to the user. More...
 
#define FILTER_V1
 Entry point marker for ABI v1. More...
 
#define LOCAL
 Force the compiler to inline a local function. More...
 
#define UNROLL
 Hint the compiler to unroll a loop. More...
 
#define MAX_PAYLOAD_LENGTH   1536
 Maximum length of any packet data returned by API functions. More...
 
#define MAX_PARAMETERS_LENGTH   1024
 Maximum length of program parameters. More...
 

Typedefs

typedef void * Context
 Opaque filter context.
 
typedef uint64_t Bool
 ABI-safe, eBPF-friendly boolean type. More...
 
typedef uint32_t Time
 
typedef uint64_t TableKey
 
typedef uint64_t TableValue
 
typedef uint32_t Cookie
 

Enumerations

enum  Result { RESULT_PASS, RESULT_DROP, RESULT_BACK, RESULT_LIMIT }
 Filter verdict. More...
 
enum  EtherType { ETHER_TYPE_IP = 0x0800, ETHER_TYPE_ARP = 0x0806, ETHER_TYPE_8021Q = 0x8100, ETHER_TYPE_IP6 = 0x86DD }
 Ethernet frame type codes. More...
 
enum  IpProto { IP_PROTO_ICMP = 1, IP_PROTO_TCP = 6, IP_PROTO_UDP = 17 }
 IPv4 and IPv6 transport protocol codes. More...
 
enum  TcpFlags
 TCP flags. More...
 
enum  TcpOption {
  TCP_OPT_EOL = 0, TCP_OPT_NOP = 1, TCP_OPT_MAXSEG = 2, TCP_OPT_WSCALE = 3,
  TCP_OPT_SACK_PERM = 4, TCP_OPT_SACK = 5, TCP_OPT_TIMESTAMPS = 8
}
 TCP option codes. More...
 

Functions

void packet_flow (Context ctx, struct Flow *info)
 Get packet flow information, including source and destination. More...
 
void * packet_ether_header (Context ctx)
 Get packet Ethernet header. More...
 
uint16_t packet_network_proto (Context ctx)
 Get packet network protocol code, e.g. IPv4. More...
 
void * packet_network_header (Context ctx)
 Get packet network header, e.g. IPv4 header. More...
 
uint8_t packet_transport_proto (Context ctx)
 Get packet transport protocol code, e.g. TCP, UDP, or ICMP. More...
 
void * packet_transport_header (Context ctx)
 Get packet transport header, e.g. TCP header. More...
 
void * packet_transport_payload (Context ctx, uint16_t *length)
 Get packet transport payload for TCP or UDP. More...
 
void set_packet_length (Context ctx, uint16_t length)
 Set new packet transport payload length (max 1400). More...
 
void set_packet_offset (Context ctx, uint16_t offset)
 Set number of bytes to strip from the beginning of transport payload. More...
 
void set_packet_syncookie (Context ctx)
 Convert response packet to an empty TCP SYN+ACK with syncookie. More...
 
void set_packet_mangled (Context ctx)
 Mark the packet as mangled by the program. More...
 
void set_src_blacklisted (Context ctx, Time duration)
 Add packet source address to temporary blacklist. More...
 
void set_src_whitelisted (Context ctx, Time duration)
 Add packet source address to temporary whitelist. More...
 
Bool table_find (Context ctx, TableKey key, struct TableRecord *record)
 Lookup value in the table by key. More...
 
Bool table_get (Context ctx, TableKey key, struct TableRecord *record)
 Lookup value in the table by key and modify record update time. More...
 
Bool table_put (Context ctx, TableKey key, TableValue value)
 Update value in the table, creating a new record if needed. More...
 
uint64_t table_size (Context ctx)
 Get number of records in the table.
 
Cookie syncookie_make (Context ctx)
 Make a cookie value for use as a sequence number in a SYN+ACK packet. More...
 
Bool syncookie_check (Context ctx, uint32_t seqnum_offset, uint32_t acknum_offset)
 Check if packet is a TCP ACK carrying a SYN cookie. More...
 
Cookie cookie_make (Context ctx, const struct Flow *id)
 Make a generic cookie value based on random seed, current time, and flow fields that identify the client. More...
 
Bool cookie_check (Context ctx, const struct Flow *id, Cookie cookie)
 Check if a generic cookie matches the flow and has not expired. More...
 
const void * parameters_get (Context ctx)
 Get a pointer to read-only program parameters. More...
 
uint32_t hash_crc32_u32 (uint32_t value, uint32_t init)
 Compute CRC32 (Castagnoli) of a 32-bit value. More...
 
uint32_t hash_crc32_u64 (uint64_t value, uint32_t init)
 Compute CRC32 (Castagnoli) of a 64-bit value. More...
 
uint32_t hash_crc32_data (const void *data, const void *end, uint32_t init)
 Compute CRC32 (Castagnoli) over [data; end). More...
 
Time time_sec (Context ctx)
 Get wallclock time in seconds.
 
uint64_t rand64 (void)
 Generate a pseudo-random, non cryptographically-secure value.
 
LOCAL uint16_t bswap16 (uint16_t value)
 Change byte order of a 16-bit value.
 
LOCAL uint32_t bswap32 (uint32_t value)
 Change byte order of a 32-bit value.
 
LOCAL uint16_t vlan_get_id (const struct VlanHeader *vlan)
 Get VLAN ID from 802.1q header.
 
LOCAL void vlan_set_id (struct VlanHeader *vlan, uint16_t id)
 Set VLAN ID in 802.1q header. More...
 

Macro Definition Documentation

◆ FILTER_V1

#define FILTER_V1

Entry point marker for ABI v1.

A filter that drops all packets looks as follows:

#include "mitigator_bpf.h"
filter(Context ctx) {
return RESULT_DROP;
}
PROGRAM_DISPLAY_ID("Example v0.1")

◆ LOCAL

#define LOCAL

Force the compiler to inline a local function.

This macro should be used on all function definitions, otherwise compiler might generate code that will fail validation (which forbids backward jumps).

Example:

LOCAL int
sum(int a, int b) {
return a + b;
}

◆ MAX_PARAMETERS_LENGTH

#define MAX_PARAMETERS_LENGTH   1024

Maximum length of program parameters.

Before using a variable offset into parameters, programs must check that it does not exceed this constant.

See also
MAX_PAYLOAD_LENGTH for comments on offset checking.
parameters_get() to get parameters.

◆ MAX_PAYLOAD_LENGTH

#define MAX_PAYLOAD_LENGTH   1536

Maximum length of any packet data returned by API functions.

Before using a variable offset into packet, programs must check that it does not exceed this constant, otherwise eBPF validator may reject the code. To avoid valid programs being mistakenly rejected, place the check immediately before using the offset.

See also
hash_crc32_data() for example usage.

◆ PROGRAM_DISPLAY_ID

#define PROGRAM_DISPLAY_ID (   id)

Mandatory program identifier for display to the user.

The system may reject programs without this identifier.

The string should help the user to identify program and its version. It can be truncated on display, guaranteed minimum is 40 characters.

See also
FILTER_V1 for usage example.

◆ UNROLL

#define UNROLL

Hint the compiler to unroll a loop.

Loops are usually translated to the following instruction sequence: condition check, loop body, backwards jump to condition check. EBPF validator forbids backwards jumps to prevent infinite loops. Loop unrolling means loop body will be pasted a fixed number of times in generated code.

Obviously, unrolling requires knowing maximum number of iterations in advance. The solution to loop "n" time is as follows:

UNROLL for (i = 0; i < MAX; i++) {
if (i >= n) {
break;
}
...
}
Note
This macro currently only affects Clang.
The hint might be ignored especially with optimizations disabled.

Typedef Documentation

◆ Bool

typedef uint64_t Bool

ABI-safe, eBPF-friendly boolean type.

Definitions of true and false from <stdbool.h> can be used with Bool.

◆ Cookie

typedef uint32_t Cookie

Cookie value.

◆ TableKey

typedef uint64_t TableKey

Key to a record in the program-wide table.

Key 0 is reserved. It is forbidden to save values by key 0 and records are never found by this key.

See also
TableRecord for table description.

◆ TableValue

typedef uint64_t TableValue

Value of a record in the program-wide table.

See also
TableRecord for table description.

◆ Time

typedef uint32_t Time

Time in seconds: Unix timestamp or duration.

See also
time_sec() to get current time.

Enumeration Type Documentation

◆ EtherType

enum EtherType

Ethernet frame type codes.

See also
packet_network_proto() for an example use of these values.
Enumerator
ETHER_TYPE_IP 

Internet Protocol version 4

ETHER_TYPE_ARP 

Address Resolution Protocol

ETHER_TYPE_8021Q 

IEEE 802.1q (VLAN)

ETHER_TYPE_IP6 

Internet Protocol version 6

◆ IpProto

enum IpProto

IPv4 and IPv6 transport protocol codes.

See also
packet_transport_proto() for an example use of these values.
https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
Enumerator
IP_PROTO_ICMP 

Internet Control Message Protocol

IP_PROTO_TCP 

Transmission Control Protocol

IP_PROTO_UDP 

User Datagram Protocol

◆ Result

enum Result

Filter verdict.

A program must not return values outside of this enumeration, otherwise packets may be dropped or processed in unexpected ways in future versions.

Enumerator
RESULT_PASS 

Pass packet (forward).

RESULT_DROP 

Drop packet (discard).

RESULT_BACK 

Send packet back. L2, L3, and L4 headers are adjusted automatically.

RESULT_LIMIT 

Pass packet if overall rate is within limit, otherwise drop packet.

◆ TcpFlags

enum TcpFlags

TCP flags.

Combinations of these flags are used for TcpHeader::th_flags.

URG, ECE, and CWR may be combined with any other flags, and PUSH is often combined with ACK, but is never mandatory. So this is the wrong way to check for ACK segments:

if (tcp->th_flags == TCP_FLAG_ACK) {
// WRONG: will not run for ACK+PUSH, which is very common
}

To check if ACK flag is present in a combination:

if (tcp->th_flags & TCP_FLAG_ACK) { ... }

To switch on the flags:

switch (tcp->th_flags & (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
case TCP_FLAG_SYN: ...; break;
case TCP_FLAG_ACK: ...; break;
case TCP_FLAG_SYN | TCP_FLAG_ACK: ...; break;
}

◆ TcpOption

enum TcpOption

TCP option codes.

Options start immediately after TCP header and are limited to 44 bytes, so a loop over them may be UNROLL'ed. Options must be padded to 4 bytes.

See also
https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml#tcp-parameters-1
Enumerator
TCP_OPT_EOL 

End of Option List

TCP_OPT_NOP 

No option (used for padding)

TCP_OPT_MAXSEG 

Maximum segment size (MSS)

TCP_OPT_WSCALE 

Window scaling factor

TCP_OPT_SACK_PERM 

Selective acknowledgement permitted

TCP_OPT_SACK 

Selective acknowledgement

TCP_OPT_TIMESTAMPS 

Timestamps

Function Documentation

◆ cookie_check()

Bool cookie_check ( Context  ctx,
const struct Flow id,
Cookie  cookie 
)

Check if a generic cookie matches the flow and has not expired.

This function checks is the cookie was generated by cookie_make() recently with the same exact flow.

See also
cookie_make for comments on filling the Flow structure.

The following code checks for a cookie in the beginning of payload:

uint16_t length = 0;
uint32_t* cookie = packet_transport_payload(ctx, &length);
struct Flow flow;
packet_flow(ctx, &flow);
flow.sport = 0;
if (cookie_check(ctx, &flow, *cookie) {
...
}

◆ cookie_make()

Cookie cookie_make ( Context  ctx,
const struct Flow id 
)

Make a generic cookie value based on random seed, current time, and flow fields that identify the client.

Use cookie_check() to check the cookie returned in response.

Zero unneeded flow fields of to ignore them, e.g. zero source port if clients are likely to change it when sending response. Always make sure struct Flow padding is zero (packet_flow() does this automatically).

The following code puts a cookie in the beginning of the response:

uint16_t length = 0;
uint32_t* cookie = packet_transport_payload(ctx, &length);
struct Flow flow;
packet_flow(ctx, &flow);
flow.sport = 0;
*cookie = cookie_make(ctx, &flow);
set_packet_length(ctx, sizeof(*cookie));
return RESULT_BACK;

◆ hash_crc32_data()

uint32_t hash_crc32_data ( const void *  data,
const void *  end,
uint32_t  init 
)

Compute CRC32 (Castagnoli) over [data; end).

Suppose a protocol requires first four bytes of payload to be CRC32 of the remaining payload, using initial value 0xFFFFFFFF. A filter can verify packets as follows:

static const uint32_t INIT = 0xFFFFFFFF;
uint16_t length = 0;
uint8_t* payload = packet_transport_payload(ctx, &length);
uint32_t crc = *(uint32_t*)payload;
uint8_t* rest = payload + sizeof(crc);
uint8_t* rest_end = payload + length;
if (length > MAX_PAYLOAD_LENGTH) {
// Never happens, but required to validate that rest_end
// does not point beyond packet data.
return RESULT_DROP;
}
if (hash_crc32_data(rest, rest_end, INIT) == crc) {
return RESULT_PASS;
}
See also
MAX_PAYLOAD_LENGTH for detailed explanation why it's checked.
hash_crc32_u32() for a simpler alternative for 32-bit data.
hash_crc32_u64() for a simpler alternative for 64-bit data.

◆ hash_crc32_u32()

uint32_t hash_crc32_u32 ( uint32_t  value,
uint32_t  init 
)

Compute CRC32 (Castagnoli) of a 32-bit value.

Note that crc32(A concatenated with B, init) == crc32(B, crc32(A, init)). For example, the following code computes CRC32 of a seed concatenated with source IP (initial value 0x814141AB does not matter).

struct Flow flow;
packet_flow(ctx, &flow);
uint32_t crc = hash_crc32_u32(flow.src, hash_crc32_u32(seed), 0x814141AB);
See also
hash_crc32_data() for dynamically-sized data.

◆ hash_crc32_u64()

uint32_t hash_crc32_u64 ( uint64_t  value,
uint32_t  init 
)

Compute CRC32 (Castagnoli) of a 64-bit value.

See also
hash_crc32_u32() for additional notes and examples.

◆ packet_ether_header()

void* packet_ether_header ( Context  ctx)

Get packet Ethernet header.

Programs may access up to MAX_LAYLOAD_LENGTH bytes starting from this header, so that VLAN tags, encapsulation, etc. can be processed. However, data always starts with a struct EtherHeader.

Note
Version: v20.08.1.
Restricted to General Protection.
Do not assume network layer header starts after Ethernet header: VLAN header may be there; use packet_network_header() instead.

◆ packet_flow()

void packet_flow ( Context  ctx,
struct Flow info 
)

Get packet flow information, including source and destination.

This is simpler and more efficient than analysing L3 and L4 headers.

◆ packet_network_header()

void* packet_network_header ( Context  ctx)

Get packet network header, e.g. IPv4 header.

Programs may access up to MAX_PAYLOAD_LENGTH bytes starting from the header, so that variable-length IP options and/or encapsulation headers can be processed. However, usually casting to a fixed-length IpHeader is sufficient.

Note
This function always succeeds. Use packet_network_proto() to check if expected header is present.
If you only need addresses, consider using packet_flow().
See also
IpHeader

◆ packet_network_proto()

uint16_t packet_network_proto ( Context  ctx)

Get packet network protocol code, e.g. IPv4.

Return values are in host byte order:

if (packet_network_proto(packet) == ETHER_TYPE_IP) { ... }
See also
EtherType

◆ packet_transport_header()

void* packet_transport_header ( Context  ctx)

Get packet transport header, e.g. TCP header.

Programs may access up to MAX_PAYLOAD_LENGTH bytes starting from the header, so that variable-length TCP options and/or encapsulation headers can be processed. However, usually casting to a fixed-length TcpHeader or UdpHeader is sufficient.

Note
This function always succeeds. Use packet_transport_proto() to check if expected header is present.
If you only need ports, consider using packet_flow().
See also
TcpHeader
UdpHeader

◆ packet_transport_payload()

void* packet_transport_payload ( Context  ctx,
uint16_t *  length 
)

Get packet transport payload for TCP or UDP.

For protocols other than TCP and UDP, data starting from L4 header is returned. Use packet_transport_proto() to check the protocol.

Example:

uint16_t length = 0;
uint8_t* payload = packet_transport_payload(ctx, &length);

◆ packet_transport_proto()

uint8_t packet_transport_proto ( Context  ctx)

Get packet transport protocol code, e.g. TCP, UDP, or ICMP.

Use IpProto constants to match on return value as follows:

◆ parameters_get()

const void* parameters_get ( Context  ctx)

Get a pointer to read-only program parameters.

Programs typically use parameters to allow keys, seeds, and thresholds to be configurable by user without recompiling the source. The entire space of MAX_PARAMETERS_LENGTH bytes is always available to the program. Bytes not supplied by user are zero-filled.

◆ set_packet_length()

void set_packet_length ( Context  ctx,
uint16_t  length 
)

Set new packet transport payload length (max 1400).

Note
Packet is marked as mangled and its headers are updated automatically.
This function takes effect after the filter has finished.

◆ set_packet_mangled()

void set_packet_mangled ( Context  ctx)

Mark the packet as mangled by the program.

A call to this function is required when changes are made directly to the packet headers or data using pointers and the filter returns RESULT_PASS. If the filter returns RESULT_BACK, packet is always mangled. If the filter returns RESULT_DROP, mangling is meaningless.

Note
Changes to length fields of network and transport headers will not be picked up by this function, use set_packet_length(), otherwise the packet will be malformed.
This function takes effect after the filter has finished.

◆ set_packet_offset()

void set_packet_offset ( Context  ctx,
uint16_t  offset 
)

Set number of bytes to strip from the beginning of transport payload.

Note
If you use this function, you must also call set_packet_length() to set up the length for the rest of the packet, otherwise it will be truncated, i.e. its length set to 0.
Packet is marked as mangled and its headers are updated automatically.
This function takes effect after the filter has finished.

◆ set_packet_syncookie()

void set_packet_syncookie ( Context  ctx)

Convert response packet to an empty TCP SYN+ACK with syncookie.

TCP sequence number is set to a cookie value recognized by syncookie_check(). IPv4 "don't fragment" flag and TCP options are kept intact.

Note
Packet is marked as mangled and its headers are updated automatically.
This function takes effect after the filter has finished.
This function only takes effect when the filter returns RESULT_BACK.

◆ set_src_blacklisted()

void set_src_blacklisted ( Context  ctx,
Time  duration 
)

Add packet source address to temporary blacklist.

Note
This function overrides effect of set_src_whitelisted().

◆ set_src_whitelisted()

void set_src_whitelisted ( Context  ctx,
Time  duration 
)

Add packet source address to temporary whitelist.

Note
This function overrides effect of set_src_blacklisted().

◆ syncookie_check()

Bool syncookie_check ( Context  ctx,
uint32_t  seqnum_offset,
uint32_t  acknum_offset 
)

Check if packet is a TCP ACK carrying a SYN cookie.

This function checks if packet's TCP acknowledgement number matches the one generated by syncookie_make() or set_packet_syncookie() recently. It fails for non-IPv4 and non-TCP packets.

This function can be used not only to implement SYN cookie protection, but also to recognize first data packets in a TCP session. For example, if seqnum_offset is 0, the first chunk of data is recognized. To recognize data starting from the 10-th octet, set seqnum_offset to 10. Likewise, set acknum_offset to 20 to recognize a packet acknowledging 20 first octets sent back to the client.

◆ syncookie_make()

Cookie syncookie_make ( Context  ctx)

Make a cookie value for use as a sequence number in a SYN+ACK packet.

Values generated by this function are recognized by syncookie_check(). This function is for custom processing of TCP handshake.

Note
Use set_packet_syncookie() instead to avoid dealing with TCP header.

◆ table_find()

Bool table_find ( Context  ctx,
TableKey  key,
struct TableRecord record 
)

Lookup value in the table by key.

Note
If any found record must also be kept in the table, prefer table_get().

◆ table_get()

Bool table_get ( Context  ctx,
TableKey  key,
struct TableRecord record 
)

Lookup value in the table by key and modify record update time.

Returned table record holds previous update time, which can be used to measure time elapsed since last table_get() or table_put() call on the record.

◆ table_put()

Bool table_put ( Context  ctx,
TableKey  key,
TableValue  value 
)

Update value in the table, creating a new record if needed.

If key is not found and new record cannot be created, return false, otherwise return true.

Note
This function modifies record update time even if the value does not change.

◆ vlan_set_id()

LOCAL void vlan_set_id ( struct VlanHeader vlan,
uint16_t  id 
)

Set VLAN ID in 802.1q header.

If you don't need to keep rarely used DEI and PRI, a faster alternative is:

vlan->control = bswap16(id);
cookie_check
Bool cookie_check(Context ctx, const struct Flow *id, Cookie cookie)
Check if a generic cookie matches the flow and has not expired.
hash_crc32_u32
uint32_t hash_crc32_u32(uint32_t value, uint32_t init)
Compute CRC32 (Castagnoli) of a 32-bit value.
RESULT_DROP
@ RESULT_DROP
Definition: mitigator_bpf.h:155
LOCAL
#define LOCAL
Force the compiler to inline a local function.
Definition: mitigator_bpf.h:82
PROGRAM_DISPLAY_ID
#define PROGRAM_DISPLAY_ID(id)
Mandatory program identifier for display to the user.
Definition: mitigator_bpf.h:43
packet_transport_payload
void * packet_transport_payload(Context ctx, uint16_t *length)
Get packet transport payload for TCP or UDP.
Result
Result
Filter verdict.
Definition: mitigator_bpf.h:151
packet_transport_proto
uint8_t packet_transport_proto(Context ctx)
Get packet transport protocol code, e.g. TCP, UDP, or ICMP.
FILTER_V1
#define FILTER_V1
Entry point marker for ABI v1.
Definition: mitigator_bpf.h:64
MAX_PAYLOAD_LENGTH
#define MAX_PAYLOAD_LENGTH
Maximum length of any packet data returned by API functions.
Definition: mitigator_bpf.h:125
mitigator_bpf.h
RESULT_BACK
@ RESULT_BACK
Definition: mitigator_bpf.h:157
ETHER_TYPE_IP
@ ETHER_TYPE_IP
Definition: mitigator_bpf.h:210
Context
void * Context
Opaque filter context.
Definition: mitigator_bpf.h:143
UNROLL
#define UNROLL
Hint the compiler to unroll a loop.
Definition: mitigator_bpf.h:112
hash_crc32_data
uint32_t hash_crc32_data(const void *data, const void *end, uint32_t init)
Compute CRC32 (Castagnoli) over [data; end).
RESULT_PASS
@ RESULT_PASS
Definition: mitigator_bpf.h:153
IP_PROTO_TCP
@ IP_PROTO_TCP
Definition: mitigator_bpf.h:255
bswap16
LOCAL uint16_t bswap16(uint16_t value)
Change byte order of a 16-bit value.
Definition: mitigator_bpf.h:761
set_packet_length
void set_packet_length(Context ctx, uint16_t length)
Set new packet transport payload length (max 1400).
cookie_make
Cookie cookie_make(Context ctx, const struct Flow *id)
Make a generic cookie value based on random seed, current time, and flow fields that identify the cli...
packet_flow
void packet_flow(Context ctx, struct Flow *info)
Get packet flow information, including source and destination.
packet_network_proto
uint16_t packet_network_proto(Context ctx)
Get packet network protocol code, e.g. IPv4.
Flow
Packet flow information.
Definition: mitigator_bpf.h:387