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 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; }
static PyObject* serialize_connection(struct nf_conntrack *ct) { PyObject *dict; uint8_t proto3, proto4; dict = PyDict_New(); if (!dict) goto error; if (add_key(dict, "handle", PyLong_FromVoidPtr(ct))) goto error; proto3 = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO); if (add_key(dict, "orig_l3proto", PyLong_FromUnsignedLong(proto3))) goto error; if (proto3 == AF_INET) { if (add_key(dict, "orig_ipv4_src", get_attr32(ct, ATTR_ORIG_IPV4_SRC, 1))) goto error; if (add_key(dict, "orig_ipv4_dst", get_attr32(ct, ATTR_ORIG_IPV4_DST, 1))) goto error; #ifdef EXTRAFIELDS if (add_key(dict, "repl_ipv4_src", get_attr32(ct, ATTR_REPL_IPV4_SRC, 1))) goto error; if (add_key(dict, "repl_ipv4_dst", get_attr32(ct, ATTR_REPL_IPV4_DST, 1))) goto error; #endif } else if (proto3 == AF_INET6) { if (add_key(dict, "orig_ipv6_src", get_attr128(ct, ATTR_ORIG_IPV6_SRC))) goto error; if (add_key(dict, "orig_ipv6_dst", get_attr128(ct, ATTR_ORIG_IPV6_DST))) goto error; #ifdef EXTRAFIELDS if (add_key(dict, "repl_ipv6_src", get_attr128(ct, ATTR_REPL_IPV6_SRC))) goto error; if (add_key(dict, "repl_ipv6_dst", get_attr128(ct, ATTR_REPL_IPV6_DST))) goto error; #endif } proto4 = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); if (add_key(dict, "orig_l4proto", PyLong_FromUnsignedLong(proto4))) goto error; if (proto4 == IPPROTO_TCP || proto4 == IPPROTO_UDP) { if (add_key(dict, "orig_port_src", get_attr16(ct, ATTR_ORIG_PORT_SRC, 1))) goto error; if (add_key(dict, "orig_port_dst", get_attr16(ct, ATTR_ORIG_PORT_DST, 1))) goto error; #ifdef EXTRAFIELDS if (add_key(dict, "repl_port_src", get_attr16(ct, ATTR_REPL_PORT_SRC, 1))) goto error; if (add_key(dict, "repl_port_dst", get_attr16(ct, ATTR_REPL_PORT_DST, 1))) goto error; #endif if (proto4 == IPPROTO_TCP) { if (add_key(dict, "tcp_state", get_attr16(ct, ATTR_TCP_STATE, 1))) goto error; #ifdef EXTRAFIELDS if (add_key(dict, "tcp_flags_orig", get_attr8(ct, ATTR_TCP_FLAGS_ORIG))) goto error; if (add_key(dict, "tcp_flags_repl", get_attr8(ct, ATTR_TCP_FLAGS_REPL))) goto error; if (add_key(dict, "tcp_mask_orig", get_attr8(ct, ATTR_TCP_MASK_ORIG))) goto error; if (add_key(dict, "tcp_mask_repl", get_attr8(ct, ATTR_TCP_MASK_REPL))) goto error; #endif } } else if (proto4 == IPPROTO_ICMP || proto4 == IPPROTO_ICMPV6) { if (add_key(dict, "icmp_type", get_attr8(ct, ATTR_ICMP_TYPE))) goto error; if (add_key(dict, "icmp_code", get_attr8(ct, ATTR_ICMP_CODE))) goto error; #ifdef EXTRAFIELDS if (add_key(dict, "icmp_id", get_attr16(ct, ATTR_ICMP_ID, 1))) goto error; #endif } if (add_key(dict, "timeout", get_attr32(ct, ATTR_TIMEOUT, 0))) goto error; if (add_key(dict, "mark", get_attr32(ct, ATTR_MARK, 0))) goto error; if (add_key(dict, "orig_counter_packets", get_attr32(ct, ATTR_ORIG_COUNTER_PACKETS, 0))) goto error; if (add_key(dict, "repl_counter_packets", get_attr32(ct, ATTR_REPL_COUNTER_PACKETS, 0))) goto error; if (add_key(dict, "orig_counter_bytes", get_attr64(ct, ATTR_ORIG_COUNTER_BYTES))) goto error; if (add_key(dict, "repl_counter_bytes", get_attr64(ct, ATTR_REPL_COUNTER_BYTES))) goto error; #ifdef EXTRAFIELDS if (add_key(dict, "use", get_attr32(ct, ATTR_USE, 1))) goto error; if (add_key(dict, "status", get_attr32(ct, ATTR_STATUS, 0))) goto error; #endif #if 0 if (add_key(dict, "id", get_attr32(ct, ATTR_ID, 1))) goto error; #endif /* * TODO: ATTR_TCP_STATE ATTR_SNAT_IPV4 ATTR_DNAT_IPV4 ATTR_SNAT_PORT ATTR_DNAT_PORT ATTR_MASTER_IPV4_SRC ATTR_MASTER_IPV4_DST ATTR_MASTER_IPV6_SRC ATTR_MASTER_IPV6_DST ATTR_MASTER_PORT_SRC ATTR_MASTER_PORT_DST ATTR_MASTER_L3PROTO ATTR_MASTER_L4PROTO ATTR_SECMARK ATTR_ORIG_NAT_SEQ_CORRECTION_POS ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE ATTR_ORIG_NAT_SEQ_OFFSET_AFTER ATTR_REPL_NAT_SEQ_CORRECTION_POS ATTR_REPL_NAT_SEQ_OFFSET_BEFORE ATTR_REPL_NAT_SEQ_OFFSET_AFTER */ return dict; error: Py_XDECREF(dict); return NULL; }