nf_conntrack_timeout.c (3432B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> 4 * (C) 2012 by Vyatta Inc. <http://www.vyatta.com> 5 */ 6 7#include <linux/types.h> 8#include <linux/netfilter.h> 9#include <linux/skbuff.h> 10#include <linux/vmalloc.h> 11#include <linux/stddef.h> 12#include <linux/err.h> 13#include <linux/percpu.h> 14#include <linux/kernel.h> 15#include <linux/netdevice.h> 16#include <linux/slab.h> 17#include <linux/export.h> 18 19#include <net/netfilter/nf_conntrack.h> 20#include <net/netfilter/nf_conntrack_core.h> 21#include <net/netfilter/nf_conntrack_extend.h> 22#include <net/netfilter/nf_conntrack_l4proto.h> 23#include <net/netfilter/nf_conntrack_timeout.h> 24 25const struct nf_ct_timeout_hooks *nf_ct_timeout_hook __read_mostly; 26EXPORT_SYMBOL_GPL(nf_ct_timeout_hook); 27 28static int untimeout(struct nf_conn *ct, void *timeout) 29{ 30 struct nf_conn_timeout *timeout_ext = nf_ct_timeout_find(ct); 31 32 if (timeout_ext && (!timeout || timeout_ext->timeout == timeout)) 33 RCU_INIT_POINTER(timeout_ext->timeout, NULL); 34 35 /* We are not intended to delete this conntrack. */ 36 return 0; 37} 38 39void nf_ct_untimeout(struct net *net, struct nf_ct_timeout *timeout) 40{ 41 struct nf_ct_iter_data iter_data = { 42 .net = net, 43 .data = timeout, 44 }; 45 46 nf_ct_iterate_cleanup_net(untimeout, &iter_data); 47} 48EXPORT_SYMBOL_GPL(nf_ct_untimeout); 49 50static void __nf_ct_timeout_put(struct nf_ct_timeout *timeout) 51{ 52 const struct nf_ct_timeout_hooks *h = rcu_dereference(nf_ct_timeout_hook); 53 54 if (h) 55 h->timeout_put(timeout); 56} 57 58int nf_ct_set_timeout(struct net *net, struct nf_conn *ct, 59 u8 l3num, u8 l4num, const char *timeout_name) 60{ 61 const struct nf_ct_timeout_hooks *h; 62 struct nf_ct_timeout *timeout; 63 struct nf_conn_timeout *timeout_ext; 64 const char *errmsg = NULL; 65 int ret = 0; 66 67 rcu_read_lock(); 68 h = rcu_dereference(nf_ct_timeout_hook); 69 if (!h) { 70 ret = -ENOENT; 71 errmsg = "Timeout policy base is empty"; 72 goto out; 73 } 74 75 timeout = h->timeout_find_get(net, timeout_name); 76 if (!timeout) { 77 ret = -ENOENT; 78 pr_info_ratelimited("No such timeout policy \"%s\"\n", 79 timeout_name); 80 goto out; 81 } 82 83 if (timeout->l3num != l3num) { 84 ret = -EINVAL; 85 pr_info_ratelimited("Timeout policy `%s' can only be used by " 86 "L%d protocol number %d\n", 87 timeout_name, 3, timeout->l3num); 88 goto err_put_timeout; 89 } 90 /* Make sure the timeout policy matches any existing protocol tracker, 91 * otherwise default to generic. 92 */ 93 if (timeout->l4proto->l4proto != l4num) { 94 ret = -EINVAL; 95 pr_info_ratelimited("Timeout policy `%s' can only be used by " 96 "L%d protocol number %d\n", 97 timeout_name, 4, timeout->l4proto->l4proto); 98 goto err_put_timeout; 99 } 100 timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC); 101 if (!timeout_ext) { 102 ret = -ENOMEM; 103 goto err_put_timeout; 104 } 105 106 rcu_read_unlock(); 107 return ret; 108 109err_put_timeout: 110 __nf_ct_timeout_put(timeout); 111out: 112 rcu_read_unlock(); 113 if (errmsg) 114 pr_info_ratelimited("%s\n", errmsg); 115 return ret; 116} 117EXPORT_SYMBOL_GPL(nf_ct_set_timeout); 118 119void nf_ct_destroy_timeout(struct nf_conn *ct) 120{ 121 struct nf_conn_timeout *timeout_ext; 122 const struct nf_ct_timeout_hooks *h; 123 124 rcu_read_lock(); 125 h = rcu_dereference(nf_ct_timeout_hook); 126 127 if (h) { 128 timeout_ext = nf_ct_timeout_find(ct); 129 if (timeout_ext) { 130 h->timeout_put(timeout_ext->timeout); 131 RCU_INIT_POINTER(timeout_ext->timeout, NULL); 132 } 133 } 134 rcu_read_unlock(); 135} 136EXPORT_SYMBOL_GPL(nf_ct_destroy_timeout);