Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Structure dynamic extension infrastructure
0003  * Copyright (C) 2004 Rusty Russell IBM Corporation
0004  * Copyright (C) 2007 Netfilter Core Team <coreteam@netfilter.org>
0005  * Copyright (C) 2007 USAGI/WIDE Project <http://www.linux-ipv6.org>
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 /* conntrack events are on by default */
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     /* remember to add new extensions below */
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     /* Conntrack must not be confirmed to avoid races on reallocation. */
0098     WARN_ON(nf_ct_is_confirmed(ct));
0099 
0100     /* struct nf_ct_ext uses u8 to store offsets/size */
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 /* Use nf_ct_ext_find wrapper. This is only useful for unconfirmed entries. */
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 }