int main(void) { int ret; struct nfct_handle *h; struct nf_conntrack *expected; struct nf_expect *exp; expected = nfct_new(); if (!expected) { perror("nfct_new"); exit(EXIT_FAILURE); } nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET); nfct_set_attr_u32(expected, ATTR_IPV4_SRC, inet_addr("1.1.1.1")); nfct_set_attr_u32(expected, ATTR_IPV4_DST, inet_addr("2.2.2.2")); nfct_set_attr_u8(expected, ATTR_L4PROTO, IPPROTO_TCP); nfct_set_attr_u16(expected, ATTR_PORT_SRC, 0); nfct_set_attr_u16(expected, ATTR_PORT_DST, htons(10241)); exp = nfexp_new(); if (!exp) { perror("nfexp_new"); nfct_destroy(expected); exit(EXIT_FAILURE); } nfexp_set_attr(exp, ATTR_EXP_EXPECTED, expected); h = nfct_open(EXPECT, 0); if (!h) { perror("nfct_open"); nfct_destroy(expected); return -1; } ret = nfexp_query(h, NFCT_Q_DESTROY, exp); printf("TEST: delete expectation "); if (ret == -1) printf("(%d)(%s)\n", ret, strerror(errno)); else printf("(OK)\n"); nfct_close(h); nfct_destroy(expected); ret == -1 ? exit(EXIT_FAILURE) : exit(EXIT_SUCCESS); }
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 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; }
/* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ static unsigned int nf_nat_rpc(struct pkt_buff *pkt, int dir, struct nf_expect *exp, uint8_t proto, uint32_t *port_ptr) { const struct nf_conntrack *expected; struct nf_conntrack *nat_tuple; uint16_t initial_port, port; expected = nfexp_get_attr(exp, ATTR_EXP_EXPECTED); nat_tuple = nfct_new(); if (nat_tuple == NULL) return NF_ACCEPT; initial_port = nfct_get_attr_u16(expected, ATTR_PORT_DST); nfexp_set_attr_u32(exp, ATTR_EXP_NAT_DIR, !dir); /* libnetfilter_conntrack needs this */ nfct_set_attr_u8(nat_tuple, ATTR_L3PROTO, AF_INET); nfct_set_attr_u32(nat_tuple, ATTR_IPV4_SRC, 0); nfct_set_attr_u32(nat_tuple, ATTR_IPV4_DST, 0); nfct_set_attr_u8(nat_tuple, ATTR_L4PROTO, proto); nfct_set_attr_u16(nat_tuple, ATTR_PORT_DST, 0); /* When you see the packet, we need to NAT it the same as the * this one. */ nfexp_set_attr(exp, ATTR_EXP_FN, "nat-follow-master"); /* Try to get same port: if not, try to change it. */ for (port = ntohs(initial_port); port != 0; port++) { int ret; nfct_set_attr_u16(nat_tuple, ATTR_PORT_SRC, htons(port)); nfexp_set_attr(exp, ATTR_EXP_NAT_TUPLE, nat_tuple); ret = cthelper_add_expect(exp); if (ret == 0) break; else if (ret != -EBUSY) { port = 0; break; } } nfct_destroy(nat_tuple); if (port == 0) return NF_DROP; *port_ptr = htonl(port); return NF_ACCEPT; }
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, int istcp, unsigned int *markp) { struct nf_conntrack *ct; struct nfct_handle *h; gotit = 0; if ((ct = nfct_new())) { nfct_set_attr_u8(ct, ATTR_L4PROTO, istcp ? IPPROTO_TCP : IPPROTO_UDP); nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(daemon->port)); #ifdef HAVE_IPV6 if (peer_addr->sa.sa_family == AF_INET6) { nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6); nfct_set_attr(ct, ATTR_IPV6_SRC, peer_addr->in6.sin6_addr.s6_addr); nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in6.sin6_port); nfct_set_attr(ct, ATTR_IPV6_DST, local_addr->addr.addr6.s6_addr); } else #endif { nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET); nfct_set_attr_u32(ct, ATTR_IPV4_SRC, peer_addr->in.sin_addr.s_addr); nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in.sin_port); nfct_set_attr_u32(ct, ATTR_IPV4_DST, local_addr->addr.addr4.s_addr); } if ((h = nfct_open(CONNTRACK, 0))) { nfct_callback_register(h, NFCT_T_ALL, callback, (void *)markp); if (nfct_query(h, NFCT_Q_GET, ct) == -1) { static int warned = 0; if (!warned) { my_syslog(LOG_ERR, _("Conntrack connection mark retrieval failed: %s"), strerror(errno)); warned = 1; } } nfct_close(h); } nfct_destroy(ct); } return gotit; }
int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig, int timeout) { int ret; struct nf_conntrack *ct; ct = nfct_clone(orig); if (ct == NULL) return -1; if (timeout > 0) nfct_set_attr_u32(ct, ATTR_TIMEOUT, timeout); /* we hit error if we try to change the expected bit */ if (nfct_attr_is_set(ct, ATTR_STATUS)) { uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); status &= ~IPS_EXPECTED; nfct_set_attr_u32(ct, ATTR_STATUS, status); } nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); /* disable TCP window tracking for recovered connections if required */ if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { uint8_t flags = IP_CT_TCP_FLAG_SACK_PERM; if (!CONFIG(sync).tcp_window_tracking) flags |= IP_CT_TCP_FLAG_BE_LIBERAL; else flags |= IP_CT_TCP_FLAG_WINDOW_SCALE; /* FIXME: workaround, we should send TCP flags in updates */ if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= TCP_CONNTRACK_TIME_WAIT) { flags |= IP_CT_TCP_FLAG_CLOSE_INIT; } nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); } ret = nfct_query(h, NFCT_Q_CREATE, ct); nfct_destroy(ct); return ret; }
static int data_cb(const struct nlmsghdr *nlh, void *data) { struct nf_conntrack *ct; char buf[4096]; ct = nfct_new(); if (ct == NULL) return MNL_CB_OK; nfct_nlmsg_parse(nlh, ct); nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); printf("%s\n", buf); nfct_destroy(ct); return MNL_CB_OK; }
/* if the handle has no callback, check for existence, otherwise, update */ int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { int ret = 1; struct nf_conntrack *tmp; tmp = nfct_new(); if (tmp == NULL) return -1; /* use the original tuple to check if it is there */ nfct_copy(tmp, ct, NFCT_CP_ORIG); if (nfct_query(h, NFCT_Q_GET, tmp) == -1) ret = (errno == ENOENT) ? 0 : -1; nfct_destroy(tmp); return ret; }
static int data_cb(const struct nlmsghdr *nlh, void *data) { struct nf_conntrack *ct; struct data_cb_s * d = (struct data_cb_s*) data; struct sockaddr_in* ext4 = (struct sockaddr_in*) d->ext; ct = nfct_new(); if (ct == NULL) return MNL_CB_OK; nfct_nlmsg_parse(nlh, ct); if (data) { ext4->sin_addr.s_addr = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); ext4->sin_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); } d->found = 1; nfct_destroy(ct); return MNL_CB_OK; }
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 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"); }
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; }
int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig, int timeout) { int ret; struct nf_conntrack *ct; ct = nfct_clone(orig); if (ct == NULL) return -1; if (timeout > 0) nfct_set_attr_u32(ct, ATTR_TIMEOUT, timeout); /* unset NAT info, otherwise we hit error */ nfct_attr_unset(ct, ATTR_SNAT_IPV4); nfct_attr_unset(ct, ATTR_DNAT_IPV4); nfct_attr_unset(ct, ATTR_SNAT_PORT); nfct_attr_unset(ct, ATTR_DNAT_PORT); if (nfct_attr_is_set(ct, ATTR_STATUS)) { uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); status &= ~IPS_NAT_MASK; nfct_set_attr_u32(ct, ATTR_STATUS, status); } /* we have to unset the helper to avoid EBUSY in reset timers */ if (nfct_attr_is_set(ct, ATTR_HELPER_NAME)) nfct_attr_unset(ct, ATTR_HELPER_NAME); /* we hit error if we try to update the master conntrack */ if (ct_is_related(ct)) { nfct_attr_unset(ct, ATTR_MASTER_L3PROTO); nfct_attr_unset(ct, ATTR_MASTER_L4PROTO); nfct_attr_unset(ct, ATTR_MASTER_IPV4_SRC); nfct_attr_unset(ct, ATTR_MASTER_IPV4_DST); nfct_attr_unset(ct, ATTR_MASTER_IPV6_SRC); nfct_attr_unset(ct, ATTR_MASTER_IPV6_DST); nfct_attr_unset(ct, ATTR_MASTER_PORT_SRC); nfct_attr_unset(ct, ATTR_MASTER_PORT_DST); } /* disable TCP window tracking for recovered connections if required */ if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { uint8_t flags = IP_CT_TCP_FLAG_SACK_PERM; if (!CONFIG(sync).tcp_window_tracking) flags |= IP_CT_TCP_FLAG_BE_LIBERAL; else flags |= IP_CT_TCP_FLAG_WINDOW_SCALE; /* FIXME: workaround, we should send TCP flags in updates */ if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= TCP_CONNTRACK_TIME_WAIT) { flags |= IP_CT_TCP_FLAG_CLOSE_INIT; } nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); } ret = nfct_query(h, NFCT_Q_UPDATE, ct); nfct_destroy(ct); return ret; }
int main(void) { int ret; struct nfct_handle *h; struct nf_conntrack *master, *expected, *mask, *nat; struct nf_expect *exp; /* * Step 1: Setup master conntrack */ master = nfct_new(); if (!master) { perror("nfct_new"); exit(EXIT_FAILURE); } nfct_set_attr_u8(master, ATTR_L3PROTO, AF_INET); nfct_set_attr_u32(master, ATTR_IPV4_SRC, inet_addr("1.1.1.1")); nfct_set_attr_u32(master, ATTR_IPV4_DST, inet_addr("2.2.2.2")); nfct_set_attr_u8(master, ATTR_L4PROTO, IPPROTO_TCP); nfct_set_attr_u16(master, ATTR_PORT_SRC, htons(1025)); nfct_set_attr_u16(master, ATTR_PORT_DST, htons(21)); nfct_setobjopt(master, NFCT_SOPT_SETUP_REPLY); nfct_set_attr_u8(master, ATTR_TCP_STATE, TCP_CONNTRACK_ESTABLISHED); nfct_set_attr_u32(master, ATTR_TIMEOUT, 200); nfct_set_attr(master, ATTR_HELPER_NAME, "ftp"); h = nfct_open(CONNTRACK, 0); if (!h) { perror("nfct_open"); nfct_destroy(master); return -1; } ret = nfct_query(h, NFCT_Q_CREATE, master); printf("TEST: add master conntrack "); if (ret == -1) printf("(%d)(%s)\n", ret, strerror(errno)); else printf("(OK)\n"); nfct_close(h); expected = nfct_new(); if (!expected) { perror("nfct_new"); exit(EXIT_FAILURE); } nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET); nfct_set_attr_u32(expected, ATTR_IPV4_SRC, inet_addr("1.1.1.1")); nfct_set_attr_u32(expected, ATTR_IPV4_DST, inet_addr("2.2.2.2")); nfct_set_attr_u8(expected, ATTR_L4PROTO, IPPROTO_TCP); nfct_set_attr_u16(expected, ATTR_PORT_SRC, 0); nfct_set_attr_u16(expected, ATTR_PORT_DST, htons(10241)); mask = nfct_new(); if (!mask) { perror("nfct_new"); nfct_destroy(master); nfct_destroy(expected); exit(EXIT_FAILURE); } nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET); nfct_set_attr_u32(mask, ATTR_IPV4_SRC, 0xffffffff); nfct_set_attr_u32(mask, ATTR_IPV4_DST, 0xffffffff); nfct_set_attr_u8(mask, ATTR_L4PROTO, IPPROTO_TCP); nfct_set_attr_u16(mask, ATTR_PORT_SRC, 0x0000); nfct_set_attr_u16(mask, ATTR_PORT_DST, 0xffff); nat = nfct_new(); if (!nat) { perror("nfct_new"); nfct_destroy(mask); nfct_destroy(master); nfct_destroy(expected); exit(EXIT_FAILURE); } nfct_set_attr_u8(nat, ATTR_L3PROTO, AF_INET); nfct_set_attr_u32(nat, ATTR_IPV4_SRC, inet_addr("3.3.3.3")); nfct_set_attr_u32(nat, ATTR_IPV4_DST, 0); nfct_set_attr_u8(nat, ATTR_L4PROTO, IPPROTO_TCP); nfct_set_attr_u16(nat, ATTR_PORT_SRC, 12345); nfct_set_attr_u16(nat, ATTR_PORT_DST, 0); /* * Step 2: Setup expectation */ exp = nfexp_new(); if (!exp) { perror("nfexp_new"); nfct_destroy(master); nfct_destroy(expected); nfct_destroy(mask); exit(EXIT_FAILURE); } nfexp_set_attr(exp, ATTR_EXP_MASTER, master); nfexp_set_attr(exp, ATTR_EXP_EXPECTED, expected); nfexp_set_attr(exp, ATTR_EXP_MASK, mask); nfexp_set_attr(exp, ATTR_EXP_NAT_TUPLE, nat); nfexp_set_attr_u32(exp, ATTR_EXP_NAT_DIR, 0); nfexp_set_attr_u32(exp, ATTR_EXP_TIMEOUT, 200); nfct_destroy(master); nfct_destroy(expected); nfct_destroy(mask); nfct_destroy(nat); h = nfct_open(EXPECT, 0); if (!h) { perror("nfct_open"); return -1; } ret = nfexp_query(h, NFCT_Q_CREATE, exp); printf("TEST: create expectation "); if (ret == -1) printf("(%d)(%s)\n", ret, strerror(errno)); else printf("(OK)\n"); nfct_close(h); ret == -1 ? exit(EXIT_FAILURE) : exit(EXIT_SUCCESS); }
int get_nat_ext_addr(struct sockaddr* src, struct sockaddr *dst, uint8_t proto, struct sockaddr_storage* ret_ext) { struct mnl_socket *nl; struct nlmsghdr *nlh; struct nfgenmsg *nfh; char buf[MNL_SOCKET_BUFFER_SIZE]; unsigned int seq, portid; struct nf_conntrack *ct; int ret; struct data_cb_s data; if ((!src)&&(!dst)) { return 0; } if (src->sa_family != dst->sa_family) { return 0; } nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { // perror("mnl_socket_open"); goto free_nl; } if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { // perror("mnl_socket_bind"); goto free_nl; } portid = mnl_socket_get_portid(nl); memset(buf, 0, sizeof(buf)); nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET; nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; nlh->nlmsg_seq = seq = time(NULL); nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); nfh->nfgen_family = src->sa_family; nfh->version = NFNETLINK_V0; nfh->res_id = 0; ct = nfct_new(); if (ct == NULL) { goto free_nl; } nfct_set_attr_u8(ct, ATTR_L3PROTO, src->sa_family); if (src->sa_family == AF_INET) { struct sockaddr_in *src4 = (struct sockaddr_in *)src; struct sockaddr_in *dst4 = (struct sockaddr_in *)dst; nfct_set_attr_u32(ct, ATTR_IPV4_SRC, src4->sin_addr.s_addr); nfct_set_attr_u32(ct, ATTR_IPV4_DST, dst4->sin_addr.s_addr); nfct_set_attr_u16(ct, ATTR_PORT_SRC, src4->sin_port); nfct_set_attr_u16(ct, ATTR_PORT_DST, dst4->sin_port); } else if (src->sa_family == AF_INET6) { struct sockaddr_in6 *src6 = (struct sockaddr_in6 *)src; struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst; nfct_set_attr(ct, ATTR_IPV6_SRC, &src6->sin6_addr); nfct_set_attr(ct, ATTR_IPV6_DST, &dst6->sin6_addr); nfct_set_attr_u16(ct, ATTR_PORT_SRC, src6->sin6_port); nfct_set_attr_u16(ct, ATTR_PORT_DST, dst6->sin6_port); } nfct_set_attr_u8(ct, ATTR_L4PROTO, proto); nfct_nlmsg_build(nlh, ct); ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len); if (ret == -1) { goto free_ct; } ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); data.ext = ret_ext; data.found = 0; while (ret > 0) { ret = mnl_cb_run(buf, ret, seq, portid, data_cb, &data); if (ret <= MNL_CB_STOP) break; ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } free_ct: nfct_destroy(ct); free_nl: mnl_socket_close(nl); return data.found; }
static int cthelper_process_packet(const uint8_t *pkt, uint32_t pktlen, struct ctd_helper *h, int proto, uint16_t port, int type) { struct pkt_buff *pktb; struct cthelper_proto_l2l3_helper *l3h; struct cthelper_proto_l4_helper *l4h; unsigned int l3hdr_len, l4protonum; struct nf_ct_entry *ct; int ret, this_proto; uint32_t dataoff, ctinfo = 0; l3h = cthelper_proto_l2l3_helper_find(pkt, &l4protonum, &l3hdr_len); if (l3h == NULL) { fprintf(stderr, "Unsupported layer 3 protocol, skipping.\n"); return -1; } l4h = cthelper_proto_l4_helper_find(pkt, l4protonum); if (l4h == NULL) { fprintf(stderr, "Unsupported layer 4 protocol, skipping.\n"); return -1; } /* get layer 3 header. */ pkt += l3h->l2hdr_len; pktlen -= l3h->l2hdr_len; /* skip packet with mismatching protocol */ this_proto = l3h->l4pkt_proto(pkt); if (this_proto != proto) { cthelper_test_stats.pkt_mismatch_proto++; return 0; } /* Look for the fake conntrack. */ ct = ct_find(pkt, l3hdr_len, l3h, l4h, &ctinfo); if (ct == NULL) { /* It doesn't exist any, create one. */ ct = ct_alloc(pkt, l3hdr_len, l3h, l4h); if (ct == NULL) { fprintf(stderr, "Not enough memory\n"); return -1; } ct_add(ct); ctinfo += IP_CT_NEW; } else ctinfo += IP_CT_ESTABLISHED; /* skip packets with mismatching ports */ if (!l4h->l4ct_cmp_port(ct->myct->ct, ntohs(port))) { cthelper_test_stats.pkt_mismatch_port++; return -1; } /* * FIXME: reminder, implement this below in the kernel for cthelper. */ /* This packet contains no data, skip it. */ /* if (l4h->l4pkt_no_data && l4h->l4pkt_no_data(pkt + l3hdr_len)) { NFG_DEBUG("skipping packet with no data\n"); continue; } */ /* Create the fake network buffer. */ pktb = pktb_alloc(AF_INET, pkt, pktlen, 128); if (pktb == NULL) { fprintf(stderr, "Not enough memory\n"); return -1; } dataoff = l3h->l3pkt_hdr_len(pkt); if (dataoff > pktb_len(pktb)) { fprintf(stderr, "wrong layer 3 offset: %d > %d\n", dataoff, pktb_len(pktb)); return -1; } /* tweak to run DNAT mangling code using the same PCAP file. */ if (type == TEST_DNAT) { struct nf_conntrack *tmp = ct->myct->ct; /* as long as this is tested, who cares the destination IP? */ in_addr_t addr = inet_addr("1.1.1.1"); /* clone the real conntrack, to add DNAT information */ ct->myct->ct = nfct_clone(ct->myct->ct); /* set fake DNAT information */ nfct_set_attr_u32(ct->myct->ct, ATTR_STATUS, IPS_DST_NAT); nfct_set_attr_u32(ct->myct->ct, ATTR_ORIG_IPV4_DST, addr); /* pass it to helper */ ret = h->cb(pktb, dataoff, ct->myct, ctinfo); /* restore real conntrack */ nfct_destroy(ct->myct->ct); ct->myct->ct = tmp; if (pktb_mangled(pktb)) { int i; uint8_t *data = pktb_network_header(pktb); printf("\e[1;31mmangled content: ", pktb_len(pktb)); for (i=0; i < pktb_len(pktb); i++) printf("%c", data[i]); printf("\e[0m\n"); } } else