void print_snatlog(struct nf_conntrack *ct, time_t *timestamp, char *proto_str) { int ret = 0, size = 0, offset = 0, len = BUF_LEN; char buf[BUF_LEN]; ret = __snprintf_start_log(buf, len, "SNAT_LOG"); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " proto=%s", proto_str); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " o-src=%s", net2addr(nfct_get_attr_u32(ct,ATTR_ORIG_IPV4_SRC))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " o-spt=%d", ntohs(nfct_get_attr_u16(ct,ATTR_ORIG_PORT_SRC))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " t-src=%s", net2addr(nfct_get_attr_u32(ct,ATTR_REPL_IPV4_DST))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " t-spt=%d", ntohs(nfct_get_attr_u16(ct,ATTR_REPL_PORT_DST))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " duration=%.0lfs", difftime(time(NULL),*timestamp)); BUFFER_SIZE(ret, size, len, offset); buf[size+1 > len ? len-1 : size] = '\0'; write_msg(LOG_INFO, buf); }
static int l4_tcp_ct_cmp_port(struct nf_conntrack *ct, uint16_t port) { PRINT_CMP("cmp_port src: %u == %u\n", port, nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); PRINT_CMP("cmp_port dst: %u == %u\n", port, nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)); if (port == nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) || port == nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)) return 1; return 0; }
static int l4_tcp_ct_cmp_tuple_orig(const uint8_t *pkt, struct nf_conntrack *ct) { const struct tcphdr *tcph = (const struct tcphdr *)pkt; PRINT_CMP("cmp_orig tcph->source: %u == %u\n", tcph->source, nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); PRINT_CMP("cmp_orig tcph->dest: %u == %u\n", tcph->dest, nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)); if (tcph->source == nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) && tcph->dest == nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)) return 1; return 0; }
static inline void ct_build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint16_t data = nfct_get_attr_u16(ct, a); data = htons(data); addattr(n, b, &data, sizeof(uint16_t)); }
static PyObject* get_attr16(struct nf_conntrack *ct, int attrid, int ntoh) { uint16_t value; value = nfct_get_attr_u16(ct, attrid); if (ntoh) value = ntohs(value); return PyLong_FromUnsignedLong(value); }
static int event_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { struct conntrack_list *no; u_int8_t l4proto; // we are interested only in SNAT connections if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) return NFCT_CB_CONTINUE; // We are interested only in TCP/UDP L4 protocols... l4proto = nfct_get_attr_u8(ct,ATTR_ORIG_L4PROTO); if (l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP) return NFCT_CB_CONTINUE; if (verbose_flag) { print_verbose(ct, type, proto_str(l4proto)); } switch(type) { case NFCT_T_NEW: no = (struct conntrack_list *)malloc(sizeof(struct conntrack_list)); no->id = nfct_get_attr_u32(ct,ATTR_ID); no->orig_ipv4_src = nfct_get_attr_u32(ct,ATTR_ORIG_IPV4_SRC); no->orig_port_src = nfct_get_attr_u16(ct,ATTR_ORIG_PORT_SRC); time(&no->timestamp); list_add(&ct_list, no); break; case NFCT_T_DESTROY: no = list_find(ct_list, nfct_get_attr_u32(ct,ATTR_ID), nfct_get_attr_u32(ct,ATTR_ORIG_IPV4_SRC), nfct_get_attr_u16(ct,ATTR_ORIG_PORT_SRC)); if (no) { print_snatlog(ct, &no->timestamp, proto_str(l4proto)); list_del(&ct_list,no); } break; default: break; } return NFCT_CB_CONTINUE; }
/* 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; }
static void ForwardingRule_dealloc(ForwardingRule *self) { struct nfct_handle *ct_handle; PyObject_GC_UnTrack(self); ForwardingRule_clear(self); if (self->is_active) { forwarding_rules[ntohs(nfct_get_attr_u16(self->conntrack, ATTR_ORIG_PORT_DST))] = NULL; Py_BEGIN_ALLOW_THREADS ct_handle = nfct_open(CONNTRACK, 0); if (ct_handle != NULL) { nfct_query(ct_handle, NFCT_Q_DESTROY, self->conntrack); nfct_close(ct_handle); } Py_END_ALLOW_THREADS }
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; }
void print_verbose(struct nf_conntrack *ct, enum nf_conntrack_msg_type type, char *proto_str) { int ret = 0, size = 0, offset = 0, len = BUF_LEN; char buf[BUF_LEN]; ret = __snprintf_start_log(buf, len, "DEBUG"); BUFFER_SIZE(ret, size, len, offset); switch(type) { case NFCT_T_NEW: ret = snprintf(buf+offset, len, " NEW"); BUFFER_SIZE(ret, size, len, offset); break; case NFCT_T_DESTROY: ret = snprintf(buf+offset, len, " DESTROY"); BUFFER_SIZE(ret, size, len, offset); break; default: break; } ret = snprintf(buf+offset, len, " id=%u", nfct_get_attr_u32(ct,ATTR_ID)); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " proto=%s", proto_str); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " orig-src=%s", net2addr(nfct_get_attr_u32(ct,ATTR_ORIG_IPV4_SRC))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " orig-dst=%s", net2addr(nfct_get_attr_u32(ct,ATTR_ORIG_IPV4_DST))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " orig-sport=%d", ntohs(nfct_get_attr_u16(ct,ATTR_ORIG_PORT_SRC))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " orig-dport=%d", ntohs(nfct_get_attr_u16(ct,ATTR_ORIG_PORT_DST))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " repl-src=%s", net2addr(nfct_get_attr_u32(ct,ATTR_REPL_IPV4_SRC))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " repl-dst=%s", net2addr(nfct_get_attr_u32(ct,ATTR_REPL_IPV4_DST))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " repl-sport=%d", ntohs(nfct_get_attr_u16(ct,ATTR_REPL_PORT_SRC))); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, " repl-dport=%d", ntohs(nfct_get_attr_u16(ct,ATTR_REPL_PORT_DST))); BUFFER_SIZE(ret, size, len, offset); buf[size+1 > len ? len-1 : size] = '\0'; write_msg(LOG_INFO, buf); }