static int conntrack_callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { struct nf_conntrack **found_conntrack = (struct nf_conntrack**) data; *found_conntrack = nfct_clone(ct); return NFCT_CB_STOP; }
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; }
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; }
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