0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/kmemleak.h>
0009 #include <linux/module.h>
0010 #include <linux/mutex.h>
0011 #include <linux/rcupdate.h>
0012 #include <linux/slab.h>
0013 #include <linux/skbuff.h>
0014 #include <net/netfilter/nf_conntrack_extend.h>
0015
0016 #include <net/netfilter/nf_conntrack_helper.h>
0017 #include <net/netfilter/nf_conntrack_acct.h>
0018 #include <net/netfilter/nf_conntrack_seqadj.h>
0019 #include <net/netfilter/nf_conntrack_ecache.h>
0020 #include <net/netfilter/nf_conntrack_zones.h>
0021 #include <net/netfilter/nf_conntrack_timestamp.h>
0022 #include <net/netfilter/nf_conntrack_timeout.h>
0023 #include <net/netfilter/nf_conntrack_labels.h>
0024 #include <net/netfilter/nf_conntrack_synproxy.h>
0025 #include <net/netfilter/nf_conntrack_act_ct.h>
0026 #include <net/netfilter/nf_nat.h>
0027
0028 #define NF_CT_EXT_PREALLOC 128u
0029
0030 atomic_t nf_conntrack_ext_genid __read_mostly = ATOMIC_INIT(1);
0031
0032 static const u8 nf_ct_ext_type_len[NF_CT_EXT_NUM] = {
0033 [NF_CT_EXT_HELPER] = sizeof(struct nf_conn_help),
0034 #if IS_ENABLED(CONFIG_NF_NAT)
0035 [NF_CT_EXT_NAT] = sizeof(struct nf_conn_nat),
0036 #endif
0037 [NF_CT_EXT_SEQADJ] = sizeof(struct nf_conn_seqadj),
0038 [NF_CT_EXT_ACCT] = sizeof(struct nf_conn_acct),
0039 #ifdef CONFIG_NF_CONNTRACK_EVENTS
0040 [NF_CT_EXT_ECACHE] = sizeof(struct nf_conntrack_ecache),
0041 #endif
0042 #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
0043 [NF_CT_EXT_TSTAMP] = sizeof(struct nf_conn_acct),
0044 #endif
0045 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
0046 [NF_CT_EXT_TIMEOUT] = sizeof(struct nf_conn_tstamp),
0047 #endif
0048 #ifdef CONFIG_NF_CONNTRACK_LABELS
0049 [NF_CT_EXT_LABELS] = sizeof(struct nf_conn_labels),
0050 #endif
0051 #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
0052 [NF_CT_EXT_SYNPROXY] = sizeof(struct nf_conn_synproxy),
0053 #endif
0054 #if IS_ENABLED(CONFIG_NET_ACT_CT)
0055 [NF_CT_EXT_ACT_CT] = sizeof(struct nf_conn_act_ct_ext),
0056 #endif
0057 };
0058
0059 static __always_inline unsigned int total_extension_size(void)
0060 {
0061
0062 BUILD_BUG_ON(NF_CT_EXT_NUM > 10);
0063
0064 return sizeof(struct nf_ct_ext) +
0065 sizeof(struct nf_conn_help)
0066 #if IS_ENABLED(CONFIG_NF_NAT)
0067 + sizeof(struct nf_conn_nat)
0068 #endif
0069 + sizeof(struct nf_conn_seqadj)
0070 + sizeof(struct nf_conn_acct)
0071 #ifdef CONFIG_NF_CONNTRACK_EVENTS
0072 + sizeof(struct nf_conntrack_ecache)
0073 #endif
0074 #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
0075 + sizeof(struct nf_conn_tstamp)
0076 #endif
0077 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
0078 + sizeof(struct nf_conn_timeout)
0079 #endif
0080 #ifdef CONFIG_NF_CONNTRACK_LABELS
0081 + sizeof(struct nf_conn_labels)
0082 #endif
0083 #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
0084 + sizeof(struct nf_conn_synproxy)
0085 #endif
0086 #if IS_ENABLED(CONFIG_NET_ACT_CT)
0087 + sizeof(struct nf_conn_act_ct_ext)
0088 #endif
0089 ;
0090 }
0091
0092 void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
0093 {
0094 unsigned int newlen, newoff, oldlen, alloc;
0095 struct nf_ct_ext *new;
0096
0097
0098 WARN_ON(nf_ct_is_confirmed(ct));
0099
0100
0101 BUILD_BUG_ON(total_extension_size() > 255u);
0102
0103 if (ct->ext) {
0104 const struct nf_ct_ext *old = ct->ext;
0105
0106 if (__nf_ct_ext_exist(old, id))
0107 return NULL;
0108 oldlen = old->len;
0109 } else {
0110 oldlen = sizeof(*new);
0111 }
0112
0113 newoff = ALIGN(oldlen, __alignof__(struct nf_ct_ext));
0114 newlen = newoff + nf_ct_ext_type_len[id];
0115
0116 alloc = max(newlen, NF_CT_EXT_PREALLOC);
0117 new = krealloc(ct->ext, alloc, gfp);
0118 if (!new)
0119 return NULL;
0120
0121 if (!ct->ext) {
0122 memset(new->offset, 0, sizeof(new->offset));
0123 new->gen_id = atomic_read(&nf_conntrack_ext_genid);
0124 }
0125
0126 new->offset[id] = newoff;
0127 new->len = newlen;
0128 memset((void *)new + newoff, 0, newlen - newoff);
0129
0130 ct->ext = new;
0131 return (void *)new + newoff;
0132 }
0133 EXPORT_SYMBOL(nf_ct_ext_add);
0134
0135
0136 void *__nf_ct_ext_find(const struct nf_ct_ext *ext, u8 id)
0137 {
0138 unsigned int gen_id = atomic_read(&nf_conntrack_ext_genid);
0139 unsigned int this_id = READ_ONCE(ext->gen_id);
0140
0141 if (!__nf_ct_ext_exist(ext, id))
0142 return NULL;
0143
0144 if (this_id == 0 || ext->gen_id == gen_id)
0145 return (void *)ext + ext->offset[id];
0146
0147 return NULL;
0148 }
0149 EXPORT_SYMBOL(__nf_ct_ext_find);
0150
0151 void nf_ct_ext_bump_genid(void)
0152 {
0153 unsigned int value = atomic_inc_return(&nf_conntrack_ext_genid);
0154
0155 if (value == UINT_MAX)
0156 atomic_set(&nf_conntrack_ext_genid, 1);
0157
0158 msleep(HZ);
0159 }