|
|
@@ -28,12 +28,12 @@
|
|
|
#include <linux/netfilter_bridge.h>
|
|
|
#include <linux/netfilter/nfnetlink.h>
|
|
|
#include <linux/netfilter/nfnetlink_queue.h>
|
|
|
+#include <linux/netfilter/nf_conntrack_common.h>
|
|
|
#include <linux/list.h>
|
|
|
#include <net/sock.h>
|
|
|
#include <net/tcp_states.h>
|
|
|
#include <net/netfilter/nf_queue.h>
|
|
|
#include <net/netns/generic.h>
|
|
|
-#include <net/netfilter/nfnetlink_queue.h>
|
|
|
|
|
|
#include <linux/atomic.h>
|
|
|
|
|
|
@@ -313,6 +313,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
|
|
|
struct net_device *outdev;
|
|
|
struct nf_conn *ct = NULL;
|
|
|
enum ip_conntrack_info uninitialized_var(ctinfo);
|
|
|
+ struct nfq_ct_hook *nfq_ct;
|
|
|
bool csum_verify;
|
|
|
char *secdata = NULL;
|
|
|
u32 seclen = 0;
|
|
|
@@ -364,8 +365,14 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (queue->flags & NFQA_CFG_F_CONNTRACK)
|
|
|
- ct = nfqnl_ct_get(entskb, &size, &ctinfo);
|
|
|
+ if (queue->flags & NFQA_CFG_F_CONNTRACK) {
|
|
|
+ nfq_ct = rcu_dereference(nfq_ct_hook);
|
|
|
+ if (nfq_ct != NULL) {
|
|
|
+ ct = nfq_ct->get_ct(entskb, &ctinfo);
|
|
|
+ if (ct != NULL)
|
|
|
+ size += nfq_ct->build_size(ct);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
if (queue->flags & NFQA_CFG_F_UID_GID) {
|
|
|
size += (nla_total_size(sizeof(u_int32_t)) /* uid */
|
|
|
@@ -508,7 +515,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
|
|
|
if (seclen && nla_put(skb, NFQA_SECCTX, seclen, secdata))
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
- if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0)
|
|
|
+ if (ct && nfq_ct->build(skb, ct, ctinfo, NFQA_CT, NFQA_CT_INFO) < 0)
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
if (cap_len > data_len &&
|
|
|
@@ -1001,6 +1008,28 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static struct nf_conn *nfqnl_ct_parse(struct nfq_ct_hook *nfq_ct,
|
|
|
+ const struct nlmsghdr *nlh,
|
|
|
+ const struct nlattr * const nfqa[],
|
|
|
+ struct nf_queue_entry *entry,
|
|
|
+ enum ip_conntrack_info *ctinfo)
|
|
|
+{
|
|
|
+ struct nf_conn *ct;
|
|
|
+
|
|
|
+ ct = nfq_ct->get_ct(entry->skb, ctinfo);
|
|
|
+ if (ct == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (nfq_ct->parse(nfqa[NFQA_CT], ct) < 0)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (nfqa[NFQA_EXP])
|
|
|
+ nfq_ct->attach_expect(nfqa[NFQA_EXP], ct,
|
|
|
+ NETLINK_CB(entry->skb).portid,
|
|
|
+ nlmsg_report(nlh));
|
|
|
+ return ct;
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
|
|
|
const struct nlmsghdr *nlh,
|
|
|
@@ -1014,6 +1043,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
|
|
|
unsigned int verdict;
|
|
|
struct nf_queue_entry *entry;
|
|
|
enum ip_conntrack_info uninitialized_var(ctinfo);
|
|
|
+ struct nfq_ct_hook *nfq_ct;
|
|
|
struct nf_conn *ct = NULL;
|
|
|
|
|
|
struct net *net = sock_net(ctnl);
|
|
|
@@ -1037,12 +1067,10 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
|
|
|
return -ENOENT;
|
|
|
|
|
|
if (nfqa[NFQA_CT]) {
|
|
|
- ct = nfqnl_ct_parse(entry->skb, nfqa[NFQA_CT], &ctinfo);
|
|
|
- if (ct && nfqa[NFQA_EXP]) {
|
|
|
- nfqnl_attach_expect(ct, nfqa[NFQA_EXP],
|
|
|
- NETLINK_CB(skb).portid,
|
|
|
- nlmsg_report(nlh));
|
|
|
- }
|
|
|
+ /* rcu lock already held from nfnl->call_rcu. */
|
|
|
+ nfq_ct = rcu_dereference(nfq_ct_hook);
|
|
|
+ if (nfq_ct != NULL)
|
|
|
+ ct = nfqnl_ct_parse(nfq_ct, nlh, nfqa, entry, &ctinfo);
|
|
|
}
|
|
|
|
|
|
if (nfqa[NFQA_PAYLOAD]) {
|
|
|
@@ -1053,8 +1081,8 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
|
|
|
payload_len, entry, diff) < 0)
|
|
|
verdict = NF_DROP;
|
|
|
|
|
|
- if (ct)
|
|
|
- nfqnl_ct_seq_adjust(entry->skb, ct, ctinfo, diff);
|
|
|
+ if (ct && diff)
|
|
|
+ nfq_ct->seq_adjust(entry->skb, ct, ctinfo, diff);
|
|
|
}
|
|
|
|
|
|
if (nfqa[NFQA_MARK])
|