diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2025-06-04 23:12:30 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2025-06-05 00:03:59 +0200 |
commit | 009cabe369b71cf5452286fd338eae382718789a (patch) | |
tree | 9f14eb626cee252ddf79d34cda9b98b57f5a9454 /src/lib.h |
knft is a tool to improve test coverage for the low-level nftables
kernel API by providing a relatively simple way to define a transaction
batch with nftables objects without having to mingle with netlink.
A set of tests 612 test (.t) files are included.
knft also provides a rudimentary deterministic fuzzer (via -f option)
along with several fuzzing modes that mangle existing tests in different
ways to improve coverage for error unwinding paths:
deltable \
delbasechain \
delchain \
delrule | - delete object in this batch
delset /
delelem /
delobj /
flushset - flush set
dup - duplicate object
reverse-commit - turn commit into abort
reverse-abort - turn abort into commit
table-dormant - inject table dormant flag
table-wakeup - inject table wake-up flag
swap - swap objects
bogus - inject bogus object to make the transaction fail
To inspect how the selected fuzzing mode mangles the test, you can use
the -d option to enable debugging along with -c to run it in dry-run
mode, eg.
# src/./knft -c -f deltable -d tests/expr/meta/03-mark_ok.t
tests/expr/meta/03-mark_ok.t...
[FUZZING] tests/expr/meta/03-mark_ok.t (deltable)
>>>> fuzz_loop at index 0 in state=0
add_table(NFPROTO_IPV4, "test", NULL, NULL, NULL);
del_table(NFPROTO_IPV4, "test", NULL);
add_chain("test", NULL, NULL, NULL, NULL);
add_rule("test", "0x1", NULL, NULL, NULL);
meta(NULL, "NFT_REG32_15", "3");
cmp("NFT_REG32_15", "0", "ffffffff");
commit();
<<<< fuzz_loop backtrack STACK limit reached
==== still more tries at index 0 in state=0
add_table(NFPROTO_IPV4, "test", NULL, NULL, NULL);
add_chain("test", NULL, NULL, NULL, NULL);
del_table(NFPROTO_IPV4, "test", NULL);
add_rule("test", "0x1", NULL, NULL, NULL);
meta(NULL, "NFT_REG32_15", "3");
cmp("NFT_REG32_15", "0", "ffffffff");
commit();
<<<< fuzz_loop backtrack STACK limit reached
...
knft provides a few more options:
-e to display the error reported by the kernel.
-n to perform test runs without flushing the existing ruleset.
This tool requires libmnl to build and to parse the netlink messages
that are sent and received by the kernel.
This tool is released under the GPLv2 (or any later).
This project is funded through the NGI0 Entrust established by NLnet
(https://nlnet.nl) with support from the European Commission's Next
Generation Internet programme.
Diffstat (limited to 'src/lib.h')
-rw-r--r-- | src/lib.h | 1899 |
1 files changed, 1899 insertions, 0 deletions
diff --git a/src/lib.h b/src/lib.h new file mode 100644 index 0000000..a5d4362 --- /dev/null +++ b/src/lib.h @@ -0,0 +1,1899 @@ +#ifndef _LIB_H +#define _LIB_H + +#include <libmnl/libmnl.h> +#include <stdlib.h> +#include "linux_list.h" + +#define ARRAY_MAX 4096 + +struct array { + void *data[ARRAY_MAX]; + int num; +}; + +struct array_u8 { + uint8_t data[ARRAY_MAX]; + int num; +}; + +struct array_u32 { + uint32_t data[ARRAY_MAX]; + int num; +}; + +enum test_batch_type { + ADD_TABLE = 0, + SET_TABLE, + DEL_TABLE, + ADD_BASECHAIN, + DEL_BASECHAIN, + ADD_CHAIN, + DEL_CHAIN, + ADD_SET, + SET_SET, + FLUSH_SET, + ADD_SETELEM, + DEL_SETELEM, + DEL_SET, + ADD_FLOWTABLE, + DEL_FLOWTABLE, + ADD_RULE, + DEL_RULE, + ADD_OBJECT, + DEL_OBJECT, +}; + +struct test_batch_cmd { + struct list_head list; + enum test_batch_type type; + int lineno; + void *obj; +}; + +struct test_batch { + struct list_head cmd; + uint32_t lineno; + char buf[1 << 21]; + struct mnl_socket *nl; + struct mnl_nlmsg_batch *batch; + struct { + int family; + const char *table; + struct rule *rule; + struct list_head *expr_list; /* for inner */ + struct set *set; + } ctx; +}; + +void setup_batch(struct test_batch *batch); + +struct table { + const char *name; + uint32_t *nfproto; + uint32_t *flags; + uint64_t *handle; + const char *userdata; + + /* storage */ + uint32_t _nfproto; + uint32_t _flags; + uint64_t _handle; +}; + +static inline struct table *table_init(void) +{ + struct table *table = calloc(1, sizeof(*table)); + + table->nfproto = &table->_nfproto; + table->flags = &table->_flags; + table->handle = &table->_handle; + + return table; +} + +void free_table(struct table *table); + +void set_table(struct test_batch *batch, struct table *table); +void add_table(struct test_batch *batch, struct table *table); +void del_table(struct test_batch *batch, struct table *table); + +struct chain { + const char *table; + const char *name; + const char *type; + const char *dev; + struct array *dev_array; + const char *userdata; + + uint32_t *family; + uint32_t *flags; + uint32_t *chain_id; + uint32_t *hooknum; + uint64_t *handle; + uint32_t *policy; + uint64_t *bytes; + uint64_t *pkts; + uint32_t *prio; + + /* storage */ + uint32_t _family; + uint32_t _flags; + uint32_t _chain_id; + uint32_t _hooknum; + uint64_t _handle; + uint32_t _policy; + uint64_t _bytes; + uint64_t _pkts; + uint32_t _prio; +}; + +static inline struct chain *chain_init(void) +{ + struct chain *c = calloc(1, sizeof(*c)); + + c->family = &c->_family; + c->flags = &c->_flags; + c->chain_id = &c->_chain_id; + c->hooknum = &c->_hooknum; + c->handle = &c->_handle; + c->policy = &c->_policy; + c->bytes = &c->_bytes; + c->pkts = &c->_pkts; + c->prio = &c->_prio; + + return c; +} + +void free_chain(struct chain *chain); + +void add_chain(struct test_batch *batch, struct chain *chain); +void del_chain(struct test_batch *batch, struct chain *chain); +void add_basechain(struct test_batch *batch, struct chain *chain); +void del_basechain(struct test_batch *batch, struct chain *chain); + +struct set { + const char *table; + const char *name; + struct list_head expr_list; + + uint32_t *family; + uint32_t *flags; + uint32_t *key_len; + uint32_t *key_type; + uint32_t *data_len; + uint32_t *data_type; + uint32_t *policy; + struct array_u8 *field_array; + uint32_t *size; + uint32_t *set_id; + uint64_t *timeout; + uint32_t *gc_interval; + const char *userdata; + uint32_t *obj_type; + uint64_t *handle; + + /* storage */ + uint32_t _family; + uint32_t _flags; + uint32_t _key_len; + uint32_t _key_type; + uint32_t _data_len; + uint32_t _data_type; + uint32_t _policy; + uint32_t _size; + uint32_t _set_id; + uint64_t _timeout; + uint32_t _gc_interval; + uint32_t _obj_type; + uint64_t _handle; +}; + +static inline struct set *set_init(void) +{ + struct set *set = calloc(1, sizeof(*set)); + + INIT_LIST_HEAD(&set->expr_list); + + set->family = &set->_family; + set->flags = &set->_flags; + set->key_len = &set->_key_len; + set->key_type = &set->_key_type; + set->data_len = &set->_data_len; + set->data_type = &set->_data_type; + set->policy = &set->_policy; + set->size = &set->_size; + set->set_id = &set->_set_id; + set->timeout = &set->_timeout; + set->gc_interval = &set->_gc_interval; + set->obj_type = &set->_obj_type; + set->handle = &set->_handle; + + return set; +} + +void add_set(struct test_batch *batch, struct set *set); +void del_set(struct test_batch *batch, struct set *set); +void flush_set(struct test_batch *batch, struct set *set); +void set_set(struct test_batch *batch, struct set *set); +void free_set(struct set *set); + +struct elem { + const char *table; + const char *set; + uint32_t set_id; + + const char *chain; + const char *objname; + uint8_t *userdata; + + struct list_head expr_list; + + uint32_t *family; + uint8_t *key; + int key_len; + uint8_t *key_end; + int key_end_len; + uint8_t *data; + int data_len; + uint32_t *flags; + uint32_t *verdict; + uint64_t *timeout; + uint64_t *expiration; + + /* storage */ + uint32_t _family; + uint8_t _key[16]; + uint8_t _key_end[16]; + uint8_t _data[64]; + uint32_t _flags; + uint32_t _verdict; + uint64_t _timeout; + uint64_t _expiration; +}; + +static inline struct elem *elem_init(void) +{ + struct elem *elem = calloc(1, sizeof(*elem)); + + INIT_LIST_HEAD(&elem->expr_list); + + elem->family = &elem->_family; + elem->key = elem->_key; + elem->key_end = elem->_key_end; + elem->data = elem->_data; + elem->flags = &elem->_flags; + elem->verdict = &elem->_verdict; + elem->timeout = &elem->_timeout; + elem->expiration = &elem->_expiration; + + return elem; +} + +void free_elem(struct elem *elem); + +void add_elem(struct test_batch *batch, struct elem *elem); +void del_elem(struct test_batch *batch, struct elem *elem); + +struct flowtable { + const char *table; + const char *name; + struct array *dev_array; + + uint32_t *family; + uint32_t *hooknum; + uint32_t *prio; + uint64_t *handle; + + /* storage */ + uint32_t _family; + uint32_t _hooknum; + uint32_t _prio; + uint64_t _handle; +}; + +static inline struct flowtable *flowtable_init(void) +{ + struct flowtable *f = calloc(1, sizeof(*f)); + + f->family = &f->_family; + f->hooknum = &f->_hooknum; + f->handle = &f->_handle; + f->prio = &f->_prio; + + return f; +} + +void add_flowtable(struct test_batch *batch, struct flowtable *flowtable); +void del_flowtable(struct test_batch *batch, struct flowtable *flowtable); +void free_flowtable(struct flowtable *flowtable); + +struct rule { + const char *table; + const char *chain; + uint32_t *family; + uint32_t *rule_id; + uint32_t *pos_id; + uint64_t *handle; + uint64_t *pos; + const char *userdata; + + /* set up when parsing match/target. */ + struct { + uint32_t *l4proto; + uint32_t *flags; + } compat; + + struct list_head expr_list; + + /* storage */ + uint32_t _family; + uint32_t _rule_id; + uint32_t _pos_id; + uint64_t _handle; + uint64_t _pos; +}; + +static inline struct rule *rule_init(void) +{ + struct rule *rule = calloc(1, sizeof(*rule)); + + rule->family = &rule->_family; + rule->rule_id = &rule->_rule_id; + rule->pos_id = &rule->_pos_id; + rule->handle = &rule->_handle; + rule->pos = &rule->_pos; + + INIT_LIST_HEAD(&rule->expr_list); + + return rule; +} + +void free_rule(struct rule *rule); + +void add_rule(struct test_batch *batch, struct rule *rule); +void del_rule(struct test_batch *batch, struct rule *rule); + +enum expr_type { + INVALID = 0, + BITWISE, + BYTEORDER, + CMP, + COUNTER, + CONNLIMIT, + CT, + DUP, + DYNSET, + EXTHDR, + FIB, + FWD, + HASH, + INNER, + IMMEDIATE, + LAST, + LIMIT, + LOG, + LOOKUP, + MASQ, + MATCH, + META, + NAT, + NUMGEN, + OBJREF, + OSF, + PAYLOAD, + QUEUE, + QUOTA, + RANGE, + REDIR, + REJECT, + RT, + SOCKET, + SYNPROXY, + TARGET, + TPROXY, + TUNNEL, + XFRM, +}; + +struct expr { + struct list_head list; + enum expr_type type; +}; + +int add_expr(struct test_batch *batch, struct expr *expr); + +struct bitwise { + struct expr expr; + + uint32_t *sreg; + uint32_t *dreg; + uint32_t *op; + uint32_t *len; + uint8_t *mask; + int mask_len; + uint8_t *xor; + int xor_len; + uint8_t *data; + int data_len; + + uint32_t _sreg; + uint32_t _dreg; + uint32_t _op; + uint32_t _len; + uint8_t _mask[16]; + uint8_t _xor[16]; + uint8_t _data[16]; +}; + +static inline struct bitwise *bitwise_init(void) +{ + struct bitwise *bitwise = calloc(1, sizeof(*bitwise)); + + bitwise->expr.type = BITWISE; + + bitwise->sreg = &bitwise->_sreg; + bitwise->dreg = &bitwise->_dreg; + bitwise->op = &bitwise->_op; + bitwise->len = &bitwise->_len; + bitwise->mask = bitwise->_mask; + bitwise->xor = bitwise->_xor; + bitwise->data = bitwise->_data; + + return bitwise; +} + +static inline void free_bitwise(struct bitwise *bitwise) +{ + free(bitwise); +} + +struct byteorder { + struct expr expr; + + uint32_t *sreg; + uint32_t *dreg; + uint32_t *op; + uint32_t *len; + uint32_t *size; + + uint32_t _sreg; + uint32_t _dreg; + uint32_t _op; + uint32_t _len; + uint32_t _size; +}; + +static inline struct byteorder *byteorder_init(void) +{ + struct byteorder *byteorder = calloc(1, sizeof(*byteorder)); + + byteorder->expr.type = BYTEORDER; + + byteorder->sreg = &byteorder->_sreg; + byteorder->dreg = &byteorder->_dreg; + byteorder->op = &byteorder->_op; + byteorder->len = &byteorder->_len; + byteorder->size = &byteorder->_size; + + return byteorder; +} + +static inline void free_byteorder(struct byteorder *byteorder) +{ + free(byteorder); +} + +struct cmp { + struct expr expr; + + uint32_t *sreg; + uint32_t *op; + uint8_t *data; + int data_len; + + uint32_t _sreg; + uint32_t _op; + uint8_t _data[16]; +}; + +static inline struct cmp *cmp_init(void) +{ + struct cmp *cmp = calloc(1, sizeof(*cmp)); + + cmp->expr.type = CMP; + + cmp->sreg = &cmp->_sreg; + cmp->op = &cmp->_op; + cmp->data = cmp->_data; + + return cmp; +} + +static inline void free_cmp(struct cmp *cmp) +{ + free(cmp); +} + +struct connlimit { + struct expr expr; + + uint32_t *count; + uint32_t *flags; + + uint32_t _count; + uint32_t _flags; +}; + +static inline struct connlimit *connlimit_init(void) +{ + struct connlimit *connlimit = calloc(1, sizeof(*connlimit)); + + connlimit->expr.type = CONNLIMIT; + + connlimit->count = &connlimit->_count; + connlimit->flags = &connlimit->_flags; + + return connlimit; +} + +static inline void free_connlimit(struct connlimit *connlimit) +{ + free(connlimit); +} + +struct counter { + struct expr expr; + + uint64_t *pkts; + uint64_t *bytes; + + /* storage */ + uint64_t _pkts; + uint64_t _bytes; +}; + +static inline struct counter *counter_init(void) +{ + struct counter *counter = calloc(1, sizeof(*counter)); + + counter->expr.type = COUNTER; + + counter->pkts = &counter->_pkts; + counter->bytes = &counter->_bytes; + + return counter; +} + +static inline void free_counter(struct counter *counter) +{ + free(counter); +} + +struct ct { + struct expr expr; + + uint32_t *sreg; + uint32_t *dreg; + uint32_t *key; + uint8_t *dir; + + uint32_t _sreg; + uint32_t _dreg; + uint32_t _key; + uint8_t _dir; +}; + +static inline struct ct *ct_init(void) +{ + struct ct *ct = calloc(1, sizeof(*ct)); + + ct->expr.type = CT; + + ct->sreg = &ct->_sreg; + ct->dreg = &ct->_dreg; + ct->key = &ct->_key; + ct->dir = &ct->_dir; + + return ct; +} + +static inline void free_ct(struct ct *ct) +{ + free(ct); +} + +struct dup { + struct expr expr; + + uint32_t *sreg_addr; + uint32_t *sreg_dev; + + uint32_t _sreg_addr; + uint32_t _sreg_dev; +}; + +static inline struct dup *dup_init(void) +{ + struct dup *dup = calloc(1, sizeof(*dup)); + + dup->expr.type = DUP; + + dup->sreg_addr = &dup->_sreg_addr; + dup->sreg_dev = &dup->_sreg_dev; + + return dup; +} + +static inline void free_dup(struct dup *dup) +{ + free(dup); +} + +struct dynset { + struct expr expr; + + const char *set; + struct list_head expr_list; + + uint32_t *set_id; + uint32_t *op; + uint32_t *sreg_key; + uint32_t *sreg_data; + uint64_t *timeout; + uint32_t *flags; + /* exprs */ + + /* storage */ + uint32_t _set_id; + uint32_t _op; + uint32_t _sreg_key; + uint32_t _sreg_data; + uint64_t _timeout; + uint32_t _flags; +}; + +static inline struct dynset *dynset_init(void) +{ + struct dynset *dynset = calloc(1, sizeof(*dynset)); + + dynset->expr.type = DYNSET; + + INIT_LIST_HEAD(&dynset->expr_list); + + dynset->set_id = &dynset->_set_id; + dynset->op = &dynset->_op; + dynset->sreg_key= &dynset->_sreg_key; + dynset->sreg_data = &dynset->_sreg_data; + dynset->timeout = &dynset->_timeout; + dynset->flags = &dynset->_flags; + + return dynset; +} + +static inline void free_dynset(struct dynset *dynset) +{ + free((void *)dynset->set); + free(dynset); +} + +struct exthdr { + struct expr expr; + + uint32_t *sreg; + uint32_t *dreg; + uint32_t *offset; + uint32_t *len; + uint32_t *type; + uint32_t *op; + uint32_t *flags; + + uint32_t _sreg; + uint32_t _dreg; + uint32_t _offset; + uint32_t _len; + uint32_t _type; + uint32_t _op; + uint32_t _flags; +}; + +static inline struct exthdr *exthdr_init(void) +{ + struct exthdr *exthdr = calloc(1, sizeof(*exthdr)); + + exthdr->expr.type = EXTHDR; + + exthdr->sreg = &exthdr->_sreg; + exthdr->dreg = &exthdr->_dreg; + exthdr->offset = &exthdr->_offset; + exthdr->len = &exthdr->_len; + exthdr->type = &exthdr->_type; + exthdr->op = &exthdr->_op; + exthdr->flags = &exthdr->_flags; + + return exthdr; +} + +static inline void free_exthdr(struct exthdr *exthdr) +{ + free(exthdr); +} + +struct fib { + struct expr expr; + + uint32_t *flags; + uint32_t *result; + uint32_t *dreg; + + /* storage */ + uint32_t _flags; + uint32_t _result; + uint32_t _dreg; +}; + +static inline struct fib *fib_init(void) +{ + struct fib *fib = calloc(1, sizeof(*fib)); + + fib->expr.type = FIB; + + fib->flags = &fib->_flags; + fib->result = &fib->_result; + fib->dreg = &fib->_dreg; + + return fib; +} + +static inline void free_fib(struct fib *fib) +{ + free(fib); +} + +struct fwd { + struct expr expr; + + uint32_t *sreg_addr; + uint32_t *sreg_dev; + uint32_t *nfproto; + + uint32_t _sreg_addr; + uint32_t _sreg_dev; + uint32_t _nfproto; +}; + +static inline struct fwd *fwd_init(void) +{ + struct fwd *fwd = calloc(1, sizeof(*fwd)); + + fwd->expr.type = FWD; + + fwd->sreg_addr = &fwd->_sreg_addr; + fwd->sreg_dev = &fwd->_sreg_dev; + fwd->nfproto = &fwd->_nfproto; + + return fwd; +} + +static inline void free_fwd(struct fwd *fwd) +{ + free(fwd); +} + +struct hash { + struct expr expr; + + uint32_t *type; + uint32_t *sreg; + uint32_t *dreg; + uint32_t *len; + uint32_t *modulus; + uint32_t *seed; + uint32_t *offset; + + uint32_t _type; + uint32_t _sreg; + uint32_t _dreg; + uint32_t _len; + uint32_t _modulus; + uint32_t _seed; + uint32_t _offset; +}; + +static inline struct hash *hash_init(void) +{ + struct hash *hash = calloc(1, sizeof(*hash)); + + hash->expr.type = HASH; + + hash->type = &hash->_type; + hash->sreg = &hash->_sreg; + hash->dreg = &hash->_dreg; + hash->len = &hash->_len; + hash->modulus = &hash->_modulus; + hash->seed = &hash->_seed; + hash->offset = &hash->_offset; + + return hash; +} + +static inline void free_hash(struct hash *hash) +{ + free(hash); +} + +struct inner { + struct expr expr; + + uint32_t _num; + uint32_t _type; + uint32_t _flags; + uint32_t _hdrsize; + + uint32_t *num; + uint32_t *type; + uint32_t *flags; + uint32_t *hdrsize; + + struct list_head expr_list; +}; + +static inline struct inner *inner_init(void) +{ + struct inner *inner = calloc(1, sizeof(*inner)); + + inner->expr.type = INNER; + + inner->num = &inner->_num; + inner->type = &inner->_type; + inner->flags = &inner->_flags; + inner->hdrsize = &inner->_hdrsize; + + INIT_LIST_HEAD(&inner->expr_list); + + return inner; +} + +void free_expr_list(struct list_head *expr_list); + +static inline void free_inner(struct inner *inner) +{ + free_expr_list(&inner->expr_list); + free(inner); +} + +struct immediate { + struct expr expr; + + const char *chain; + + uint32_t *dreg; + uint32_t *chain_id; + uint32_t *verdict; + uint8_t *data; + int data_len; + + uint32_t _dreg; + uint32_t _chain_id; + uint32_t _verdict; + uint8_t _data[16]; +}; + +static inline struct immediate *immediate_init(void) +{ + struct immediate *imm = calloc(1, sizeof(*imm)); + + imm->expr.type = IMMEDIATE; + + imm->dreg = &imm->_dreg; + imm->chain_id = &imm->_chain_id; + imm->verdict = &imm->_verdict; + imm->data = imm->_data; + + return imm; +} + +static inline void free_immediate(struct immediate *immediate) +{ + free((void *)immediate->chain); + free(immediate); +} + +struct last { + struct expr expr; + + uint64_t *msecs; + uint32_t *set; + + /* storage */ + uint64_t _msecs; + uint32_t _set; +}; + +static inline struct last *last_init(void) +{ + struct last *last = calloc(1, sizeof(*last)); + + last->expr.type = LAST; + + last->msecs = &last->_msecs; + last->set = &last->_set; + + return last; +} + +static inline void free_last(struct last *last) +{ + free(last); +} + +struct limit { + struct expr expr; + + uint64_t *rate; + uint64_t *unit; + uint32_t *burst; + uint32_t *type; + uint32_t *flags; + + /* storage */ + uint64_t _rate; + uint64_t _unit; + uint32_t _burst; + uint32_t _type; + uint32_t _flags; +}; + +static inline struct limit *limit_init(void) +{ + struct limit *limit = calloc(1, sizeof(*limit)); + + limit->expr.type = LIMIT; + + limit->rate = &limit->_rate; + limit->unit = &limit->_unit; + limit->burst = &limit->_burst; + limit->type = &limit->_type; + limit->flags = &limit->_flags; + + return limit; +} + +static inline void free_limit(struct limit *limit) +{ + free(limit); +} + +struct log { + struct expr expr; + + const char *prefix; + + uint32_t *snaplen; + uint16_t *group; + uint16_t *qthreshold; + uint32_t *level; + uint32_t *flags; + + /* storage */ + uint32_t _snaplen; + uint16_t _group; + uint16_t _qthreshold; + uint32_t _level; + uint32_t _flags; +}; + +static inline struct log *log_init(void) +{ + struct log *log = calloc(1, sizeof(*log)); + + log->expr.type = LOG; + + log->snaplen = &log->_snaplen; + log->group = &log->_group; + log->qthreshold = &log->_qthreshold; + log->level = &log->_level; + log->flags = &log->_flags; + + return log; +} + +static inline void free_log(struct log *log) +{ + free((void *)log->prefix); + free(log); +} + +struct lookup { + struct expr expr; + + const char *set; + uint32_t *set_id; + uint32_t *sreg; + uint32_t *dreg; + uint32_t *flags; + + /* storage */ + uint32_t _set_id; + uint32_t _sreg; + uint32_t _dreg; +}; + +static inline struct lookup *lookup_init(void) +{ + struct lookup *lookup = calloc(1, sizeof(*lookup)); + + lookup->expr.type = LOOKUP; + + lookup->set_id = &lookup->_set_id; + lookup->sreg = &lookup->_sreg; + lookup->dreg = &lookup->_dreg; + lookup->flags = NULL; // TODO + + return lookup; +} + +static inline void free_lookup(struct lookup *lookup) +{ + free((void *)lookup->set); + free(lookup); +} + +struct masq { + struct expr expr; + + uint32_t *sreg_proto_min; + uint32_t *sreg_proto_max; + uint32_t *flags; + + uint32_t _sreg_proto_min; + uint32_t _sreg_proto_max; + uint32_t _flags; +}; + +static inline struct masq *masq_init(void) +{ + struct masq *masq = calloc(1, sizeof(*masq)); + + masq->expr.type = MASQ; + + masq->sreg_proto_min = &masq->_sreg_proto_min; + masq->sreg_proto_max = &masq->_sreg_proto_max; + masq->flags = &masq->_flags; + + return masq; +} + +static inline void free_masq(struct masq *masq) +{ + free(masq); +} + +struct match { + struct expr expr; + + const char *name; + + uint32_t *rev; + uint8_t *data; + int data_len; + uint32_t *l4proto; + uint32_t *flags; + + /* storage */ + uint32_t _rev; + uint8_t _data[65536]; + uint32_t _l4proto; + uint32_t _flags; +}; + +static inline struct match *match_init(void) +{ + struct match *match = calloc(1, sizeof(*match)); + + match->expr.type = MATCH; + + match->rev = &match->_rev; + match->data = match->_data; + match->l4proto = &match->_l4proto; + match->flags = &match->_flags; + + return match; +} + +static inline void free_match(struct match *match) +{ + free((void *)match->name); + free(match); +} + +struct meta { + struct expr expr; + + uint32_t *sreg; + uint32_t *dreg; + uint32_t *key; + + uint32_t _sreg; + uint32_t _dreg; + uint32_t _key; +}; + +static inline struct meta *meta_init(void) +{ + struct meta *meta = calloc(1, sizeof(*meta)); + + meta->expr.type = META; + + meta->sreg = &meta->_sreg; + meta->dreg = &meta->_dreg; + meta->key = &meta->_key; + + return meta; +} + +static inline void free_meta(struct meta *meta) +{ + free(meta); +} + +struct nat { + struct expr expr; + + uint32_t *sreg_addr_min; + uint32_t *sreg_addr_max; + uint32_t *sreg_proto_min; + uint32_t *sreg_proto_max; + uint32_t *nfproto; + uint32_t *type; + uint32_t *flags; + + uint32_t _sreg_addr_min; + uint32_t _sreg_addr_max; + uint32_t _sreg_proto_min; + uint32_t _sreg_proto_max; + uint32_t _nfproto; + uint32_t _type; + uint32_t _flags; +}; + +static inline struct nat *nat_init(void) +{ + struct nat *nat = calloc(1, sizeof(*nat)); + + nat->expr.type = NAT; + + nat->sreg_addr_min = &nat->_sreg_addr_min; + nat->sreg_addr_max = &nat->_sreg_addr_max; + nat->sreg_proto_min = &nat->_sreg_proto_min; + nat->sreg_proto_max = &nat->_sreg_proto_max; + nat->nfproto = &nat->_nfproto; + nat->type = &nat->_type; + nat->flags = &nat->_flags; + + return nat; +} + +static inline void free_nat(struct nat *nat) +{ + free(nat); +} + +struct numgen { + struct expr expr; + + uint32_t *dreg; + uint32_t *modulus; + uint32_t *type; + uint32_t *offset; + + uint32_t _dreg; + uint32_t _modulus; + uint32_t _type; + uint32_t _offset; +}; + +static inline struct numgen *numgen_init(void) +{ + struct numgen *numgen = calloc(1, sizeof(*numgen)); + + numgen->expr.type = NUMGEN; + + numgen->dreg = &numgen->_dreg; + numgen->modulus = &numgen->_modulus; + numgen->type = &numgen->_type; + numgen->offset = &numgen->_offset; + + return numgen; +} + +static inline void free_numgen(struct numgen *numgen) +{ + free(numgen); +} + +struct objref { + struct expr expr; + + const char *set_name; + const char *name; + + uint32_t *type; + uint32_t *sreg; + uint32_t *set_id; + + uint32_t _type; + uint32_t _sreg; + uint32_t _set_id; +}; + +static inline struct objref *objref_init(void) +{ + struct objref *objref = calloc(1, sizeof(*objref)); + + objref->expr.type = OBJREF; + + objref->type = &objref->_type; + objref->sreg = &objref->_sreg; + objref->set_id = &objref->_set_id; + + return objref; +} + +static inline void free_objref(struct objref *objref) +{ + free((void *)objref->set_name); + free((void *)objref->name); + free(objref); +} + +struct osf { + struct expr expr; + + uint32_t *dreg; + uint32_t *ttl; + uint32_t *flags; + + uint32_t _dreg; + uint32_t _ttl; + uint32_t _flags; +}; + +static inline struct osf *osf_init(void) +{ + struct osf *osf = calloc(1, sizeof(*osf)); + + osf->expr.type = OSF; + + osf->dreg = &osf->_dreg; + osf->ttl = &osf->_ttl; + osf->flags = &osf->_flags; + + return osf; +} + +static inline void free_osf(struct osf *osf) +{ + free(osf); +} + +struct payload { + struct expr expr; + + uint32_t *sreg; + uint32_t *dreg; + uint32_t *offset; + uint32_t *base; + uint32_t *len; + uint32_t *csum_type; + uint32_t *csum_offset; + uint32_t *csum_flags; + + /* storage */ + uint32_t _sreg; + uint32_t _dreg; + uint32_t _offset; + uint32_t _base; + uint32_t _len; + uint32_t _csum_type; + uint32_t _csum_offset; + uint32_t _csum_flags; +}; + +static inline struct payload *payload_init(void) +{ + struct payload *payload = calloc(1, sizeof(*payload)); + + payload->expr.type = PAYLOAD; + + payload->sreg = &payload->_sreg; + payload->dreg = &payload->_dreg; + payload->offset = &payload->_offset; + payload->base = &payload->_base; + payload->len = &payload->_len; + payload->csum_type = &payload->_csum_type; + payload->csum_offset = &payload->_csum_offset; + payload->csum_flags = &payload->_csum_flags; + + return payload; +} + +static inline void free_payload(struct payload *payload) +{ + free(payload); +} + +struct queue { + struct expr expr; + + uint32_t *sreg_qnum; + uint16_t *queue_num; + uint16_t *queue_total; + uint16_t *flags; + + uint32_t _sreg_qnum; + uint16_t _queue_num; + uint16_t _queue_total; + uint16_t _flags; +}; + +static inline struct queue *queue_init(void) +{ + struct queue *queue = calloc(1, sizeof(*queue)); + + queue->expr.type = QUEUE; + + queue->sreg_qnum = &queue->_sreg_qnum; + queue->queue_num = &queue->_queue_num; + queue->queue_total = &queue->_queue_total; + queue->flags = &queue->_flags; + + return queue; +} + +static inline void free_queue(struct queue *queue) +{ + free(queue); +} + +struct quota { + struct expr expr; + + uint64_t *bytes; + uint64_t *consumed; + uint32_t *flags; + + /* storage */ + uint64_t _bytes; + uint64_t _consumed; + uint32_t _flags; +}; + +static inline struct quota *quota_init(void) +{ + struct quota *quota = calloc(1, sizeof(*quota)); + + quota->expr.type = QUOTA; + + quota->bytes = "a->_bytes; + quota->consumed = "a->_consumed; + quota->flags = "a->_flags; + + return quota; +} + +static inline void free_quota(struct quota *quota) +{ + free(quota); +} + +struct range { + struct expr expr; + + uint32_t *sreg; + uint32_t *op; + uint8_t *data_from; + int data_from_len; + uint8_t *data_to; + int data_to_len; + + uint32_t _sreg; + uint32_t _op; + uint8_t _data_from[16]; + uint8_t _data_to[16]; +}; + +static inline struct range *range_init(void) +{ + struct range *range = calloc(1, sizeof(*range)); + + range->expr.type = RANGE; + + range->sreg = &range->_sreg; + range->op = &range->_op; + range->data_from = range->_data_from; + range->data_to = range->_data_to; + + return range; +} + +static inline void free_range(struct range *range) +{ + free(range); +} + +struct redir { + struct expr expr; + + uint32_t *sreg_proto_min; + uint32_t *sreg_proto_max; + uint32_t *flags; + + uint32_t _sreg_proto_min; + uint32_t _sreg_proto_max; + uint32_t _flags; +}; + +static inline struct redir *redir_init(void) +{ + struct redir *redir = calloc(1, sizeof(*redir)); + + redir->expr.type = REDIR; + + redir->sreg_proto_min = &redir->_sreg_proto_min; + redir->sreg_proto_max = &redir->_sreg_proto_max; + redir->flags = &redir->_flags; + + return redir; +} + +static inline void free_redir(struct redir *redir) +{ + free(redir); +} + +struct reject { + struct expr expr; + + uint32_t *type; + uint8_t *icmp_code; + + /* storage */ + uint32_t _type; + uint8_t _icmp_code; +}; + +static inline struct reject *reject_init(void) +{ + struct reject *reject = calloc(1, sizeof(*reject)); + + reject->expr.type = REJECT; + + reject->type = &reject->_type; + reject->icmp_code = &reject->_icmp_code; + + return reject; +} + +static inline void free_reject(struct reject *reject) +{ + free(reject); +} + +struct rt { + struct expr expr; + + uint32_t *dreg; + uint32_t *key; + + uint32_t _dreg; + uint32_t _key; +}; + +static inline struct rt *rt_init(void) +{ + struct rt *rt = calloc(1, sizeof(*rt)); + + rt->expr.type = RT; + + rt->dreg = &rt->_dreg; + rt->key = &rt->_key; + + return rt; +} + +static inline void free_rt(struct rt *rt) +{ + free(rt); +} + +struct socket { + struct expr expr; + + uint32_t *dreg; + uint32_t *key; + uint32_t *level; + + uint32_t _dreg; + uint32_t _key; + uint32_t _level; +}; + +static inline struct socket *socket_init(void) +{ + struct socket *socket = calloc(1, sizeof(*socket)); + + socket->expr.type = SOCKET; + + socket->dreg = &socket->_dreg; + socket->key = &socket->_key; + socket->level = &socket->_level; + + return socket; +} + +static inline void free_socket(struct socket *socket) +{ + free(socket); +} + +struct synproxy { + struct expr expr; + + uint16_t *mss; + uint8_t *wscale; + uint32_t *flags; + + /* storage */ + uint16_t _mss; + uint8_t _wscale; + uint32_t _flags; +}; + +static inline struct synproxy *synproxy_init(void) +{ + struct synproxy *synproxy = calloc(1, sizeof(*synproxy)); + + synproxy->expr.type = SYNPROXY; + + synproxy->mss = &synproxy->_mss; + synproxy->wscale = &synproxy->_wscale; + synproxy->flags = &synproxy->_flags; + + return synproxy; +} + +static inline void free_synproxy(struct synproxy *synproxy) +{ + free(synproxy); +} + +struct target { + struct expr expr; + + const char *name; + + uint32_t *rev; + uint8_t *data; + int data_len; + uint32_t *l4proto; + uint32_t *flags; + + /* storage */ + uint32_t _rev; + uint8_t _data[65536]; + uint32_t _l4proto; + uint32_t _flags; +}; + +static inline struct target *target_init(void) +{ + struct target *target = calloc(1, sizeof(*target)); + + target->expr.type = TARGET; + + target->rev = &target->_rev; + target->data = target->_data; + target->l4proto = &target->_l4proto; + target->flags = &target->_flags; + + return target; +} + +static void free_target(struct target *target) +{ + free((void *)target->name); + free(target); +} + +struct tproxy { + struct expr expr; + + uint32_t *nfproto; + uint32_t *sreg_addr; + uint32_t *sreg_port; + + uint32_t _nfproto; + uint32_t _sreg_addr; + uint32_t _sreg_port; +}; + +static inline struct tproxy *tproxy_init(void) +{ + struct tproxy *tproxy = calloc(1, sizeof(*tproxy)); + + tproxy->expr.type = TPROXY; + + tproxy->nfproto = &tproxy->_nfproto; + tproxy->sreg_addr = &tproxy->_sreg_addr; + tproxy->sreg_port = &tproxy->_sreg_port; + + return tproxy; +} + +static inline void free_tproxy(struct tproxy *tproxy) +{ + free(tproxy); +} + +struct tunnel { + struct expr expr; + + uint32_t *dreg; + uint32_t *key; +// uint32_t *mode; + + uint32_t _dreg; + uint32_t _key; +//XXX uint32_t _mode; +}; + +static inline struct tunnel *tunnel_init(void) +{ + struct tunnel *tunnel = calloc(1, sizeof(*tunnel)); + + tunnel->expr.type = TUNNEL; + + tunnel->dreg = &tunnel->_dreg; + tunnel->key = &tunnel->_key; +//XXX tunnel->mode = &tunnel->_mode; + + return tunnel; +} + +static inline void free_tunnel(struct tunnel *tunnel) +{ + free(tunnel); +} + +struct xfrm { + struct expr expr; + + uint32_t *dreg; + uint32_t *key; + uint32_t *spnum; + uint8_t *dir; + + uint32_t _dreg; + uint32_t _key; + uint32_t _spnum; + uint8_t _dir; +}; + +static inline struct xfrm *xfrm_init(void) +{ + struct xfrm *xfrm = calloc(1, sizeof(*xfrm)); + + xfrm->expr.type = XFRM; + + xfrm->dreg = &xfrm->_dreg; + xfrm->key = &xfrm->_key; + xfrm->spnum = &xfrm->_spnum; + xfrm->dir = &xfrm->_dir; + + return xfrm; +} + +static inline void free_xfrm(struct xfrm *xfrm) +{ + free(xfrm); +} + +struct ct_helper { + const char *name; + uint8_t *l4proto; + uint16_t *l3proto; + + /* storage */ + uint8_t _l4proto; + uint16_t _l3proto; +}; + +static inline struct ct_helper *ct_helper_init(void) +{ + struct ct_helper *ct_helper = calloc(1, sizeof(*ct_helper)); + + ct_helper->l4proto = &ct_helper->_l4proto; + ct_helper->l3proto = &ct_helper->_l3proto; + + return ct_helper; +} + +struct ct_timeout { + const char *name; + uint8_t *l4proto; + uint16_t *l3proto; + struct array_u32 *timeout_array; + + /* storage */ + uint8_t _l4proto; + uint16_t _l3proto; +}; + +static inline struct ct_timeout *ct_timeout_init(void) +{ + struct ct_timeout *ct_timeout = calloc(1, sizeof(*ct_timeout)); + + ct_timeout->l4proto = &ct_timeout->_l4proto; + ct_timeout->l3proto = &ct_timeout->_l3proto; + + return ct_timeout; +} + +struct ct_expect { + const char *name; + uint8_t *l4proto; + uint16_t *l3proto; + uint16_t *dport; + uint32_t *timeout; + uint8_t *size; + + /* storage */ + uint8_t _l4proto; + uint16_t _l3proto; + uint16_t _dport; + uint32_t _timeout; + uint8_t _size; +}; + +static inline struct ct_expect *ct_expect_init(void) +{ + struct ct_expect *ct_expect = calloc(1, sizeof(*ct_expect)); + + ct_expect->l4proto = &ct_expect->_l4proto; + ct_expect->l3proto = &ct_expect->_l3proto; + ct_expect->dport = &ct_expect->_dport; + ct_expect->timeout = &ct_expect->_timeout; + ct_expect->size = &ct_expect->_size; + + return ct_expect; +} + +struct tunnel_tmpl { + uint32_t *id; + uint32_t *flags; + uint16_t *sport; + uint16_t *dport; + uint8_t *tos; + uint8_t *ttl; + uint32_t *src_v4; + uint8_t *src_v6; + uint32_t *dst_v4; + uint8_t *dst_v6; + uint32_t *flowlabel; + + /* storage */ + uint32_t _id; + uint32_t _flags; + uint16_t _sport; + uint16_t _dport; + uint8_t _tos; + uint8_t _ttl; + uint32_t _src_v4; + uint8_t _src_v6[16]; + uint32_t _dst_v4; + uint8_t _dst_v6[16]; + uint32_t _flowlabel; +}; + +static inline struct tunnel_tmpl *tunnel_tmpl_init(void) +{ + struct tunnel_tmpl *tunnel = calloc(1, sizeof(*tunnel)); + + tunnel->id = &tunnel->_id; + tunnel->flags = &tunnel->_flags; + tunnel->sport = &tunnel->_sport; + tunnel->dport = &tunnel->_dport; + tunnel->tos = &tunnel->_tos; + tunnel->ttl = &tunnel->_ttl; + tunnel->src_v4 = &tunnel->_src_v4; + tunnel->src_v6 = tunnel->_src_v6; + tunnel->dst_v4 = &tunnel->_dst_v4; + tunnel->dst_v6 = tunnel->_dst_v6; + tunnel->flowlabel = &tunnel->_flowlabel; + + return tunnel; +} + +struct secmark { + char *ctx; +}; + +static inline struct secmark *secmark_init(void) +{ + struct secmark *secmark = calloc(1, sizeof(*secmark)); + + return secmark; +} + +struct obj { + const char *table; + const char *name; + uint64_t *handle; + const char *userdata; + uint32_t *type; + uint32_t *family; + + union { + struct counter *counter; + struct quota *quota; + struct ct_helper *ct_helper; + struct limit *limit; + struct connlimit *connlimit; + struct tunnel_tmpl *tun; + struct ct_timeout *ct_timeout; + struct ct_expect *ct_expect; + struct secmark *secmark; + struct synproxy *synproxy; + } u; + + /* storage */ + uint32_t _type; + uint32_t _family; + uint64_t _handle; +}; + +static inline struct obj *obj_init(void) +{ + struct obj *obj = calloc(1, sizeof(*obj)); + + obj->type = &obj->_type; + obj->family = &obj->_family; + obj->handle = &obj->_handle; + + return obj; +} + +void add_obj(struct test_batch *batch, struct obj *obj); +void del_obj(struct test_batch *batch, struct obj *obj); +void free_obj(struct obj *obj); + +int batch_commit(struct test_batch *batch); +int batch_abort(struct test_batch *batch); + +static inline bool batch_empty(struct test_batch *batch) +{ + return list_empty(&batch->cmd); +} + +void batch_reset(struct test_batch *batch); +void batch_stop(struct test_batch *batch); + +int flush_ruleset(struct mnl_socket *nl); + +struct array *array_alloc(void); +bool array_add(struct array *array, void *data); +void array_free(struct array *array); + +struct array_u8 *array_u8_alloc(void); +bool array_u8_add(struct array_u8 *array, const char *data); +void array_u8_free(struct array_u8 *array); + +struct array_u32 *array_u32_alloc(void); +bool array_u32_add(struct array_u32 *array, const char *value); +void array_u32_free(struct array_u32 *array); + +bool kernel_is_tainted(void); +int list_hooks(struct mnl_socket *nl); + +#endif |