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. ====================
Unified · Split
| @@ -77,12 +77,18 @@ struct nf_hook_state { · 76 unmodified lines | ||
| 77 | 77 | typedef unsigned int nf_hookfn(void *priv, |
| 78 | 78 | struct sk_buff *skb, |
| 79 | 79 | const struct nf_hook_state *state); |
| 80 | +enum nf_hook_ops_type { | |
| 81 | + NF_HOOK_OP_UNDEFINED, | |
| 82 | + NF_HOOK_OP_NF_TABLES, | |
| 83 | +}; | |
| 84 | + | |
| 80 | 85 | struct nf_hook_ops { |
| 81 | 86 | /* User fills in from here down. */ |
| 82 | 87 | nf_hookfn *hook; |
| 83 | 88 | struct net_device *dev; |
| 84 | 89 | void *priv; |
| 85 | − u_int8_t pf; | |
| 90 | + u8 pf; | |
| 91 | + enum nf_hook_ops_type hook_ops_type:8; | |
| 86 | 92 | unsigned int hooknum; |
| 87 | 93 | /* Hooks are ordered in ascending priority. */ |
| 88 | 94 | int priority; |
| @@ -11,6 +11,7 @@ struct nfnl_info { · 10 unmodified lines | ||
| 11 | 11 | struct net *net; |
| 12 | 12 | struct sock *sk; |
| 13 | 13 | const struct nlmsghdr *nlh; |
| 14 | + const struct nfgenmsg *nfmsg; | |
| 14 | 15 | struct netlink_ext_ack *extack; |
| 15 | 16 | }; |
| 16 | 17 | |
| @@ -346,6 +346,13 @@ nf_ct_set(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info info) · 345 unmodified lines | ||
| 346 | 346 | skb_set_nfct(skb, (unsigned long)ct | info); |
| 347 | 347 | } |
| 348 | 348 | |
| 349 | +extern unsigned int nf_conntrack_net_id; | |
| 350 | + | |
| 351 | +static inline struct nf_conntrack_net *nf_ct_pernet(const struct net *net) | |
| 352 | +{ | |
| 353 | + return net_generic(net, nf_conntrack_net_id); | |
| 354 | +} | |
| 355 | + | |
| 349 | 356 | #define NF_CT_STAT_INC(net, count) __this_cpu_inc((net)->ct.stat->count) |
| 350 | 357 | #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count) |
| 351 | 358 | #define NF_CT_STAT_ADD_ATOMIC(net, count, v) this_cpu_add((net)->ct.stat->count, (v)) |
| @@ -177,6 +177,8 @@ struct flow_offload { · 176 unmodified lines | ||
| 177 | 177 | #define NF_FLOW_TIMEOUT (30 * HZ) |
| 178 | 178 | #define nf_flowtable_time_stamp (u32)jiffies |
| 179 | 179 | |
| 180 | +unsigned long flow_offload_get_timeout(struct flow_offload *flow); | |
| 181 | + | |
| 180 | 182 | static inline __s32 nf_flow_timeout_delta(unsigned int timeout) |
| 181 | 183 | { |
| 182 | 184 | return (__s32)(timeout - nf_flowtable_time_stamp); |
| @@ -27,6 +27,10 @@ struct nf_tcp_net { · 26 unmodified lines | ||
| 27 | 27 | u8 tcp_loose; |
| 28 | 28 | u8 tcp_be_liberal; |
| 29 | 29 | u8 tcp_max_retrans; |
| 30 | +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
| 31 | + unsigned int offload_timeout; | |
| 32 | + unsigned int offload_pickup; | |
| 33 | +#endif | |
| 30 | 34 | }; |
| 31 | 35 | |
| 32 | 36 | enum udp_conntrack { |
| @@ -37,6 +41,10 @@ enum udp_conntrack { · 4 unmodified lines | ||
| 37 | 41 | |
| 38 | 42 | struct nf_udp_net { |
| 39 | 43 | unsigned int timeouts[UDP_CT_MAX]; |
| 44 | +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
| 45 | + unsigned int offload_timeout; | |
| 46 | + unsigned int offload_pickup; | |
| 47 | +#endif | |
| 40 | 48 | }; |
| 41 | 49 | |
| 42 | 50 | struct nf_icmp_net { |
| @@ -60,7 +60,8 @@ struct nfgenmsg { · 59 unmodified lines | ||
| 60 | 60 | #define NFNL_SUBSYS_CTHELPER 9 |
| 61 | 61 | #define NFNL_SUBSYS_NFTABLES 10 |
| 62 | 62 | #define NFNL_SUBSYS_NFT_COMPAT 11 |
| 63 | −#define NFNL_SUBSYS_COUNT 12 | |
| 63 | +#define NFNL_SUBSYS_HOOK 12 | |
| 64 | +#define NFNL_SUBSYS_COUNT 13 | |
| 64 | 65 | |
| 65 | 66 | /* Reserved control nfnetlink messages */ |
| 66 | 67 | #define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE |
| @@ -0,0 +1,55 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ | |
| 2 | +#ifndef _NFNL_HOOK_H_ | |
| 3 | +#define _NFNL_HOOK_H_ | |
| 4 | + | |
| 5 | +enum nfnl_hook_msg_types { | |
| 6 | + NFNL_MSG_HOOK_GET, | |
| 7 | + NFNL_MSG_HOOK_MAX, | |
| 8 | +}; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * enum nfnl_hook_attributes - netfilter hook netlink attributes | |
| 12 | + * | |
| 13 | + * @NFNLA_HOOK_HOOKNUM: netfilter hook number (NLA_U32) | |
| 14 | + * @NFNLA_HOOK_PRIORITY: netfilter hook priority (NLA_U32) | |
| 15 | + * @NFNLA_HOOK_DEV: netdevice name (NLA_STRING) | |
| 16 | + * @NFNLA_HOOK_FUNCTION_NAME: hook function name (NLA_STRING) | |
| 17 | + * @NFNLA_HOOK_MODULE_NAME: kernel module that registered this hook (NLA_STRING) | |
| 18 | + * @NFNLA_HOOK_CHAIN_INFO: basechain hook metadata (NLA_NESTED) | |
| 19 | + */ | |
| 20 | +enum nfnl_hook_attributes { | |
| 21 | + NFNLA_HOOK_UNSPEC, | |
| 22 | + NFNLA_HOOK_HOOKNUM, | |
| 23 | + NFNLA_HOOK_PRIORITY, | |
| 24 | + NFNLA_HOOK_DEV, | |
| 25 | + NFNLA_HOOK_FUNCTION_NAME, | |
| 26 | + NFNLA_HOOK_MODULE_NAME, | |
| 27 | + NFNLA_HOOK_CHAIN_INFO, | |
| 28 | + __NFNLA_HOOK_MAX | |
| 29 | +}; | |
| 30 | +#define NFNLA_HOOK_MAX (__NFNLA_HOOK_MAX - 1) | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * enum nfnl_hook_chain_info_attributes - chain description | |
| 34 | + * | |
| 35 | + * NFNLA_HOOK_INFO_DESC: nft chain and table name (enum nft_table_attributes) (NLA_NESTED) | |
| 36 | + * NFNLA_HOOK_INFO_TYPE: chain type (enum nfnl_hook_chaintype) (NLA_U32) | |
| 37 | + */ | |
| 38 | +enum nfnl_hook_chain_info_attributes { | |
| 39 | + NFNLA_HOOK_INFO_UNSPEC, | |
| 40 | + NFNLA_HOOK_INFO_DESC, | |
| 41 | + NFNLA_HOOK_INFO_TYPE, | |
| 42 | + __NFNLA_HOOK_INFO_MAX, | |
| 43 | +}; | |
| 44 | +#define NFNLA_HOOK_INFO_MAX (__NFNLA_HOOK_INFO_MAX - 1) | |
| 45 | + | |
| 46 | +/** | |
| 47 | + * enum nfnl_hook_chaintype - chain type | |
| 48 | + * | |
| 49 | + * @NFNL_HOOK_TYPE_NFTABLES nf_tables base chain | |
| 50 | + */ | |
| 51 | +enum nfnl_hook_chaintype { | |
| 52 | + NFNL_HOOK_TYPE_NFTABLES = 0x1, | |
| 53 | +}; | |
| 54 | + | |
| 55 | +#endif /* _NFNL_HOOK_H */ | |
| @@ -19,6 +19,16 @@ config NETFILTER_FAMILY_BRIDGE · 18 unmodified lines | ||
| 19 | 19 | config NETFILTER_FAMILY_ARP |
| 20 | 20 | bool |
| 21 | 21 | |
| 22 | +config NETFILTER_NETLINK_HOOK | |
| 23 | + tristate "Netfilter base hook dump support" | |
| 24 | + depends on NETFILTER_ADVANCED | |
| 25 | + depends on NF_TABLES | |
| 26 | + select NETFILTER_NETLINK | |
| 27 | + help | |
| 28 | + If this option is enabled, the kernel will include support | |
| 29 | + to list the base netfilter hooks via NFNETLINK. | |
| 30 | + This is helpful for debugging. | |
| 31 | + | |
| 22 | 32 | config NETFILTER_NETLINK_ACCT |
| 23 | 33 | tristate "Netfilter NFACCT over NFNETLINK interface" |
| 24 | 34 | depends on NETFILTER_ADVANCED |
| @@ -22,6 +22,7 @@ obj-$(CONFIG_NETFILTER_NETLINK_ACCT) += nfnetlink_acct.o · 21 unmodified lines | ||
| 22 | 22 | obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o |
| 23 | 23 | obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o |
| 24 | 24 | obj-$(CONFIG_NETFILTER_NETLINK_OSF) += nfnetlink_osf.o |
| 25 | +obj-$(CONFIG_NETFILTER_NETLINK_HOOK) += nfnetlink_hook.o | |
| 25 | 26 | |
| 26 | 27 | # connection tracking |
| 27 | 28 | obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o |
| @@ -55,8 +55,6 @@ · 54 unmodified lines | ||
| 55 | 55 | |
| 56 | 56 | #include "nf_internals.h" |
| 57 | 57 | |
| 58 | −extern unsigned int nf_conntrack_net_id; | |
| 59 | − | |
| 60 | 58 | __cacheline_aligned_in_smp spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS]; |
| 61 | 59 | EXPORT_SYMBOL_GPL(nf_conntrack_locks); |
| 62 | 60 | |
| @@ -87,8 +85,6 @@ static __read_mostly bool nf_conntrack_locks_all; · 24 unmodified lines | ||
| 87 | 85 | |
| 88 | 86 | static struct conntrack_gc_work conntrack_gc_work; |
| 89 | 87 | |
| 90 | −extern unsigned int nf_conntrack_net_id; | |
| 91 | − | |
| 92 | 88 | void nf_conntrack_lock(spinlock_t *lock) __acquires(lock) |
| 93 | 89 | { |
| 94 | 90 | /* 1) Acquire the lock */ |
| @@ -1404,7 +1400,7 @@ static void gc_worker(struct work_struct *work) · 1309 unmodified lines | ||
| 1404 | 1400 | continue; |
| 1405 | 1401 | |
| 1406 | 1402 | net = nf_ct_net(tmp); |
| 1407 | − cnet = net_generic(net, nf_conntrack_net_id); | |
| 1403 | + cnet = nf_ct_pernet(net); | |
| 1408 | 1404 | if (atomic_read(&cnet->count) < nf_conntrack_max95) |
| 1409 | 1405 | continue; |
| 1410 | 1406 | |
| @@ -1484,7 +1480,7 @@ __nf_conntrack_alloc(struct net *net, · 73 unmodified lines | ||
| 1484 | 1480 | const struct nf_conntrack_tuple *repl, |
| 1485 | 1481 | gfp_t gfp, u32 hash) |
| 1486 | 1482 | { |
| 1487 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 1483 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 1488 | 1484 | unsigned int ct_count; |
| 1489 | 1485 | struct nf_conn *ct; |
| 1490 | 1486 | |
| @@ -1556,7 +1552,7 @@ void nf_conntrack_free(struct nf_conn *ct) · 65 unmodified lines | ||
| 1556 | 1552 | |
| 1557 | 1553 | nf_ct_ext_destroy(ct); |
| 1558 | 1554 | kmem_cache_free(nf_conntrack_cachep, ct); |
| 1559 | − cnet = net_generic(net, nf_conntrack_net_id); | |
| 1555 | + cnet = nf_ct_pernet(net); | |
| 1560 | 1556 | |
| 1561 | 1557 | smp_mb__before_atomic(); |
| 1562 | 1558 | atomic_dec(&cnet->count); |
| @@ -1614,7 +1610,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, · 51 unmodified lines | ||
| 1614 | 1610 | GFP_ATOMIC); |
| 1615 | 1611 | |
| 1616 | 1612 | local_bh_disable(); |
| 1617 | − cnet = net_generic(net, nf_conntrack_net_id); | |
| 1613 | + cnet = nf_ct_pernet(net); | |
| 1618 | 1614 | if (cnet->expect_count) { |
| 1619 | 1615 | spin_lock(&nf_conntrack_expect_lock); |
| 1620 | 1616 | exp = nf_ct_find_expectation(net, zone, tuple); |
| @@ -2317,7 +2313,7 @@ __nf_ct_unconfirmed_destroy(struct net *net) · 696 unmodified lines | ||
| 2317 | 2313 | |
| 2318 | 2314 | void nf_ct_unconfirmed_destroy(struct net *net) |
| 2319 | 2315 | { |
| 2320 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 2316 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 2321 | 2317 | |
| 2322 | 2318 | might_sleep(); |
| 2323 | 2319 | |
| @@ -2333,7 +2329,7 @@ void nf_ct_iterate_cleanup_net(struct net *net, · 9 unmodified lines | ||
| 2333 | 2329 | int (*iter)(struct nf_conn *i, void *data), |
| 2334 | 2330 | void *data, u32 portid, int report) |
| 2335 | 2331 | { |
| 2336 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 2332 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 2337 | 2333 | struct iter_data d; |
| 2338 | 2334 | |
| 2339 | 2335 | might_sleep(); |
| @@ -2367,7 +2363,7 @@ nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data) · 27 unmodified lines | ||
| 2367 | 2363 | |
| 2368 | 2364 | down_read(&net_rwsem); |
| 2369 | 2365 | for_each_net(net) { |
| 2370 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 2366 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 2371 | 2367 | |
| 2372 | 2368 | if (atomic_read(&cnet->count) == 0) |
| 2373 | 2369 | continue; |
| @@ -2449,7 +2445,7 @@ void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list) · 75 unmodified lines | ||
| 2449 | 2445 | i_see_dead_people: |
| 2450 | 2446 | busy = 0; |
| 2451 | 2447 | list_for_each_entry(net, net_exit_list, exit_list) { |
| 2452 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 2448 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 2453 | 2449 | |
| 2454 | 2450 | nf_ct_iterate_cleanup(kill_all, net, 0, 0); |
| 2455 | 2451 | if (atomic_read(&cnet->count) != 0) |
| @@ -2733,7 +2729,7 @@ void nf_conntrack_init_end(void) · 277 unmodified lines | ||
| 2733 | 2729 | |
| 2734 | 2730 | int nf_conntrack_init_net(struct net *net) |
| 2735 | 2731 | { |
| 2736 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 2732 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 2737 | 2733 | int ret = -ENOMEM; |
| 2738 | 2734 | int cpu; |
| 2739 | 2735 | |
| @@ -27,8 +27,6 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <net/netfilter/nf_conntrack_ecache.h> |
| 28 | 28 | #include <net/netfilter/nf_conntrack_extend.h> |
| 29 | 29 | |
| 30 | −extern unsigned int nf_conntrack_net_id; | |
| 31 | − | |
| 32 | 30 | static DEFINE_MUTEX(nf_ct_ecache_mutex); |
| 33 | 31 | |
| 34 | 32 | #define ECACHE_RETRY_WAIT (HZ/10) |
| @@ -348,7 +346,7 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); · 313 unmodified lines | ||
| 348 | 346 | |
| 349 | 347 | void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state) |
| 350 | 348 | { |
| 351 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 349 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 352 | 350 | |
| 353 | 351 | if (state == NFCT_ECACHE_DESTROY_FAIL && |
| 354 | 352 | !delayed_work_pending(&cnet->ecache_dwork)) { |
| @@ -371,7 +369,7 @@ static const struct nf_ct_ext_type event_extend = { · 16 unmodified lines | ||
| 371 | 369 | |
| 372 | 370 | void nf_conntrack_ecache_pernet_init(struct net *net) |
| 373 | 371 | { |
| 374 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 372 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 375 | 373 | |
| 376 | 374 | net->ct.sysctl_events = nf_ct_events; |
| 377 | 375 | cnet->ct_net = &net->ct; |
| @@ -380,7 +378,7 @@ void nf_conntrack_ecache_pernet_init(struct net *net) · 2 unmodified lines | ||
| 380 | 378 | |
| 381 | 379 | void nf_conntrack_ecache_pernet_fini(struct net *net) |
| 382 | 380 | { |
| 383 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 381 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 384 | 382 | |
| 385 | 383 | cancel_delayed_work_sync(&cnet->ecache_dwork); |
| 386 | 384 | } |
| @@ -43,8 +43,6 @@ unsigned int nf_ct_expect_max __read_mostly; · 42 unmodified lines | ||
| 43 | 43 | static struct kmem_cache *nf_ct_expect_cachep __read_mostly; |
| 44 | 44 | static unsigned int nf_ct_expect_hashrnd __read_mostly; |
| 45 | 45 | |
| 46 | −extern unsigned int nf_conntrack_net_id; | |
| 47 | − | |
| 48 | 46 | /* nf_conntrack_expect helper functions */ |
| 49 | 47 | void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, |
| 50 | 48 | u32 portid, int report) |
| @@ -58,7 +56,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, · 7 unmodified lines | ||
| 58 | 56 | |
| 59 | 57 | hlist_del_rcu(&exp->hnode); |
| 60 | 58 | |
| 61 | − cnet = net_generic(net, nf_conntrack_net_id); | |
| 59 | + cnet = nf_ct_pernet(net); | |
| 62 | 60 | cnet->expect_count--; |
| 63 | 61 | |
| 64 | 62 | hlist_del_rcu(&exp->lnode); |
| @@ -123,7 +121,7 @@ __nf_ct_expect_find(struct net *net, · 58 unmodified lines | ||
| 123 | 121 | const struct nf_conntrack_zone *zone, |
| 124 | 122 | const struct nf_conntrack_tuple *tuple) |
| 125 | 123 | { |
| 126 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 124 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 127 | 125 | struct nf_conntrack_expect *i; |
| 128 | 126 | unsigned int h; |
| 129 | 127 | |
| @@ -164,7 +162,7 @@ nf_ct_find_expectation(struct net *net, · 34 unmodified lines | ||
| 164 | 162 | const struct nf_conntrack_zone *zone, |
| 165 | 163 | const struct nf_conntrack_tuple *tuple) |
| 166 | 164 | { |
| 167 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 165 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 168 | 166 | struct nf_conntrack_expect *i, *exp = NULL; |
| 169 | 167 | unsigned int h; |
| 170 | 168 | |
| @@ -397,7 +395,7 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) · 226 unmodified lines | ||
| 397 | 395 | master_help->expecting[exp->class]++; |
| 398 | 396 | |
| 399 | 397 | hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]); |
| 400 | − cnet = net_generic(net, nf_conntrack_net_id); | |
| 398 | + cnet = nf_ct_pernet(net); | |
| 401 | 399 | cnet->expect_count++; |
| 402 | 400 | |
| 403 | 401 | NF_CT_STAT_INC(net, expect_create); |
| @@ -468,7 +466,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect, · 64 unmodified lines | ||
| 468 | 466 | } |
| 469 | 467 | } |
| 470 | 468 | |
| 471 | − cnet = net_generic(net, nf_conntrack_net_id); | |
| 469 | + cnet = nf_ct_pernet(net); | |
| 472 | 470 | if (cnet->expect_count >= nf_ct_expect_max) { |
| 473 | 471 | net_warn_ratelimited("nf_conntrack: expectation table full\n"); |
| 474 | 472 | ret = -EMFILE; |
| @@ -43,8 +43,6 @@ MODULE_PARM_DESC(nf_conntrack_helper, · 42 unmodified lines | ||
| 43 | 43 | static DEFINE_MUTEX(nf_ct_nat_helpers_mutex); |
| 44 | 44 | static struct list_head nf_ct_nat_helpers __read_mostly; |
| 45 | 45 | |
| 46 | −extern unsigned int nf_conntrack_net_id; | |
| 47 | − | |
| 48 | 46 | /* Stupid hash, but collision free for the default registrations of the |
| 49 | 47 | * helpers currently in the kernel. */ |
| 50 | 48 | static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple) |
| @@ -214,7 +212,7 @@ EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); · 163 unmodified lines | ||
| 214 | 212 | static struct nf_conntrack_helper * |
| 215 | 213 | nf_ct_lookup_helper(struct nf_conn *ct, struct net *net) |
| 216 | 214 | { |
| 217 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 215 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 218 | 216 | |
| 219 | 217 | if (!cnet->sysctl_auto_assign_helper) { |
| 220 | 218 | if (cnet->auto_assign_helper_warned) |
| @@ -560,7 +558,7 @@ static const struct nf_ct_ext_type helper_extend = { · 339 unmodified lines | ||
| 560 | 558 | |
| 561 | 559 | void nf_conntrack_helper_pernet_init(struct net *net) |
| 562 | 560 | { |
| 563 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 561 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 564 | 562 | |
| 565 | 563 | cnet->sysctl_auto_assign_helper = nf_ct_auto_assign_helper; |
| 566 | 564 | } |
| @@ -1528,7 +1528,7 @@ static int ctnetlink_del_conntrack(struct sk_buff *skb, · 1527 unmodified lines | ||
| 1528 | 1528 | const struct nfnl_info *info, |
| 1529 | 1529 | const struct nlattr * const cda[]) |
| 1530 | 1530 | { |
| 1531 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 1531 | + u8 family = info->nfmsg->nfgen_family; | |
| 1532 | 1532 | struct nf_conntrack_tuple_hash *h; |
| 1533 | 1533 | struct nf_conntrack_tuple tuple; |
| 1534 | 1534 | struct nf_conntrack_zone zone; |
| @@ -1541,12 +1541,12 @@ static int ctnetlink_del_conntrack(struct sk_buff *skb, · 6 unmodified lines | ||
| 1541 | 1541 | |
| 1542 | 1542 | if (cda[CTA_TUPLE_ORIG]) |
| 1543 | 1543 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, |
| 1544 | − nfmsg->nfgen_family, &zone); | |
| 1544 | + family, &zone); | |
| 1545 | 1545 | else if (cda[CTA_TUPLE_REPLY]) |
| 1546 | 1546 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, |
| 1547 | − nfmsg->nfgen_family, &zone); | |
| 1547 | + family, &zone); | |
| 1548 | 1548 | else { |
| 1549 | − u_int8_t u3 = nfmsg->version ? nfmsg->nfgen_family : AF_UNSPEC; | |
| 1549 | + u_int8_t u3 = info->nfmsg->version ? family : AF_UNSPEC; | |
| 1550 | 1550 | |
| 1551 | 1551 | return ctnetlink_flush_conntrack(info->net, cda, |
| 1552 | 1552 | NETLINK_CB(skb).portid, |
| @@ -1586,8 +1586,7 @@ static int ctnetlink_get_conntrack(struct sk_buff *skb, · 33 unmodified lines | ||
| 1586 | 1586 | const struct nfnl_info *info, |
| 1587 | 1587 | const struct nlattr * const cda[]) |
| 1588 | 1588 | { |
| 1589 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 1590 | − u_int8_t u3 = nfmsg->nfgen_family; | |
| 1589 | + u_int8_t u3 = info->nfmsg->nfgen_family; | |
| 1591 | 1590 | struct nf_conntrack_tuple_hash *h; |
| 1592 | 1591 | struct nf_conntrack_tuple tuple; |
| 1593 | 1592 | struct nf_conntrack_zone zone; |
| @@ -2363,10 +2362,9 @@ static int ctnetlink_new_conntrack(struct sk_buff *skb, · 769 unmodified lines | ||
| 2363 | 2362 | const struct nfnl_info *info, |
| 2364 | 2363 | const struct nlattr * const cda[]) |
| 2365 | 2364 | { |
| 2366 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 2367 | 2365 | struct nf_conntrack_tuple otuple, rtuple; |
| 2368 | 2366 | struct nf_conntrack_tuple_hash *h = NULL; |
| 2369 | − u_int8_t u3 = nfmsg->nfgen_family; | |
| 2367 | + u_int8_t u3 = info->nfmsg->nfgen_family; | |
| 2370 | 2368 | struct nf_conntrack_zone zone; |
| 2371 | 2369 | struct nf_conn *ct; |
| 2372 | 2370 | int err; |
| @@ -3259,8 +3257,7 @@ static int ctnetlink_get_expect(struct sk_buff *skb, · 886 unmodified lines | ||
| 3259 | 3257 | const struct nfnl_info *info, |
| 3260 | 3258 | const struct nlattr * const cda[]) |
| 3261 | 3259 | { |
| 3262 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 3263 | − u_int8_t u3 = nfmsg->nfgen_family; | |
| 3260 | + u_int8_t u3 = info->nfmsg->nfgen_family; | |
| 3264 | 3261 | struct nf_conntrack_tuple tuple; |
| 3265 | 3262 | struct nf_conntrack_expect *exp; |
| 3266 | 3263 | struct nf_conntrack_zone zone; |
| @@ -3349,8 +3346,7 @@ static int ctnetlink_del_expect(struct sk_buff *skb, · 82 unmodified lines | ||
| 3349 | 3346 | const struct nfnl_info *info, |
| 3350 | 3347 | const struct nlattr * const cda[]) |
| 3351 | 3348 | { |
| 3352 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 3353 | − u_int8_t u3 = nfmsg->nfgen_family; | |
| 3349 | + u_int8_t u3 = info->nfmsg->nfgen_family; | |
| 3354 | 3350 | struct nf_conntrack_expect *exp; |
| 3355 | 3351 | struct nf_conntrack_tuple tuple; |
| 3356 | 3352 | struct nf_conntrack_zone zone; |
| @@ -3601,8 +3597,7 @@ static int ctnetlink_new_expect(struct sk_buff *skb, · 244 unmodified lines | ||
| 3601 | 3597 | const struct nfnl_info *info, |
| 3602 | 3598 | const struct nlattr * const cda[]) |
| 3603 | 3599 | { |
| 3604 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 3605 | − u_int8_t u3 = nfmsg->nfgen_family; | |
| 3600 | + u_int8_t u3 = info->nfmsg->nfgen_family; | |
| 3606 | 3601 | struct nf_conntrack_tuple tuple; |
| 3607 | 3602 | struct nf_conntrack_expect *exp; |
| 3608 | 3603 | struct nf_conntrack_zone zone; |
| @@ -42,8 +42,6 @@ · 41 unmodified lines | ||
| 42 | 42 | #include <net/ipv6.h> |
| 43 | 43 | #include <net/inet_frag.h> |
| 44 | 44 | |
| 45 | −extern unsigned int nf_conntrack_net_id; | |
| 46 | − | |
| 47 | 45 | static DEFINE_MUTEX(nf_ct_proto_mutex); |
| 48 | 46 | |
| 49 | 47 | #ifdef CONFIG_SYSCTL |
| @@ -446,7 +444,7 @@ static struct nf_ct_bridge_info *nf_ct_bridge_info; · 396 unmodified lines | ||
| 446 | 444 | |
| 447 | 445 | static int nf_ct_netns_do_get(struct net *net, u8 nfproto) |
| 448 | 446 | { |
| 449 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 447 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 450 | 448 | bool fixup_needed = false, retry = true; |
| 451 | 449 | int err = 0; |
| 452 | 450 | retry: |
| @@ -531,7 +529,7 @@ retry: · 78 unmodified lines | ||
| 531 | 529 | |
| 532 | 530 | static void nf_ct_netns_do_put(struct net *net, u8 nfproto) |
| 533 | 531 | { |
| 534 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 532 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 535 | 533 | |
| 536 | 534 | mutex_lock(&nf_ct_proto_mutex); |
| 537 | 535 | switch (nfproto) { |
| @@ -1441,6 +1441,11 @@ void nf_conntrack_tcp_init_net(struct net *net) · 1440 unmodified lines | ||
| 1441 | 1441 | * will be started. |
| 1442 | 1442 | */ |
| 1443 | 1443 | tn->tcp_max_retrans = 3; |
| 1444 | + | |
| 1445 | +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
| 1446 | + tn->offload_timeout = 30 * HZ; | |
| 1447 | + tn->offload_pickup = 120 * HZ; | |
| 1448 | +#endif | |
| 1444 | 1449 | } |
| 1445 | 1450 | |
| 1446 | 1451 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp = |
| @@ -270,6 +270,11 @@ void nf_conntrack_udp_init_net(struct net *net) · 269 unmodified lines | ||
| 270 | 270 | |
| 271 | 271 | for (i = 0; i < UDP_CT_MAX; i++) |
| 272 | 272 | un->timeouts[i] = udp_timeouts[i]; |
| 273 | + | |
| 274 | +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
| 275 | + un->offload_timeout = 30 * HZ; | |
| 276 | + un->offload_pickup = 30 * HZ; | |
| 277 | +#endif | |
| 273 | 278 | } |
| 274 | 279 | |
| 275 | 280 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp = |
| @@ -512,9 +512,7 @@ static void nf_conntrack_standalone_fini_proc(struct net *net) · 511 unmodified lines | ||
| 512 | 512 | |
| 513 | 513 | u32 nf_conntrack_count(const struct net *net) |
| 514 | 514 | { |
| 515 | − const struct nf_conntrack_net *cnet; | |
| 516 | − | |
| 517 | − cnet = net_generic(net, nf_conntrack_net_id); | |
| 515 | + const struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 518 | 516 | |
| 519 | 517 | return atomic_read(&cnet->count); |
| 520 | 518 | } |
| @@ -575,11 +573,19 @@ enum nf_ct_sysctl_index { · 54 unmodified lines | ||
| 575 | 573 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_CLOSE, |
| 576 | 574 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_RETRANS, |
| 577 | 575 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_UNACK, |
| 576 | +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
| 577 | + NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD, | |
| 578 | + NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD_PICKUP, | |
| 579 | +#endif | |
| 578 | 580 | NF_SYSCTL_CT_PROTO_TCP_LOOSE, |
| 579 | 581 | NF_SYSCTL_CT_PROTO_TCP_LIBERAL, |
| 580 | 582 | NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS, |
| 581 | 583 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP, |
| 582 | 584 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM, |
| 585 | +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
| 586 | + NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD, | |
| 587 | + NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD_PICKUP, | |
| 588 | +#endif | |
| 583 | 589 | NF_SYSCTL_CT_PROTO_TIMEOUT_ICMP, |
| 584 | 590 | NF_SYSCTL_CT_PROTO_TIMEOUT_ICMPV6, |
| 585 | 591 | #ifdef CONFIG_NF_CT_PROTO_SCTP |
| @@ -762,6 +768,20 @@ static struct ctl_table nf_ct_sysctl_table[] = { · 176 unmodified lines | ||
| 762 | 768 | .mode = 0644, |
| 763 | 769 | .proc_handler = proc_dointvec_jiffies, |
| 764 | 770 | }, |
| 771 | +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
| 772 | + [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD] = { | |
| 773 | + .procname = "nf_flowtable_tcp_timeout", | |
| 774 | + .maxlen = sizeof(unsigned int), | |
| 775 | + .mode = 0644, | |
| 776 | + .proc_handler = proc_dointvec_jiffies, | |
| 777 | + }, | |
| 778 | + [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD_PICKUP] = { | |
| 779 | + .procname = "nf_flowtable_tcp_pickup", | |
| 780 | + .maxlen = sizeof(unsigned int), | |
| 781 | + .mode = 0644, | |
| 782 | + .proc_handler = proc_dointvec_jiffies, | |
| 783 | + }, | |
| 784 | +#endif | |
| 765 | 785 | [NF_SYSCTL_CT_PROTO_TCP_LOOSE] = { |
| 766 | 786 | .procname = "nf_conntrack_tcp_loose", |
| 767 | 787 | .maxlen = sizeof(u8), |
| @@ -796,6 +816,20 @@ static struct ctl_table nf_ct_sysctl_table[] = { · 28 unmodified lines | ||
| 796 | 816 | .mode = 0644, |
| 797 | 817 | .proc_handler = proc_dointvec_jiffies, |
| 798 | 818 | }, |
| 819 | +#if IS_ENABLED(CONFIG_NFT_FLOW_OFFLOAD) | |
| 820 | + [NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD] = { | |
| 821 | + .procname = "nf_flowtable_udp_timeout", | |
| 822 | + .maxlen = sizeof(unsigned int), | |
| 823 | + .mode = 0644, | |
| 824 | + .proc_handler = proc_dointvec_jiffies, | |
| 825 | + }, | |
| 826 | + [NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD_PICKUP] = { | |
| 827 | + .procname = "nf_flowtable_udp_pickup", | |
| 828 | + .maxlen = sizeof(unsigned int), | |
| 829 | + .mode = 0644, | |
| 830 | + .proc_handler = proc_dointvec_jiffies, | |
| 831 | + }, | |
| 832 | +#endif | |
| 799 | 833 | [NF_SYSCTL_CT_PROTO_TIMEOUT_ICMP] = { |
| 800 | 834 | .procname = "nf_conntrack_icmp_timeout", |
| 801 | 835 | .maxlen = sizeof(unsigned int), |
| @@ -971,6 +1005,12 @@ static void nf_conntrack_standalone_init_tcp_sysctl(struct net *net, · 169 unmodified lines | ||
| 971 | 1005 | XASSIGN(LIBERAL, &tn->tcp_be_liberal); |
| 972 | 1006 | XASSIGN(MAX_RETRANS, &tn->tcp_max_retrans); |
| 973 | 1007 | #undef XASSIGN |
| 1008 | + | |
| 1009 | +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
| 1010 | + table[NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD].data = &tn->offload_timeout; | |
| 1011 | + table[NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD_PICKUP].data = &tn->offload_pickup; | |
| 1012 | +#endif | |
| 1013 | + | |
| 974 | 1014 | } |
| 975 | 1015 | |
| 976 | 1016 | 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, · 55 unmodified lines | ||
| 1032 | 1072 | |
| 1033 | 1073 | static int nf_conntrack_standalone_init_sysctl(struct net *net) |
| 1034 | 1074 | { |
| 1035 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 1075 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 1036 | 1076 | struct nf_udp_net *un = nf_udp_pernet(net); |
| 1037 | 1077 | struct ctl_table *table; |
| 1038 | 1078 | |
| @@ -1059,6 +1099,10 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net) · 20 unmodified lines | ||
| 1059 | 1099 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_ICMPV6].data = &nf_icmpv6_pernet(net)->timeout; |
| 1060 | 1100 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP].data = &un->timeouts[UDP_CT_UNREPLIED]; |
| 1061 | 1101 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM].data = &un->timeouts[UDP_CT_REPLIED]; |
| 1102 | +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
| 1103 | + table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD].data = &un->offload_timeout; | |
| 1104 | + table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD_PICKUP].data = &un->offload_pickup; | |
| 1105 | +#endif | |
| 1062 | 1106 | |
| 1063 | 1107 | nf_conntrack_standalone_init_tcp_sysctl(net, table); |
| 1064 | 1108 | nf_conntrack_standalone_init_sctp_sysctl(net, table); |
| @@ -1085,7 +1129,7 @@ out_unregister_netfilter: · 20 unmodified lines | ||
| 1085 | 1129 | |
| 1086 | 1130 | static void nf_conntrack_standalone_fini_sysctl(struct net *net) |
| 1087 | 1131 | { |
| 1088 | − struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id); | |
| 1132 | + struct nf_conntrack_net *cnet = nf_ct_pernet(net); | |
| 1089 | 1133 | struct ctl_table *table; |
| 1090 | 1134 | |
| 1091 | 1135 | table = cnet->sysctl_header->ctl_table_arg; |
| @@ -178,12 +178,10 @@ static void flow_offload_fixup_tcp(struct ip_ct_tcp *tcp) · 177 unmodified lines | ||
| 178 | 178 | tcp->seen[1].td_maxwin = 0; |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | −#define NF_FLOWTABLE_TCP_PICKUP_TIMEOUT (120 * HZ) | |
| 182 | −#define NF_FLOWTABLE_UDP_PICKUP_TIMEOUT (30 * HZ) | |
| 183 | − | |
| 184 | 181 | static void flow_offload_fixup_ct_timeout(struct nf_conn *ct) |
| 185 | 182 | { |
| 186 | 183 | const struct nf_conntrack_l4proto *l4proto; |
| 184 | + struct net *net = nf_ct_net(ct); | |
| 187 | 185 | int l4num = nf_ct_protonum(ct); |
| 188 | 186 | unsigned int timeout; |
| 189 | 187 | |
| @@ -191,12 +189,17 @@ static void flow_offload_fixup_ct_timeout(struct nf_conn *ct) · 1 unmodified line | ||
| 191 | 189 | if (!l4proto) |
| 192 | 190 | return; |
| 193 | 191 | |
| 194 | − if (l4num == IPPROTO_TCP) | |
| 195 | − timeout = NF_FLOWTABLE_TCP_PICKUP_TIMEOUT; | |
| 196 | − else if (l4num == IPPROTO_UDP) | |
| 197 | − timeout = NF_FLOWTABLE_UDP_PICKUP_TIMEOUT; | |
| 198 | − else | |
| 192 | + if (l4num == IPPROTO_TCP) { | |
| 193 | + struct nf_tcp_net *tn = nf_tcp_pernet(net); | |
| 194 | + | |
| 195 | + timeout = tn->offload_pickup; | |
| 196 | + } else if (l4num == IPPROTO_UDP) { | |
| 197 | + struct nf_udp_net *tn = nf_udp_pernet(net); | |
| 198 | + | |
| 199 | + timeout = tn->offload_pickup; | |
| 200 | + } else { | |
| 199 | 201 | return; |
| 202 | + } | |
| 200 | 203 | |
| 201 | 204 | if (nf_flow_timeout_delta(ct->timeout) > (__s32)timeout) |
| 202 | 205 | ct->timeout = nfct_time_stamp + timeout; |
| @@ -268,11 +271,35 @@ static const struct rhashtable_params nf_flow_offload_rhash_params = { · 65 unmodified lines | ||
| 268 | 271 | .automatic_shrinking = true, |
| 269 | 272 | }; |
| 270 | 273 | |
| 274 | +unsigned long flow_offload_get_timeout(struct flow_offload *flow) | |
| 275 | +{ | |
| 276 | + const struct nf_conntrack_l4proto *l4proto; | |
| 277 | + unsigned long timeout = NF_FLOW_TIMEOUT; | |
| 278 | + struct net *net = nf_ct_net(flow->ct); | |
| 279 | + int l4num = nf_ct_protonum(flow->ct); | |
| 280 | + | |
| 281 | + l4proto = nf_ct_l4proto_find(l4num); | |
| 282 | + if (!l4proto) | |
| 283 | + return timeout; | |
| 284 | + | |
| 285 | + if (l4num == IPPROTO_TCP) { | |
| 286 | + struct nf_tcp_net *tn = nf_tcp_pernet(net); | |
| 287 | + | |
| 288 | + timeout = tn->offload_timeout; | |
| 289 | + } else if (l4num == IPPROTO_UDP) { | |
| 290 | + struct nf_udp_net *tn = nf_udp_pernet(net); | |
| 291 | + | |
| 292 | + timeout = tn->offload_timeout; | |
| 293 | + } | |
| 294 | + | |
| 295 | + return timeout; | |
| 296 | +} | |
| 297 | + | |
| 271 | 298 | int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) |
| 272 | 299 | { |
| 273 | 300 | int err; |
| 274 | 301 | |
| 275 | − flow->timeout = nf_flowtable_time_stamp + NF_FLOW_TIMEOUT; | |
| 302 | + flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow); | |
| 276 | 303 | |
| 277 | 304 | err = rhashtable_insert_fast(&flow_table->rhashtable, |
| 278 | 305 | &flow->tuplehash[0].node, |
| @@ -304,7 +331,7 @@ EXPORT_SYMBOL_GPL(flow_offload_add); · 25 unmodified lines | ||
| 304 | 331 | void flow_offload_refresh(struct nf_flowtable *flow_table, |
| 305 | 332 | struct flow_offload *flow) |
| 306 | 333 | { |
| 307 | − flow->timeout = nf_flowtable_time_stamp + NF_FLOW_TIMEOUT; | |
| 334 | + flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow); | |
| 308 | 335 | |
| 309 | 336 | if (likely(!nf_flowtable_hw_offload(flow_table))) |
| 310 | 337 | return; |
| @@ -937,7 +937,7 @@ static void flow_offload_work_stats(struct flow_offload_work *offload) · 936 unmodified lines | ||
| 937 | 937 | |
| 938 | 938 | lastused = max_t(u64, stats[0].lastused, stats[1].lastused); |
| 939 | 939 | offload->flow->timeout = max_t(u64, offload->flow->timeout, |
| 940 | − lastused + NF_FLOW_TIMEOUT); | |
| 940 | + lastused + flow_offload_get_timeout(offload->flow)); | |
| 941 | 941 | |
| 942 | 942 | if (offload->flowtable->flags & NF_FLOWTABLE_COUNTER) { |
| 943 | 943 | if (stats[0].pkts) |
| @@ -1041,7 +1041,7 @@ void nf_flow_offload_stats(struct nf_flowtable *flowtable, · 97 unmodified lines | ||
| 1041 | 1041 | __s32 delta; |
| 1042 | 1042 | |
| 1043 | 1043 | delta = nf_flow_timeout_delta(flow->timeout); |
| 1044 | − if ((delta >= (9 * NF_FLOW_TIMEOUT) / 10)) | |
| 1044 | + if ((delta >= (9 * flow_offload_get_timeout(flow)) / 10)) | |
| 1045 | 1045 | return; |
| 1046 | 1046 | |
| 1047 | 1047 | 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, · 861 unmodified lines | ||
| 862 | 862 | static int nf_tables_gettable(struct sk_buff *skb, const struct nfnl_info *info, |
| 863 | 863 | const struct nlattr * const nla[]) |
| 864 | 864 | { |
| 865 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 866 | 865 | struct netlink_ext_ack *extack = info->extack; |
| 867 | 866 | u8 genmask = nft_genmask_cur(info->net); |
| 868 | − int family = nfmsg->nfgen_family; | |
| 867 | + u8 family = info->nfmsg->nfgen_family; | |
| 869 | 868 | const struct nft_table *table; |
| 870 | 869 | struct net *net = info->net; |
| 871 | 870 | struct sk_buff *skb2; |
| @@ -1068,10 +1067,9 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info, · 196 unmodified lines | ||
| 1068 | 1067 | const struct nlattr * const nla[]) |
| 1069 | 1068 | { |
| 1070 | 1069 | struct nftables_pernet *nft_net = nft_pernet(info->net); |
| 1071 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 1072 | 1070 | struct netlink_ext_ack *extack = info->extack; |
| 1073 | 1071 | u8 genmask = nft_genmask_next(info->net); |
| 1074 | − int family = nfmsg->nfgen_family; | |
| 1072 | + u8 family = info->nfmsg->nfgen_family; | |
| 1075 | 1073 | struct net *net = info->net; |
| 1076 | 1074 | const struct nlattr *attr; |
| 1077 | 1075 | struct nft_table *table; |
| @@ -1263,10 +1261,9 @@ out: · 185 unmodified lines | ||
| 1263 | 1261 | static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info, |
| 1264 | 1262 | const struct nlattr * const nla[]) |
| 1265 | 1263 | { |
| 1266 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 1267 | 1264 | struct netlink_ext_ack *extack = info->extack; |
| 1268 | 1265 | u8 genmask = nft_genmask_next(info->net); |
| 1269 | − int family = nfmsg->nfgen_family; | |
| 1266 | + u8 family = info->nfmsg->nfgen_family; | |
| 1270 | 1267 | struct net *net = info->net; |
| 1271 | 1268 | const struct nlattr *attr; |
| 1272 | 1269 | struct nft_table *table; |
| @@ -1636,10 +1633,9 @@ done: · 363 unmodified lines | ||
| 1636 | 1633 | static int nf_tables_getchain(struct sk_buff *skb, const struct nfnl_info *info, |
| 1637 | 1634 | const struct nlattr * const nla[]) |
| 1638 | 1635 | { |
| 1639 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 1640 | 1636 | struct netlink_ext_ack *extack = info->extack; |
| 1641 | 1637 | u8 genmask = nft_genmask_cur(info->net); |
| 1642 | − int family = nfmsg->nfgen_family; | |
| 1638 | + u8 family = info->nfmsg->nfgen_family; | |
| 1643 | 1639 | const struct nft_chain *chain; |
| 1644 | 1640 | struct net *net = info->net; |
| 1645 | 1641 | struct nft_table *table; |
| @@ -2015,11 +2011,12 @@ static void nft_basechain_hook_init(struct nf_hook_ops *ops, u8 family, · 369 unmodified lines | ||
| 2015 | 2011 | const struct nft_chain_hook *hook, |
| 2016 | 2012 | struct nft_chain *chain) |
| 2017 | 2013 | { |
| 2018 | − ops->pf = family; | |
| 2019 | − ops->hooknum = hook->num; | |
| 2020 | − ops->priority = hook->priority; | |
| 2021 | − ops->priv = chain; | |
| 2022 | − ops->hook = hook->type->hooks[ops->hooknum]; | |
| 2014 | + ops->pf = family; | |
| 2015 | + ops->hooknum = hook->num; | |
| 2016 | + ops->priority = hook->priority; | |
| 2017 | + ops->priv = chain; | |
| 2018 | + ops->hook = hook->type->hooks[ops->hooknum]; | |
| 2019 | + ops->hook_ops_type = NF_HOOK_OP_NF_TABLES; | |
| 2023 | 2020 | } |
| 2024 | 2021 | |
| 2025 | 2022 | 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, · 345 unmodified lines | ||
| 2371 | 2368 | const struct nlattr * const nla[]) |
| 2372 | 2369 | { |
| 2373 | 2370 | struct nftables_pernet *nft_net = nft_pernet(info->net); |
| 2374 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 2375 | 2371 | struct netlink_ext_ack *extack = info->extack; |
| 2376 | 2372 | u8 genmask = nft_genmask_next(info->net); |
| 2377 | − int family = nfmsg->nfgen_family; | |
| 2373 | + u8 family = info->nfmsg->nfgen_family; | |
| 2378 | 2374 | struct nft_chain *chain = NULL; |
| 2379 | 2375 | struct net *net = info->net; |
| 2380 | 2376 | const struct nlattr *attr; |
| @@ -2469,10 +2465,9 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info, · 88 unmodified lines | ||
| 2469 | 2465 | static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info, |
| 2470 | 2466 | const struct nlattr * const nla[]) |
| 2471 | 2467 | { |
| 2472 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 2473 | 2468 | struct netlink_ext_ack *extack = info->extack; |
| 2474 | 2469 | u8 genmask = nft_genmask_next(info->net); |
| 2475 | − int family = nfmsg->nfgen_family; | |
| 2470 | + u8 family = info->nfmsg->nfgen_family; | |
| 2476 | 2471 | struct net *net = info->net; |
| 2477 | 2472 | const struct nlattr *attr; |
| 2478 | 2473 | struct nft_table *table; |
| @@ -3096,10 +3091,9 @@ static int nf_tables_dump_rules_done(struct netlink_callback *cb) · 617 unmodified lines | ||
| 3096 | 3091 | static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info, |
| 3097 | 3092 | const struct nlattr * const nla[]) |
| 3098 | 3093 | { |
| 3099 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 3100 | 3094 | struct netlink_ext_ack *extack = info->extack; |
| 3101 | 3095 | u8 genmask = nft_genmask_cur(info->net); |
| 3102 | − int family = nfmsg->nfgen_family; | |
| 3096 | + u8 family = info->nfmsg->nfgen_family; | |
| 3103 | 3097 | const struct nft_chain *chain; |
| 3104 | 3098 | const struct nft_rule *rule; |
| 3105 | 3099 | struct net *net = info->net; |
| @@ -3237,13 +3231,12 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info, · 131 unmodified lines | ||
| 3237 | 3231 | const struct nlattr * const nla[]) |
| 3238 | 3232 | { |
| 3239 | 3233 | struct nftables_pernet *nft_net = nft_pernet(info->net); |
| 3240 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 3241 | 3234 | struct netlink_ext_ack *extack = info->extack; |
| 3242 | 3235 | unsigned int size, i, n, ulen = 0, usize = 0; |
| 3243 | 3236 | u8 genmask = nft_genmask_next(info->net); |
| 3244 | 3237 | struct nft_rule *rule, *old_rule = NULL; |
| 3245 | 3238 | struct nft_expr_info *expr_info = NULL; |
| 3246 | − int family = nfmsg->nfgen_family; | |
| 3239 | + u8 family = info->nfmsg->nfgen_family; | |
| 3247 | 3240 | struct net *net = info->net; |
| 3248 | 3241 | struct nft_flow_rule *flow; |
| 3249 | 3242 | struct nft_userdata *udata; |
| @@ -3477,15 +3470,15 @@ static struct nft_rule *nft_rule_lookup_byid(const struct net *net, · 227 unmodified lines | ||
| 3477 | 3470 | static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info, |
| 3478 | 3471 | const struct nlattr * const nla[]) |
| 3479 | 3472 | { |
| 3480 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 3481 | 3473 | struct netlink_ext_ack *extack = info->extack; |
| 3482 | − int family = nfmsg->nfgen_family, err = 0; | |
| 3483 | 3474 | u8 genmask = nft_genmask_next(info->net); |
| 3475 | + u8 family = info->nfmsg->nfgen_family; | |
| 3484 | 3476 | struct nft_chain *chain = NULL; |
| 3485 | 3477 | struct net *net = info->net; |
| 3486 | 3478 | struct nft_table *table; |
| 3487 | 3479 | struct nft_rule *rule; |
| 3488 | 3480 | struct nft_ctx ctx; |
| 3481 | + int err = 0; | |
| 3489 | 3482 | |
| 3490 | 3483 | table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask, |
| 3491 | 3484 | NETLINK_CB(skb).portid); |
| @@ -3665,30 +3658,6 @@ static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = { · 173 unmodified lines | ||
| 3665 | 3658 | [NFTA_SET_DESC_CONCAT] = { .type = NLA_NESTED }, |
| 3666 | 3659 | }; |
| 3667 | 3660 | |
| 3668 | −static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net, | |
| 3669 | − const struct sk_buff *skb, | |
| 3670 | − const struct nlmsghdr *nlh, | |
| 3671 | − const struct nlattr * const nla[], | |
| 3672 | − struct netlink_ext_ack *extack, | |
| 3673 | − u8 genmask, u32 nlpid) | |
| 3674 | −{ | |
| 3675 | − const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | |
| 3676 | − int family = nfmsg->nfgen_family; | |
| 3677 | − struct nft_table *table = NULL; | |
| 3678 | − | |
| 3679 | − if (nla[NFTA_SET_TABLE] != NULL) { | |
| 3680 | − table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, | |
| 3681 | − genmask, nlpid); | |
| 3682 | − if (IS_ERR(table)) { | |
| 3683 | − NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]); | |
| 3684 | − return PTR_ERR(table); | |
| 3685 | − } | |
| 3686 | − } | |
| 3687 | − | |
| 3688 | − nft_ctx_init(ctx, net, skb, nlh, family, table, NULL, nla); | |
| 3689 | − return 0; | |
| 3690 | −} | |
| 3691 | − | |
| 3692 | 3661 | static struct nft_set *nft_set_lookup(const struct nft_table *table, |
| 3693 | 3662 | const struct nlattr *nla, u8 genmask) |
| 3694 | 3663 | { |
| @@ -4068,20 +4037,26 @@ static int nf_tables_dump_sets_done(struct netlink_callback *cb) · 373 unmodified lines | ||
| 4068 | 4037 | static int nf_tables_getset(struct sk_buff *skb, const struct nfnl_info *info, |
| 4069 | 4038 | const struct nlattr * const nla[]) |
| 4070 | 4039 | { |
| 4071 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 4072 | 4040 | struct netlink_ext_ack *extack = info->extack; |
| 4073 | 4041 | u8 genmask = nft_genmask_cur(info->net); |
| 4042 | + u8 family = info->nfmsg->nfgen_family; | |
| 4043 | + struct nft_table *table = NULL; | |
| 4074 | 4044 | struct net *net = info->net; |
| 4075 | 4045 | const struct nft_set *set; |
| 4076 | 4046 | struct sk_buff *skb2; |
| 4077 | 4047 | struct nft_ctx ctx; |
| 4078 | 4048 | int err; |
| 4079 | 4049 | |
| 4080 | − /* Verify existence before starting dump */ | |
| 4081 | − err = nft_ctx_init_from_setattr(&ctx, net, skb, info->nlh, nla, extack, | |
| 4082 | − genmask, 0); | |
| 4083 | − if (err < 0) | |
| 4084 | − return err; | |
| 4050 | + if (nla[NFTA_SET_TABLE]) { | |
| 4051 | + table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, | |
| 4052 | + genmask, 0); | |
| 4053 | + if (IS_ERR(table)) { | |
| 4054 | + NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]); | |
| 4055 | + return PTR_ERR(table); | |
| 4056 | + } | |
| 4057 | + } | |
| 4058 | + | |
| 4059 | + nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); | |
| 4085 | 4060 | |
| 4086 | 4061 | if (info->nlh->nlmsg_flags & NLM_F_DUMP) { |
| 4087 | 4062 | struct netlink_dump_control c = { |
| @@ -4096,12 +4071,12 @@ static int nf_tables_getset(struct sk_buff *skb, const struct nfnl_info *info, · 8 unmodified lines | ||
| 4096 | 4071 | } |
| 4097 | 4072 | |
| 4098 | 4073 | /* Only accept unspec with dump */ |
| 4099 | − if (nfmsg->nfgen_family == NFPROTO_UNSPEC) | |
| 4074 | + if (info->nfmsg->nfgen_family == NFPROTO_UNSPEC) | |
| 4100 | 4075 | return -EAFNOSUPPORT; |
| 4101 | 4076 | if (!nla[NFTA_SET_TABLE]) |
| 4102 | 4077 | return -EINVAL; |
| 4103 | 4078 | |
| 4104 | − set = nft_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask); | |
| 4079 | + set = nft_set_lookup(table, nla[NFTA_SET_NAME], genmask); | |
| 4105 | 4080 | if (IS_ERR(set)) |
| 4106 | 4081 | return PTR_ERR(set); |
| 4107 | 4082 | |
| @@ -4189,11 +4164,10 @@ static int nf_tables_set_desc_parse(struct nft_set_desc *desc, · 81 unmodified lines | ||
| 4189 | 4164 | static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, |
| 4190 | 4165 | const struct nlattr * const nla[]) |
| 4191 | 4166 | { |
| 4192 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 4193 | 4167 | u32 ktype, dtype, flags, policy, gc_int, objtype; |
| 4194 | 4168 | struct netlink_ext_ack *extack = info->extack; |
| 4195 | 4169 | u8 genmask = nft_genmask_next(info->net); |
| 4196 | − int family = nfmsg->nfgen_family; | |
| 4170 | + u8 family = info->nfmsg->nfgen_family; | |
| 4197 | 4171 | const struct nft_set_ops *ops; |
| 4198 | 4172 | struct nft_expr *expr = NULL; |
| 4199 | 4173 | struct net *net = info->net; |
| @@ -4493,31 +4467,31 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) · 293 unmodified lines | ||
| 4493 | 4467 | static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info, |
| 4494 | 4468 | const struct nlattr * const nla[]) |
| 4495 | 4469 | { |
| 4496 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 4497 | 4470 | struct netlink_ext_ack *extack = info->extack; |
| 4498 | 4471 | u8 genmask = nft_genmask_next(info->net); |
| 4472 | + u8 family = info->nfmsg->nfgen_family; | |
| 4499 | 4473 | struct net *net = info->net; |
| 4500 | 4474 | const struct nlattr *attr; |
| 4475 | + struct nft_table *table; | |
| 4501 | 4476 | struct nft_set *set; |
| 4502 | 4477 | struct nft_ctx ctx; |
| 4503 | − int err; | |
| 4504 | 4478 | |
| 4505 | − if (nfmsg->nfgen_family == NFPROTO_UNSPEC) | |
| 4479 | + if (info->nfmsg->nfgen_family == NFPROTO_UNSPEC) | |
| 4506 | 4480 | return -EAFNOSUPPORT; |
| 4507 | − if (nla[NFTA_SET_TABLE] == NULL) | |
| 4508 | − return -EINVAL; | |
| 4509 | 4481 | |
| 4510 | − err = nft_ctx_init_from_setattr(&ctx, net, skb, info->nlh, nla, extack, | |
| 4511 | − genmask, NETLINK_CB(skb).portid); | |
| 4512 | − if (err < 0) | |
| 4513 | − return err; | |
| 4482 | + table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, | |
| 4483 | + genmask, NETLINK_CB(skb).portid); | |
| 4484 | + if (IS_ERR(table)) { | |
| 4485 | + NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]); | |
| 4486 | + return PTR_ERR(table); | |
| 4487 | + } | |
| 4514 | 4488 | |
| 4515 | 4489 | if (nla[NFTA_SET_HANDLE]) { |
| 4516 | 4490 | attr = nla[NFTA_SET_HANDLE]; |
| 4517 | − set = nft_set_lookup_byhandle(ctx.table, attr, genmask); | |
| 4491 | + set = nft_set_lookup_byhandle(table, attr, genmask); | |
| 4518 | 4492 | } else { |
| 4519 | 4493 | attr = nla[NFTA_SET_NAME]; |
| 4520 | − set = nft_set_lookup(ctx.table, attr, genmask); | |
| 4494 | + set = nft_set_lookup(table, attr, genmask); | |
| 4521 | 4495 | } |
| 4522 | 4496 | |
| 4523 | 4497 | if (IS_ERR(set)) { |
| @@ -4531,6 +4505,8 @@ static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info, · 7 unmodified lines | ||
| 4531 | 4505 | return -EBUSY; |
| 4532 | 4506 | } |
| 4533 | 4507 | |
| 4508 | + nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); | |
| 4509 | + | |
| 4534 | 4510 | return nft_delset(&ctx, set); |
| 4535 | 4511 | } |
| 4536 | 4512 | |
| @@ -4732,28 +4708,6 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + · 195 unmodified lines | ||
| 4732 | 4708 | [NFTA_SET_ELEM_LIST_SET_ID] = { .type = NLA_U32 }, |
| 4733 | 4709 | }; |
| 4734 | 4710 | |
| 4735 | −static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net, | |
| 4736 | − const struct sk_buff *skb, | |
| 4737 | − const struct nlmsghdr *nlh, | |
| 4738 | − const struct nlattr * const nla[], | |
| 4739 | − struct netlink_ext_ack *extack, | |
| 4740 | − u8 genmask, u32 nlpid) | |
| 4741 | −{ | |
| 4742 | − const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | |
| 4743 | − int family = nfmsg->nfgen_family; | |
| 4744 | − struct nft_table *table; | |
| 4745 | − | |
| 4746 | − table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family, | |
| 4747 | − genmask, nlpid); | |
| 4748 | − if (IS_ERR(table)) { | |
| 4749 | − NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]); | |
| 4750 | − return PTR_ERR(table); | |
| 4751 | − } | |
| 4752 | − | |
| 4753 | − nft_ctx_init(ctx, net, skb, nlh, family, table, NULL, nla); | |
| 4754 | − return 0; | |
| 4755 | −} | |
| 4756 | − | |
| 4757 | 4711 | static int nft_set_elem_expr_dump(struct sk_buff *skb, |
| 4758 | 4712 | const struct nft_set *set, |
| 4759 | 4713 | const struct nft_set_ext *ext) |
| @@ -5211,21 +5165,27 @@ static int nf_tables_getsetelem(struct sk_buff *skb, · 451 unmodified lines | ||
| 5211 | 5165 | { |
| 5212 | 5166 | struct netlink_ext_ack *extack = info->extack; |
| 5213 | 5167 | u8 genmask = nft_genmask_cur(info->net); |
| 5168 | + u8 family = info->nfmsg->nfgen_family; | |
| 5214 | 5169 | struct net *net = info->net; |
| 5170 | + struct nft_table *table; | |
| 5215 | 5171 | struct nft_set *set; |
| 5216 | 5172 | struct nlattr *attr; |
| 5217 | 5173 | struct nft_ctx ctx; |
| 5218 | 5174 | int rem, err = 0; |
| 5219 | 5175 | |
| 5220 | − err = nft_ctx_init_from_elemattr(&ctx, net, skb, info->nlh, nla, extack, | |
| 5221 | − genmask, NETLINK_CB(skb).portid); | |
| 5222 | − if (err < 0) | |
| 5223 | − return err; | |
| 5176 | + table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family, | |
| 5177 | + genmask, NETLINK_CB(skb).portid); | |
| 5178 | + if (IS_ERR(table)) { | |
| 5179 | + NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]); | |
| 5180 | + return PTR_ERR(table); | |
| 5181 | + } | |
| 5224 | 5182 | |
| 5225 | − set = nft_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET], genmask); | |
| 5183 | + set = nft_set_lookup(table, nla[NFTA_SET_ELEM_LIST_SET], genmask); | |
| 5226 | 5184 | if (IS_ERR(set)) |
| 5227 | 5185 | return PTR_ERR(set); |
| 5228 | 5186 | |
| 5187 | + nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); | |
| 5188 | + | |
| 5229 | 5189 | if (info->nlh->nlmsg_flags & NLM_F_DUMP) { |
| 5230 | 5190 | struct netlink_dump_control c = { |
| 5231 | 5191 | .start = nf_tables_dump_set_start, |
| @@ -5994,8 +5954,10 @@ static int nf_tables_newsetelem(struct sk_buff *skb, · 762 unmodified lines | ||
| 5994 | 5954 | struct nftables_pernet *nft_net = nft_pernet(info->net); |
| 5995 | 5955 | struct netlink_ext_ack *extack = info->extack; |
| 5996 | 5956 | u8 genmask = nft_genmask_next(info->net); |
| 5957 | + u8 family = info->nfmsg->nfgen_family; | |
| 5997 | 5958 | struct net *net = info->net; |
| 5998 | 5959 | const struct nlattr *attr; |
| 5960 | + struct nft_table *table; | |
| 5999 | 5961 | struct nft_set *set; |
| 6000 | 5962 | struct nft_ctx ctx; |
| 6001 | 5963 | int rem, err; |
| @@ -6003,12 +5965,14 @@ static int nf_tables_newsetelem(struct sk_buff *skb, · 1 unmodified line | ||
| 6003 | 5965 | if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) |
| 6004 | 5966 | return -EINVAL; |
| 6005 | 5967 | |
| 6006 | − err = nft_ctx_init_from_elemattr(&ctx, net, skb, info->nlh, nla, extack, | |
| 6007 | − genmask, NETLINK_CB(skb).portid); | |
| 6008 | − if (err < 0) | |
| 6009 | − return err; | |
| 5968 | + table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family, | |
| 5969 | + genmask, NETLINK_CB(skb).portid); | |
| 5970 | + if (IS_ERR(table)) { | |
| 5971 | + NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]); | |
| 5972 | + return PTR_ERR(table); | |
| 5973 | + } | |
| 6010 | 5974 | |
| 6011 | − set = nft_set_lookup_global(net, ctx.table, nla[NFTA_SET_ELEM_LIST_SET], | |
| 5975 | + set = nft_set_lookup_global(net, table, nla[NFTA_SET_ELEM_LIST_SET], | |
| 6012 | 5976 | nla[NFTA_SET_ELEM_LIST_SET_ID], genmask); |
| 6013 | 5977 | if (IS_ERR(set)) |
| 6014 | 5978 | return PTR_ERR(set); |
| @@ -6016,6 +5980,8 @@ static int nf_tables_newsetelem(struct sk_buff *skb, · 1 unmodified line | ||
| 6016 | 5980 | if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT) |
| 6017 | 5981 | return -EBUSY; |
| 6018 | 5982 | |
| 5983 | + nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); | |
| 5984 | + | |
| 6019 | 5985 | nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { |
| 6020 | 5986 | err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags); |
| 6021 | 5987 | if (err < 0) |
| @@ -6023,7 +5989,7 @@ static int nf_tables_newsetelem(struct sk_buff *skb, · 1 unmodified line | ||
| 6023 | 5989 | } |
| 6024 | 5990 | |
| 6025 | 5991 | if (nft_net->validate_state == NFT_VALIDATE_DO) |
| 6026 | − return nft_table_validate(net, ctx.table); | |
| 5992 | + return nft_table_validate(net, table); | |
| 6027 | 5993 | |
| 6028 | 5994 | return 0; |
| 6029 | 5995 | } |
| @@ -6261,23 +6227,29 @@ static int nf_tables_delsetelem(struct sk_buff *skb, · 231 unmodified lines | ||
| 6261 | 6227 | { |
| 6262 | 6228 | struct netlink_ext_ack *extack = info->extack; |
| 6263 | 6229 | u8 genmask = nft_genmask_next(info->net); |
| 6230 | + u8 family = info->nfmsg->nfgen_family; | |
| 6264 | 6231 | struct net *net = info->net; |
| 6265 | 6232 | const struct nlattr *attr; |
| 6233 | + struct nft_table *table; | |
| 6266 | 6234 | struct nft_set *set; |
| 6267 | 6235 | struct nft_ctx ctx; |
| 6268 | 6236 | int rem, err = 0; |
| 6269 | 6237 | |
| 6270 | − err = nft_ctx_init_from_elemattr(&ctx, net, skb, info->nlh, nla, extack, | |
| 6271 | − genmask, NETLINK_CB(skb).portid); | |
| 6272 | − if (err < 0) | |
| 6273 | − return err; | |
| 6238 | + table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family, | |
| 6239 | + genmask, NETLINK_CB(skb).portid); | |
| 6240 | + if (IS_ERR(table)) { | |
| 6241 | + NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]); | |
| 6242 | + return PTR_ERR(table); | |
| 6243 | + } | |
| 6274 | 6244 | |
| 6275 | − set = nft_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET], genmask); | |
| 6245 | + set = nft_set_lookup(table, nla[NFTA_SET_ELEM_LIST_SET], genmask); | |
| 6276 | 6246 | if (IS_ERR(set)) |
| 6277 | 6247 | return PTR_ERR(set); |
| 6278 | 6248 | if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT) |
| 6279 | 6249 | return -EBUSY; |
| 6280 | 6250 | |
| 6251 | + nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); | |
| 6252 | + | |
| 6281 | 6253 | if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS]) |
| 6282 | 6254 | return nft_set_flush(&ctx, set, genmask); |
| 6283 | 6255 | |
| @@ -6545,11 +6517,10 @@ err_free_trans: · 261 unmodified lines | ||
| 6545 | 6517 | static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info, |
| 6546 | 6518 | const struct nlattr * const nla[]) |
| 6547 | 6519 | { |
| 6548 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 6549 | 6520 | struct netlink_ext_ack *extack = info->extack; |
| 6550 | 6521 | u8 genmask = nft_genmask_next(info->net); |
| 6522 | + u8 family = info->nfmsg->nfgen_family; | |
| 6551 | 6523 | const struct nft_object_type *type; |
| 6552 | − int family = nfmsg->nfgen_family; | |
| 6553 | 6524 | struct net *net = info->net; |
| 6554 | 6525 | struct nft_table *table; |
| 6555 | 6526 | struct nft_object *obj; |
| @@ -6801,10 +6772,9 @@ static int nf_tables_dump_obj_done(struct netlink_callback *cb) · 245 unmodified lines | ||
| 6801 | 6772 | static int nf_tables_getobj(struct sk_buff *skb, const struct nfnl_info *info, |
| 6802 | 6773 | const struct nlattr * const nla[]) |
| 6803 | 6774 | { |
| 6804 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 6805 | 6775 | struct netlink_ext_ack *extack = info->extack; |
| 6806 | 6776 | u8 genmask = nft_genmask_cur(info->net); |
| 6807 | − int family = nfmsg->nfgen_family; | |
| 6777 | + u8 family = info->nfmsg->nfgen_family; | |
| 6808 | 6778 | const struct nft_table *table; |
| 6809 | 6779 | struct net *net = info->net; |
| 6810 | 6780 | struct nft_object *obj; |
| @@ -6891,10 +6861,9 @@ static void nft_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj) · 80 unmodified lines | ||
| 6891 | 6861 | static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info, |
| 6892 | 6862 | const struct nlattr * const nla[]) |
| 6893 | 6863 | { |
| 6894 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 6895 | 6864 | struct netlink_ext_ack *extack = info->extack; |
| 6896 | 6865 | u8 genmask = nft_genmask_next(info->net); |
| 6897 | − int family = nfmsg->nfgen_family; | |
| 6866 | + u8 family = info->nfmsg->nfgen_family; | |
| 6898 | 6867 | struct net *net = info->net; |
| 6899 | 6868 | const struct nlattr *attr; |
| 6900 | 6869 | struct nft_table *table; |
| @@ -7322,12 +7291,11 @@ static int nf_tables_newflowtable(struct sk_buff *skb, · 421 unmodified lines | ||
| 7322 | 7291 | const struct nfnl_info *info, |
| 7323 | 7292 | const struct nlattr * const nla[]) |
| 7324 | 7293 | { |
| 7325 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 7326 | 7294 | struct netlink_ext_ack *extack = info->extack; |
| 7327 | 7295 | struct nft_flowtable_hook flowtable_hook; |
| 7328 | 7296 | u8 genmask = nft_genmask_next(info->net); |
| 7297 | + u8 family = info->nfmsg->nfgen_family; | |
| 7329 | 7298 | const struct nf_flowtable_type *type; |
| 7330 | − int family = nfmsg->nfgen_family; | |
| 7331 | 7299 | struct nft_flowtable *flowtable; |
| 7332 | 7300 | struct nft_hook *hook, *next; |
| 7333 | 7301 | struct net *net = info->net; |
| @@ -7511,10 +7479,9 @@ static int nf_tables_delflowtable(struct sk_buff *skb, · 177 unmodified lines | ||
| 7511 | 7479 | const struct nfnl_info *info, |
| 7512 | 7480 | const struct nlattr * const nla[]) |
| 7513 | 7481 | { |
| 7514 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 7515 | 7482 | struct netlink_ext_ack *extack = info->extack; |
| 7516 | 7483 | u8 genmask = nft_genmask_next(info->net); |
| 7517 | − int family = nfmsg->nfgen_family; | |
| 7484 | + u8 family = info->nfmsg->nfgen_family; | |
| 7518 | 7485 | struct nft_flowtable *flowtable; |
| 7519 | 7486 | struct net *net = info->net; |
| 7520 | 7487 | const struct nlattr *attr; |
| @@ -7706,9 +7673,8 @@ static int nf_tables_getflowtable(struct sk_buff *skb, · 185 unmodified lines | ||
| 7706 | 7673 | const struct nfnl_info *info, |
| 7707 | 7674 | const struct nlattr * const nla[]) |
| 7708 | 7675 | { |
| 7709 | − const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 7710 | 7676 | u8 genmask = nft_genmask_cur(info->net); |
| 7711 | − int family = nfmsg->nfgen_family; | |
| 7677 | + u8 family = info->nfmsg->nfgen_family; | |
| 7712 | 7678 | struct nft_flowtable *flowtable; |
| 7713 | 7679 | const struct nft_table *table; |
| 7714 | 7680 | struct net *net = info->net; |
| @@ -68,6 +68,7 @@ static const char *const nfnl_lockdep_names[NFNL_SUBSYS_COUNT] = { · 67 unmodified lines | ||
| 68 | 68 | [NFNL_SUBSYS_CTHELPER] = "nfnl_subsys_cthelper", |
| 69 | 69 | [NFNL_SUBSYS_NFTABLES] = "nfnl_subsys_nftables", |
| 70 | 70 | [NFNL_SUBSYS_NFT_COMPAT] = "nfnl_subsys_nftcompat", |
| 71 | + [NFNL_SUBSYS_HOOK] = "nfnl_subsys_hook", | |
| 71 | 72 | }; |
| 72 | 73 | |
| 73 | 74 | static const int nfnl_group2type[NFNLGRP_MAX+1] = { |
| @@ -256,6 +257,7 @@ replay: · 182 unmodified lines | ||
| 256 | 257 | .net = net, |
| 257 | 258 | .sk = nfnlnet->nfnl, |
| 258 | 259 | .nlh = nlh, |
| 260 | + .nfmsg = nlmsg_data(nlh), | |
| 259 | 261 | .extack = extack, |
| 260 | 262 | }; |
| 261 | 263 | |
| @@ -491,6 +493,7 @@ replay_abort: · 229 unmodified lines | ||
| 491 | 493 | .net = net, |
| 492 | 494 | .sk = nfnlnet->nfnl, |
| 493 | 495 | .nlh = nlh, |
| 496 | + .nfmsg = nlmsg_data(nlh), | |
| 494 | 497 | .extack = &extack, |
| 495 | 498 | }; |
| 496 | 499 | |
| @@ -0,0 +1,375 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | +/* | |
| 3 | + * Copyright (c) 2021 Red Hat GmbH | |
| 4 | + * | |
| 5 | + * Author: Florian Westphal <fw@strlen.de> | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/module.h> | |
| 9 | +#include <linux/kernel.h> | |
| 10 | +#include <linux/types.h> | |
| 11 | +#include <linux/skbuff.h> | |
| 12 | +#include <linux/errno.h> | |
| 13 | +#include <linux/netlink.h> | |
| 14 | +#include <linux/slab.h> | |
| 15 | + | |
| 16 | +#include <linux/netfilter.h> | |
| 17 | + | |
| 18 | +#include <linux/netfilter/nfnetlink.h> | |
| 19 | +#include <linux/netfilter/nfnetlink_hook.h> | |
| 20 | + | |
| 21 | +#include <net/netfilter/nf_tables.h> | |
| 22 | +#include <net/sock.h> | |
| 23 | + | |
| 24 | +static const struct nla_policy nfnl_hook_nla_policy[NFNLA_HOOK_MAX + 1] = { | |
| 25 | + [NFNLA_HOOK_HOOKNUM] = { .type = NLA_U32 }, | |
| 26 | + [NFNLA_HOOK_PRIORITY] = { .type = NLA_U32 }, | |
| 27 | + [NFNLA_HOOK_DEV] = { .type = NLA_STRING, | |
| 28 | + .len = IFNAMSIZ - 1 }, | |
| 29 | + [NFNLA_HOOK_FUNCTION_NAME] = { .type = NLA_NUL_STRING, | |
| 30 | + .len = KSYM_NAME_LEN, }, | |
| 31 | + [NFNLA_HOOK_MODULE_NAME] = { .type = NLA_NUL_STRING, | |
| 32 | + .len = MODULE_NAME_LEN, }, | |
| 33 | + [NFNLA_HOOK_CHAIN_INFO] = { .type = NLA_NESTED, }, | |
| 34 | +}; | |
| 35 | + | |
| 36 | +static int nf_netlink_dump_start_rcu(struct sock *nlsk, struct sk_buff *skb, | |
| 37 | + const struct nlmsghdr *nlh, | |
| 38 | + struct netlink_dump_control *c) | |
| 39 | +{ | |
| 40 | + int err; | |
| 41 | + | |
| 42 | + if (!try_module_get(THIS_MODULE)) | |
| 43 | + return -EINVAL; | |
| 44 | + | |
| 45 | + rcu_read_unlock(); | |
| 46 | + err = netlink_dump_start(nlsk, skb, nlh, c); | |
| 47 | + rcu_read_lock(); | |
| 48 | + module_put(THIS_MODULE); | |
| 49 | + | |
| 50 | + return err; | |
| 51 | +} | |
| 52 | + | |
| 53 | +struct nfnl_dump_hook_data { | |
| 54 | + char devname[IFNAMSIZ]; | |
| 55 | + unsigned long headv; | |
| 56 | + u8 hook; | |
| 57 | +}; | |
| 58 | + | |
| 59 | +static int nfnl_hook_put_nft_chain_info(struct sk_buff *nlskb, | |
| 60 | + const struct nfnl_dump_hook_data *ctx, | |
| 61 | + unsigned int seq, | |
| 62 | + const struct nf_hook_ops *ops) | |
| 63 | +{ | |
| 64 | + struct net *net = sock_net(nlskb->sk); | |
| 65 | + struct nlattr *nest, *nest2; | |
| 66 | + struct nft_chain *chain; | |
| 67 | + int ret = 0; | |
| 68 | + | |
| 69 | + if (ops->hook_ops_type != NF_HOOK_OP_NF_TABLES) | |
| 70 | + return 0; | |
| 71 | + | |
| 72 | + chain = ops->priv; | |
| 73 | + if (WARN_ON_ONCE(!chain)) | |
| 74 | + return 0; | |
| 75 | + | |
| 76 | + if (!nft_is_active(net, chain)) | |
| 77 | + return 0; | |
| 78 | + | |
| 79 | + nest = nla_nest_start(nlskb, NFNLA_HOOK_CHAIN_INFO); | |
| 80 | + if (!nest) | |
| 81 | + return -EMSGSIZE; | |
| 82 | + | |
| 83 | + ret = nla_put_be32(nlskb, NFNLA_HOOK_INFO_TYPE, | |
| 84 | + htonl(NFNL_HOOK_TYPE_NFTABLES)); | |
| 85 | + if (ret) | |
| 86 | + goto cancel_nest; | |
| 87 | + | |
| 88 | + nest2 = nla_nest_start(nlskb, NFNLA_HOOK_INFO_DESC); | |
| 89 | + if (!nest2) | |
| 90 | + goto cancel_nest; | |
| 91 | + | |
| 92 | + ret = nla_put_string(nlskb, NFTA_CHAIN_TABLE, chain->table->name); | |
| 93 | + if (ret) | |
| 94 | + goto cancel_nest; | |
| 95 | + | |
| 96 | + ret = nla_put_string(nlskb, NFTA_CHAIN_NAME, chain->name); | |
| 97 | + if (ret) | |
| 98 | + goto cancel_nest; | |
| 99 | + | |
| 100 | + nla_nest_end(nlskb, nest2); | |
| 101 | + nla_nest_end(nlskb, nest); | |
| 102 | + return ret; | |
| 103 | + | |
| 104 | +cancel_nest: | |
| 105 | + nla_nest_cancel(nlskb, nest); | |
| 106 | + return -EMSGSIZE; | |
| 107 | +} | |
| 108 | + | |
| 109 | +static int nfnl_hook_dump_one(struct sk_buff *nlskb, | |
| 110 | + const struct nfnl_dump_hook_data *ctx, | |
| 111 | + const struct nf_hook_ops *ops, | |
| 112 | + unsigned int seq) | |
| 113 | +{ | |
| 114 | + u16 event = nfnl_msg_type(NFNL_SUBSYS_HOOK, NFNL_MSG_HOOK_GET); | |
| 115 | + unsigned int portid = NETLINK_CB(nlskb).portid; | |
| 116 | + struct nlmsghdr *nlh; | |
| 117 | + int ret = -EMSGSIZE; | |
| 118 | +#ifdef CONFIG_KALLSYMS | |
| 119 | + char sym[KSYM_SYMBOL_LEN]; | |
| 120 | + char *module_name; | |
| 121 | +#endif | |
| 122 | + nlh = nfnl_msg_put(nlskb, portid, seq, event, | |
| 123 | + NLM_F_MULTI, ops->pf, NFNETLINK_V0, 0); | |
| 124 | + if (!nlh) | |
| 125 | + goto nla_put_failure; | |
| 126 | + | |
| 127 | +#ifdef CONFIG_KALLSYMS | |
| 128 | + ret = snprintf(sym, sizeof(sym), "%ps", ops->hook); | |
| 129 | + if (ret < 0 || ret > (int)sizeof(sym)) | |
| 130 | + goto nla_put_failure; | |
| 131 | + | |
| 132 | + module_name = strstr(sym, " ["); | |
| 133 | + if (module_name) { | |
| 134 | + char *end; | |
| 135 | + | |
| 136 | + module_name += 2; | |
| 137 | + end = strchr(module_name, ']'); | |
| 138 | + if (end) { | |
| 139 | + *end = 0; | |
| 140 | + | |
| 141 | + ret = nla_put_string(nlskb, NFNLA_HOOK_MODULE_NAME, module_name); | |
| 142 | + if (ret) | |
| 143 | + goto nla_put_failure; | |
| 144 | + } | |
| 145 | + } | |
| 146 | + | |
| 147 | + ret = nla_put_string(nlskb, NFNLA_HOOK_FUNCTION_NAME, sym); | |
| 148 | + if (ret) | |
| 149 | + goto nla_put_failure; | |
| 150 | +#endif | |
| 151 | + | |
| 152 | + ret = nla_put_be32(nlskb, NFNLA_HOOK_HOOKNUM, htonl(ops->hooknum)); | |
| 153 | + if (ret) | |
| 154 | + goto nla_put_failure; | |
| 155 | + | |
| 156 | + ret = nla_put_be32(nlskb, NFNLA_HOOK_PRIORITY, htonl(ops->priority)); | |
| 157 | + if (ret) | |
| 158 | + goto nla_put_failure; | |
| 159 | + | |
| 160 | + ret = nfnl_hook_put_nft_chain_info(nlskb, ctx, seq, ops); | |
| 161 | + if (ret) | |
| 162 | + goto nla_put_failure; | |
| 163 | + | |
| 164 | + nlmsg_end(nlskb, nlh); | |
| 165 | + return 0; | |
| 166 | +nla_put_failure: | |
| 167 | + nlmsg_trim(nlskb, nlh); | |
| 168 | + return ret; | |
| 169 | +} | |
| 170 | + | |
| 171 | +static const struct nf_hook_entries * | |
| 172 | +nfnl_hook_entries_head(u8 pf, unsigned int hook, struct net *net, const char *dev) | |
| 173 | +{ | |
| 174 | + const struct nf_hook_entries *hook_head = NULL; | |
| 175 | + struct net_device *netdev; | |
| 176 | + | |
| 177 | + switch (pf) { | |
| 178 | + case NFPROTO_IPV4: | |
| 179 | + if (hook >= ARRAY_SIZE(net->nf.hooks_ipv4)) | |
| 180 | + return ERR_PTR(-EINVAL); | |
| 181 | + hook_head = rcu_dereference(net->nf.hooks_ipv4[hook]); | |
| 182 | + break; | |
| 183 | + case NFPROTO_IPV6: | |
| 184 | + if (hook >= ARRAY_SIZE(net->nf.hooks_ipv6)) | |
| 185 | + return ERR_PTR(-EINVAL); | |
| 186 | + hook_head = rcu_dereference(net->nf.hooks_ipv6[hook]); | |
| 187 | + break; | |
| 188 | + case NFPROTO_ARP: | |
| 189 | +#ifdef CONFIG_NETFILTER_FAMILY_ARP | |
| 190 | + if (hook >= ARRAY_SIZE(net->nf.hooks_arp)) | |
| 191 | + return ERR_PTR(-EINVAL); | |
| 192 | + hook_head = rcu_dereference(net->nf.hooks_arp[hook]); | |
| 193 | +#endif | |
| 194 | + break; | |
| 195 | + case NFPROTO_BRIDGE: | |
| 196 | +#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE | |
| 197 | + if (hook >= ARRAY_SIZE(net->nf.hooks_bridge)) | |
| 198 | + return ERR_PTR(-EINVAL); | |
| 199 | + hook_head = rcu_dereference(net->nf.hooks_bridge[hook]); | |
| 200 | +#endif | |
| 201 | + break; | |
| 202 | +#if IS_ENABLED(CONFIG_DECNET) | |
| 203 | + case NFPROTO_DECNET: | |
| 204 | + if (hook >= ARRAY_SIZE(net->nf.hooks_decnet)) | |
| 205 | + return ERR_PTR(-EINVAL); | |
| 206 | + hook_head = rcu_dereference(net->nf.hooks_decnet[hook]); | |
| 207 | + break; | |
| 208 | +#endif | |
| 209 | +#ifdef CONFIG_NETFILTER_INGRESS | |
| 210 | + case NFPROTO_NETDEV: | |
| 211 | + if (hook != NF_NETDEV_INGRESS) | |
| 212 | + return ERR_PTR(-EOPNOTSUPP); | |
| 213 | + | |
| 214 | + if (!dev) | |
| 215 | + return ERR_PTR(-ENODEV); | |
| 216 | + | |
| 217 | + netdev = dev_get_by_name_rcu(net, dev); | |
| 218 | + if (!netdev) | |
| 219 | + return ERR_PTR(-ENODEV); | |
| 220 | + | |
| 221 | + return rcu_dereference(netdev->nf_hooks_ingress); | |
| 222 | +#endif | |
| 223 | + default: | |
| 224 | + return ERR_PTR(-EPROTONOSUPPORT); | |
| 225 | + } | |
| 226 | + | |
| 227 | + return hook_head; | |
| 228 | +} | |
| 229 | + | |
| 230 | +static int nfnl_hook_dump(struct sk_buff *nlskb, | |
| 231 | + struct netlink_callback *cb) | |
| 232 | +{ | |
| 233 | + struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); | |
| 234 | + struct nfnl_dump_hook_data *ctx = cb->data; | |
| 235 | + int err, family = nfmsg->nfgen_family; | |
| 236 | + struct net *net = sock_net(nlskb->sk); | |
| 237 | + struct nf_hook_ops * const *ops; | |
| 238 | + const struct nf_hook_entries *e; | |
| 239 | + unsigned int i = cb->args[0]; | |
| 240 | + | |
| 241 | + rcu_read_lock(); | |
| 242 | + | |
| 243 | + e = nfnl_hook_entries_head(family, ctx->hook, net, ctx->devname); | |
| 244 | + if (!e) | |
| 245 | + goto done; | |
| 246 | + | |
| 247 | + if (IS_ERR(e)) { | |
| 248 | + cb->seq++; | |
| 249 | + goto done; | |
| 250 | + } | |
| 251 | + | |
| 252 | + if ((unsigned long)e != ctx->headv || i >= e->num_hook_entries) | |
| 253 | + cb->seq++; | |
| 254 | + | |
| 255 | + ops = nf_hook_entries_get_hook_ops(e); | |
| 256 | + | |
| 257 | + for (; i < e->num_hook_entries; i++) { | |
| 258 | + err = nfnl_hook_dump_one(nlskb, ctx, ops[i], cb->seq); | |
| 259 | + if (err) | |
| 260 | + break; | |
| 261 | + } | |
| 262 | + | |
| 263 | +done: | |
| 264 | + nl_dump_check_consistent(cb, nlmsg_hdr(nlskb)); | |
| 265 | + rcu_read_unlock(); | |
| 266 | + cb->args[0] = i; | |
| 267 | + return nlskb->len; | |
| 268 | +} | |
| 269 | + | |
| 270 | +static int nfnl_hook_dump_start(struct netlink_callback *cb) | |
| 271 | +{ | |
| 272 | + const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); | |
| 273 | + const struct nlattr * const *nla = cb->data; | |
| 274 | + struct nfnl_dump_hook_data *ctx = NULL; | |
| 275 | + struct net *net = sock_net(cb->skb->sk); | |
| 276 | + u8 family = nfmsg->nfgen_family; | |
| 277 | + char name[IFNAMSIZ] = ""; | |
| 278 | + const void *head; | |
| 279 | + u32 hooknum; | |
| 280 | + | |
| 281 | + hooknum = ntohl(nla_get_be32(nla[NFNLA_HOOK_HOOKNUM])); | |
| 282 | + if (hooknum > 255) | |
| 283 | + return -EINVAL; | |
| 284 | + | |
| 285 | + if (family == NFPROTO_NETDEV) { | |
| 286 | + if (!nla[NFNLA_HOOK_DEV]) | |
| 287 | + return -EINVAL; | |
| 288 | + | |
| 289 | + nla_strscpy(name, nla[NFNLA_HOOK_DEV], sizeof(name)); | |
| 290 | + } | |
| 291 | + | |
| 292 | + rcu_read_lock(); | |
| 293 | + /* Not dereferenced; for consistency check only */ | |
| 294 | + head = nfnl_hook_entries_head(family, hooknum, net, name); | |
| 295 | + rcu_read_unlock(); | |
| 296 | + | |
| 297 | + if (head && IS_ERR(head)) | |
| 298 | + return PTR_ERR(head); | |
| 299 | + | |
| 300 | + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
| 301 | + if (!ctx) | |
| 302 | + return -ENOMEM; | |
| 303 | + | |
| 304 | + strscpy(ctx->devname, name, sizeof(ctx->devname)); | |
| 305 | + ctx->headv = (unsigned long)head; | |
| 306 | + ctx->hook = hooknum; | |
| 307 | + | |
| 308 | + cb->seq = 1; | |
| 309 | + cb->data = ctx; | |
| 310 | + | |
| 311 | + return 0; | |
| 312 | +} | |
| 313 | + | |
| 314 | +static int nfnl_hook_dump_stop(struct netlink_callback *cb) | |
| 315 | +{ | |
| 316 | + kfree(cb->data); | |
| 317 | + return 0; | |
| 318 | +} | |
| 319 | + | |
| 320 | +static int nfnl_hook_get(struct sk_buff *skb, | |
| 321 | + const struct nfnl_info *info, | |
| 322 | + const struct nlattr * const nla[]) | |
| 323 | +{ | |
| 324 | + if (!nla[NFNLA_HOOK_HOOKNUM]) | |
| 325 | + return -EINVAL; | |
| 326 | + | |
| 327 | + if (info->nlh->nlmsg_flags & NLM_F_DUMP) { | |
| 328 | + struct netlink_dump_control c = { | |
| 329 | + .start = nfnl_hook_dump_start, | |
| 330 | + .done = nfnl_hook_dump_stop, | |
| 331 | + .dump = nfnl_hook_dump, | |
| 332 | + .module = THIS_MODULE, | |
| 333 | + .data = (void *)nla, | |
| 334 | + }; | |
| 335 | + | |
| 336 | + return nf_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); | |
| 337 | + } | |
| 338 | + | |
| 339 | + return -EOPNOTSUPP; | |
| 340 | +} | |
| 341 | + | |
| 342 | +static const struct nfnl_callback nfnl_hook_cb[NFNL_MSG_HOOK_MAX] = { | |
| 343 | + [NFNL_MSG_HOOK_GET] = { | |
| 344 | + .call = nfnl_hook_get, | |
| 345 | + .type = NFNL_CB_RCU, | |
| 346 | + .attr_count = NFNLA_HOOK_MAX, | |
| 347 | + .policy = nfnl_hook_nla_policy | |
| 348 | + }, | |
| 349 | +}; | |
| 350 | + | |
| 351 | +static const struct nfnetlink_subsystem nfhook_subsys = { | |
| 352 | + .name = "nfhook", | |
| 353 | + .subsys_id = NFNL_SUBSYS_HOOK, | |
| 354 | + .cb_count = NFNL_MSG_HOOK_MAX, | |
| 355 | + .cb = nfnl_hook_cb, | |
| 356 | +}; | |
| 357 | + | |
| 358 | +MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_HOOK); | |
| 359 | + | |
| 360 | +static int __init nfnetlink_hook_init(void) | |
| 361 | +{ | |
| 362 | + return nfnetlink_subsys_register(&nfhook_subsys); | |
| 363 | +} | |
| 364 | + | |
| 365 | +static void __exit nfnetlink_hook_exit(void) | |
| 366 | +{ | |
| 367 | + nfnetlink_subsys_unregister(&nfhook_subsys); | |
| 368 | +} | |
| 369 | + | |
| 370 | +module_init(nfnetlink_hook_init); | |
| 371 | +module_exit(nfnetlink_hook_exit); | |
| 372 | + | |
| 373 | +MODULE_LICENSE("GPL"); | |
| 374 | +MODULE_AUTHOR("Florian Westphal <fw@strlen.de>"); | |
| 375 | +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, · 870 unmodified lines | ||
| 871 | 871 | const struct nlattr * const nfula[]) |
| 872 | 872 | { |
| 873 | 873 | struct nfnl_log_net *log = nfnl_log_pernet(info->net); |
| 874 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 875 | − u_int16_t group_num = ntohs(nfmsg->res_id); | |
| 874 | + u_int16_t group_num = ntohs(info->nfmsg->res_id); | |
| 876 | 875 | struct nfulnl_msg_config_cmd *cmd = NULL; |
| 877 | 876 | struct nfulnl_instance *inst; |
| 878 | 877 | u16 flags = 0; |
| 879 | 878 | int ret = 0; |
| 880 | 879 | |
| 881 | 880 | if (nfula[NFULA_CFG_CMD]) { |
| 882 | − u_int8_t pf = nfmsg->nfgen_family; | |
| 881 | + u_int8_t pf = info->nfmsg->nfgen_family; | |
| 883 | 882 | cmd = nla_data(nfula[NFULA_CFG_CMD]); |
| 884 | 883 | |
| 885 | 884 | /* Commands without queue context */ |
| @@ -1051,8 +1051,7 @@ static int nfqnl_recv_verdict_batch(struct sk_buff *skb, · 1050 unmodified lines | ||
| 1051 | 1051 | const struct nlattr * const nfqa[]) |
| 1052 | 1052 | { |
| 1053 | 1053 | struct nfnl_queue_net *q = nfnl_queue_pernet(info->net); |
| 1054 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 1055 | − u16 queue_num = ntohs(nfmsg->res_id); | |
| 1054 | + u16 queue_num = ntohs(info->nfmsg->res_id); | |
| 1056 | 1055 | struct nf_queue_entry *entry, *tmp; |
| 1057 | 1056 | struct nfqnl_msg_verdict_hdr *vhdr; |
| 1058 | 1057 | struct nfqnl_instance *queue; |
| @@ -1160,8 +1159,7 @@ static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info, · 101 unmodified lines | ||
| 1160 | 1159 | const struct nlattr * const nfqa[]) |
| 1161 | 1160 | { |
| 1162 | 1161 | struct nfnl_queue_net *q = nfnl_queue_pernet(info->net); |
| 1163 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 1164 | − u_int16_t queue_num = ntohs(nfmsg->res_id); | |
| 1162 | + u_int16_t queue_num = ntohs(info->nfmsg->res_id); | |
| 1165 | 1163 | struct nfqnl_msg_verdict_hdr *vhdr; |
| 1166 | 1164 | enum ip_conntrack_info ctinfo; |
| 1167 | 1165 | struct nfqnl_instance *queue; |
| @@ -1243,8 +1241,7 @@ static int nfqnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info, · 75 unmodified lines | ||
| 1243 | 1241 | const struct nlattr * const nfqa[]) |
| 1244 | 1242 | { |
| 1245 | 1243 | struct nfnl_queue_net *q = nfnl_queue_pernet(info->net); |
| 1246 | − struct nfgenmsg *nfmsg = nlmsg_data(info->nlh); | |
| 1247 | − u_int16_t queue_num = ntohs(nfmsg->res_id); | |
| 1244 | + u_int16_t queue_num = ntohs(info->nfmsg->res_id); | |
| 1248 | 1245 | struct nfqnl_msg_config_cmd *cmd = NULL; |
| 1249 | 1246 | struct nfqnl_instance *queue; |
| 1250 | 1247 | __u32 flags = 0, mask = 0; |
| @@ -625,7 +625,7 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, · 624 unmodified lines | ||
| 625 | 625 | const struct nfnl_info *info, |
| 626 | 626 | const struct nlattr * const tb[]) |
| 627 | 627 | { |
| 628 | − struct nfgenmsg *nfmsg; | |
| 628 | + u8 family = info->nfmsg->nfgen_family; | |
| 629 | 629 | const char *name, *fmt; |
| 630 | 630 | struct sk_buff *skb2; |
| 631 | 631 | int ret = 0, target; |
| @@ -640,9 +640,7 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, · 8 unmodified lines | ||
| 640 | 640 | rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); |
| 641 | 641 | target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); |
| 642 | 642 | |
| 643 | − nfmsg = nlmsg_data(info->nlh); | |
| 644 | − | |
| 645 | − switch(nfmsg->nfgen_family) { | |
| 643 | + switch(family) { | |
| 646 | 644 | case AF_INET: |
| 647 | 645 | fmt = "ipt_%s"; |
| 648 | 646 | break; |
| @@ -656,8 +654,7 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, · 7 unmodified lines | ||
| 656 | 654 | fmt = "arpt_%s"; |
| 657 | 655 | break; |
| 658 | 656 | default: |
| 659 | − pr_err("nft_compat: unsupported protocol %d\n", | |
| 660 | − nfmsg->nfgen_family); | |
| 657 | + pr_err("nft_compat: unsupported protocol %d\n", family); | |
| 661 | 658 | return -EINVAL; |
| 662 | 659 | } |
| 663 | 660 | |
| @@ -665,9 +662,8 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, · 1 unmodified line | ||
| 665 | 662 | return -EINVAL; |
| 666 | 663 | |
| 667 | 664 | rcu_read_unlock(); |
| 668 | − try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name, | |
| 669 | − rev, target, &ret), | |
| 670 | − fmt, name); | |
| 665 | + try_then_request_module(xt_find_revision(family, name, rev, target, &ret), | |
| 666 | + fmt, name); | |
| 671 | 667 | if (ret < 0) |
| 672 | 668 | goto out_put; |
| 673 | 669 | |
| @@ -682,8 +678,7 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, · 8 unmodified lines | ||
| 682 | 678 | info->nlh->nlmsg_seq, |
| 683 | 679 | NFNL_MSG_TYPE(info->nlh->nlmsg_type), |
| 684 | 680 | NFNL_MSG_COMPAT_GET, |
| 685 | − nfmsg->nfgen_family, | |
| 686 | − name, ret, target) <= 0) { | |
| 681 | + family, name, ret, target) <= 0) { | |
| 687 | 682 | kfree_skb(skb2); |
| 688 | 683 | goto out_put; |
| 689 | 684 | } |
| @@ -327,7 +327,9 @@ static void nft_exthdr_sctp_eval(const struct nft_expr *expr, · 326 unmodified lines | ||
| 327 | 327 | break; |
| 328 | 328 | |
| 329 | 329 | dest[priv->len / NFT_REG32_SIZE] = 0; |
| 330 | − memcpy(dest, (char *)sch + priv->offset, priv->len); | |
| 330 | + if (skb_copy_bits(pkt->skb, offset + priv->offset, | |
| 331 | + dest, priv->len) < 0) | |
| 332 | + break; | |
| 331 | 333 | return; |
| 332 | 334 | } |
| 333 | 335 | offset += SCTP_PAD4(ntohs(sch->length)); |