#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
Go to the source code of this file.
Data Structures | |
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... | |
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. | |
#define FILTER_V1 |
Entry point marker for ABI v1.
A filter that drops all packets looks as follows:
#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:
#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.
#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.
#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. Maximum is 40 characters, including NUL terminator.
#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:
typedef uint64_t Bool |
ABI-safe, eBPF-friendly boolean type.
Definitions of true and false from <stdbool.h> can be used with Bool.
typedef uint32_t Cookie |
Cookie value.
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.
typedef uint64_t TableValue |
Value of a record in the program-wide table.
typedef uint32_t Time |
Time in seconds: Unix timestamp or duration.
enum EtherType |
Ethernet frame type codes.
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 |
enum IpProto |
IPv4 and IPv6 transport protocol codes.
Enumerator | |
---|---|
IP_PROTO_ICMP | Internet Control Message Protocol |
IP_PROTO_TCP | Transmission Control Protocol |
IP_PROTO_UDP | User Datagram Protocol |
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.
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:
To check if ACK flag is present in a combination:
To switch on the flags:
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.
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.
The following code checks for a cookie in the beginning of payload:
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:
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:
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).
uint32_t hash_crc32_u64 | ( | uint64_t | value, |
uint32_t | init | ||
) |
Compute CRC32 (Castagnoli) of a 64-bit value.
Get packet flow information, including source and destination.
This is simpler and more efficient than analysing L3 and L4 headers.
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.
uint16_t packet_network_proto | ( | Context | ctx | ) |
Get packet network protocol code, e.g. IPv4.
Return values are in network byte order, so the proper check for IPv4 is:
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.
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:
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:
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.
void set_packet_length | ( | Context | ctx, |
uint16_t | length | ||
) |
Set new packet transport payload length (max 1400).
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.
void set_packet_offset | ( | Context | ctx, |
uint16_t | offset | ||
) |
Set number of bytes to strip from the beginning of transport payload.
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.
Add packet source address to temporary blacklist.
Add packet source address to temporary whitelist.
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.
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.
Bool table_find | ( | Context | ctx, |
TableKey | key, | ||
struct TableRecord * | record | ||
) |
Lookup value in the table by key.
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.
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.