1/* 2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 */ 9 10#include <linux/skbuff.h> 11#include <linux/netfilter.h> 12#include <linux/netfilter/nfnetlink.h> 13#include <linux/netfilter/nfnetlink_queue.h> 14#include <net/netfilter/nf_conntrack.h> 15#include <net/netfilter/nfnetlink_queue.h> 16 17struct nf_conn *nfqnl_ct_get(struct sk_buff *entskb, size_t *size, 18 enum ip_conntrack_info *ctinfo) 19{ 20 struct nfq_ct_hook *nfq_ct; 21 struct nf_conn *ct; 22 23 /* rcu_read_lock()ed by __nf_queue already. */ 24 nfq_ct = rcu_dereference(nfq_ct_hook); 25 if (nfq_ct == NULL) 26 return NULL; 27 28 ct = nf_ct_get(entskb, ctinfo); 29 if (ct) { 30 if (!nf_ct_is_untracked(ct)) 31 *size += nfq_ct->build_size(ct); 32 else 33 ct = NULL; 34 } 35 return ct; 36} 37 38struct nf_conn * 39nfqnl_ct_parse(const struct sk_buff *skb, const struct nlattr *attr, 40 enum ip_conntrack_info *ctinfo) 41{ 42 struct nfq_ct_hook *nfq_ct; 43 struct nf_conn *ct; 44 45 /* rcu_read_lock()ed by __nf_queue already. */ 46 nfq_ct = rcu_dereference(nfq_ct_hook); 47 if (nfq_ct == NULL) 48 return NULL; 49 50 ct = nf_ct_get(skb, ctinfo); 51 if (ct && !nf_ct_is_untracked(ct)) 52 nfq_ct->parse(attr, ct); 53 54 return ct; 55} 56 57int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct, 58 enum ip_conntrack_info ctinfo) 59{ 60 struct nfq_ct_hook *nfq_ct; 61 struct nlattr *nest_parms; 62 u_int32_t tmp; 63 64 nfq_ct = rcu_dereference(nfq_ct_hook); 65 if (nfq_ct == NULL) 66 return 0; 67 68 nest_parms = nla_nest_start(skb, NFQA_CT | NLA_F_NESTED); 69 if (!nest_parms) 70 goto nla_put_failure; 71 72 if (nfq_ct->build(skb, ct) < 0) 73 goto nla_put_failure; 74 75 nla_nest_end(skb, nest_parms); 76 77 tmp = ctinfo; 78 if (nla_put_be32(skb, NFQA_CT_INFO, htonl(tmp))) 79 goto nla_put_failure; 80 81 return 0; 82 83nla_put_failure: 84 return -1; 85} 86 87void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, 88 enum ip_conntrack_info ctinfo, int diff) 89{ 90 struct nfq_ct_hook *nfq_ct; 91 92 nfq_ct = rcu_dereference(nfq_ct_hook); 93 if (nfq_ct == NULL) 94 return; 95 96 if ((ct->status & IPS_NAT_MASK) && diff) 97 nfq_ct->seq_adjust(skb, ct, ctinfo, diff); 98} 99 100int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr, 101 u32 portid, u32 report) 102{ 103 struct nfq_ct_hook *nfq_ct; 104 105 if (nf_ct_is_untracked(ct)) 106 return 0; 107 108 nfq_ct = rcu_dereference(nfq_ct_hook); 109 if (nfq_ct == NULL) 110 return -EOPNOTSUPP; 111 112 return nfq_ct->attach_expect(attr, ct, portid, report); 113} 114