From 9c0ed46f68cada9f3455be91adb553d020012596 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Mar 2019 11:56:05 +0100 Subject: Rename 'qa' directory to 'tests' When searching for library tests, 'qa' is easily overlooked. Use a more common name instead. Suggested-by: Pablo Neira Ayuso Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- tests/test_api.c | 751 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 751 insertions(+) create mode 100644 tests/test_api.c (limited to 'tests/test_api.c') diff --git a/tests/test_api.c b/tests/test_api.c new file mode 100644 index 0000000..57fdb90 --- /dev/null +++ b/tests/test_api.c @@ -0,0 +1,751 @@ +/* + * Run this after adding a new attribute to the nf_conntrack object + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * this file contains a test to check the set/get/copy/cmp APIs. + */ + +static void eval_sigterm(int status) +{ + switch(WTERMSIG(status)) { + case SIGSEGV: + printf("received SIGSEV\n"); + break; + case 0: + printf("OK\n"); + break; + default: + printf("exited with signal: %d\n", WTERMSIG(status)); + break; + } +} + +static void test_nfct_bitmask(void) +{ + struct nfct_bitmask *a, *b; + unsigned short int maxb, i; + struct nf_conntrack *ct1, *ct2; + + printf("== test nfct_bitmask_* API ==\n"); + + maxb = rand() & 0xffff; + + a = nfct_bitmask_new(maxb); + + assert(!nfct_bitmask_test_bit(a, maxb + 32)); + nfct_bitmask_set_bit(a, maxb + 32); + assert(!nfct_bitmask_test_bit(a, maxb + 32)); + + for (i = 0; i <= maxb; i++) + assert(!nfct_bitmask_test_bit(a, i)); + + for (i = 0; i <= maxb; i++) { + if (rand() & 1) { + assert(!nfct_bitmask_test_bit(a, i)); + continue; + } + nfct_bitmask_set_bit(a, i); + assert(nfct_bitmask_test_bit(a, i)); + } + + b = nfct_bitmask_clone(a); + assert(b); + + for (i = 0; i <= maxb; i++) { + if (nfct_bitmask_test_bit(a, i)) + assert(nfct_bitmask_test_bit(b, i)); + else + assert(!nfct_bitmask_test_bit(b, i)); + } + + nfct_bitmask_destroy(a); + + for (i = 0; i <= maxb; i++) { + if (rand() & 1) + continue; + nfct_bitmask_unset_bit(b, i); + assert(!nfct_bitmask_test_bit(b, i)); + } + + /* nfct_bitmask_clear() */ + for (i = 0; i < maxb; i++) { + nfct_bitmask_set_bit(b, i); + assert(nfct_bitmask_test_bit(b, i)); + nfct_bitmask_clear(b); + assert(!nfct_bitmask_test_bit(b, i)); + } + + for (i = 0; i < maxb; i++) + nfct_bitmask_set_bit(b, i); + nfct_bitmask_clear(b); + for (i = 0; i < maxb; i++) + assert(!nfct_bitmask_test_bit(b, i)); + + /* nfct_bitmask_equal() */ + for (i = 0; i < maxb / 32 * 32; i += 32) { + a = nfct_bitmask_new(i); + assert(!nfct_bitmask_equal(a, b)); + nfct_bitmask_destroy(a); + } + + a = nfct_bitmask_clone(b); + assert(nfct_bitmask_equal(a, b)); + for (i = 0; i < maxb; i++) { + if (nfct_bitmask_test_bit(a, i)) { + nfct_bitmask_unset_bit(a, i); + assert(!nfct_bitmask_equal(a, b)); + nfct_bitmask_set_bit(a, i); + } else { + nfct_bitmask_set_bit(a, i); + assert(!nfct_bitmask_equal(a, b)); + nfct_bitmask_unset_bit(a, i); + } + assert(nfct_bitmask_equal(a, b)); + } + + nfct_bitmask_destroy(a); + nfct_bitmask_destroy(b); + + ct1 = nfct_new(); + ct2 = nfct_new(); + + maxb = rand() & 0xff; + maxb += 128; + maxb /= 2; + a = nfct_bitmask_new(maxb * 2); + b = nfct_bitmask_new(maxb); + nfct_set_attr(ct1, ATTR_CONNLABELS, a); + nfct_set_attr(ct2, ATTR_CONNLABELS, b); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + + nfct_bitmask_set_bit(a, maxb); + nfct_bitmask_set_bit(b, maxb); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + + nfct_bitmask_set_bit(a, maxb * 2); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 0); + nfct_destroy(ct1); + nfct_destroy(ct2); + printf("OK\n"); +} + +/* These attributes cannot be set, ignore them. */ +static int attr_is_readonly(int attr) +{ + switch (attr) { + case ATTR_ORIG_COUNTER_PACKETS: + case ATTR_REPL_COUNTER_PACKETS: + case ATTR_ORIG_COUNTER_BYTES: + case ATTR_REPL_COUNTER_BYTES: + case ATTR_USE: + case ATTR_SECCTX: + case ATTR_TIMESTAMP_START: + case ATTR_TIMESTAMP_STOP: + return 1; + } + return 0; +} + + +static int test_nfct_cmp_api_single(struct nf_conntrack *ct1, + struct nf_conntrack *ct2, int attr) +{ + char data[256]; + struct nfct_bitmask *b; + int bit; + + if (attr_is_readonly(attr)) + return 0; + + switch (attr) { + case ATTR_SECMARK: /* obsolete */ + return 0; + + /* FIXME: not implemented comparators: */ + case ATTR_SNAT_IPV4: + case ATTR_DNAT_IPV4: + case ATTR_SNAT_IPV6: + case ATTR_DNAT_IPV6: + case ATTR_SNAT_PORT: + case ATTR_DNAT_PORT: + + case ATTR_TCP_FLAGS_ORIG: + case ATTR_TCP_FLAGS_REPL: + case ATTR_TCP_MASK_ORIG: + case ATTR_TCP_MASK_REPL: + + case ATTR_MASTER_IPV4_SRC: + case ATTR_MASTER_IPV4_DST: + case ATTR_MASTER_IPV6_SRC: + case ATTR_MASTER_IPV6_DST: + case ATTR_MASTER_PORT_SRC: + case ATTR_MASTER_PORT_DST: + case ATTR_MASTER_L3PROTO: + case ATTR_MASTER_L4PROTO: + + case ATTR_ORIG_NAT_SEQ_CORRECTION_POS: + case ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE: + case ATTR_ORIG_NAT_SEQ_OFFSET_AFTER: + case ATTR_REPL_NAT_SEQ_CORRECTION_POS: + case ATTR_REPL_NAT_SEQ_OFFSET_BEFORE: + case ATTR_REPL_NAT_SEQ_OFFSET_AFTER: + + case ATTR_SCTP_VTAG_ORIG: + case ATTR_SCTP_VTAG_REPL: + + case ATTR_HELPER_NAME: + + case ATTR_DCCP_ROLE: + case ATTR_DCCP_HANDSHAKE_SEQ: + + case ATTR_TCP_WSCALE_ORIG: + case ATTR_TCP_WSCALE_REPL: + + case ATTR_SYNPROXY_ISN: + case ATTR_SYNPROXY_ITS: + case ATTR_SYNPROXY_TSOFF: + + case ATTR_HELPER_INFO: + return 0; /* XXX */ + + default: + break; + } + + if (attr >= ATTR_SCTP_STATE) { + nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_SCTP); + nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_SCTP); + } else if (attr >= ATTR_TCP_FLAGS_ORIG) { + nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_TCP); + nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_TCP); + } else if (attr >= ATTR_ICMP_CODE) { + nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_ICMP); + nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_ICMP); + } else if (attr >= ATTR_ORIG_PORT_SRC) { + nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_TCP); + nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_TCP); + } + + nfct_copy(ct2, ct1, NFCT_CP_OVERRIDE); + memset(data, 42, sizeof(data)); + + assert(nfct_attr_is_set(ct1, attr)); + assert(nfct_attr_is_set(ct2, attr)); + + switch (attr) { + case ATTR_CONNLABELS: + case ATTR_CONNLABELS_MASK: + b = (void *) nfct_get_attr(ct1, attr); + assert(b); + b = nfct_bitmask_clone(b); + assert(b); + bit = nfct_bitmask_maxbit(b); + if (nfct_bitmask_test_bit(b, bit)) { + nfct_bitmask_unset_bit(b, bit); + assert(!nfct_bitmask_test_bit(b, bit)); + } else { + nfct_bitmask_set_bit(b, bit); + assert(nfct_bitmask_test_bit(b, bit)); + } + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + nfct_set_attr(ct2, attr, b); + break; + case ATTR_HELPER_INFO: + nfct_set_attr_l(ct2, attr, "test", 4); + break; + default: + nfct_set_attr(ct2, attr, data); + break; + } + + if (nfct_cmp(ct1, ct2, NFCT_CMP_ALL) != 0) { + fprintf(stderr, "nfct_cmp assert failure for attr %d\n", attr); + fprintf(stderr, "%p, %p, %x, %x\n", nfct_get_attr(ct1, attr), + nfct_get_attr(ct2, attr), + nfct_get_attr_u32(ct1, attr), nfct_get_attr_u32(ct2, attr)); + return -1; + } + if (nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) != 0) { + fprintf(stderr, "nfct_cmp strict assert failure for attr %d\n", attr); + return -1; + } + return 0; +} + +static int test_cmp_attr32(int attr, bool at1, bool at2, + uint32_t v1, uint32_t v2, unsigned int flags) +{ + struct nf_conntrack *ct1 = nfct_new(); + struct nf_conntrack *ct2 = nfct_new(); + int ret; + + if (at1) + nfct_set_attr_u32(ct1, attr, v1); + if (at2) + nfct_set_attr_u32(ct2, attr, v2); + + ret = nfct_cmp(ct1, ct2, NFCT_CMP_ALL | flags); + + nfct_destroy(ct1); + nfct_destroy(ct2); + + return ret; +} + +static void test_nfct_cmp_attr(int attr) +{ + unsigned int flags = 0; + + /* 0000, 1000, 1100, 0010, 1010... */ + /* attr at1 at2 v1 v2 */ + assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); + + flags = NFCT_CMP_STRICT; + assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); + + flags = NFCT_CMP_MASK; + assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); + + flags = NFCT_CMP_STRICT|NFCT_CMP_MASK; + assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1); + assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0); + assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */ + assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 0); /* verbose */ + assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1); +} + +static void test_nfct_cmp_api(struct nf_conntrack *ct1, struct nf_conntrack *ct2) +{ + int i; + + printf("== test cmp API ==\n"); + + test_nfct_cmp_attr(ATTR_ZONE); + test_nfct_cmp_attr(ATTR_ORIG_ZONE); + test_nfct_cmp_attr(ATTR_REPL_ZONE); + test_nfct_cmp_attr(ATTR_MARK); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0); + + nfct_copy(ct1, ct2, NFCT_CP_OVERRIDE); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 1); + + for (i=0; i < ATTR_MAX ; i++) { + nfct_attr_unset(ct1, i); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 1); + } + nfct_copy(ct1, ct2, NFCT_CP_OVERRIDE); + for (i=0; i < ATTR_MAX ; i++) { + nfct_attr_unset(ct2, i); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 0); + } + + for (i=0; i < ATTR_MAX ; i++) + assert(test_nfct_cmp_api_single(ct1, ct2, i) == 0); + + nfct_copy(ct2, ct1, NFCT_CP_OVERRIDE); + for (i=0; i < ATTR_MAX ; i++) { + nfct_attr_unset(ct1, i); + nfct_attr_unset(ct2, i); + + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 1); + assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 1); + } + nfct_destroy(ct1); + nfct_destroy(ct2); +} + +static void test_nfexp_cmp_api(struct nf_expect *ex1, struct nf_expect *ex2) +{ + int i; + + printf("== test expect cmp API ==\n"); + + /* XXX: missing nfexp_copy API. */ + memcpy(ex1, ex2, nfexp_maxsize()); + + assert(nfexp_cmp(ex1, ex2, 0) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 1); + + assert(nfexp_attr_is_set(ex1, 0) == 1); + nfexp_attr_unset(ex1, 0); + assert(nfexp_attr_is_set(ex1, 0) == 0); + + memcpy(ex1, ex2, nfexp_maxsize()); + for (i=0; i < ATTR_EXP_MAX; i++) { + nfexp_attr_unset(ex1, i); + + assert(nfexp_cmp(ex1, ex2, 0) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 0); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 1); + } + memcpy(ex1, ex2, nfexp_maxsize()); + for (i=0; i < ATTR_EXP_MAX; i++) { + nfexp_attr_unset(ex2, i); + + assert(nfexp_cmp(ex1, ex2, 0) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 0); + } + memcpy(ex1, ex2, nfexp_maxsize()); + for (i=0; i < ATTR_EXP_MAX; i++) { + nfexp_attr_unset(ex1, i); + nfexp_attr_unset(ex2, i); + + assert(nfexp_cmp(ex1, ex2, 0) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 1); + assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 1); + } + nfexp_destroy(ex1); + nfexp_destroy(ex2); +} + +int main(void) +{ + int ret, i; + struct nf_conntrack *ct, *ct2, *tmp; + struct nf_expect *exp, *tmp_exp; + char data[256]; + const char *val; + int status; + struct nfct_bitmask *b, *b2; + + srand(time(NULL)); + + /* initialize fake data for testing purposes */ + for (i=0; i