1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Structure dynamic extension infrastructure 3 * Copyright (C) 2004 Rusty Russell IBM Corporation 4 * Copyright (C) 2007 Netfilter Core Team <coreteam@netfilter.org> 5 * Copyright (C) 2007 USAGI/WIDE Project <http://www.linux-ipv6.org> 6 */ 7 #include <linux/kernel.h> 8 #include <linux/kmemleak.h> 9 #include <linux/module.h> 10 #include <linux/mutex.h> 11 #include <linux/rcupdate.h> 12 #include <linux/slab.h> 13 #include <linux/skbuff.h> 14 #include <net/netfilter/nf_conntrack_extend.h> 15 16 #include <net/netfilter/nf_conntrack_helper.h> 17 #include <net/netfilter/nf_conntrack_acct.h> 18 #include <net/netfilter/nf_conntrack_seqadj.h> 19 #include <net/netfilter/nf_conntrack_ecache.h> 20 #include <net/netfilter/nf_conntrack_zones.h> 21 #include <net/netfilter/nf_conntrack_timestamp.h> 22 #include <net/netfilter/nf_conntrack_timeout.h> 23 #include <net/netfilter/nf_conntrack_labels.h> 24 #include <net/netfilter/nf_conntrack_synproxy.h> 25 #include <net/netfilter/nf_conntrack_act_ct.h> 26 #include <net/netfilter/nf_nat.h> 27 28 #define NF_CT_EXT_PREALLOC 128u /* conntrack events are on by default */ 29 30 static const u8 nf_ct_ext_type_len[NF_CT_EXT_NUM] = { 31 [NF_CT_EXT_HELPER] = sizeof(struct nf_conn_help), 32 #if IS_ENABLED(CONFIG_NF_NAT) 33 [NF_CT_EXT_NAT] = sizeof(struct nf_conn_nat), 34 #endif 35 [NF_CT_EXT_SEQADJ] = sizeof(struct nf_conn_seqadj), 36 [NF_CT_EXT_ACCT] = sizeof(struct nf_conn_acct), 37 #ifdef CONFIG_NF_CONNTRACK_EVENTS 38 [NF_CT_EXT_ECACHE] = sizeof(struct nf_conntrack_ecache), 39 #endif 40 #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP 41 [NF_CT_EXT_TSTAMP] = sizeof(struct nf_conn_acct), 42 #endif 43 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT 44 [NF_CT_EXT_TIMEOUT] = sizeof(struct nf_conn_tstamp), 45 #endif 46 #ifdef CONFIG_NF_CONNTRACK_LABELS 47 [NF_CT_EXT_LABELS] = sizeof(struct nf_conn_labels), 48 #endif 49 #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) 50 [NF_CT_EXT_SYNPROXY] = sizeof(struct nf_conn_synproxy), 51 #endif 52 #if IS_ENABLED(CONFIG_NET_ACT_CT) 53 [NF_CT_EXT_ACT_CT] = sizeof(struct nf_conn_act_ct_ext), 54 #endif 55 }; 56 57 static __always_inline unsigned int total_extension_size(void) 58 { 59 /* remember to add new extensions below */ 60 BUILD_BUG_ON(NF_CT_EXT_NUM > 10); 61 62 return sizeof(struct nf_ct_ext) + 63 sizeof(struct nf_conn_help) 64 #if IS_ENABLED(CONFIG_NF_NAT) 65 + sizeof(struct nf_conn_nat) 66 #endif 67 + sizeof(struct nf_conn_seqadj) 68 + sizeof(struct nf_conn_acct) 69 #ifdef CONFIG_NF_CONNTRACK_EVENTS 70 + sizeof(struct nf_conntrack_ecache) 71 #endif 72 #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP 73 + sizeof(struct nf_conn_tstamp) 74 #endif 75 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT 76 + sizeof(struct nf_conn_timeout) 77 #endif 78 #ifdef CONFIG_NF_CONNTRACK_LABELS 79 + sizeof(struct nf_conn_labels) 80 #endif 81 #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) 82 + sizeof(struct nf_conn_synproxy) 83 #endif 84 #if IS_ENABLED(CONFIG_NET_ACT_CT) 85 + sizeof(struct nf_conn_act_ct_ext) 86 #endif 87 ; 88 } 89 90 void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) 91 { 92 unsigned int newlen, newoff, oldlen, alloc; 93 struct nf_ct_ext *new; 94 95 /* Conntrack must not be confirmed to avoid races on reallocation. */ 96 WARN_ON(nf_ct_is_confirmed(ct)); 97 98 /* struct nf_ct_ext uses u8 to store offsets/size */ 99 BUILD_BUG_ON(total_extension_size() > 255u); 100 101 if (ct->ext) { 102 const struct nf_ct_ext *old = ct->ext; 103 104 if (__nf_ct_ext_exist(old, id)) 105 return NULL; 106 oldlen = old->len; 107 } else { 108 oldlen = sizeof(*new); 109 } 110 111 newoff = ALIGN(oldlen, __alignof__(struct nf_ct_ext)); 112 newlen = newoff + nf_ct_ext_type_len[id]; 113 114 alloc = max(newlen, NF_CT_EXT_PREALLOC); 115 new = krealloc(ct->ext, alloc, gfp); 116 if (!new) 117 return NULL; 118 119 if (!ct->ext) 120 memset(new->offset, 0, sizeof(new->offset)); 121 122 new->offset[id] = newoff; 123 new->len = newlen; 124 memset((void *)new + newoff, 0, newlen - newoff); 125 126 ct->ext = new; 127 return (void *)new + newoff; 128 } 129 EXPORT_SYMBOL(nf_ct_ext_add); 130