mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 08:31:55 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter updates for net-next The following patchset contains Netfilter updates for net-next: 1) Add nfgenmsg field to nfnetlink's struct nfnl_info and use it. 2) Remove nft_ctx_init_from_elemattr() and nft_ctx_init_from_setattr() helper functions. 3) Add the nf_ct_pernet() helper function to fetch the conntrack pernetns data area. 4) Expose TCP and UDP flowtable offload timeouts through sysctl, from Oz Shlomo. 5) Add nfnetlink_hook subsystem to fetch the netfilter hook pipeline configuration, from Florian Westphal. This also includes a new field to annotate the hook type as metadata. 6) Fix unsafe memory access to non-linear skbuff in the new SCTP chunk support for nft_exthdr, from Phil Sutter. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
7f3579e189
@ -77,12 +77,18 @@ struct nf_hook_state {
|
||||
typedef unsigned int nf_hookfn(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state);
|
||||
enum nf_hook_ops_type {
|
||||
NF_HOOK_OP_UNDEFINED,
|
||||
NF_HOOK_OP_NF_TABLES,
|
||||
};
|
||||
|
||||
struct nf_hook_ops {
|
||||
/* User fills in from here down. */
|
||||
nf_hookfn *hook;
|
||||
struct net_device *dev;
|
||||
void *priv;
|
||||
u_int8_t pf;
|
||||
u8 pf;
|
||||
enum nf_hook_ops_type hook_ops_type:8;
|
||||
unsigned int hooknum;
|
||||
/* Hooks are ordered in ascending priority. */
|
||||
int priority;
|
||||
|
@ -11,6 +11,7 @@ struct nfnl_info {
|
||||
struct net *net;
|
||||
struct sock *sk;
|
||||
const struct nlmsghdr *nlh;
|
||||
const struct nfgenmsg *nfmsg;
|
||||
struct netlink_ext_ack *extack;
|
||||
};
|
||||
|
||||
|
@ -346,6 +346,13 @@ nf_ct_set(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info info)
|
||||
skb_set_nfct(skb, (unsigned long)ct | info);
|
||||
}
|
||||
|
||||
extern unsigned int nf_conntrack_net_id;
|
||||
|
||||
static inline struct nf_conntrack_net *nf_ct_pernet(const struct net *net)
|
||||
{
|
||||
return net_generic(net, nf_conntrack_net_id);
|
||||
}
|
||||
|
||||
#define NF_CT_STAT_INC(net, count) __this_cpu_inc((net)->ct.stat->count)
|
||||
#define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
|
||||
#define NF_CT_STAT_ADD_ATOMIC(net, count, v) this_cpu_add((net)->ct.stat->count, (v))
|
||||
|
@ -177,6 +177,8 @@ struct flow_offload {
|
||||
#define NF_FLOW_TIMEOUT (30 * HZ)
|
||||
#define nf_flowtable_time_stamp (u32)jiffies
|
||||
|
||||
unsigned long flow_offload_get_timeout(struct flow_offload *flow);
|
||||
|
||||
static inline __s32 nf_flow_timeout_delta(unsigned int timeout)
|
||||
{
|
||||
return (__s32)(timeout - nf_flowtable_time_stamp);
|
||||
|
@ -27,6 +27,10 @@ struct nf_tcp_net {
|
||||
u8 tcp_loose;
|
||||
u8 tcp_be_liberal;
|
||||
u8 tcp_max_retrans;
|
||||
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
|
||||
unsigned int offload_timeout;
|
||||
unsigned int offload_pickup;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum udp_conntrack {
|
||||
@ -37,6 +41,10 @@ enum udp_conntrack {
|
||||
|
||||
struct nf_udp_net {
|
||||
unsigned int timeouts[UDP_CT_MAX];
|
||||
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
|
||||
unsigned int offload_timeout;
|
||||
unsigned int offload_pickup;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct nf_icmp_net {
|
||||
|
@ -60,7 +60,8 @@ struct nfgenmsg {
|
||||
#define NFNL_SUBSYS_CTHELPER 9
|
||||
#define NFNL_SUBSYS_NFTABLES 10
|
||||
#define NFNL_SUBSYS_NFT_COMPAT 11
|
||||
#define NFNL_SUBSYS_COUNT 12
|
||||
#define NFNL_SUBSYS_HOOK 12
|
||||
#define NFNL_SUBSYS_COUNT 13
|
||||
|
||||
/* Reserved control nfnetlink messages */
|
||||
#define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE
|
||||
|
55
include/uapi/linux/netfilter/nfnetlink_hook.h
Normal file
55
include/uapi/linux/netfilter/nfnetlink_hook.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef _NFNL_HOOK_H_
|
||||
#define _NFNL_HOOK_H_
|
||||
|
||||
enum nfnl_hook_msg_types {
|
||||
NFNL_MSG_HOOK_GET,
|
||||
NFNL_MSG_HOOK_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nfnl_hook_attributes - netfilter hook netlink attributes
|
||||
*
|
||||
* @NFNLA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
|
||||
* @NFNLA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
|
||||
* @NFNLA_HOOK_DEV: netdevice name (NLA_STRING)
|
||||
* @NFNLA_HOOK_FUNCTION_NAME: hook function name (NLA_STRING)
|
||||
* @NFNLA_HOOK_MODULE_NAME: kernel module that registered this hook (NLA_STRING)
|
||||
* @NFNLA_HOOK_CHAIN_INFO: basechain hook metadata (NLA_NESTED)
|
||||
*/
|
||||
enum nfnl_hook_attributes {
|
||||
NFNLA_HOOK_UNSPEC,
|
||||
NFNLA_HOOK_HOOKNUM,
|
||||
NFNLA_HOOK_PRIORITY,
|
||||
NFNLA_HOOK_DEV,
|
||||
NFNLA_HOOK_FUNCTION_NAME,
|
||||
NFNLA_HOOK_MODULE_NAME,
|
||||
NFNLA_HOOK_CHAIN_INFO,
|
||||
__NFNLA_HOOK_MAX
|
||||
};
|
||||
#define NFNLA_HOOK_MAX (__NFNLA_HOOK_MAX - 1)
|
||||
|
||||
/**
|
||||
* enum nfnl_hook_chain_info_attributes - chain description
|
||||
*
|
||||
* NFNLA_HOOK_INFO_DESC: nft chain and table name (enum nft_table_attributes) (NLA_NESTED)
|
||||
* NFNLA_HOOK_INFO_TYPE: chain type (enum nfnl_hook_chaintype) (NLA_U32)
|
||||
*/
|
||||
enum nfnl_hook_chain_info_attributes {
|
||||
NFNLA_HOOK_INFO_UNSPEC,
|
||||
NFNLA_HOOK_INFO_DESC,
|
||||
NFNLA_HOOK_INFO_TYPE,
|
||||
__NFNLA_HOOK_INFO_MAX,
|
||||
};
|
||||
#define NFNLA_HOOK_INFO_MAX (__NFNLA_HOOK_INFO_MAX - 1)
|
||||
|
||||
/**
|
||||
* enum nfnl_hook_chaintype - chain type
|
||||
*
|
||||
* @NFNL_HOOK_TYPE_NFTABLES nf_tables base chain
|
||||
*/
|
||||
enum nfnl_hook_chaintype {
|
||||
NFNL_HOOK_TYPE_NFTABLES = 0x1,
|
||||
};
|
||||
|
||||
#endif /* _NFNL_HOOK_H */
|
@ -19,6 +19,16 @@ config NETFILTER_FAMILY_BRIDGE
|
||||
config NETFILTER_FAMILY_ARP
|
||||
bool
|
||||
|
||||
config NETFILTER_NETLINK_HOOK
|
||||
tristate "Netfilter base hook dump support"
|
||||
depends on NETFILTER_ADVANCED
|
||||
depends on NF_TABLES
|
||||
select NETFILTER_NETLINK
|
||||
help
|
||||
If this option is enabled, the kernel will include support
|
||||
to list the base netfilter hooks via NFNETLINK.
|
||||
This is helpful for debugging.
|
||||
|
||||
config NETFILTER_NETLINK_ACCT
|
||||
tristate "Netfilter NFACCT over NFNETLINK interface"
|
||||
depends on NETFILTER_ADVANCED
|
||||
|
@ -22,6 +22,7 @@ obj-$(CONFIG_NETFILTER_NETLINK_ACCT) += nfnetlink_acct.o
|
||||
obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
|
||||
obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
|
||||
obj-$(CONFIG_NETFILTER_NETLINK_OSF) += nfnetlink_osf.o
|
||||
obj-$(CONFIG_NETFILTER_NETLINK_HOOK) += nfnetlink_hook.o
|
||||
|
||||
# connection tracking
|
||||
obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
|
||||
|
@ -55,8 +55,6 @@
|
||||
|
||||
#include "nf_internals.h"
|
||||
|
||||
extern unsigned int nf_conntrack_net_id;
|
||||
|
||||
__cacheline_aligned_in_smp spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS];
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_locks);
|
||||
|
||||
@ -87,8 +85,6 @@ static __read_mostly bool nf_conntrack_locks_all;
|
||||
|
||||
static struct conntrack_gc_work conntrack_gc_work;
|
||||
|
||||
extern unsigned int nf_conntrack_net_id;
|
||||
|
||||
void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
|
||||
{
|
||||
/* 1) Acquire the lock */
|
||||
@ -1404,7 +1400,7 @@ static void gc_worker(struct work_struct *work)
|
||||
continue;
|
||||
|
||||
net = nf_ct_net(tmp);
|
||||
cnet = net_generic(net, nf_conntrack_net_id);
|
||||
cnet = nf_ct_pernet(net);
|
||||
if (atomic_read(&cnet->count) < nf_conntrack_max95)
|
||||
continue;
|
||||
|
||||
@ -1484,7 +1480,7 @@ __nf_conntrack_alloc(struct net *net,
|
||||
const struct nf_conntrack_tuple *repl,
|
||||
gfp_t gfp, u32 hash)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
unsigned int ct_count;
|
||||
struct nf_conn *ct;
|
||||
|
||||
@ -1556,7 +1552,7 @@ void nf_conntrack_free(struct nf_conn *ct)
|
||||
|
||||
nf_ct_ext_destroy(ct);
|
||||
kmem_cache_free(nf_conntrack_cachep, ct);
|
||||
cnet = net_generic(net, nf_conntrack_net_id);
|
||||
cnet = nf_ct_pernet(net);
|
||||
|
||||
smp_mb__before_atomic();
|
||||
atomic_dec(&cnet->count);
|
||||
@ -1614,7 +1610,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
|
||||
GFP_ATOMIC);
|
||||
|
||||
local_bh_disable();
|
||||
cnet = net_generic(net, nf_conntrack_net_id);
|
||||
cnet = nf_ct_pernet(net);
|
||||
if (cnet->expect_count) {
|
||||
spin_lock(&nf_conntrack_expect_lock);
|
||||
exp = nf_ct_find_expectation(net, zone, tuple);
|
||||
@ -2317,7 +2313,7 @@ __nf_ct_unconfirmed_destroy(struct net *net)
|
||||
|
||||
void nf_ct_unconfirmed_destroy(struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
might_sleep();
|
||||
|
||||
@ -2333,7 +2329,7 @@ void nf_ct_iterate_cleanup_net(struct net *net,
|
||||
int (*iter)(struct nf_conn *i, void *data),
|
||||
void *data, u32 portid, int report)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
struct iter_data d;
|
||||
|
||||
might_sleep();
|
||||
@ -2367,7 +2363,7 @@ nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data)
|
||||
|
||||
down_read(&net_rwsem);
|
||||
for_each_net(net) {
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
if (atomic_read(&cnet->count) == 0)
|
||||
continue;
|
||||
@ -2449,7 +2445,7 @@ void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list)
|
||||
i_see_dead_people:
|
||||
busy = 0;
|
||||
list_for_each_entry(net, net_exit_list, exit_list) {
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
nf_ct_iterate_cleanup(kill_all, net, 0, 0);
|
||||
if (atomic_read(&cnet->count) != 0)
|
||||
@ -2733,7 +2729,7 @@ void nf_conntrack_init_end(void)
|
||||
|
||||
int nf_conntrack_init_net(struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
int ret = -ENOMEM;
|
||||
int cpu;
|
||||
|
||||
|
@ -27,8 +27,6 @@
|
||||
#include <net/netfilter/nf_conntrack_ecache.h>
|
||||
#include <net/netfilter/nf_conntrack_extend.h>
|
||||
|
||||
extern unsigned int nf_conntrack_net_id;
|
||||
|
||||
static DEFINE_MUTEX(nf_ct_ecache_mutex);
|
||||
|
||||
#define ECACHE_RETRY_WAIT (HZ/10)
|
||||
@ -348,7 +346,7 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier);
|
||||
|
||||
void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
if (state == NFCT_ECACHE_DESTROY_FAIL &&
|
||||
!delayed_work_pending(&cnet->ecache_dwork)) {
|
||||
@ -371,7 +369,7 @@ static const struct nf_ct_ext_type event_extend = {
|
||||
|
||||
void nf_conntrack_ecache_pernet_init(struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
net->ct.sysctl_events = nf_ct_events;
|
||||
cnet->ct_net = &net->ct;
|
||||
@ -380,7 +378,7 @@ void nf_conntrack_ecache_pernet_init(struct net *net)
|
||||
|
||||
void nf_conntrack_ecache_pernet_fini(struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
cancel_delayed_work_sync(&cnet->ecache_dwork);
|
||||
}
|
||||
|
@ -43,8 +43,6 @@ unsigned int nf_ct_expect_max __read_mostly;
|
||||
static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
|
||||
static unsigned int nf_ct_expect_hashrnd __read_mostly;
|
||||
|
||||
extern unsigned int nf_conntrack_net_id;
|
||||
|
||||
/* nf_conntrack_expect helper functions */
|
||||
void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
|
||||
u32 portid, int report)
|
||||
@ -58,7 +56,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
|
||||
|
||||
hlist_del_rcu(&exp->hnode);
|
||||
|
||||
cnet = net_generic(net, nf_conntrack_net_id);
|
||||
cnet = nf_ct_pernet(net);
|
||||
cnet->expect_count--;
|
||||
|
||||
hlist_del_rcu(&exp->lnode);
|
||||
@ -123,7 +121,7 @@ __nf_ct_expect_find(struct net *net,
|
||||
const struct nf_conntrack_zone *zone,
|
||||
const struct nf_conntrack_tuple *tuple)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
struct nf_conntrack_expect *i;
|
||||
unsigned int h;
|
||||
|
||||
@ -164,7 +162,7 @@ nf_ct_find_expectation(struct net *net,
|
||||
const struct nf_conntrack_zone *zone,
|
||||
const struct nf_conntrack_tuple *tuple)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
struct nf_conntrack_expect *i, *exp = NULL;
|
||||
unsigned int h;
|
||||
|
||||
@ -397,7 +395,7 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
|
||||
master_help->expecting[exp->class]++;
|
||||
|
||||
hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
|
||||
cnet = net_generic(net, nf_conntrack_net_id);
|
||||
cnet = nf_ct_pernet(net);
|
||||
cnet->expect_count++;
|
||||
|
||||
NF_CT_STAT_INC(net, expect_create);
|
||||
@ -468,7 +466,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
|
||||
}
|
||||
}
|
||||
|
||||
cnet = net_generic(net, nf_conntrack_net_id);
|
||||
cnet = nf_ct_pernet(net);
|
||||
if (cnet->expect_count >= nf_ct_expect_max) {
|
||||
net_warn_ratelimited("nf_conntrack: expectation table full\n");
|
||||
ret = -EMFILE;
|
||||
|
@ -43,8 +43,6 @@ MODULE_PARM_DESC(nf_conntrack_helper,
|
||||
static DEFINE_MUTEX(nf_ct_nat_helpers_mutex);
|
||||
static struct list_head nf_ct_nat_helpers __read_mostly;
|
||||
|
||||
extern unsigned int nf_conntrack_net_id;
|
||||
|
||||
/* Stupid hash, but collision free for the default registrations of the
|
||||
* helpers currently in the kernel. */
|
||||
static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
|
||||
@ -214,7 +212,7 @@ EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
|
||||
static struct nf_conntrack_helper *
|
||||
nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
if (!cnet->sysctl_auto_assign_helper) {
|
||||
if (cnet->auto_assign_helper_warned)
|
||||
@ -560,7 +558,7 @@ static const struct nf_ct_ext_type helper_extend = {
|
||||
|
||||
void nf_conntrack_helper_pernet_init(struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
cnet->sysctl_auto_assign_helper = nf_ct_auto_assign_helper;
|
||||
}
|
||||
|
@ -1528,7 +1528,7 @@ static int ctnetlink_del_conntrack(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const cda[])
|
||||
{
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct nf_conntrack_tuple_hash *h;
|
||||
struct nf_conntrack_tuple tuple;
|
||||
struct nf_conntrack_zone zone;
|
||||
@ -1541,12 +1541,12 @@ static int ctnetlink_del_conntrack(struct sk_buff *skb,
|
||||
|
||||
if (cda[CTA_TUPLE_ORIG])
|
||||
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG,
|
||||
nfmsg->nfgen_family, &zone);
|
||||
family, &zone);
|
||||
else if (cda[CTA_TUPLE_REPLY])
|
||||
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY,
|
||||
nfmsg->nfgen_family, &zone);
|
||||
family, &zone);
|
||||
else {
|
||||
u_int8_t u3 = nfmsg->version ? nfmsg->nfgen_family : AF_UNSPEC;
|
||||
u_int8_t u3 = info->nfmsg->version ? family : AF_UNSPEC;
|
||||
|
||||
return ctnetlink_flush_conntrack(info->net, cda,
|
||||
NETLINK_CB(skb).portid,
|
||||
@ -1586,8 +1586,7 @@ static int ctnetlink_get_conntrack(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const cda[])
|
||||
{
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u_int8_t u3 = nfmsg->nfgen_family;
|
||||
u_int8_t u3 = info->nfmsg->nfgen_family;
|
||||
struct nf_conntrack_tuple_hash *h;
|
||||
struct nf_conntrack_tuple tuple;
|
||||
struct nf_conntrack_zone zone;
|
||||
@ -2363,10 +2362,9 @@ static int ctnetlink_new_conntrack(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const cda[])
|
||||
{
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct nf_conntrack_tuple otuple, rtuple;
|
||||
struct nf_conntrack_tuple_hash *h = NULL;
|
||||
u_int8_t u3 = nfmsg->nfgen_family;
|
||||
u_int8_t u3 = info->nfmsg->nfgen_family;
|
||||
struct nf_conntrack_zone zone;
|
||||
struct nf_conn *ct;
|
||||
int err;
|
||||
@ -3259,8 +3257,7 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const cda[])
|
||||
{
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u_int8_t u3 = nfmsg->nfgen_family;
|
||||
u_int8_t u3 = info->nfmsg->nfgen_family;
|
||||
struct nf_conntrack_tuple tuple;
|
||||
struct nf_conntrack_expect *exp;
|
||||
struct nf_conntrack_zone zone;
|
||||
@ -3349,8 +3346,7 @@ static int ctnetlink_del_expect(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const cda[])
|
||||
{
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u_int8_t u3 = nfmsg->nfgen_family;
|
||||
u_int8_t u3 = info->nfmsg->nfgen_family;
|
||||
struct nf_conntrack_expect *exp;
|
||||
struct nf_conntrack_tuple tuple;
|
||||
struct nf_conntrack_zone zone;
|
||||
@ -3601,8 +3597,7 @@ static int ctnetlink_new_expect(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const cda[])
|
||||
{
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u_int8_t u3 = nfmsg->nfgen_family;
|
||||
u_int8_t u3 = info->nfmsg->nfgen_family;
|
||||
struct nf_conntrack_tuple tuple;
|
||||
struct nf_conntrack_expect *exp;
|
||||
struct nf_conntrack_zone zone;
|
||||
|
@ -42,8 +42,6 @@
|
||||
#include <net/ipv6.h>
|
||||
#include <net/inet_frag.h>
|
||||
|
||||
extern unsigned int nf_conntrack_net_id;
|
||||
|
||||
static DEFINE_MUTEX(nf_ct_proto_mutex);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
@ -446,7 +444,7 @@ static struct nf_ct_bridge_info *nf_ct_bridge_info;
|
||||
|
||||
static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
bool fixup_needed = false, retry = true;
|
||||
int err = 0;
|
||||
retry:
|
||||
@ -531,7 +529,7 @@ retry:
|
||||
|
||||
static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
mutex_lock(&nf_ct_proto_mutex);
|
||||
switch (nfproto) {
|
||||
|
@ -1441,6 +1441,11 @@ void nf_conntrack_tcp_init_net(struct net *net)
|
||||
* will be started.
|
||||
*/
|
||||
tn->tcp_max_retrans = 3;
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
|
||||
tn->offload_timeout = 30 * HZ;
|
||||
tn->offload_pickup = 120 * HZ;
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp =
|
||||
|
@ -270,6 +270,11 @@ void nf_conntrack_udp_init_net(struct net *net)
|
||||
|
||||
for (i = 0; i < UDP_CT_MAX; i++)
|
||||
un->timeouts[i] = udp_timeouts[i];
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
|
||||
un->offload_timeout = 30 * HZ;
|
||||
un->offload_pickup = 30 * HZ;
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp =
|
||||
|
@ -512,9 +512,7 @@ static void nf_conntrack_standalone_fini_proc(struct net *net)
|
||||
|
||||
u32 nf_conntrack_count(const struct net *net)
|
||||
{
|
||||
const struct nf_conntrack_net *cnet;
|
||||
|
||||
cnet = net_generic(net, nf_conntrack_net_id);
|
||||
const struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
||||
return atomic_read(&cnet->count);
|
||||
}
|
||||
@ -575,11 +573,19 @@ enum nf_ct_sysctl_index {
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_CLOSE,
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_RETRANS,
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_UNACK,
|
||||
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD,
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD_PICKUP,
|
||||
#endif
|
||||
NF_SYSCTL_CT_PROTO_TCP_LOOSE,
|
||||
NF_SYSCTL_CT_PROTO_TCP_LIBERAL,
|
||||
NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS,
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_UDP,
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM,
|
||||
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD,
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD_PICKUP,
|
||||
#endif
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_ICMP,
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_ICMPV6,
|
||||
#ifdef CONFIG_NF_CT_PROTO_SCTP
|
||||
@ -762,6 +768,20 @@ static struct ctl_table nf_ct_sysctl_table[] = {
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
},
|
||||
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
|
||||
[NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD] = {
|
||||
.procname = "nf_flowtable_tcp_timeout",
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
},
|
||||
[NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD_PICKUP] = {
|
||||
.procname = "nf_flowtable_tcp_pickup",
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
},
|
||||
#endif
|
||||
[NF_SYSCTL_CT_PROTO_TCP_LOOSE] = {
|
||||
.procname = "nf_conntrack_tcp_loose",
|
||||
.maxlen = sizeof(u8),
|
||||
@ -796,6 +816,20 @@ static struct ctl_table nf_ct_sysctl_table[] = {
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
},
|
||||
#if IS_ENABLED(CONFIG_NFT_FLOW_OFFLOAD)
|
||||
[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD] = {
|
||||
.procname = "nf_flowtable_udp_timeout",
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
},
|
||||
[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD_PICKUP] = {
|
||||
.procname = "nf_flowtable_udp_pickup",
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
},
|
||||
#endif
|
||||
[NF_SYSCTL_CT_PROTO_TIMEOUT_ICMP] = {
|
||||
.procname = "nf_conntrack_icmp_timeout",
|
||||
.maxlen = sizeof(unsigned int),
|
||||
@ -971,6 +1005,12 @@ static void nf_conntrack_standalone_init_tcp_sysctl(struct net *net,
|
||||
XASSIGN(LIBERAL, &tn->tcp_be_liberal);
|
||||
XASSIGN(MAX_RETRANS, &tn->tcp_max_retrans);
|
||||
#undef XASSIGN
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
|
||||
table[NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD].data = &tn->offload_timeout;
|
||||
table[NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD_PICKUP].data = &tn->offload_pickup;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void nf_conntrack_standalone_init_sctp_sysctl(struct net *net,
|
||||
@ -1032,7 +1072,7 @@ static void nf_conntrack_standalone_init_gre_sysctl(struct net *net,
|
||||
|
||||
static int nf_conntrack_standalone_init_sysctl(struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
struct nf_udp_net *un = nf_udp_pernet(net);
|
||||
struct ctl_table *table;
|
||||
|
||||
@ -1059,6 +1099,10 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
|
||||
table[NF_SYSCTL_CT_PROTO_TIMEOUT_ICMPV6].data = &nf_icmpv6_pernet(net)->timeout;
|
||||
table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP].data = &un->timeouts[UDP_CT_UNREPLIED];
|
||||
table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM].data = &un->timeouts[UDP_CT_REPLIED];
|
||||
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
|
||||
table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD].data = &un->offload_timeout;
|
||||
table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD_PICKUP].data = &un->offload_pickup;
|
||||
#endif
|
||||
|
||||
nf_conntrack_standalone_init_tcp_sysctl(net, table);
|
||||
nf_conntrack_standalone_init_sctp_sysctl(net, table);
|
||||
@ -1085,7 +1129,7 @@ out_unregister_netfilter:
|
||||
|
||||
static void nf_conntrack_standalone_fini_sysctl(struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
struct ctl_table *table;
|
||||
|
||||
table = cnet->sysctl_header->ctl_table_arg;
|
||||
|
@ -178,12 +178,10 @@ static void flow_offload_fixup_tcp(struct ip_ct_tcp *tcp)
|
||||
tcp->seen[1].td_maxwin = 0;
|
||||
}
|
||||
|
||||
#define NF_FLOWTABLE_TCP_PICKUP_TIMEOUT (120 * HZ)
|
||||
#define NF_FLOWTABLE_UDP_PICKUP_TIMEOUT (30 * HZ)
|
||||
|
||||
static void flow_offload_fixup_ct_timeout(struct nf_conn *ct)
|
||||
{
|
||||
const struct nf_conntrack_l4proto *l4proto;
|
||||
struct net *net = nf_ct_net(ct);
|
||||
int l4num = nf_ct_protonum(ct);
|
||||
unsigned int timeout;
|
||||
|
||||
@ -191,12 +189,17 @@ static void flow_offload_fixup_ct_timeout(struct nf_conn *ct)
|
||||
if (!l4proto)
|
||||
return;
|
||||
|
||||
if (l4num == IPPROTO_TCP)
|
||||
timeout = NF_FLOWTABLE_TCP_PICKUP_TIMEOUT;
|
||||
else if (l4num == IPPROTO_UDP)
|
||||
timeout = NF_FLOWTABLE_UDP_PICKUP_TIMEOUT;
|
||||
else
|
||||
if (l4num == IPPROTO_TCP) {
|
||||
struct nf_tcp_net *tn = nf_tcp_pernet(net);
|
||||
|
||||
timeout = tn->offload_pickup;
|
||||
} else if (l4num == IPPROTO_UDP) {
|
||||
struct nf_udp_net *tn = nf_udp_pernet(net);
|
||||
|
||||
timeout = tn->offload_pickup;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nf_flow_timeout_delta(ct->timeout) > (__s32)timeout)
|
||||
ct->timeout = nfct_time_stamp + timeout;
|
||||
@ -268,11 +271,35 @@ static const struct rhashtable_params nf_flow_offload_rhash_params = {
|
||||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
unsigned long flow_offload_get_timeout(struct flow_offload *flow)
|
||||
{
|
||||
const struct nf_conntrack_l4proto *l4proto;
|
||||
unsigned long timeout = NF_FLOW_TIMEOUT;
|
||||
struct net *net = nf_ct_net(flow->ct);
|
||||
int l4num = nf_ct_protonum(flow->ct);
|
||||
|
||||
l4proto = nf_ct_l4proto_find(l4num);
|
||||
if (!l4proto)
|
||||
return timeout;
|
||||
|
||||
if (l4num == IPPROTO_TCP) {
|
||||
struct nf_tcp_net *tn = nf_tcp_pernet(net);
|
||||
|
||||
timeout = tn->offload_timeout;
|
||||
} else if (l4num == IPPROTO_UDP) {
|
||||
struct nf_udp_net *tn = nf_udp_pernet(net);
|
||||
|
||||
timeout = tn->offload_timeout;
|
||||
}
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
|
||||
{
|
||||
int err;
|
||||
|
||||
flow->timeout = nf_flowtable_time_stamp + NF_FLOW_TIMEOUT;
|
||||
flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
|
||||
|
||||
err = rhashtable_insert_fast(&flow_table->rhashtable,
|
||||
&flow->tuplehash[0].node,
|
||||
@ -304,7 +331,7 @@ EXPORT_SYMBOL_GPL(flow_offload_add);
|
||||
void flow_offload_refresh(struct nf_flowtable *flow_table,
|
||||
struct flow_offload *flow)
|
||||
{
|
||||
flow->timeout = nf_flowtable_time_stamp + NF_FLOW_TIMEOUT;
|
||||
flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
|
||||
|
||||
if (likely(!nf_flowtable_hw_offload(flow_table)))
|
||||
return;
|
||||
|
@ -937,7 +937,7 @@ static void flow_offload_work_stats(struct flow_offload_work *offload)
|
||||
|
||||
lastused = max_t(u64, stats[0].lastused, stats[1].lastused);
|
||||
offload->flow->timeout = max_t(u64, offload->flow->timeout,
|
||||
lastused + NF_FLOW_TIMEOUT);
|
||||
lastused + flow_offload_get_timeout(offload->flow));
|
||||
|
||||
if (offload->flowtable->flags & NF_FLOWTABLE_COUNTER) {
|
||||
if (stats[0].pkts)
|
||||
@ -1041,7 +1041,7 @@ void nf_flow_offload_stats(struct nf_flowtable *flowtable,
|
||||
__s32 delta;
|
||||
|
||||
delta = nf_flow_timeout_delta(flow->timeout);
|
||||
if ((delta >= (9 * NF_FLOW_TIMEOUT) / 10))
|
||||
if ((delta >= (9 * flow_offload_get_timeout(flow)) / 10))
|
||||
return;
|
||||
|
||||
offload = nf_flow_offload_work_alloc(flowtable, flow, FLOW_CLS_STATS);
|
||||
|
@ -862,10 +862,9 @@ static int nft_netlink_dump_start_rcu(struct sock *nlsk, struct sk_buff *skb,
|
||||
static int nf_tables_gettable(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_cur(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
const struct nft_table *table;
|
||||
struct net *net = info->net;
|
||||
struct sk_buff *skb2;
|
||||
@ -1068,10 +1067,9 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
struct nftables_pernet *nft_net = nft_pernet(info->net);
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
const struct nlattr *attr;
|
||||
struct nft_table *table;
|
||||
@ -1263,10 +1261,9 @@ out:
|
||||
static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
const struct nlattr *attr;
|
||||
struct nft_table *table;
|
||||
@ -1636,10 +1633,9 @@ done:
|
||||
static int nf_tables_getchain(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_cur(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
const struct nft_chain *chain;
|
||||
struct net *net = info->net;
|
||||
struct nft_table *table;
|
||||
@ -2015,11 +2011,12 @@ static void nft_basechain_hook_init(struct nf_hook_ops *ops, u8 family,
|
||||
const struct nft_chain_hook *hook,
|
||||
struct nft_chain *chain)
|
||||
{
|
||||
ops->pf = family;
|
||||
ops->hooknum = hook->num;
|
||||
ops->priority = hook->priority;
|
||||
ops->priv = chain;
|
||||
ops->hook = hook->type->hooks[ops->hooknum];
|
||||
ops->pf = family;
|
||||
ops->hooknum = hook->num;
|
||||
ops->priority = hook->priority;
|
||||
ops->priv = chain;
|
||||
ops->hook = hook->type->hooks[ops->hooknum];
|
||||
ops->hook_ops_type = NF_HOOK_OP_NF_TABLES;
|
||||
}
|
||||
|
||||
static int nft_basechain_init(struct nft_base_chain *basechain, u8 family,
|
||||
@ -2371,10 +2368,9 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
struct nftables_pernet *nft_net = nft_pernet(info->net);
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct nft_chain *chain = NULL;
|
||||
struct net *net = info->net;
|
||||
const struct nlattr *attr;
|
||||
@ -2469,10 +2465,9 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
const struct nlattr *attr;
|
||||
struct nft_table *table;
|
||||
@ -3096,10 +3091,9 @@ static int nf_tables_dump_rules_done(struct netlink_callback *cb)
|
||||
static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_cur(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
const struct nft_chain *chain;
|
||||
const struct nft_rule *rule;
|
||||
struct net *net = info->net;
|
||||
@ -3237,13 +3231,12 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
struct nftables_pernet *nft_net = nft_pernet(info->net);
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
unsigned int size, i, n, ulen = 0, usize = 0;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
struct nft_rule *rule, *old_rule = NULL;
|
||||
struct nft_expr_info *expr_info = NULL;
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
struct nft_flow_rule *flow;
|
||||
struct nft_userdata *udata;
|
||||
@ -3477,15 +3470,15 @@ static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
|
||||
static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
int family = nfmsg->nfgen_family, err = 0;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct nft_chain *chain = NULL;
|
||||
struct net *net = info->net;
|
||||
struct nft_table *table;
|
||||
struct nft_rule *rule;
|
||||
struct nft_ctx ctx;
|
||||
int err = 0;
|
||||
|
||||
table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask,
|
||||
NETLINK_CB(skb).portid);
|
||||
@ -3665,30 +3658,6 @@ static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
|
||||
[NFTA_SET_DESC_CONCAT] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
|
||||
const struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const nla[],
|
||||
struct netlink_ext_ack *extack,
|
||||
u8 genmask, u32 nlpid)
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||
int family = nfmsg->nfgen_family;
|
||||
struct nft_table *table = NULL;
|
||||
|
||||
if (nla[NFTA_SET_TABLE] != NULL) {
|
||||
table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family,
|
||||
genmask, nlpid);
|
||||
if (IS_ERR(table)) {
|
||||
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]);
|
||||
return PTR_ERR(table);
|
||||
}
|
||||
}
|
||||
|
||||
nft_ctx_init(ctx, net, skb, nlh, family, table, NULL, nla);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nft_set *nft_set_lookup(const struct nft_table *table,
|
||||
const struct nlattr *nla, u8 genmask)
|
||||
{
|
||||
@ -4068,20 +4037,26 @@ static int nf_tables_dump_sets_done(struct netlink_callback *cb)
|
||||
static int nf_tables_getset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_cur(info->net);
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct nft_table *table = NULL;
|
||||
struct net *net = info->net;
|
||||
const struct nft_set *set;
|
||||
struct sk_buff *skb2;
|
||||
struct nft_ctx ctx;
|
||||
int err;
|
||||
|
||||
/* Verify existence before starting dump */
|
||||
err = nft_ctx_init_from_setattr(&ctx, net, skb, info->nlh, nla, extack,
|
||||
genmask, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (nla[NFTA_SET_TABLE]) {
|
||||
table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family,
|
||||
genmask, 0);
|
||||
if (IS_ERR(table)) {
|
||||
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]);
|
||||
return PTR_ERR(table);
|
||||
}
|
||||
}
|
||||
|
||||
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
|
||||
|
||||
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||
struct netlink_dump_control c = {
|
||||
@ -4096,12 +4071,12 @@ static int nf_tables_getset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
}
|
||||
|
||||
/* Only accept unspec with dump */
|
||||
if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
|
||||
if (info->nfmsg->nfgen_family == NFPROTO_UNSPEC)
|
||||
return -EAFNOSUPPORT;
|
||||
if (!nla[NFTA_SET_TABLE])
|
||||
return -EINVAL;
|
||||
|
||||
set = nft_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
|
||||
set = nft_set_lookup(table, nla[NFTA_SET_NAME], genmask);
|
||||
if (IS_ERR(set))
|
||||
return PTR_ERR(set);
|
||||
|
||||
@ -4189,11 +4164,10 @@ static int nf_tables_set_desc_parse(struct nft_set_desc *desc,
|
||||
static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u32 ktype, dtype, flags, policy, gc_int, objtype;
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
const struct nft_set_ops *ops;
|
||||
struct nft_expr *expr = NULL;
|
||||
struct net *net = info->net;
|
||||
@ -4493,31 +4467,31 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
|
||||
static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
const struct nlattr *attr;
|
||||
struct nft_table *table;
|
||||
struct nft_set *set;
|
||||
struct nft_ctx ctx;
|
||||
int err;
|
||||
|
||||
if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
|
||||
if (info->nfmsg->nfgen_family == NFPROTO_UNSPEC)
|
||||
return -EAFNOSUPPORT;
|
||||
if (nla[NFTA_SET_TABLE] == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
err = nft_ctx_init_from_setattr(&ctx, net, skb, info->nlh, nla, extack,
|
||||
genmask, NETLINK_CB(skb).portid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family,
|
||||
genmask, NETLINK_CB(skb).portid);
|
||||
if (IS_ERR(table)) {
|
||||
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]);
|
||||
return PTR_ERR(table);
|
||||
}
|
||||
|
||||
if (nla[NFTA_SET_HANDLE]) {
|
||||
attr = nla[NFTA_SET_HANDLE];
|
||||
set = nft_set_lookup_byhandle(ctx.table, attr, genmask);
|
||||
set = nft_set_lookup_byhandle(table, attr, genmask);
|
||||
} else {
|
||||
attr = nla[NFTA_SET_NAME];
|
||||
set = nft_set_lookup(ctx.table, attr, genmask);
|
||||
set = nft_set_lookup(table, attr, genmask);
|
||||
}
|
||||
|
||||
if (IS_ERR(set)) {
|
||||
@ -4531,6 +4505,8 @@ static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
|
||||
|
||||
return nft_delset(&ctx, set);
|
||||
}
|
||||
|
||||
@ -4732,28 +4708,6 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX +
|
||||
[NFTA_SET_ELEM_LIST_SET_ID] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
|
||||
const struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const nla[],
|
||||
struct netlink_ext_ack *extack,
|
||||
u8 genmask, u32 nlpid)
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||
int family = nfmsg->nfgen_family;
|
||||
struct nft_table *table;
|
||||
|
||||
table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
|
||||
genmask, nlpid);
|
||||
if (IS_ERR(table)) {
|
||||
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]);
|
||||
return PTR_ERR(table);
|
||||
}
|
||||
|
||||
nft_ctx_init(ctx, net, skb, nlh, family, table, NULL, nla);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_set_elem_expr_dump(struct sk_buff *skb,
|
||||
const struct nft_set *set,
|
||||
const struct nft_set_ext *ext)
|
||||
@ -5211,21 +5165,27 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
|
||||
{
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_cur(info->net);
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
struct nft_table *table;
|
||||
struct nft_set *set;
|
||||
struct nlattr *attr;
|
||||
struct nft_ctx ctx;
|
||||
int rem, err = 0;
|
||||
|
||||
err = nft_ctx_init_from_elemattr(&ctx, net, skb, info->nlh, nla, extack,
|
||||
genmask, NETLINK_CB(skb).portid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
|
||||
genmask, NETLINK_CB(skb).portid);
|
||||
if (IS_ERR(table)) {
|
||||
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]);
|
||||
return PTR_ERR(table);
|
||||
}
|
||||
|
||||
set = nft_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
|
||||
set = nft_set_lookup(table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
|
||||
if (IS_ERR(set))
|
||||
return PTR_ERR(set);
|
||||
|
||||
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
|
||||
|
||||
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||
struct netlink_dump_control c = {
|
||||
.start = nf_tables_dump_set_start,
|
||||
@ -5994,8 +5954,10 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
|
||||
struct nftables_pernet *nft_net = nft_pernet(info->net);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
const struct nlattr *attr;
|
||||
struct nft_table *table;
|
||||
struct nft_set *set;
|
||||
struct nft_ctx ctx;
|
||||
int rem, err;
|
||||
@ -6003,12 +5965,14 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
|
||||
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
err = nft_ctx_init_from_elemattr(&ctx, net, skb, info->nlh, nla, extack,
|
||||
genmask, NETLINK_CB(skb).portid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
|
||||
genmask, NETLINK_CB(skb).portid);
|
||||
if (IS_ERR(table)) {
|
||||
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]);
|
||||
return PTR_ERR(table);
|
||||
}
|
||||
|
||||
set = nft_set_lookup_global(net, ctx.table, nla[NFTA_SET_ELEM_LIST_SET],
|
||||
set = nft_set_lookup_global(net, table, nla[NFTA_SET_ELEM_LIST_SET],
|
||||
nla[NFTA_SET_ELEM_LIST_SET_ID], genmask);
|
||||
if (IS_ERR(set))
|
||||
return PTR_ERR(set);
|
||||
@ -6016,6 +5980,8 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
|
||||
if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
|
||||
return -EBUSY;
|
||||
|
||||
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
|
||||
|
||||
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
|
||||
err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags);
|
||||
if (err < 0)
|
||||
@ -6023,7 +5989,7 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
if (nft_net->validate_state == NFT_VALIDATE_DO)
|
||||
return nft_table_validate(net, ctx.table);
|
||||
return nft_table_validate(net, table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -6261,23 +6227,29 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
|
||||
{
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
const struct nlattr *attr;
|
||||
struct nft_table *table;
|
||||
struct nft_set *set;
|
||||
struct nft_ctx ctx;
|
||||
int rem, err = 0;
|
||||
|
||||
err = nft_ctx_init_from_elemattr(&ctx, net, skb, info->nlh, nla, extack,
|
||||
genmask, NETLINK_CB(skb).portid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
|
||||
genmask, NETLINK_CB(skb).portid);
|
||||
if (IS_ERR(table)) {
|
||||
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]);
|
||||
return PTR_ERR(table);
|
||||
}
|
||||
|
||||
set = nft_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
|
||||
set = nft_set_lookup(table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
|
||||
if (IS_ERR(set))
|
||||
return PTR_ERR(set);
|
||||
if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
|
||||
return -EBUSY;
|
||||
|
||||
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
|
||||
|
||||
if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS])
|
||||
return nft_set_flush(&ctx, set, genmask);
|
||||
|
||||
@ -6545,11 +6517,10 @@ err_free_trans:
|
||||
static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
const struct nft_object_type *type;
|
||||
int family = nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
struct nft_table *table;
|
||||
struct nft_object *obj;
|
||||
@ -6801,10 +6772,9 @@ static int nf_tables_dump_obj_done(struct netlink_callback *cb)
|
||||
static int nf_tables_getobj(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_cur(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
const struct nft_table *table;
|
||||
struct net *net = info->net;
|
||||
struct nft_object *obj;
|
||||
@ -6891,10 +6861,9 @@ static void nft_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj)
|
||||
static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct net *net = info->net;
|
||||
const struct nlattr *attr;
|
||||
struct nft_table *table;
|
||||
@ -7322,12 +7291,11 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
struct nft_flowtable_hook flowtable_hook;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
const struct nf_flowtable_type *type;
|
||||
int family = nfmsg->nfgen_family;
|
||||
struct nft_flowtable *flowtable;
|
||||
struct nft_hook *hook, *next;
|
||||
struct net *net = info->net;
|
||||
@ -7511,10 +7479,9 @@ static int nf_tables_delflowtable(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
u8 genmask = nft_genmask_next(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct nft_flowtable *flowtable;
|
||||
struct net *net = info->net;
|
||||
const struct nlattr *attr;
|
||||
@ -7706,9 +7673,8 @@ static int nf_tables_getflowtable(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u8 genmask = nft_genmask_cur(info->net);
|
||||
int family = nfmsg->nfgen_family;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
struct nft_flowtable *flowtable;
|
||||
const struct nft_table *table;
|
||||
struct net *net = info->net;
|
||||
|
@ -68,6 +68,7 @@ static const char *const nfnl_lockdep_names[NFNL_SUBSYS_COUNT] = {
|
||||
[NFNL_SUBSYS_CTHELPER] = "nfnl_subsys_cthelper",
|
||||
[NFNL_SUBSYS_NFTABLES] = "nfnl_subsys_nftables",
|
||||
[NFNL_SUBSYS_NFT_COMPAT] = "nfnl_subsys_nftcompat",
|
||||
[NFNL_SUBSYS_HOOK] = "nfnl_subsys_hook",
|
||||
};
|
||||
|
||||
static const int nfnl_group2type[NFNLGRP_MAX+1] = {
|
||||
@ -256,6 +257,7 @@ replay:
|
||||
.net = net,
|
||||
.sk = nfnlnet->nfnl,
|
||||
.nlh = nlh,
|
||||
.nfmsg = nlmsg_data(nlh),
|
||||
.extack = extack,
|
||||
};
|
||||
|
||||
@ -491,6 +493,7 @@ replay_abort:
|
||||
.net = net,
|
||||
.sk = nfnlnet->nfnl,
|
||||
.nlh = nlh,
|
||||
.nfmsg = nlmsg_data(nlh),
|
||||
.extack = &extack,
|
||||
};
|
||||
|
||||
|
375
net/netfilter/nfnetlink_hook.c
Normal file
375
net/netfilter/nfnetlink_hook.c
Normal file
@ -0,0 +1,375 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2021 Red Hat GmbH
|
||||
*
|
||||
* Author: Florian Westphal <fw@strlen.de>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nfnetlink_hook.h>
|
||||
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
static const struct nla_policy nfnl_hook_nla_policy[NFNLA_HOOK_MAX + 1] = {
|
||||
[NFNLA_HOOK_HOOKNUM] = { .type = NLA_U32 },
|
||||
[NFNLA_HOOK_PRIORITY] = { .type = NLA_U32 },
|
||||
[NFNLA_HOOK_DEV] = { .type = NLA_STRING,
|
||||
.len = IFNAMSIZ - 1 },
|
||||
[NFNLA_HOOK_FUNCTION_NAME] = { .type = NLA_NUL_STRING,
|
||||
.len = KSYM_NAME_LEN, },
|
||||
[NFNLA_HOOK_MODULE_NAME] = { .type = NLA_NUL_STRING,
|
||||
.len = MODULE_NAME_LEN, },
|
||||
[NFNLA_HOOK_CHAIN_INFO] = { .type = NLA_NESTED, },
|
||||
};
|
||||
|
||||
static int nf_netlink_dump_start_rcu(struct sock *nlsk, struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
struct netlink_dump_control *c)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_unlock();
|
||||
err = netlink_dump_start(nlsk, skb, nlh, c);
|
||||
rcu_read_lock();
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct nfnl_dump_hook_data {
|
||||
char devname[IFNAMSIZ];
|
||||
unsigned long headv;
|
||||
u8 hook;
|
||||
};
|
||||
|
||||
static int nfnl_hook_put_nft_chain_info(struct sk_buff *nlskb,
|
||||
const struct nfnl_dump_hook_data *ctx,
|
||||
unsigned int seq,
|
||||
const struct nf_hook_ops *ops)
|
||||
{
|
||||
struct net *net = sock_net(nlskb->sk);
|
||||
struct nlattr *nest, *nest2;
|
||||
struct nft_chain *chain;
|
||||
int ret = 0;
|
||||
|
||||
if (ops->hook_ops_type != NF_HOOK_OP_NF_TABLES)
|
||||
return 0;
|
||||
|
||||
chain = ops->priv;
|
||||
if (WARN_ON_ONCE(!chain))
|
||||
return 0;
|
||||
|
||||
if (!nft_is_active(net, chain))
|
||||
return 0;
|
||||
|
||||
nest = nla_nest_start(nlskb, NFNLA_HOOK_CHAIN_INFO);
|
||||
if (!nest)
|
||||
return -EMSGSIZE;
|
||||
|
||||
ret = nla_put_be32(nlskb, NFNLA_HOOK_INFO_TYPE,
|
||||
htonl(NFNL_HOOK_TYPE_NFTABLES));
|
||||
if (ret)
|
||||
goto cancel_nest;
|
||||
|
||||
nest2 = nla_nest_start(nlskb, NFNLA_HOOK_INFO_DESC);
|
||||
if (!nest2)
|
||||
goto cancel_nest;
|
||||
|
||||
ret = nla_put_string(nlskb, NFTA_CHAIN_TABLE, chain->table->name);
|
||||
if (ret)
|
||||
goto cancel_nest;
|
||||
|
||||
ret = nla_put_string(nlskb, NFTA_CHAIN_NAME, chain->name);
|
||||
if (ret)
|
||||
goto cancel_nest;
|
||||
|
||||
nla_nest_end(nlskb, nest2);
|
||||
nla_nest_end(nlskb, nest);
|
||||
return ret;
|
||||
|
||||
cancel_nest:
|
||||
nla_nest_cancel(nlskb, nest);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int nfnl_hook_dump_one(struct sk_buff *nlskb,
|
||||
const struct nfnl_dump_hook_data *ctx,
|
||||
const struct nf_hook_ops *ops,
|
||||
unsigned int seq)
|
||||
{
|
||||
u16 event = nfnl_msg_type(NFNL_SUBSYS_HOOK, NFNL_MSG_HOOK_GET);
|
||||
unsigned int portid = NETLINK_CB(nlskb).portid;
|
||||
struct nlmsghdr *nlh;
|
||||
int ret = -EMSGSIZE;
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
char sym[KSYM_SYMBOL_LEN];
|
||||
char *module_name;
|
||||
#endif
|
||||
nlh = nfnl_msg_put(nlskb, portid, seq, event,
|
||||
NLM_F_MULTI, ops->pf, NFNETLINK_V0, 0);
|
||||
if (!nlh)
|
||||
goto nla_put_failure;
|
||||
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
ret = snprintf(sym, sizeof(sym), "%ps", ops->hook);
|
||||
if (ret < 0 || ret > (int)sizeof(sym))
|
||||
goto nla_put_failure;
|
||||
|
||||
module_name = strstr(sym, " [");
|
||||
if (module_name) {
|
||||
char *end;
|
||||
|
||||
module_name += 2;
|
||||
end = strchr(module_name, ']');
|
||||
if (end) {
|
||||
*end = 0;
|
||||
|
||||
ret = nla_put_string(nlskb, NFNLA_HOOK_MODULE_NAME, module_name);
|
||||
if (ret)
|
||||
goto nla_put_failure;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nla_put_string(nlskb, NFNLA_HOOK_FUNCTION_NAME, sym);
|
||||
if (ret)
|
||||
goto nla_put_failure;
|
||||
#endif
|
||||
|
||||
ret = nla_put_be32(nlskb, NFNLA_HOOK_HOOKNUM, htonl(ops->hooknum));
|
||||
if (ret)
|
||||
goto nla_put_failure;
|
||||
|
||||
ret = nla_put_be32(nlskb, NFNLA_HOOK_PRIORITY, htonl(ops->priority));
|
||||
if (ret)
|
||||
goto nla_put_failure;
|
||||
|
||||
ret = nfnl_hook_put_nft_chain_info(nlskb, ctx, seq, ops);
|
||||
if (ret)
|
||||
goto nla_put_failure;
|
||||
|
||||
nlmsg_end(nlskb, nlh);
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
nlmsg_trim(nlskb, nlh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct nf_hook_entries *
|
||||
nfnl_hook_entries_head(u8 pf, unsigned int hook, struct net *net, const char *dev)
|
||||
{
|
||||
const struct nf_hook_entries *hook_head = NULL;
|
||||
struct net_device *netdev;
|
||||
|
||||
switch (pf) {
|
||||
case NFPROTO_IPV4:
|
||||
if (hook >= ARRAY_SIZE(net->nf.hooks_ipv4))
|
||||
return ERR_PTR(-EINVAL);
|
||||
hook_head = rcu_dereference(net->nf.hooks_ipv4[hook]);
|
||||
break;
|
||||
case NFPROTO_IPV6:
|
||||
if (hook >= ARRAY_SIZE(net->nf.hooks_ipv6))
|
||||
return ERR_PTR(-EINVAL);
|
||||
hook_head = rcu_dereference(net->nf.hooks_ipv6[hook]);
|
||||
break;
|
||||
case NFPROTO_ARP:
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_ARP
|
||||
if (hook >= ARRAY_SIZE(net->nf.hooks_arp))
|
||||
return ERR_PTR(-EINVAL);
|
||||
hook_head = rcu_dereference(net->nf.hooks_arp[hook]);
|
||||
#endif
|
||||
break;
|
||||
case NFPROTO_BRIDGE:
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
if (hook >= ARRAY_SIZE(net->nf.hooks_bridge))
|
||||
return ERR_PTR(-EINVAL);
|
||||
hook_head = rcu_dereference(net->nf.hooks_bridge[hook]);
|
||||
#endif
|
||||
break;
|
||||
#if IS_ENABLED(CONFIG_DECNET)
|
||||
case NFPROTO_DECNET:
|
||||
if (hook >= ARRAY_SIZE(net->nf.hooks_decnet))
|
||||
return ERR_PTR(-EINVAL);
|
||||
hook_head = rcu_dereference(net->nf.hooks_decnet[hook]);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_NETFILTER_INGRESS
|
||||
case NFPROTO_NETDEV:
|
||||
if (hook != NF_NETDEV_INGRESS)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
netdev = dev_get_by_name_rcu(net, dev);
|
||||
if (!netdev)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
return rcu_dereference(netdev->nf_hooks_ingress);
|
||||
#endif
|
||||
default:
|
||||
return ERR_PTR(-EPROTONOSUPPORT);
|
||||
}
|
||||
|
||||
return hook_head;
|
||||
}
|
||||
|
||||
static int nfnl_hook_dump(struct sk_buff *nlskb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
|
||||
struct nfnl_dump_hook_data *ctx = cb->data;
|
||||
int err, family = nfmsg->nfgen_family;
|
||||
struct net *net = sock_net(nlskb->sk);
|
||||
struct nf_hook_ops * const *ops;
|
||||
const struct nf_hook_entries *e;
|
||||
unsigned int i = cb->args[0];
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
e = nfnl_hook_entries_head(family, ctx->hook, net, ctx->devname);
|
||||
if (!e)
|
||||
goto done;
|
||||
|
||||
if (IS_ERR(e)) {
|
||||
cb->seq++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((unsigned long)e != ctx->headv || i >= e->num_hook_entries)
|
||||
cb->seq++;
|
||||
|
||||
ops = nf_hook_entries_get_hook_ops(e);
|
||||
|
||||
for (; i < e->num_hook_entries; i++) {
|
||||
err = nfnl_hook_dump_one(nlskb, ctx, ops[i], cb->seq);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
nl_dump_check_consistent(cb, nlmsg_hdr(nlskb));
|
||||
rcu_read_unlock();
|
||||
cb->args[0] = i;
|
||||
return nlskb->len;
|
||||
}
|
||||
|
||||
static int nfnl_hook_dump_start(struct netlink_callback *cb)
|
||||
{
|
||||
const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
|
||||
const struct nlattr * const *nla = cb->data;
|
||||
struct nfnl_dump_hook_data *ctx = NULL;
|
||||
struct net *net = sock_net(cb->skb->sk);
|
||||
u8 family = nfmsg->nfgen_family;
|
||||
char name[IFNAMSIZ] = "";
|
||||
const void *head;
|
||||
u32 hooknum;
|
||||
|
||||
hooknum = ntohl(nla_get_be32(nla[NFNLA_HOOK_HOOKNUM]));
|
||||
if (hooknum > 255)
|
||||
return -EINVAL;
|
||||
|
||||
if (family == NFPROTO_NETDEV) {
|
||||
if (!nla[NFNLA_HOOK_DEV])
|
||||
return -EINVAL;
|
||||
|
||||
nla_strscpy(name, nla[NFNLA_HOOK_DEV], sizeof(name));
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
/* Not dereferenced; for consistency check only */
|
||||
head = nfnl_hook_entries_head(family, hooknum, net, name);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (head && IS_ERR(head))
|
||||
return PTR_ERR(head);
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
strscpy(ctx->devname, name, sizeof(ctx->devname));
|
||||
ctx->headv = (unsigned long)head;
|
||||
ctx->hook = hooknum;
|
||||
|
||||
cb->seq = 1;
|
||||
cb->data = ctx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfnl_hook_dump_stop(struct netlink_callback *cb)
|
||||
{
|
||||
kfree(cb->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfnl_hook_get(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const nla[])
|
||||
{
|
||||
if (!nla[NFNLA_HOOK_HOOKNUM])
|
||||
return -EINVAL;
|
||||
|
||||
if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||
struct netlink_dump_control c = {
|
||||
.start = nfnl_hook_dump_start,
|
||||
.done = nfnl_hook_dump_stop,
|
||||
.dump = nfnl_hook_dump,
|
||||
.module = THIS_MODULE,
|
||||
.data = (void *)nla,
|
||||
};
|
||||
|
||||
return nf_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct nfnl_callback nfnl_hook_cb[NFNL_MSG_HOOK_MAX] = {
|
||||
[NFNL_MSG_HOOK_GET] = {
|
||||
.call = nfnl_hook_get,
|
||||
.type = NFNL_CB_RCU,
|
||||
.attr_count = NFNLA_HOOK_MAX,
|
||||
.policy = nfnl_hook_nla_policy
|
||||
},
|
||||
};
|
||||
|
||||
static const struct nfnetlink_subsystem nfhook_subsys = {
|
||||
.name = "nfhook",
|
||||
.subsys_id = NFNL_SUBSYS_HOOK,
|
||||
.cb_count = NFNL_MSG_HOOK_MAX,
|
||||
.cb = nfnl_hook_cb,
|
||||
};
|
||||
|
||||
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_HOOK);
|
||||
|
||||
static int __init nfnetlink_hook_init(void)
|
||||
{
|
||||
return nfnetlink_subsys_register(&nfhook_subsys);
|
||||
}
|
||||
|
||||
static void __exit nfnetlink_hook_exit(void)
|
||||
{
|
||||
nfnetlink_subsys_unregister(&nfhook_subsys);
|
||||
}
|
||||
|
||||
module_init(nfnetlink_hook_init);
|
||||
module_exit(nfnetlink_hook_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
|
||||
MODULE_DESCRIPTION("nfnetlink_hook: list registered netfilter hooks");
|
@ -871,15 +871,14 @@ static int nfulnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nfula[])
|
||||
{
|
||||
struct nfnl_log_net *log = nfnl_log_pernet(info->net);
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u_int16_t group_num = ntohs(nfmsg->res_id);
|
||||
u_int16_t group_num = ntohs(info->nfmsg->res_id);
|
||||
struct nfulnl_msg_config_cmd *cmd = NULL;
|
||||
struct nfulnl_instance *inst;
|
||||
u16 flags = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (nfula[NFULA_CFG_CMD]) {
|
||||
u_int8_t pf = nfmsg->nfgen_family;
|
||||
u_int8_t pf = info->nfmsg->nfgen_family;
|
||||
cmd = nla_data(nfula[NFULA_CFG_CMD]);
|
||||
|
||||
/* Commands without queue context */
|
||||
|
@ -1051,8 +1051,7 @@ static int nfqnl_recv_verdict_batch(struct sk_buff *skb,
|
||||
const struct nlattr * const nfqa[])
|
||||
{
|
||||
struct nfnl_queue_net *q = nfnl_queue_pernet(info->net);
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u16 queue_num = ntohs(nfmsg->res_id);
|
||||
u16 queue_num = ntohs(info->nfmsg->res_id);
|
||||
struct nf_queue_entry *entry, *tmp;
|
||||
struct nfqnl_msg_verdict_hdr *vhdr;
|
||||
struct nfqnl_instance *queue;
|
||||
@ -1160,8 +1159,7 @@ static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nfqa[])
|
||||
{
|
||||
struct nfnl_queue_net *q = nfnl_queue_pernet(info->net);
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u_int16_t queue_num = ntohs(nfmsg->res_id);
|
||||
u_int16_t queue_num = ntohs(info->nfmsg->res_id);
|
||||
struct nfqnl_msg_verdict_hdr *vhdr;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct nfqnl_instance *queue;
|
||||
@ -1243,8 +1241,7 @@ static int nfqnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
const struct nlattr * const nfqa[])
|
||||
{
|
||||
struct nfnl_queue_net *q = nfnl_queue_pernet(info->net);
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
|
||||
u_int16_t queue_num = ntohs(nfmsg->res_id);
|
||||
u_int16_t queue_num = ntohs(info->nfmsg->res_id);
|
||||
struct nfqnl_msg_config_cmd *cmd = NULL;
|
||||
struct nfqnl_instance *queue;
|
||||
__u32 flags = 0, mask = 0;
|
||||
|
@ -625,7 +625,7 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb,
|
||||
const struct nfnl_info *info,
|
||||
const struct nlattr * const tb[])
|
||||
{
|
||||
struct nfgenmsg *nfmsg;
|
||||
u8 family = info->nfmsg->nfgen_family;
|
||||
const char *name, *fmt;
|
||||
struct sk_buff *skb2;
|
||||
int ret = 0, target;
|
||||
@ -640,9 +640,7 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb,
|
||||
rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
|
||||
target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
|
||||
|
||||
nfmsg = nlmsg_data(info->nlh);
|
||||
|
||||
switch(nfmsg->nfgen_family) {
|
||||
switch(family) {
|
||||
case AF_INET:
|
||||
fmt = "ipt_%s";
|
||||
break;
|
||||
@ -656,8 +654,7 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb,
|
||||
fmt = "arpt_%s";
|
||||
break;
|
||||
default:
|
||||
pr_err("nft_compat: unsupported protocol %d\n",
|
||||
nfmsg->nfgen_family);
|
||||
pr_err("nft_compat: unsupported protocol %d\n", family);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -665,9 +662,8 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb,
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_unlock();
|
||||
try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name,
|
||||
rev, target, &ret),
|
||||
fmt, name);
|
||||
try_then_request_module(xt_find_revision(family, name, rev, target, &ret),
|
||||
fmt, name);
|
||||
if (ret < 0)
|
||||
goto out_put;
|
||||
|
||||
@ -682,8 +678,7 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb,
|
||||
info->nlh->nlmsg_seq,
|
||||
NFNL_MSG_TYPE(info->nlh->nlmsg_type),
|
||||
NFNL_MSG_COMPAT_GET,
|
||||
nfmsg->nfgen_family,
|
||||
name, ret, target) <= 0) {
|
||||
family, name, ret, target) <= 0) {
|
||||
kfree_skb(skb2);
|
||||
goto out_put;
|
||||
}
|
||||
|
@ -327,7 +327,9 @@ static void nft_exthdr_sctp_eval(const struct nft_expr *expr,
|
||||
break;
|
||||
|
||||
dest[priv->len / NFT_REG32_SIZE] = 0;
|
||||
memcpy(dest, (char *)sch + priv->offset, priv->len);
|
||||
if (skb_copy_bits(pkt->skb, offset + priv->offset,
|
||||
dest, priv->len) < 0)
|
||||
break;
|
||||
return;
|
||||
}
|
||||
offset += SCTP_PAD4(ntohs(sch->length));
|
||||
|
Loading…
Reference in New Issue
Block a user