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); }
/* if the handle has no callback, check for existence, otherwise, update */ int nl_get_expect(struct nfct_handle *h, const struct nf_expect *exp) { int ret = 1; struct nf_expect *tmp; /* XXX: we only need the expectation, not the mask and the master. */ tmp = nfexp_clone(exp); if (tmp == NULL) return -1; if (nfexp_query(h, NFCT_Q_GET, tmp) == -1) ret = (errno == ENOENT) ? 0 : -1; nfexp_destroy(tmp); return ret; }
int nl_create_expect(struct nfct_handle *h, const struct nf_expect *orig, int timeout) { int ret; struct nf_expect *exp; exp = nfexp_clone(orig); if (exp == NULL) return -1; if (timeout > 0) nfexp_set_attr_u32(exp, ATTR_EXP_TIMEOUT, timeout); ret = nfexp_query(h, NFCT_Q_CREATE, exp); nfexp_destroy(exp); return ret; }
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<sizeof(data); i++) data[i] = 0x01; ct = nfct_new(); if (!ct) { perror("nfct_new"); return 0; } tmp = nfct_new(); if (!tmp) { perror("nfct_new"); return 0; } printf("== test set API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_MAX; i++) nfct_set_attr(ct, i, data); exit(0); } else { wait(&status); eval_sigterm(status); } b = nfct_bitmask_new(rand() & 0xffff); assert(b); b2 = nfct_bitmask_new(rand() & 0xffff); assert(b2); for (i=0; i<ATTR_MAX; i++) { switch (i) { case ATTR_CONNLABELS: nfct_set_attr(ct, i, b); break; case ATTR_CONNLABELS_MASK: nfct_set_attr(ct, i, b2); break; default: nfct_set_attr(ct, i, data); break; } } printf("== test get API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_MAX; i++) nfct_get_attr(ct, i); exit(0); } else { wait(&status); eval_sigterm(status); } printf("== validate set API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_MAX; i++) { if (attr_is_readonly(i)) continue; switch(i) { /* These attributes require special handling */ case ATTR_HELPER_INFO: nfct_set_attr_l(ct, i, data, sizeof(data)); break; case ATTR_CONNLABELS: case ATTR_CONNLABELS_MASK: /* already set above */ break; default: data[0] = (uint8_t) i; nfct_set_attr(ct, i, data); } val = nfct_get_attr(ct, i); switch (i) { case ATTR_CONNLABELS: assert((void *) val == b); continue; case ATTR_CONNLABELS_MASK: assert((void *) val == b2); continue; } if (val[0] != data[0]) { printf("ERROR: set/get operations don't match " "for attribute %d (%x != %x)\n", i, val[0], data[0]); } } exit(0); } else { wait(&status); eval_sigterm(status); } printf("== test copy API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_MAX; i++) nfct_copy_attr(tmp, ct, i); exit(0); } else { wait(&status); eval_sigterm(status); } ret = fork(); if (ret == 0) { test_nfct_cmp_api(tmp, ct); exit(0); } else { wait(&status); eval_sigterm(status); } exp = nfexp_new(); if (!exp) { perror("nfexp_new"); return 0; } tmp_exp = nfexp_new(); if (!tmp_exp) { perror("nfexp_new"); return 0; } printf("== test expect set API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_EXP_MAX; i++) nfexp_set_attr(exp, i, data); exit(0); } else { wait(&status); eval_sigterm(status); } for (i=0; i<ATTR_EXP_MAX; i++) nfexp_set_attr(exp, i, data); printf("== test expect get API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_EXP_MAX; i++) nfexp_get_attr(exp, i); exit(0); } else { wait(&status); eval_sigterm(status); } printf("== validate expect set API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_EXP_MAX; i++) { data[0] = (uint8_t) i; nfexp_set_attr(exp, i, data); val = nfexp_get_attr(exp, i); if (val[0] != data[0]) { printf("ERROR: set/get operations don't match " "for attribute %d (%x != %x)\n", i, val[0], data[0]); } } exit(0); } else { wait(&status); eval_sigterm(status); } ret = fork(); if (ret == 0) { test_nfexp_cmp_api(tmp_exp, exp); exit(0); } else { wait(&status); eval_sigterm(status); } ct2 = nfct_new(); if (!ct2) { perror("nfct_new"); return 0; } printf("== test set grp API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_GRP_MAX; i++) nfct_set_attr_grp(ct2, i, data); exit(0); } else { wait(&status); eval_sigterm(status); } for (i=0; i<ATTR_GRP_MAX; i++) nfct_set_attr_grp(ct2, i, data); printf("== test get grp API ==\n"); ret = fork(); if (ret == 0) { char buf[32]; /* IPv6 group address is 16 bytes * 2 */ for (i=0; i<ATTR_GRP_MAX; i++) nfct_get_attr_grp(ct2, i, buf); exit(0); } else { wait(&status); eval_sigterm(status); } printf("== validate set grp API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_GRP_MAX; i++) { char buf[32]; /* IPv6 group address is 16 bytes */ data[0] = (uint8_t) i; nfct_set_attr_grp(ct2, i, data); nfct_get_attr_grp(ct2, i, buf); /* These attributes cannot be set, ignore them. */ switch(i) { case ATTR_GRP_ORIG_COUNTERS: case ATTR_GRP_REPL_COUNTERS: case ATTR_GRP_ORIG_ADDR_SRC: case ATTR_GRP_ORIG_ADDR_DST: case ATTR_GRP_REPL_ADDR_SRC: case ATTR_GRP_REPL_ADDR_DST: continue; } if (buf[0] != data[0]) { printf("ERROR: set/get operations don't match " "for attribute %d (%x != %x)\n", i, buf[0], data[0]); } } exit(0); } else { wait(&status); eval_sigterm(status); } nfct_destroy(ct2); printf("== destroy cloned ct entry ==\n"); nfct_destroy(ct); nfct_destroy(tmp); nfexp_destroy(exp); nfexp_destroy(tmp_exp); printf("OK\n"); test_nfct_bitmask(); return EXIT_SUCCESS; }
static int rpc_helper_cb(struct pkt_buff *pkt, uint32_t protoff, struct myct *myct, uint32_t ctinfo) { int dir = CTINFO2DIR(ctinfo); unsigned int offset = protoff, datalen; uint32_t *data, *port_ptr = NULL, xid; uint16_t port; uint8_t proto = nfct_get_attr_u8(myct->ct, ATTR_L4PROTO); enum msg_type rm_dir; struct rpc_info *rpc_info = myct->priv_data; union nfct_attr_grp_addr addr, daddr; struct nf_expect *exp = NULL; int ret = NF_ACCEPT; /* Until there's been traffic both ways, don't look into TCP packets. */ if (proto == IPPROTO_TCP && ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY) { pr_debug("TCP RPC: Conntrackinfo = %u\n", ctinfo); return ret; } if (proto == IPPROTO_TCP) { struct tcphdr *th = (struct tcphdr *) (pktb_network_header(pkt) + protoff); offset += th->doff * 4; } else { offset += sizeof(struct udphdr); } /* Skip broken headers */ if (offset % 4) { pr_debug("RPC: broken header: offset %u%%4 != 0\n", offset); return ret; } /* Take into Record Fragment header */ if (proto == IPPROTO_TCP) offset += 4; datalen = pktb_len(pkt); data = (uint32_t *)(pktb_network_header(pkt) + offset); /* rpc_msg { * xid * direction * xdr_union { * call_body * reply_body * } * } */ /* Check minimal msg size: xid + direction */ if (datalen < OFFSET(offset, 2*4)) { pr_debug("RPC: too short packet: %u < %u\n", datalen, offset); return ret; } xid = IXDR_GET_INT32(data); rm_dir = IXDR_GET_INT32(data); /* Check direction */ if (!((rm_dir == CALL && dir == MYCT_DIR_ORIG) || (rm_dir == REPLY && dir == MYCT_DIR_REPL))) { pr_debug("RPC: rm_dir != dir %u != %u\n", rm_dir, dir); goto out; } if (rm_dir == CALL) { if (rpc_call(data, offset, datalen, rpc_info) < 0) goto out; rpc_info->xid = xid; return ret; } else { /* Check XID */ if (xid != rpc_info->xid) { pr_debug("RPC REPL: XID does not match: %u != %u\n", xid, rpc_info->xid); goto out; } if (rpc_reply(data, offset, datalen, rpc_info, &port_ptr) < 0) goto out; port = IXDR_GET_INT32(port_ptr); port = htons(port); /* We refer to the reverse direction ("!dir") tuples here, * because we're expecting something in the other direction. * Doesn't matter unless NAT is happening. */ cthelper_get_addr_dst(myct->ct, !dir, &daddr); cthelper_get_addr_src(myct->ct, !dir, &addr); exp = nfexp_new(); if (exp == NULL) goto out; if (cthelper_expect_init(exp, myct->ct, 0, &addr, &daddr, rpc_info->pm_prot, NULL, &port, NF_CT_EXPECT_PERMANENT)) { pr_debug("RPC: failed to init expectation\n"); goto out_exp; } /* Now, NAT might want to mangle the packet, and register the * (possibly changed) expectation itself. */ if (nfct_get_attr_u32(myct->ct, ATTR_STATUS) & IPS_NAT_MASK) { ret = nf_nat_rpc(pkt, dir, exp, rpc_info->pm_prot, port_ptr); goto out_exp; } /* Can't expect this? Best to drop packet now. */ if (cthelper_add_expect(exp) < 0) { pr_debug("RPC: cannot add expectation: %s\n", strerror(errno)); ret = NF_DROP; } } out_exp: nfexp_destroy(exp); out: rpc_info->xid = 0; return ret; }
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; /* initialize fake data for testing purposes */ for (i=0; i<sizeof(data); i++) data[i] = 0x01; ct = nfct_new(); if (!ct) { perror("nfct_new"); return 0; } tmp = nfct_new(); if (!tmp) { perror("nfct_new"); return 0; } printf("== test set API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_MAX; i++) nfct_set_attr(ct, i, data); exit(0); } else { wait(&status); eval_sigterm(status); } for (i=0; i<ATTR_MAX; i++) nfct_set_attr(ct, i, data); printf("== test get API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_MAX; i++) nfct_get_attr(ct, i); exit(0); } else { wait(&status); eval_sigterm(status); } printf("== validate set API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_MAX; i++) { /* These attributes cannot be set, ignore them. */ switch(i) { 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: continue; /* These attributes require special handling */ case ATTR_HELPER_INFO: nfct_set_attr_l(ct, i, data, sizeof(data)); break; default: data[0] = (uint8_t) i; nfct_set_attr(ct, i, data); } val = nfct_get_attr(ct, i); if (val[0] != data[0]) { printf("ERROR: set/get operations don't match " "for attribute %d (%x != %x)\n", i, val[0], data[0]); } } exit(0); } else { wait(&status); eval_sigterm(status); } printf("== test copy API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_MAX; i++) nfct_copy_attr(tmp, ct, i); exit(0); } else { wait(&status); eval_sigterm(status); } printf("== test cmp API ==\n"); ret = fork(); if (ret == 0) { nfct_cmp(tmp, ct, NFCT_CMP_ALL); exit(0); } else { wait(&status); eval_sigterm(status); } exp = nfexp_new(); if (!exp) { perror("nfexp_new"); return 0; } tmp_exp = nfexp_new(); if (!tmp_exp) { perror("nfexp_new"); return 0; } printf("== test expect set API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_EXP_MAX; i++) nfexp_set_attr(exp, i, data); exit(0); } else { wait(&status); eval_sigterm(status); } for (i=0; i<ATTR_EXP_MAX; i++) nfexp_set_attr(exp, i, data); printf("== test expect get API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_EXP_MAX; i++) nfexp_get_attr(exp, i); exit(0); } else { wait(&status); eval_sigterm(status); } printf("== validate expect set API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_EXP_MAX; i++) { data[0] = (uint8_t) i; nfexp_set_attr(exp, i, data); val = nfexp_get_attr(exp, i); if (val[0] != data[0]) { printf("ERROR: set/get operations don't match " "for attribute %d (%x != %x)\n", i, val[0], data[0]); } } exit(0); } else { wait(&status); eval_sigterm(status); } /* XXX: missing nfexp_copy API. */ memcpy(tmp_exp, exp, nfexp_maxsize()); printf("== test expect cmp API ==\n"); ret = fork(); if (ret == 0) { nfexp_cmp(tmp_exp, exp, 0); exit(0); } else { wait(&status); eval_sigterm(status); } ct2 = nfct_clone(ct); assert(ct2); assert(nfct_cmp(ct, ct2, NFCT_CMP_ALL) == 1); nfct_destroy(ct2); ct2 = nfct_new(); if (!ct2) { perror("nfct_new"); return 0; } printf("== test set grp API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_GRP_MAX; i++) nfct_set_attr_grp(ct2, i, data); exit(0); } else { wait(&status); eval_sigterm(status); } for (i=0; i<ATTR_GRP_MAX; i++) nfct_set_attr_grp(ct2, i, data); printf("== test get grp API ==\n"); ret = fork(); if (ret == 0) { char buf[32]; /* IPv6 group address is 16 bytes * 2 */ for (i=0; i<ATTR_GRP_MAX; i++) nfct_get_attr_grp(ct2, i, buf); exit(0); } else { wait(&status); eval_sigterm(status); } printf("== validate set grp API ==\n"); ret = fork(); if (ret == 0) { for (i=0; i<ATTR_GRP_MAX; i++) { char buf[32]; /* IPv6 group address is 16 bytes */ data[0] = (uint8_t) i; nfct_set_attr_grp(ct2, i, data); nfct_get_attr_grp(ct2, i, buf); /* These attributes cannot be set, ignore them. */ switch(i) { case ATTR_GRP_ORIG_COUNTERS: case ATTR_GRP_REPL_COUNTERS: case ATTR_GRP_ORIG_ADDR_SRC: case ATTR_GRP_ORIG_ADDR_DST: case ATTR_GRP_REPL_ADDR_SRC: case ATTR_GRP_REPL_ADDR_DST: continue; } if (buf[0] != data[0]) { printf("ERROR: set/get operations don't match " "for attribute %d (%x != %x)\n", i, buf[0], data[0]); } } exit(0); } else { wait(&status); eval_sigterm(status); } nfct_destroy(ct2); printf("== destroy cloned ct entry ==\n"); nfct_destroy(ct); nfct_destroy(tmp); nfexp_destroy(exp); nfexp_destroy(tmp_exp); printf("OK\n"); return EXIT_SUCCESS; }