#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 | Ip6Addr |
IPv6 address representation. More... | |
struct | Ip6Header |
IPv6 header. More... | |
struct | UdpHeader |
UDP header. More... | |
struct | TcpHeader |
TCP header. More... | |
struct | IcmpHeader |
ICMP and ICMPv6 header. More... | |
union | NetAddr |
Network address, either IPv4 or IPv6. More... | |
struct | Flow |
Packet flow information. More... | |
struct | TableRecord |
Record in the program-wide table. More... | |
struct | TableExResult |
Result of a lookup in the extended table. More... | |
Macros | |
#define | PROGRAM_DISPLAY_ID(id) |
Mandatory program identifier for display to the user. More... | |
#define | ENTRYPOINT |
Entry point function marker. More... | |
#define | LOCAL |
Force the compiler to inline a local function. More... | |
#define | PACKED |
Specify structure or union to be packed. 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... | |
#define | TABLE_EX_KEY_SIZE 16 |
Maximum allowed size of an extended table key. | |
#define | TABLE_EX_VALUE_SIZE 8 |
Maximum size of an extended table record value. | |
Typedefs | |
typedef void * | Context |
Opaque filter context. | |
typedef uint64_t | Bool |
ABI-safe, EBPF-friendly boolean type. More... | |
typedef uint32_t | Time |
typedef uint32_t | IpAddr |
IPv4 address. | |
typedef uint64_t | TableKey |
typedef uint64_t | TableValue |
typedef uint32_t | Cookie |
Enumerations | |
enum | Result { RESULT_PASS , RESULT_DROP , RESULT_BACK , RESULT_LIMIT , RESULT_SORB } |
Filter verdict. More... | |
enum | EtherType |
Ethernet frame type codes. More... | |
enum | IpProto |
IPv4 and IPv6 transport protocol codes. More... | |
enum | TcpFlags |
TCP flags. More... | |
enum | TcpOption |
TCP option codes. More... | |
enum | IcmpType |
ICMPv4 types. | |
enum | Icmp6Type |
ICMPv6 types. | |
Functions | |
const void * | parameters_get (Context ctx) |
Get a pointer to read-only program parameters. More... | |
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 basic table by key. More... | |
Bool | table_get (Context ctx, TableKey key, struct TableRecord *record) |
Lookup value in the basic table by key and modify record update time. More... | |
Bool | table_put (Context ctx, TableKey key, TableValue value) |
Update value in the basic table, creating a new record if needed. More... | |
uint64_t | table_size (Context ctx) |
Get number of records in the table. | |
struct TableExResult | table_ex_find (Context ctx, const void *key, const void *key_end, void *value, void *value_end) |
Lookup value in the extended table by key. More... | |
struct TableExResult | table_ex_get (Context ctx, const void *key, const void *key_end, void *value, void *value_end) |
Lookup value in the extended table by key and modify record update time. More... | |
Bool | table_ex_put (Context ctx, const void *key, const void *key_end, const void *value, const void *value_end) |
Update value in the extended table, creating a new record if needed. More... | |
uint64_t | table_ex_size (Context ctx) |
Get number of records in the extended table. | |
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... | |
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... | |
void | set_packet_isn_syncookie (Context ctx) |
Convert response packet to an empty TCP SYN+ACK with ISN syncookie. More... | |
Bool | isn_syncookie_check (Context ctx, uint32_t seqnum_offset, uint32_t acknum_offset) |
Check if packet is a TCP ACK carrying an ISN SYN cookie. More... | |
void | isn_send_ack_packet (Context ctx) |
Send ACK packet with ISN syncookie. More... | |
Bool | bloom_check (Context ctx, uint64_t hash) |
Check if hash value is stored in the bloom filter. More... | |
void | bloom_add (Context ctx, uint64_t hash) |
Add hash value to the bloom filter. | |
void | bloom_reset (Context ctx) |
Reset bloom filter to the initial state. | |
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... | |
uint64_t | rand64 (void) |
Generate a pseudo-random, non cryptographically-secure value. | |
Time | time_sec (Context ctx) |
Get system time in seconds. | |
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 uint64_t | bswap64 (uint64_t value) |
Change byte order of a 64-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... | |
#define ENTRYPOINT |
Entry point function marker.
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 verification (which forbids backward jumps).
Example:
#define MAX_PARAMETERS_LENGTH 1024 |
Maximum length of program parameters.
Before using a variable offset into parameters, a program 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, a program must check that it does not exceed this constant, otherwise EBPF verifier may reject the code. To avoid valid programs being mistakenly rejected, place the check immediately before using the offset.
#define PACKED |
#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.
#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 verifier 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 knowledge of maximum iteration count in advance, thus the code to loop "n" times 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 basic 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 basic table.
typedef uint32_t Time |
Time in seconds: Unix timestamp or duration.
enum EtherType |
Ethernet frame type codes.
enum IpProto |
IPv4 and IPv6 transport protocol codes.
enum Result |
Filter verdict.
Program return values.
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 hash value is stored in the bloom filter.
False positive matches are possible, but false negatives are not.
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.
void isn_send_ack_packet | ( | Context | ctx | ) |
Send ACK packet with ISN syncookie.
Must be called to send empty ACK packet with correct ISN syncooke to open TCP connection on the protected host.
Check if packet is a TCP ACK carrying an ISN SYN cookie.
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.
Get packet flow information, including source and destination.
This is simpler and more efficient than analysing L3 and L4 headers. Unused bytes, e.g. in IPv6 addresses for IPv4 packet, are zero-filled.
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 header, e.g. IpHeader, is sufficient.
uint16_t packet_network_proto | ( | Context | ctx | ) |
Get packet network protocol code, e.g. IPv4.
Return values are in host byte order:
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_isn_syncookie | ( | Context | ctx | ) |
Convert response packet to an empty TCP SYN+ACK with ISN syncookie.
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 is always set, 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 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.
struct TableExResult table_ex_find | ( | Context | ctx, |
const void * | key, | ||
const void * | key_end, | ||
void * | value, | ||
void * | value_end | ||
) |
Lookup value in the extended table by key.
Buffer from key
to key_end
must not exceed TABLE_EX_KEY_SIZE bytes. Buffer from value
to value_end
must not exceed TABLE_EX_VALUE_SIZE bytes.
struct TableExResult table_ex_get | ( | Context | ctx, |
const void * | key, | ||
const void * | key_end, | ||
void * | value, | ||
void * | value_end | ||
) |
Lookup value in the extended table by key and modify record update time.
Result holds previous update time, which can be used to measure time elapsed since last table_ex_get() call on the record.
Bool table_ex_put | ( | Context | ctx, |
const void * | key, | ||
const void * | key_end, | ||
const void * | value, | ||
const void * | value_end | ||
) |
Update value in the extended table, creating a new record if needed.
If key is not found and new record cannot be created, return false, otherwise return true.
Bool table_find | ( | Context | ctx, |
TableKey | key, | ||
struct TableRecord * | record | ||
) |
Lookup value in the basic table by key.
Bool table_get | ( | Context | ctx, |
TableKey | key, | ||
struct TableRecord * | record | ||
) |
Lookup value in the basic 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 basic table, creating a new record if needed.
If key is not found and new record cannot be created, return false, otherwise return true.
LOCAL void vlan_set_id | ( | struct VlanHeader * | vlan, |
uint16_t | id | ||
) |