Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 your net-next
tree, they are:

1) Remove obsolete nf_log tracing from nf_tables, from Florian Westphal.

2) Add support for map lookups to numgen, random and hash expressions,
from Laura Garcia.

3) Allow to register nat hooks for iptables and nftables at the same
time. Patchset from Florian Westpha.

4) Timeout support for rbtree sets.

5) ip6_rpfilter works needs interface for link-local addresses, from
Vincent Bernat.

6) Add nf_ct_hook and nf_nat_hook structures and use them.

7) Do not drop packets on packets raceing to insert conntrack entries
into hashes, this is particularly a problem in nfqueue setups.

8) Address fallout from xt_osf separation to nf_osf, patches
from Florian Westphal and Fernando Mancera.

9) Remove reference to struct nft_af_info, which doesn't exist anymore.
From Taehee Yoo.

This batch comes with is a conflict between 25fd386e0bc0 ("netfilter:
core: add missing __rcu annotation") in your tree and 2c205dd3981f
("netfilter: add struct nf_nat_hook and use it") coming in this batch.
This conflict can be solved by leaving the __rcu tag on
__netfilter_net_init() - added by 25fd386e0bc0 - and remove all code
related to nf_nat_decode_session_hook - which is gone after
2c205dd3981f, as described by:

diff --cc net/netfilter/core.c
index e0ae4aae96f5,206fb2c4c319..168af54db975
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@@ -611,7 -580,13 +611,8 @@@ const struct nf_conntrack_zone nf_ct_zo
EXPORT_SYMBOL_GPL(nf_ct_zone_dflt);
#endif /* CONFIG_NF_CONNTRACK */

- static void __net_init __netfilter_net_init(struct nf_hook_entries **e, int max)
-#ifdef CONFIG_NF_NAT_NEEDED
-void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
-EXPORT_SYMBOL(nf_nat_decode_session_hook);
-#endif
-
+ static void __net_init
+ __netfilter_net_init(struct nf_hook_entries __rcu **e, int max)
{
int h;

I can also merge your net-next tree into nf-next, solve the conflict and
resend the pull request if you prefer so.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1035 -573
+27 -7
include/linux/netfilter.h
··· 67 67 struct net_device *dev; 68 68 void *priv; 69 69 u_int8_t pf; 70 - bool nat_hook; 71 70 unsigned int hooknum; 72 71 /* Hooks are ordered in ascending priority. */ 73 72 int priority; ··· 320 321 int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry); 321 322 322 323 #include <net/flow.h> 323 - extern void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); 324 + 325 + struct nf_conn; 326 + enum nf_nat_manip_type; 327 + struct nlattr; 328 + enum ip_conntrack_dir; 329 + 330 + struct nf_nat_hook { 331 + int (*parse_nat_setup)(struct nf_conn *ct, enum nf_nat_manip_type manip, 332 + const struct nlattr *attr); 333 + void (*decode_session)(struct sk_buff *skb, struct flowi *fl); 334 + unsigned int (*manip_pkt)(struct sk_buff *skb, struct nf_conn *ct, 335 + enum nf_nat_manip_type mtype, 336 + enum ip_conntrack_dir dir); 337 + }; 338 + 339 + extern struct nf_nat_hook __rcu *nf_nat_hook; 324 340 325 341 static inline void 326 342 nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) 327 343 { 328 344 #ifdef CONFIG_NF_NAT_NEEDED 329 - void (*decodefn)(struct sk_buff *, struct flowi *); 345 + struct nf_nat_hook *nat_hook; 330 346 331 347 rcu_read_lock(); 332 - decodefn = rcu_dereference(nf_nat_decode_session_hook); 333 - if (decodefn) 334 - decodefn(skb, fl); 348 + nat_hook = rcu_dereference(nf_nat_hook); 349 + if (nat_hook->decode_session) 350 + nat_hook->decode_session(skb, fl); 335 351 rcu_read_unlock(); 336 352 #endif 337 353 } ··· 388 374 389 375 extern void (*ip_ct_attach)(struct sk_buff *, const struct sk_buff *) __rcu; 390 376 void nf_ct_attach(struct sk_buff *, const struct sk_buff *); 391 - extern void (*nf_ct_destroy)(struct nf_conntrack *) __rcu; 392 377 #else 393 378 static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} 394 379 #endif 395 380 396 381 struct nf_conn; 397 382 enum ip_conntrack_info; 383 + 384 + struct nf_ct_hook { 385 + int (*update)(struct net *net, struct sk_buff *skb); 386 + void (*destroy)(struct nf_conntrack *); 387 + }; 388 + extern struct nf_ct_hook __rcu *nf_ct_hook; 389 + 398 390 struct nlattr; 399 391 400 392 struct nfnl_ct_hook {
+6
include/linux/netfilter/nf_osf.h
··· 21 21 FMATCH_OPT_WRONG, 22 22 }; 23 23 24 + struct nf_osf_finger { 25 + struct rcu_head rcu_head; 26 + struct list_head finger_entry; 27 + struct nf_osf_user_finger finger; 28 + }; 29 + 24 30 bool nf_osf_match(const struct sk_buff *skb, u_int8_t family, 25 31 int hooknum, struct net_device *in, struct net_device *out, 26 32 const struct nf_osf_info *info, struct net *net,
+4
include/net/netfilter/nf_nat.h
··· 75 75 #endif 76 76 } 77 77 78 + int nf_nat_register_fn(struct net *net, const struct nf_hook_ops *ops, 79 + const struct nf_hook_ops *nat_ops, unsigned int ops_count); 80 + void nf_nat_unregister_fn(struct net *net, const struct nf_hook_ops *ops, 81 + unsigned int ops_count); 78 82 #endif
+4 -7
include/net/netfilter/nf_nat_core.h
··· 11 11 unsigned int nf_nat_packet(struct nf_conn *ct, enum ip_conntrack_info ctinfo, 12 12 unsigned int hooknum, struct sk_buff *skb); 13 13 14 + unsigned int 15 + nf_nat_inet_fn(void *priv, struct sk_buff *skb, 16 + const struct nf_hook_state *state); 17 + 14 18 int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family); 15 19 16 20 static inline int nf_nat_initialized(struct nf_conn *ct, ··· 25 21 else 26 22 return ct->status & IPS_DST_NAT_DONE; 27 23 } 28 - 29 - struct nlattr; 30 - 31 - extern int 32 - (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, 33 - enum nf_nat_manip_type manip, 34 - const struct nlattr *attr); 35 24 36 25 #endif /* _NF_NAT_CORE_H */
+4 -48
include/net/netfilter/nf_nat_l3proto.h
··· 44 44 enum ip_conntrack_info ctinfo, 45 45 unsigned int hooknum); 46 46 47 - unsigned int nf_nat_ipv4_in(void *priv, struct sk_buff *skb, 48 - const struct nf_hook_state *state, 49 - unsigned int (*do_chain)(void *priv, 50 - struct sk_buff *skb, 51 - const struct nf_hook_state *state)); 52 - 53 - unsigned int nf_nat_ipv4_out(void *priv, struct sk_buff *skb, 54 - const struct nf_hook_state *state, 55 - unsigned int (*do_chain)(void *priv, 56 - struct sk_buff *skb, 57 - const struct nf_hook_state *state)); 58 - 59 - unsigned int nf_nat_ipv4_local_fn(void *priv, 60 - struct sk_buff *skb, 61 - const struct nf_hook_state *state, 62 - unsigned int (*do_chain)(void *priv, 63 - struct sk_buff *skb, 64 - const struct nf_hook_state *state)); 65 - 66 - unsigned int nf_nat_ipv4_fn(void *priv, struct sk_buff *skb, 67 - const struct nf_hook_state *state, 68 - unsigned int (*do_chain)(void *priv, 69 - struct sk_buff *skb, 70 - const struct nf_hook_state *state)); 71 - 72 47 int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, struct nf_conn *ct, 73 48 enum ip_conntrack_info ctinfo, 74 49 unsigned int hooknum, unsigned int hdrlen); 75 50 76 - unsigned int nf_nat_ipv6_in(void *priv, struct sk_buff *skb, 77 - const struct nf_hook_state *state, 78 - unsigned int (*do_chain)(void *priv, 79 - struct sk_buff *skb, 80 - const struct nf_hook_state *state)); 51 + int nf_nat_l3proto_ipv4_register_fn(struct net *net, const struct nf_hook_ops *ops); 52 + void nf_nat_l3proto_ipv4_unregister_fn(struct net *net, const struct nf_hook_ops *ops); 81 53 82 - unsigned int nf_nat_ipv6_out(void *priv, struct sk_buff *skb, 83 - const struct nf_hook_state *state, 84 - unsigned int (*do_chain)(void *priv, 85 - struct sk_buff *skb, 86 - const struct nf_hook_state *state)); 87 - 88 - unsigned int nf_nat_ipv6_local_fn(void *priv, 89 - struct sk_buff *skb, 90 - const struct nf_hook_state *state, 91 - unsigned int (*do_chain)(void *priv, 92 - struct sk_buff *skb, 93 - const struct nf_hook_state *state)); 94 - 95 - unsigned int nf_nat_ipv6_fn(void *priv, struct sk_buff *skb, 96 - const struct nf_hook_state *state, 97 - unsigned int (*do_chain)(void *priv, 98 - struct sk_buff *skb, 99 - const struct nf_hook_state *state)); 54 + int nf_nat_l3proto_ipv6_register_fn(struct net *net, const struct nf_hook_ops *ops); 55 + void nf_nat_l3proto_ipv6_unregister_fn(struct net *net, const struct nf_hook_ops *ops); 100 56 101 57 #endif /* _NF_NAT_L3PROTO_H */
+4 -4
include/net/netfilter/nf_tables.h
··· 885 885 * @owner: module owner 886 886 * @hook_mask: mask of valid hooks 887 887 * @hooks: array of hook functions 888 - * @init: chain initialization function 889 - * @free: chain release function 888 + * @ops_register: base chain register function 889 + * @ops_unregister: base chain unregister function 890 890 */ 891 891 struct nft_chain_type { 892 892 const char *name; ··· 895 895 struct module *owner; 896 896 unsigned int hook_mask; 897 897 nf_hookfn *hooks[NF_MAX_HOOKS]; 898 - int (*init)(struct nft_ctx *ctx); 899 - void (*free)(struct nft_ctx *ctx); 898 + int (*ops_register)(struct net *net, const struct nf_hook_ops *ops); 899 + void (*ops_unregister)(struct net *net, const struct nf_hook_ops *ops); 900 900 }; 901 901 902 902 int nft_chain_validate_dependency(const struct nft_chain *chain,
-2
include/net/netns/nftables.h
··· 4 4 5 5 #include <linux/list.h> 6 6 7 - struct nft_af_info; 8 - 9 7 struct netns_nftables { 10 8 struct list_head tables; 11 9 struct list_head commit_list;
+2 -6
include/uapi/linux/netfilter/nf_osf.h
··· 1 1 #ifndef _NF_OSF_H 2 2 #define _NF_OSF_H 3 3 4 + #include <linux/types.h> 5 + 4 6 #define MAXGENRELEN 32 5 7 6 8 #define NF_OSF_GENRE (1 << 0) ··· 57 55 58 56 /* MAX_IPOPTLEN is maximum if all options are NOPs or EOLs */ 59 57 struct nf_osf_opt opt[MAX_IPOPTLEN]; 60 - }; 61 - 62 - struct nf_osf_finger { 63 - struct rcu_head rcu_head; 64 - struct list_head finger_entry; 65 - struct nf_osf_user_finger finger; 66 58 }; 67 59 68 60 struct nf_osf_nlmsg {
+4
include/uapi/linux/netfilter/nf_tables.h
··· 856 856 * @NFTA_HASH_SEED: seed value (NLA_U32) 857 857 * @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32) 858 858 * @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types) 859 + * @NFTA_HASH_SET_NAME: name of the map to lookup (NLA_STRING) 860 + * @NFTA_HASH_SET_ID: id of the map (NLA_U32) 859 861 */ 860 862 enum nft_hash_attributes { 861 863 NFTA_HASH_UNSPEC, ··· 868 866 NFTA_HASH_SEED, 869 867 NFTA_HASH_OFFSET, 870 868 NFTA_HASH_TYPE, 869 + NFTA_HASH_SET_NAME, 870 + NFTA_HASH_SET_ID, 871 871 __NFTA_HASH_MAX, 872 872 }; 873 873 #define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
+4 -1
net/ipv4/netfilter/ip_tables.c
··· 1783 1783 1784 1784 /* set res now, will see skbs right after nf_register_net_hooks */ 1785 1785 WRITE_ONCE(*res, new_table); 1786 + if (!ops) 1787 + return 0; 1786 1788 1787 1789 ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); 1788 1790 if (ret != 0) { ··· 1802 1800 void ipt_unregister_table(struct net *net, struct xt_table *table, 1803 1801 const struct nf_hook_ops *ops) 1804 1802 { 1805 - nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); 1803 + if (ops) 1804 + nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); 1806 1805 __ipt_unregister_table(net, table); 1807 1806 } 1808 1807
+43 -42
net/ipv4/netfilter/iptable_nat.c
··· 38 38 return ipt_do_table(skb, state, state->net->ipv4.nat_table); 39 39 } 40 40 41 - static unsigned int iptable_nat_ipv4_fn(void *priv, 42 - struct sk_buff *skb, 43 - const struct nf_hook_state *state) 44 - { 45 - return nf_nat_ipv4_fn(priv, skb, state, iptable_nat_do_chain); 46 - } 47 - 48 - static unsigned int iptable_nat_ipv4_in(void *priv, 49 - struct sk_buff *skb, 50 - const struct nf_hook_state *state) 51 - { 52 - return nf_nat_ipv4_in(priv, skb, state, iptable_nat_do_chain); 53 - } 54 - 55 - static unsigned int iptable_nat_ipv4_out(void *priv, 56 - struct sk_buff *skb, 57 - const struct nf_hook_state *state) 58 - { 59 - return nf_nat_ipv4_out(priv, skb, state, iptable_nat_do_chain); 60 - } 61 - 62 - static unsigned int iptable_nat_ipv4_local_fn(void *priv, 63 - struct sk_buff *skb, 64 - const struct nf_hook_state *state) 65 - { 66 - return nf_nat_ipv4_local_fn(priv, skb, state, iptable_nat_do_chain); 67 - } 68 - 69 41 static const struct nf_hook_ops nf_nat_ipv4_ops[] = { 70 - /* Before packet filtering, change destination */ 71 42 { 72 - .hook = iptable_nat_ipv4_in, 43 + .hook = iptable_nat_do_chain, 73 44 .pf = NFPROTO_IPV4, 74 - .nat_hook = true, 75 45 .hooknum = NF_INET_PRE_ROUTING, 76 46 .priority = NF_IP_PRI_NAT_DST, 77 47 }, 78 - /* After packet filtering, change source */ 79 48 { 80 - .hook = iptable_nat_ipv4_out, 49 + .hook = iptable_nat_do_chain, 81 50 .pf = NFPROTO_IPV4, 82 - .nat_hook = true, 83 51 .hooknum = NF_INET_POST_ROUTING, 84 52 .priority = NF_IP_PRI_NAT_SRC, 85 53 }, 86 - /* Before packet filtering, change destination */ 87 54 { 88 - .hook = iptable_nat_ipv4_local_fn, 55 + .hook = iptable_nat_do_chain, 89 56 .pf = NFPROTO_IPV4, 90 - .nat_hook = true, 91 57 .hooknum = NF_INET_LOCAL_OUT, 92 58 .priority = NF_IP_PRI_NAT_DST, 93 59 }, 94 - /* After packet filtering, change source */ 95 60 { 96 - .hook = iptable_nat_ipv4_fn, 61 + .hook = iptable_nat_do_chain, 97 62 .pf = NFPROTO_IPV4, 98 - .nat_hook = true, 99 63 .hooknum = NF_INET_LOCAL_IN, 100 64 .priority = NF_IP_PRI_NAT_SRC, 101 65 }, 102 66 }; 67 + 68 + static int ipt_nat_register_lookups(struct net *net) 69 + { 70 + int i, ret; 71 + 72 + for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) { 73 + ret = nf_nat_l3proto_ipv4_register_fn(net, &nf_nat_ipv4_ops[i]); 74 + if (ret) { 75 + while (i) 76 + nf_nat_l3proto_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[--i]); 77 + 78 + return ret; 79 + } 80 + } 81 + 82 + return 0; 83 + } 84 + 85 + static void ipt_nat_unregister_lookups(struct net *net) 86 + { 87 + int i; 88 + 89 + for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) 90 + nf_nat_l3proto_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[i]); 91 + } 103 92 104 93 static int __net_init iptable_nat_table_init(struct net *net) 105 94 { ··· 102 113 if (repl == NULL) 103 114 return -ENOMEM; 104 115 ret = ipt_register_table(net, &nf_nat_ipv4_table, repl, 105 - nf_nat_ipv4_ops, &net->ipv4.nat_table); 116 + NULL, &net->ipv4.nat_table); 117 + if (ret < 0) { 118 + kfree(repl); 119 + return ret; 120 + } 121 + 122 + ret = ipt_nat_register_lookups(net); 123 + if (ret < 0) { 124 + ipt_unregister_table(net, net->ipv4.nat_table, NULL); 125 + net->ipv4.nat_table = NULL; 126 + } 127 + 106 128 kfree(repl); 107 129 return ret; 108 130 } ··· 122 122 { 123 123 if (!net->ipv4.nat_table) 124 124 return; 125 - ipt_unregister_table(net, net->ipv4.nat_table, nf_nat_ipv4_ops); 125 + ipt_nat_unregister_lookups(net); 126 + ipt_unregister_table(net, net->ipv4.nat_table, NULL); 126 127 net->ipv4.nat_table = NULL; 127 128 } 128 129
+56 -79
net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
··· 241 241 } 242 242 EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); 243 243 244 - unsigned int 244 + static unsigned int 245 245 nf_nat_ipv4_fn(void *priv, struct sk_buff *skb, 246 - const struct nf_hook_state *state, 247 - unsigned int (*do_chain)(void *priv, 248 - struct sk_buff *skb, 249 - const struct nf_hook_state *state)) 246 + const struct nf_hook_state *state) 250 247 { 251 248 struct nf_conn *ct; 252 249 enum ip_conntrack_info ctinfo; 253 - struct nf_conn_nat *nat; 254 - /* maniptype == SRC for postrouting. */ 255 - enum nf_nat_manip_type maniptype = HOOK2MANIP(state->hook); 256 250 257 251 ct = nf_ct_get(skb, &ctinfo); 258 - /* Can't track? It's not due to stress, or conntrack would 259 - * have dropped it. Hence it's the user's responsibilty to 260 - * packet filter it out, or implement conntrack/NAT for that 261 - * protocol. 8) --RR 262 - */ 263 252 if (!ct) 264 253 return NF_ACCEPT; 265 254 266 - nat = nfct_nat(ct); 267 - 268 - switch (ctinfo) { 269 - case IP_CT_RELATED: 270 - case IP_CT_RELATED_REPLY: 255 + if (ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY) { 271 256 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { 272 257 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, 273 258 state->hook)) ··· 260 275 else 261 276 return NF_ACCEPT; 262 277 } 263 - /* Only ICMPs can be IP_CT_IS_REPLY: */ 264 - /* fall through */ 265 - case IP_CT_NEW: 266 - /* Seen it before? This can happen for loopback, retrans, 267 - * or local packets. 268 - */ 269 - if (!nf_nat_initialized(ct, maniptype)) { 270 - unsigned int ret; 271 - 272 - ret = do_chain(priv, skb, state); 273 - if (ret != NF_ACCEPT) 274 - return ret; 275 - 276 - if (nf_nat_initialized(ct, HOOK2MANIP(state->hook))) 277 - break; 278 - 279 - ret = nf_nat_alloc_null_binding(ct, state->hook); 280 - if (ret != NF_ACCEPT) 281 - return ret; 282 - } else { 283 - pr_debug("Already setup manip %s for ct %p\n", 284 - maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 285 - ct); 286 - if (nf_nat_oif_changed(state->hook, ctinfo, nat, 287 - state->out)) 288 - goto oif_changed; 289 - } 290 - break; 291 - 292 - default: 293 - /* ESTABLISHED */ 294 - WARN_ON(ctinfo != IP_CT_ESTABLISHED && 295 - ctinfo != IP_CT_ESTABLISHED_REPLY); 296 - if (nf_nat_oif_changed(state->hook, ctinfo, nat, state->out)) 297 - goto oif_changed; 298 278 } 299 279 300 - return nf_nat_packet(ct, ctinfo, state->hook, skb); 301 - 302 - oif_changed: 303 - nf_ct_kill_acct(ct, ctinfo, skb); 304 - return NF_DROP; 280 + return nf_nat_inet_fn(priv, skb, state); 305 281 } 306 282 EXPORT_SYMBOL_GPL(nf_nat_ipv4_fn); 307 283 308 - unsigned int 284 + static unsigned int 309 285 nf_nat_ipv4_in(void *priv, struct sk_buff *skb, 310 - const struct nf_hook_state *state, 311 - unsigned int (*do_chain)(void *priv, 312 - struct sk_buff *skb, 313 - const struct nf_hook_state *state)) 286 + const struct nf_hook_state *state) 314 287 { 315 288 unsigned int ret; 316 289 __be32 daddr = ip_hdr(skb)->daddr; 317 290 318 - ret = nf_nat_ipv4_fn(priv, skb, state, do_chain); 291 + ret = nf_nat_ipv4_fn(priv, skb, state); 319 292 if (ret != NF_DROP && ret != NF_STOLEN && 320 293 daddr != ip_hdr(skb)->daddr) 321 294 skb_dst_drop(skb); 322 295 323 296 return ret; 324 297 } 325 - EXPORT_SYMBOL_GPL(nf_nat_ipv4_in); 326 298 327 - unsigned int 299 + static unsigned int 328 300 nf_nat_ipv4_out(void *priv, struct sk_buff *skb, 329 - const struct nf_hook_state *state, 330 - unsigned int (*do_chain)(void *priv, 331 - struct sk_buff *skb, 332 - const struct nf_hook_state *state)) 301 + const struct nf_hook_state *state) 333 302 { 334 303 #ifdef CONFIG_XFRM 335 304 const struct nf_conn *ct; ··· 292 353 #endif 293 354 unsigned int ret; 294 355 295 - ret = nf_nat_ipv4_fn(priv, skb, state, do_chain); 356 + ret = nf_nat_ipv4_fn(priv, skb, state); 296 357 #ifdef CONFIG_XFRM 297 358 if (ret != NF_DROP && ret != NF_STOLEN && 298 359 !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && ··· 312 373 #endif 313 374 return ret; 314 375 } 315 - EXPORT_SYMBOL_GPL(nf_nat_ipv4_out); 316 376 317 - unsigned int 377 + static unsigned int 318 378 nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb, 319 - const struct nf_hook_state *state, 320 - unsigned int (*do_chain)(void *priv, 321 - struct sk_buff *skb, 322 - const struct nf_hook_state *state)) 379 + const struct nf_hook_state *state) 323 380 { 324 381 const struct nf_conn *ct; 325 382 enum ip_conntrack_info ctinfo; 326 383 unsigned int ret; 327 384 int err; 328 385 329 - ret = nf_nat_ipv4_fn(priv, skb, state, do_chain); 386 + ret = nf_nat_ipv4_fn(priv, skb, state); 330 387 if (ret != NF_DROP && ret != NF_STOLEN && 331 388 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 332 389 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); ··· 346 411 } 347 412 return ret; 348 413 } 349 - EXPORT_SYMBOL_GPL(nf_nat_ipv4_local_fn); 414 + 415 + static const struct nf_hook_ops nf_nat_ipv4_ops[] = { 416 + /* Before packet filtering, change destination */ 417 + { 418 + .hook = nf_nat_ipv4_in, 419 + .pf = NFPROTO_IPV4, 420 + .hooknum = NF_INET_PRE_ROUTING, 421 + .priority = NF_IP_PRI_NAT_DST, 422 + }, 423 + /* After packet filtering, change source */ 424 + { 425 + .hook = nf_nat_ipv4_out, 426 + .pf = NFPROTO_IPV4, 427 + .hooknum = NF_INET_POST_ROUTING, 428 + .priority = NF_IP_PRI_NAT_SRC, 429 + }, 430 + /* Before packet filtering, change destination */ 431 + { 432 + .hook = nf_nat_ipv4_local_fn, 433 + .pf = NFPROTO_IPV4, 434 + .hooknum = NF_INET_LOCAL_OUT, 435 + .priority = NF_IP_PRI_NAT_DST, 436 + }, 437 + /* After packet filtering, change source */ 438 + { 439 + .hook = nf_nat_ipv4_fn, 440 + .pf = NFPROTO_IPV4, 441 + .hooknum = NF_INET_LOCAL_IN, 442 + .priority = NF_IP_PRI_NAT_SRC, 443 + }, 444 + }; 445 + 446 + int nf_nat_l3proto_ipv4_register_fn(struct net *net, const struct nf_hook_ops *ops) 447 + { 448 + return nf_nat_register_fn(net, ops, nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops)); 449 + } 450 + EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv4_register_fn); 451 + 452 + void nf_nat_l3proto_ipv4_unregister_fn(struct net *net, const struct nf_hook_ops *ops) 453 + { 454 + nf_nat_unregister_fn(net, ops, ARRAY_SIZE(nf_nat_ipv4_ops)); 455 + } 456 + EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv4_unregister_fn); 350 457 351 458 static int __init nf_nat_l3proto_ipv4_init(void) 352 459 {
+12 -40
net/ipv4/netfilter/nft_chain_nat_ipv4.c
··· 27 27 #include <net/ip.h> 28 28 29 29 static unsigned int nft_nat_do_chain(void *priv, 30 - struct sk_buff *skb, 31 - const struct nf_hook_state *state) 30 + struct sk_buff *skb, 31 + const struct nf_hook_state *state) 32 32 { 33 33 struct nft_pktinfo pkt; 34 34 ··· 38 38 return nft_do_chain(&pkt, priv); 39 39 } 40 40 41 - static unsigned int nft_nat_ipv4_fn(void *priv, 42 - struct sk_buff *skb, 43 - const struct nf_hook_state *state) 41 + static int nft_nat_ipv4_reg(struct net *net, const struct nf_hook_ops *ops) 44 42 { 45 - return nf_nat_ipv4_fn(priv, skb, state, nft_nat_do_chain); 43 + return nf_nat_l3proto_ipv4_register_fn(net, ops); 46 44 } 47 45 48 - static unsigned int nft_nat_ipv4_in(void *priv, 49 - struct sk_buff *skb, 50 - const struct nf_hook_state *state) 46 + static void nft_nat_ipv4_unreg(struct net *net, const struct nf_hook_ops *ops) 51 47 { 52 - return nf_nat_ipv4_in(priv, skb, state, nft_nat_do_chain); 53 - } 54 - 55 - static unsigned int nft_nat_ipv4_out(void *priv, 56 - struct sk_buff *skb, 57 - const struct nf_hook_state *state) 58 - { 59 - return nf_nat_ipv4_out(priv, skb, state, nft_nat_do_chain); 60 - } 61 - 62 - static unsigned int nft_nat_ipv4_local_fn(void *priv, 63 - struct sk_buff *skb, 64 - const struct nf_hook_state *state) 65 - { 66 - return nf_nat_ipv4_local_fn(priv, skb, state, nft_nat_do_chain); 67 - } 68 - 69 - static int nft_nat_ipv4_init(struct nft_ctx *ctx) 70 - { 71 - return nf_ct_netns_get(ctx->net, ctx->family); 72 - } 73 - 74 - static void nft_nat_ipv4_free(struct nft_ctx *ctx) 75 - { 76 - nf_ct_netns_put(ctx->net, ctx->family); 48 + nf_nat_l3proto_ipv4_unregister_fn(net, ops); 77 49 } 78 50 79 51 static const struct nft_chain_type nft_chain_nat_ipv4 = { ··· 58 86 (1 << NF_INET_LOCAL_OUT) | 59 87 (1 << NF_INET_LOCAL_IN), 60 88 .hooks = { 61 - [NF_INET_PRE_ROUTING] = nft_nat_ipv4_in, 62 - [NF_INET_POST_ROUTING] = nft_nat_ipv4_out, 63 - [NF_INET_LOCAL_OUT] = nft_nat_ipv4_local_fn, 64 - [NF_INET_LOCAL_IN] = nft_nat_ipv4_fn, 89 + [NF_INET_PRE_ROUTING] = nft_nat_do_chain, 90 + [NF_INET_POST_ROUTING] = nft_nat_do_chain, 91 + [NF_INET_LOCAL_OUT] = nft_nat_do_chain, 92 + [NF_INET_LOCAL_IN] = nft_nat_do_chain, 65 93 }, 66 - .init = nft_nat_ipv4_init, 67 - .free = nft_nat_ipv4_free, 94 + .ops_register = nft_nat_ipv4_reg, 95 + .ops_unregister = nft_nat_ipv4_unreg, 68 96 }; 69 97 70 98 static int __init nft_chain_nat_init(void)
+4 -1
net/ipv6/netfilter/ip6_tables.c
··· 1793 1793 1794 1794 /* set res now, will see skbs right after nf_register_net_hooks */ 1795 1795 WRITE_ONCE(*res, new_table); 1796 + if (!ops) 1797 + return 0; 1796 1798 1797 1799 ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); 1798 1800 if (ret != 0) { ··· 1812 1810 void ip6t_unregister_table(struct net *net, struct xt_table *table, 1813 1811 const struct nf_hook_ops *ops) 1814 1812 { 1815 - nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); 1813 + if (ops) 1814 + nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); 1816 1815 __ip6t_unregister_table(net, table); 1817 1816 } 1818 1817
+2
net/ipv6/netfilter/ip6t_rpfilter.c
··· 48 48 } 49 49 50 50 fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0; 51 + if ((flags & XT_RPFILTER_LOOSE) == 0) 52 + fl6.flowi6_oif = dev->ifindex; 51 53 52 54 rt = (void *)ip6_route_lookup(net, &fl6, skb, lookup_flags); 53 55 if (rt->dst.error)
+42 -42
net/ipv6/netfilter/ip6table_nat.c
··· 40 40 return ip6t_do_table(skb, state, state->net->ipv6.ip6table_nat); 41 41 } 42 42 43 - static unsigned int ip6table_nat_fn(void *priv, 44 - struct sk_buff *skb, 45 - const struct nf_hook_state *state) 46 - { 47 - return nf_nat_ipv6_fn(priv, skb, state, ip6table_nat_do_chain); 48 - } 49 - 50 - static unsigned int ip6table_nat_in(void *priv, 51 - struct sk_buff *skb, 52 - const struct nf_hook_state *state) 53 - { 54 - return nf_nat_ipv6_in(priv, skb, state, ip6table_nat_do_chain); 55 - } 56 - 57 - static unsigned int ip6table_nat_out(void *priv, 58 - struct sk_buff *skb, 59 - const struct nf_hook_state *state) 60 - { 61 - return nf_nat_ipv6_out(priv, skb, state, ip6table_nat_do_chain); 62 - } 63 - 64 - static unsigned int ip6table_nat_local_fn(void *priv, 65 - struct sk_buff *skb, 66 - const struct nf_hook_state *state) 67 - { 68 - return nf_nat_ipv6_local_fn(priv, skb, state, ip6table_nat_do_chain); 69 - } 70 - 71 43 static const struct nf_hook_ops nf_nat_ipv6_ops[] = { 72 - /* Before packet filtering, change destination */ 73 44 { 74 - .hook = ip6table_nat_in, 45 + .hook = ip6table_nat_do_chain, 75 46 .pf = NFPROTO_IPV6, 76 - .nat_hook = true, 77 47 .hooknum = NF_INET_PRE_ROUTING, 78 48 .priority = NF_IP6_PRI_NAT_DST, 79 49 }, 80 - /* After packet filtering, change source */ 81 50 { 82 - .hook = ip6table_nat_out, 51 + .hook = ip6table_nat_do_chain, 83 52 .pf = NFPROTO_IPV6, 84 - .nat_hook = true, 85 53 .hooknum = NF_INET_POST_ROUTING, 86 54 .priority = NF_IP6_PRI_NAT_SRC, 87 55 }, 88 - /* Before packet filtering, change destination */ 89 56 { 90 - .hook = ip6table_nat_local_fn, 57 + .hook = ip6table_nat_do_chain, 91 58 .pf = NFPROTO_IPV6, 92 - .nat_hook = true, 93 59 .hooknum = NF_INET_LOCAL_OUT, 94 60 .priority = NF_IP6_PRI_NAT_DST, 95 61 }, 96 - /* After packet filtering, change source */ 97 62 { 98 - .hook = ip6table_nat_fn, 99 - .nat_hook = true, 63 + .hook = ip6table_nat_do_chain, 100 64 .pf = NFPROTO_IPV6, 101 65 .hooknum = NF_INET_LOCAL_IN, 102 66 .priority = NF_IP6_PRI_NAT_SRC, 103 67 }, 104 68 }; 69 + 70 + static int ip6t_nat_register_lookups(struct net *net) 71 + { 72 + int i, ret; 73 + 74 + for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) { 75 + ret = nf_nat_l3proto_ipv6_register_fn(net, &nf_nat_ipv6_ops[i]); 76 + if (ret) { 77 + while (i) 78 + nf_nat_l3proto_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[--i]); 79 + 80 + return ret; 81 + } 82 + } 83 + 84 + return 0; 85 + } 86 + 87 + static void ip6t_nat_unregister_lookups(struct net *net) 88 + { 89 + int i; 90 + 91 + for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) 92 + nf_nat_l3proto_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[i]); 93 + } 105 94 106 95 static int __net_init ip6table_nat_table_init(struct net *net) 107 96 { ··· 104 115 if (repl == NULL) 105 116 return -ENOMEM; 106 117 ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl, 107 - nf_nat_ipv6_ops, &net->ipv6.ip6table_nat); 118 + NULL, &net->ipv6.ip6table_nat); 119 + if (ret < 0) { 120 + kfree(repl); 121 + return ret; 122 + } 123 + 124 + ret = ip6t_nat_register_lookups(net); 125 + if (ret < 0) { 126 + ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL); 127 + net->ipv6.ip6table_nat = NULL; 128 + } 108 129 kfree(repl); 109 130 return ret; 110 131 } ··· 123 124 { 124 125 if (!net->ipv6.ip6table_nat) 125 126 return; 126 - ip6t_unregister_table(net, net->ipv6.ip6table_nat, nf_nat_ipv6_ops); 127 + ip6t_nat_unregister_lookups(net); 128 + ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL); 127 129 net->ipv6.ip6table_nat = NULL; 128 130 } 129 131
+56 -73
net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
··· 252 252 } 253 253 EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation); 254 254 255 - unsigned int 255 + static unsigned int 256 256 nf_nat_ipv6_fn(void *priv, struct sk_buff *skb, 257 - const struct nf_hook_state *state, 258 - unsigned int (*do_chain)(void *priv, 259 - struct sk_buff *skb, 260 - const struct nf_hook_state *state)) 257 + const struct nf_hook_state *state) 261 258 { 262 259 struct nf_conn *ct; 263 260 enum ip_conntrack_info ctinfo; 264 - struct nf_conn_nat *nat; 265 - enum nf_nat_manip_type maniptype = HOOK2MANIP(state->hook); 266 261 __be16 frag_off; 267 262 int hdrlen; 268 263 u8 nexthdr; ··· 271 276 if (!ct) 272 277 return NF_ACCEPT; 273 278 274 - nat = nfct_nat(ct); 275 - 276 - switch (ctinfo) { 277 - case IP_CT_RELATED: 278 - case IP_CT_RELATED_REPLY: 279 + if (ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY) { 279 280 nexthdr = ipv6_hdr(skb)->nexthdr; 280 281 hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), 281 282 &nexthdr, &frag_off); ··· 284 293 else 285 294 return NF_ACCEPT; 286 295 } 287 - /* Only ICMPs can be IP_CT_IS_REPLY: */ 288 - /* fall through */ 289 - case IP_CT_NEW: 290 - /* Seen it before? This can happen for loopback, retrans, 291 - * or local packets. 292 - */ 293 - if (!nf_nat_initialized(ct, maniptype)) { 294 - unsigned int ret; 295 - 296 - ret = do_chain(priv, skb, state); 297 - if (ret != NF_ACCEPT) 298 - return ret; 299 - 300 - if (nf_nat_initialized(ct, HOOK2MANIP(state->hook))) 301 - break; 302 - 303 - ret = nf_nat_alloc_null_binding(ct, state->hook); 304 - if (ret != NF_ACCEPT) 305 - return ret; 306 - } else { 307 - pr_debug("Already setup manip %s for ct %p\n", 308 - maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 309 - ct); 310 - if (nf_nat_oif_changed(state->hook, ctinfo, nat, state->out)) 311 - goto oif_changed; 312 - } 313 - break; 314 - 315 - default: 316 - /* ESTABLISHED */ 317 - WARN_ON(ctinfo != IP_CT_ESTABLISHED && 318 - ctinfo != IP_CT_ESTABLISHED_REPLY); 319 - if (nf_nat_oif_changed(state->hook, ctinfo, nat, state->out)) 320 - goto oif_changed; 321 296 } 322 297 323 - return nf_nat_packet(ct, ctinfo, state->hook, skb); 324 - 325 - oif_changed: 326 - nf_ct_kill_acct(ct, ctinfo, skb); 327 - return NF_DROP; 298 + return nf_nat_inet_fn(priv, skb, state); 328 299 } 329 - EXPORT_SYMBOL_GPL(nf_nat_ipv6_fn); 330 300 331 - unsigned int 301 + static unsigned int 332 302 nf_nat_ipv6_in(void *priv, struct sk_buff *skb, 333 - const struct nf_hook_state *state, 334 - unsigned int (*do_chain)(void *priv, 335 - struct sk_buff *skb, 336 - const struct nf_hook_state *state)) 303 + const struct nf_hook_state *state) 337 304 { 338 305 unsigned int ret; 339 306 struct in6_addr daddr = ipv6_hdr(skb)->daddr; 340 307 341 - ret = nf_nat_ipv6_fn(priv, skb, state, do_chain); 308 + ret = nf_nat_ipv6_fn(priv, skb, state); 342 309 if (ret != NF_DROP && ret != NF_STOLEN && 343 310 ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) 344 311 skb_dst_drop(skb); 345 312 346 313 return ret; 347 314 } 348 - EXPORT_SYMBOL_GPL(nf_nat_ipv6_in); 349 315 350 - unsigned int 316 + static unsigned int 351 317 nf_nat_ipv6_out(void *priv, struct sk_buff *skb, 352 - const struct nf_hook_state *state, 353 - unsigned int (*do_chain)(void *priv, 354 - struct sk_buff *skb, 355 - const struct nf_hook_state *state)) 318 + const struct nf_hook_state *state) 356 319 { 357 320 #ifdef CONFIG_XFRM 358 321 const struct nf_conn *ct; ··· 315 370 #endif 316 371 unsigned int ret; 317 372 318 - ret = nf_nat_ipv6_fn(priv, skb, state, do_chain); 373 + ret = nf_nat_ipv6_fn(priv, skb, state); 319 374 #ifdef CONFIG_XFRM 320 375 if (ret != NF_DROP && ret != NF_STOLEN && 321 376 !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && ··· 335 390 #endif 336 391 return ret; 337 392 } 338 - EXPORT_SYMBOL_GPL(nf_nat_ipv6_out); 339 393 340 - unsigned int 394 + static unsigned int 341 395 nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb, 342 - const struct nf_hook_state *state, 343 - unsigned int (*do_chain)(void *priv, 344 - struct sk_buff *skb, 345 - const struct nf_hook_state *state)) 396 + const struct nf_hook_state *state) 346 397 { 347 398 const struct nf_conn *ct; 348 399 enum ip_conntrack_info ctinfo; 349 400 unsigned int ret; 350 401 int err; 351 402 352 - ret = nf_nat_ipv6_fn(priv, skb, state, do_chain); 403 + ret = nf_nat_ipv6_fn(priv, skb, state); 353 404 if (ret != NF_DROP && ret != NF_STOLEN && 354 405 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 355 406 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); ··· 369 428 } 370 429 return ret; 371 430 } 372 - EXPORT_SYMBOL_GPL(nf_nat_ipv6_local_fn); 431 + 432 + static const struct nf_hook_ops nf_nat_ipv6_ops[] = { 433 + /* Before packet filtering, change destination */ 434 + { 435 + .hook = nf_nat_ipv6_in, 436 + .pf = NFPROTO_IPV6, 437 + .hooknum = NF_INET_PRE_ROUTING, 438 + .priority = NF_IP6_PRI_NAT_DST, 439 + }, 440 + /* After packet filtering, change source */ 441 + { 442 + .hook = nf_nat_ipv6_out, 443 + .pf = NFPROTO_IPV6, 444 + .hooknum = NF_INET_POST_ROUTING, 445 + .priority = NF_IP6_PRI_NAT_SRC, 446 + }, 447 + /* Before packet filtering, change destination */ 448 + { 449 + .hook = nf_nat_ipv6_local_fn, 450 + .pf = NFPROTO_IPV6, 451 + .hooknum = NF_INET_LOCAL_OUT, 452 + .priority = NF_IP6_PRI_NAT_DST, 453 + }, 454 + /* After packet filtering, change source */ 455 + { 456 + .hook = nf_nat_ipv6_fn, 457 + .pf = NFPROTO_IPV6, 458 + .hooknum = NF_INET_LOCAL_IN, 459 + .priority = NF_IP6_PRI_NAT_SRC, 460 + }, 461 + }; 462 + 463 + int nf_nat_l3proto_ipv6_register_fn(struct net *net, const struct nf_hook_ops *ops) 464 + { 465 + return nf_nat_register_fn(net, ops, nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops)); 466 + } 467 + EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv6_register_fn); 468 + 469 + void nf_nat_l3proto_ipv6_unregister_fn(struct net *net, const struct nf_hook_ops *ops) 470 + { 471 + nf_nat_unregister_fn(net, ops, ARRAY_SIZE(nf_nat_ipv6_ops)); 472 + } 473 + EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv6_unregister_fn); 373 474 374 475 static int __init nf_nat_l3proto_ipv6_init(void) 375 476 {
+10 -38
net/ipv6/netfilter/nft_chain_nat_ipv6.c
··· 36 36 return nft_do_chain(&pkt, priv); 37 37 } 38 38 39 - static unsigned int nft_nat_ipv6_fn(void *priv, 40 - struct sk_buff *skb, 41 - const struct nf_hook_state *state) 39 + static int nft_nat_ipv6_reg(struct net *net, const struct nf_hook_ops *ops) 42 40 { 43 - return nf_nat_ipv6_fn(priv, skb, state, nft_nat_do_chain); 41 + return nf_nat_l3proto_ipv6_register_fn(net, ops); 44 42 } 45 43 46 - static unsigned int nft_nat_ipv6_in(void *priv, 47 - struct sk_buff *skb, 48 - const struct nf_hook_state *state) 44 + static void nft_nat_ipv6_unreg(struct net *net, const struct nf_hook_ops *ops) 49 45 { 50 - return nf_nat_ipv6_in(priv, skb, state, nft_nat_do_chain); 51 - } 52 - 53 - static unsigned int nft_nat_ipv6_out(void *priv, 54 - struct sk_buff *skb, 55 - const struct nf_hook_state *state) 56 - { 57 - return nf_nat_ipv6_out(priv, skb, state, nft_nat_do_chain); 58 - } 59 - 60 - static unsigned int nft_nat_ipv6_local_fn(void *priv, 61 - struct sk_buff *skb, 62 - const struct nf_hook_state *state) 63 - { 64 - return nf_nat_ipv6_local_fn(priv, skb, state, nft_nat_do_chain); 65 - } 66 - 67 - static int nft_nat_ipv6_init(struct nft_ctx *ctx) 68 - { 69 - return nf_ct_netns_get(ctx->net, ctx->family); 70 - } 71 - 72 - static void nft_nat_ipv6_free(struct nft_ctx *ctx) 73 - { 74 - nf_ct_netns_put(ctx->net, ctx->family); 46 + nf_nat_l3proto_ipv6_unregister_fn(net, ops); 75 47 } 76 48 77 49 static const struct nft_chain_type nft_chain_nat_ipv6 = { ··· 56 84 (1 << NF_INET_LOCAL_OUT) | 57 85 (1 << NF_INET_LOCAL_IN), 58 86 .hooks = { 59 - [NF_INET_PRE_ROUTING] = nft_nat_ipv6_in, 60 - [NF_INET_POST_ROUTING] = nft_nat_ipv6_out, 61 - [NF_INET_LOCAL_OUT] = nft_nat_ipv6_local_fn, 62 - [NF_INET_LOCAL_IN] = nft_nat_ipv6_fn, 87 + [NF_INET_PRE_ROUTING] = nft_nat_do_chain, 88 + [NF_INET_POST_ROUTING] = nft_nat_do_chain, 89 + [NF_INET_LOCAL_OUT] = nft_nat_do_chain, 90 + [NF_INET_LOCAL_IN] = nft_nat_do_chain, 63 91 }, 64 - .init = nft_nat_ipv6_init, 65 - .free = nft_nat_ipv6_free, 92 + .ops_register = nft_nat_ipv6_reg, 93 + .ops_unregister = nft_nat_ipv6_unreg, 66 94 }; 67 95 68 96 static int __init nft_chain_nat_ipv6_init(void)
+1 -1
net/netfilter/Kconfig
··· 445 445 endif # NF_CONNTRACK 446 446 447 447 config NF_OSF 448 - tristate 'Passive OS fingerprint infrastructure' 448 + tristate 449 449 450 450 config NF_TABLES 451 451 select NETFILTER_NETLINK
+64 -38
net/netfilter/core.c
··· 138 138 continue; 139 139 } 140 140 141 - if (reg->nat_hook && orig_ops[i]->nat_hook) { 142 - kvfree(new); 143 - return ERR_PTR(-EBUSY); 144 - } 145 - 146 141 if (inserted || reg->priority > orig_ops[i]->priority) { 147 142 new_ops[nhooks] = (void *)orig_ops[i]; 148 143 new->hooks[nhooks] = old->hooks[i]; ··· 181 186 #endif 182 187 } 183 188 189 + int nf_hook_entries_insert_raw(struct nf_hook_entries __rcu **pp, 190 + const struct nf_hook_ops *reg) 191 + { 192 + struct nf_hook_entries *new_hooks; 193 + struct nf_hook_entries *p; 194 + 195 + p = rcu_dereference_raw(*pp); 196 + new_hooks = nf_hook_entries_grow(p, reg); 197 + if (IS_ERR(new_hooks)) 198 + return PTR_ERR(new_hooks); 199 + 200 + hooks_validate(new_hooks); 201 + 202 + rcu_assign_pointer(*pp, new_hooks); 203 + 204 + BUG_ON(p == new_hooks); 205 + nf_hook_entries_free(p); 206 + return 0; 207 + } 208 + EXPORT_SYMBOL_GPL(nf_hook_entries_insert_raw); 209 + 184 210 /* 185 211 * __nf_hook_entries_try_shrink - try to shrink hook array 186 212 * 213 + * @old -- current hook blob at @pp 187 214 * @pp -- location of hook blob 188 215 * 189 216 * Hook unregistration must always succeed, so to-be-removed hooks ··· 218 201 * 219 202 * Returns address to free, or NULL. 220 203 */ 221 - static void *__nf_hook_entries_try_shrink(struct nf_hook_entries __rcu **pp) 204 + static void *__nf_hook_entries_try_shrink(struct nf_hook_entries *old, 205 + struct nf_hook_entries __rcu **pp) 222 206 { 223 - struct nf_hook_entries *old, *new = NULL; 224 207 unsigned int i, j, skip = 0, hook_entries; 208 + struct nf_hook_entries *new = NULL; 225 209 struct nf_hook_ops **orig_ops; 226 210 struct nf_hook_ops **new_ops; 227 211 228 - old = nf_entry_dereference(*pp); 229 212 if (WARN_ON_ONCE(!old)) 230 213 return NULL; 231 214 ··· 364 347 * This cannot fail, hook unregistration must always succeed. 365 348 * Therefore replace the to-be-removed hook with a dummy hook. 366 349 */ 367 - static void nf_remove_net_hook(struct nf_hook_entries *old, 368 - const struct nf_hook_ops *unreg, int pf) 350 + static bool nf_remove_net_hook(struct nf_hook_entries *old, 351 + const struct nf_hook_ops *unreg) 369 352 { 370 353 struct nf_hook_ops **orig_ops; 371 - bool found = false; 372 354 unsigned int i; 373 355 374 356 orig_ops = nf_hook_entries_get_hook_ops(old); ··· 376 360 continue; 377 361 WRITE_ONCE(old->hooks[i].hook, accept_all); 378 362 WRITE_ONCE(orig_ops[i], &dummy_ops); 379 - found = true; 380 - break; 363 + return true; 381 364 } 382 365 383 - if (found) { 384 - #ifdef CONFIG_NETFILTER_INGRESS 385 - if (pf == NFPROTO_NETDEV && unreg->hooknum == NF_NETDEV_INGRESS) 386 - net_dec_ingress_queue(); 387 - #endif 388 - #ifdef HAVE_JUMP_LABEL 389 - static_key_slow_dec(&nf_hooks_needed[pf][unreg->hooknum]); 390 - #endif 391 - } else { 392 - WARN_ONCE(1, "hook not found, pf %d num %d", pf, unreg->hooknum); 393 - } 366 + return false; 394 367 } 395 368 396 369 static void __nf_unregister_net_hook(struct net *net, int pf, ··· 400 395 return; 401 396 } 402 397 403 - nf_remove_net_hook(p, reg, pf); 398 + if (nf_remove_net_hook(p, reg)) { 399 + #ifdef CONFIG_NETFILTER_INGRESS 400 + if (pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) 401 + net_dec_ingress_queue(); 402 + #endif 403 + #ifdef HAVE_JUMP_LABEL 404 + static_key_slow_dec(&nf_hooks_needed[pf][reg->hooknum]); 405 + #endif 406 + } else { 407 + WARN_ONCE(1, "hook not found, pf %d num %d", pf, reg->hooknum); 408 + } 404 409 405 - p = __nf_hook_entries_try_shrink(pp); 410 + p = __nf_hook_entries_try_shrink(p, pp); 406 411 mutex_unlock(&nf_hook_mutex); 407 412 if (!p) 408 413 return; ··· 431 416 } 432 417 } 433 418 EXPORT_SYMBOL(nf_unregister_net_hook); 419 + 420 + void nf_hook_entries_delete_raw(struct nf_hook_entries __rcu **pp, 421 + const struct nf_hook_ops *reg) 422 + { 423 + struct nf_hook_entries *p; 424 + 425 + p = rcu_dereference_raw(*pp); 426 + if (nf_remove_net_hook(p, reg)) { 427 + p = __nf_hook_entries_try_shrink(p, pp); 428 + nf_hook_entries_free(p); 429 + } 430 + } 431 + EXPORT_SYMBOL_GPL(nf_hook_entries_delete_raw); 434 432 435 433 int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) 436 434 { ··· 563 535 struct nfnl_ct_hook __rcu *nfnl_ct_hook __read_mostly; 564 536 EXPORT_SYMBOL_GPL(nfnl_ct_hook); 565 537 538 + struct nf_ct_hook __rcu *nf_ct_hook __read_mostly; 539 + EXPORT_SYMBOL_GPL(nf_ct_hook); 540 + 566 541 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 567 542 /* This does not belong here, but locally generated errors need it if connection 568 543 tracking in use: without this, connection may not be in hash table, and hence ··· 573 542 void (*ip_ct_attach)(struct sk_buff *, const struct sk_buff *) 574 543 __rcu __read_mostly; 575 544 EXPORT_SYMBOL(ip_ct_attach); 545 + 546 + struct nf_nat_hook __rcu *nf_nat_hook __read_mostly; 547 + EXPORT_SYMBOL_GPL(nf_nat_hook); 576 548 577 549 void nf_ct_attach(struct sk_buff *new, const struct sk_buff *skb) 578 550 { ··· 591 557 } 592 558 EXPORT_SYMBOL(nf_ct_attach); 593 559 594 - void (*nf_ct_destroy)(struct nf_conntrack *) __rcu __read_mostly; 595 - EXPORT_SYMBOL(nf_ct_destroy); 596 - 597 560 void nf_conntrack_destroy(struct nf_conntrack *nfct) 598 561 { 599 - void (*destroy)(struct nf_conntrack *); 562 + struct nf_ct_hook *ct_hook; 600 563 601 564 rcu_read_lock(); 602 - destroy = rcu_dereference(nf_ct_destroy); 603 - BUG_ON(destroy == NULL); 604 - destroy(nfct); 565 + ct_hook = rcu_dereference(nf_ct_hook); 566 + BUG_ON(ct_hook == NULL); 567 + ct_hook->destroy(nfct); 605 568 rcu_read_unlock(); 606 569 } 607 570 EXPORT_SYMBOL(nf_conntrack_destroy); ··· 610 579 }; 611 580 EXPORT_SYMBOL_GPL(nf_ct_zone_dflt); 612 581 #endif /* CONFIG_NF_CONNTRACK */ 613 - 614 - #ifdef CONFIG_NF_NAT_NEEDED 615 - void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); 616 - EXPORT_SYMBOL(nf_nat_decode_session_hook); 617 - #endif 618 582 619 583 static void __net_init 620 584 __netfilter_net_init(struct nf_hook_entries __rcu **e, int max)
+83 -8
net/netfilter/nf_conntrack_core.c
··· 58 58 59 59 #include "nf_internals.h" 60 60 61 - int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, 62 - enum nf_nat_manip_type manip, 63 - const struct nlattr *attr) __read_mostly; 64 - EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); 65 - 66 61 __cacheline_aligned_in_smp spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS]; 67 62 EXPORT_SYMBOL_GPL(nf_conntrack_locks); 68 63 ··· 1607 1612 nf_conntrack_get(skb_nfct(nskb)); 1608 1613 } 1609 1614 1615 + static int nf_conntrack_update(struct net *net, struct sk_buff *skb) 1616 + { 1617 + const struct nf_conntrack_l3proto *l3proto; 1618 + const struct nf_conntrack_l4proto *l4proto; 1619 + struct nf_conntrack_tuple_hash *h; 1620 + struct nf_conntrack_tuple tuple; 1621 + enum ip_conntrack_info ctinfo; 1622 + struct nf_nat_hook *nat_hook; 1623 + unsigned int dataoff, status; 1624 + struct nf_conn *ct; 1625 + u16 l3num; 1626 + u8 l4num; 1627 + 1628 + ct = nf_ct_get(skb, &ctinfo); 1629 + if (!ct || nf_ct_is_confirmed(ct)) 1630 + return 0; 1631 + 1632 + l3num = nf_ct_l3num(ct); 1633 + l3proto = nf_ct_l3proto_find_get(l3num); 1634 + 1635 + if (l3proto->get_l4proto(skb, skb_network_offset(skb), &dataoff, 1636 + &l4num) <= 0) 1637 + return -1; 1638 + 1639 + l4proto = nf_ct_l4proto_find_get(l3num, l4num); 1640 + 1641 + if (!nf_ct_get_tuple(skb, skb_network_offset(skb), dataoff, l3num, 1642 + l4num, net, &tuple, l3proto, l4proto)) 1643 + return -1; 1644 + 1645 + if (ct->status & IPS_SRC_NAT) { 1646 + memcpy(tuple.src.u3.all, 1647 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.all, 1648 + sizeof(tuple.src.u3.all)); 1649 + tuple.src.u.all = 1650 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all; 1651 + } 1652 + 1653 + if (ct->status & IPS_DST_NAT) { 1654 + memcpy(tuple.dst.u3.all, 1655 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.all, 1656 + sizeof(tuple.dst.u3.all)); 1657 + tuple.dst.u.all = 1658 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all; 1659 + } 1660 + 1661 + h = nf_conntrack_find_get(net, nf_ct_zone(ct), &tuple); 1662 + if (!h) 1663 + return 0; 1664 + 1665 + /* Store status bits of the conntrack that is clashing to re-do NAT 1666 + * mangling according to what it has been done already to this packet. 1667 + */ 1668 + status = ct->status; 1669 + 1670 + nf_ct_put(ct); 1671 + ct = nf_ct_tuplehash_to_ctrack(h); 1672 + nf_ct_set(skb, ct, ctinfo); 1673 + 1674 + nat_hook = rcu_dereference(nf_nat_hook); 1675 + if (!nat_hook) 1676 + return 0; 1677 + 1678 + if (status & IPS_SRC_NAT && 1679 + nat_hook->manip_pkt(skb, ct, NF_NAT_MANIP_SRC, 1680 + IP_CT_DIR_ORIGINAL) == NF_DROP) 1681 + return -1; 1682 + 1683 + if (status & IPS_DST_NAT && 1684 + nat_hook->manip_pkt(skb, ct, NF_NAT_MANIP_DST, 1685 + IP_CT_DIR_ORIGINAL) == NF_DROP) 1686 + return -1; 1687 + 1688 + return 0; 1689 + } 1690 + 1610 1691 /* Bring out ya dead! */ 1611 1692 static struct nf_conn * 1612 1693 get_next_corpse(int (*iter)(struct nf_conn *i, void *data), ··· 1884 1813 1885 1814 void nf_conntrack_cleanup_end(void) 1886 1815 { 1887 - RCU_INIT_POINTER(nf_ct_destroy, NULL); 1888 - 1816 + RCU_INIT_POINTER(nf_ct_hook, NULL); 1889 1817 cancel_delayed_work_sync(&conntrack_gc_work.dwork); 1890 1818 nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_htable_size); 1891 1819 ··· 2201 2131 return ret; 2202 2132 } 2203 2133 2134 + static struct nf_ct_hook nf_conntrack_hook = { 2135 + .update = nf_conntrack_update, 2136 + .destroy = destroy_conntrack, 2137 + }; 2138 + 2204 2139 void nf_conntrack_init_end(void) 2205 2140 { 2206 2141 /* For use by REJECT target */ 2207 2142 RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); 2208 - RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); 2143 + RCU_INIT_POINTER(nf_ct_hook, &nf_conntrack_hook); 2209 2144 } 2210 2145 2211 2146 /*
+5 -5
net/netfilter/nf_conntrack_netlink.c
··· 1431 1431 enum nf_nat_manip_type manip, 1432 1432 const struct nlattr *attr) 1433 1433 { 1434 - typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup; 1434 + struct nf_nat_hook *nat_hook; 1435 1435 int err; 1436 1436 1437 - parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook); 1438 - if (!parse_nat_setup) { 1437 + nat_hook = rcu_dereference(nf_nat_hook); 1438 + if (!nat_hook) { 1439 1439 #ifdef CONFIG_MODULES 1440 1440 rcu_read_unlock(); 1441 1441 nfnl_unlock(NFNL_SUBSYS_CTNETLINK); ··· 1446 1446 } 1447 1447 nfnl_lock(NFNL_SUBSYS_CTNETLINK); 1448 1448 rcu_read_lock(); 1449 - if (nfnetlink_parse_nat_setup_hook) 1449 + if (nat_hook->parse_nat_setup) 1450 1450 return -EAGAIN; 1451 1451 #endif 1452 1452 return -EOPNOTSUPP; 1453 1453 } 1454 1454 1455 - err = parse_nat_setup(ct, manip, attr); 1455 + err = nat_hook->parse_nat_setup(ct, manip, attr); 1456 1456 if (err == -EAGAIN) { 1457 1457 #ifdef CONFIG_MODULES 1458 1458 rcu_read_unlock();
+5
net/netfilter/nf_internals.h
··· 15 15 /* nf_log.c */ 16 16 int __init netfilter_log_init(void); 17 17 18 + /* core.c */ 19 + void nf_hook_entries_delete_raw(struct nf_hook_entries __rcu **pp, 20 + const struct nf_hook_ops *reg); 21 + int nf_hook_entries_insert_raw(struct nf_hook_entries __rcu **pp, 22 + const struct nf_hook_ops *reg); 18 23 #endif
+271 -27
net/netfilter/nf_nat_core.c
··· 32 32 #include <net/netfilter/nf_conntrack_zones.h> 33 33 #include <linux/netfilter/nf_nat.h> 34 34 35 + #include "nf_internals.h" 36 + 35 37 static spinlock_t nf_nat_locks[CONNTRACK_LOCKS]; 36 38 37 39 static DEFINE_MUTEX(nf_nat_proto_mutex); ··· 41 39 __read_mostly; 42 40 static const struct nf_nat_l4proto __rcu **nf_nat_l4protos[NFPROTO_NUMPROTO] 43 41 __read_mostly; 42 + static unsigned int nat_net_id __read_mostly; 44 43 45 44 static struct hlist_head *nf_nat_bysource __read_mostly; 46 45 static unsigned int nf_nat_htable_size __read_mostly; 47 46 static unsigned int nf_nat_hash_rnd __read_mostly; 47 + 48 + struct nf_nat_lookup_hook_priv { 49 + struct nf_hook_entries __rcu *entries; 50 + 51 + struct rcu_head rcu_head; 52 + }; 53 + 54 + struct nf_nat_hooks_net { 55 + struct nf_hook_ops *nat_hook_ops; 56 + unsigned int users; 57 + }; 58 + 59 + struct nat_net { 60 + struct nf_nat_hooks_net nat_proto_net[NFPROTO_NUMPROTO]; 61 + }; 48 62 49 63 inline const struct nf_nat_l3proto * 50 64 __nf_nat_l3proto_find(u8 family) ··· 493 475 } 494 476 EXPORT_SYMBOL_GPL(nf_nat_alloc_null_binding); 495 477 478 + static unsigned int nf_nat_manip_pkt(struct sk_buff *skb, struct nf_conn *ct, 479 + enum nf_nat_manip_type mtype, 480 + enum ip_conntrack_dir dir) 481 + { 482 + const struct nf_nat_l3proto *l3proto; 483 + const struct nf_nat_l4proto *l4proto; 484 + struct nf_conntrack_tuple target; 485 + 486 + /* We are aiming to look like inverse of other direction. */ 487 + nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); 488 + 489 + l3proto = __nf_nat_l3proto_find(target.src.l3num); 490 + l4proto = __nf_nat_l4proto_find(target.src.l3num, 491 + target.dst.protonum); 492 + if (!l3proto->manip_pkt(skb, 0, l4proto, &target, mtype)) 493 + return NF_DROP; 494 + 495 + return NF_ACCEPT; 496 + } 497 + 496 498 /* Do packet manipulations according to nf_nat_setup_info. */ 497 499 unsigned int nf_nat_packet(struct nf_conn *ct, 498 500 enum ip_conntrack_info ctinfo, 499 501 unsigned int hooknum, 500 502 struct sk_buff *skb) 501 503 { 502 - const struct nf_nat_l3proto *l3proto; 503 - const struct nf_nat_l4proto *l4proto; 504 - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 505 - unsigned long statusbit; 506 504 enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum); 505 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 506 + unsigned int verdict = NF_ACCEPT; 507 + unsigned long statusbit; 507 508 508 509 if (mtype == NF_NAT_MANIP_SRC) 509 510 statusbit = IPS_SRC_NAT; ··· 534 497 statusbit ^= IPS_NAT_MASK; 535 498 536 499 /* Non-atomic: these bits don't change. */ 537 - if (ct->status & statusbit) { 538 - struct nf_conntrack_tuple target; 500 + if (ct->status & statusbit) 501 + verdict = nf_nat_manip_pkt(skb, ct, mtype, dir); 539 502 540 - /* We are aiming to look like inverse of other direction. */ 541 - nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); 542 - 543 - l3proto = __nf_nat_l3proto_find(target.src.l3num); 544 - l4proto = __nf_nat_l4proto_find(target.src.l3num, 545 - target.dst.protonum); 546 - if (!l3proto->manip_pkt(skb, 0, l4proto, &target, mtype)) 547 - return NF_DROP; 548 - } 549 - return NF_ACCEPT; 503 + return verdict; 550 504 } 551 505 EXPORT_SYMBOL_GPL(nf_nat_packet); 506 + 507 + unsigned int 508 + nf_nat_inet_fn(void *priv, struct sk_buff *skb, 509 + const struct nf_hook_state *state) 510 + { 511 + struct nf_conn *ct; 512 + enum ip_conntrack_info ctinfo; 513 + struct nf_conn_nat *nat; 514 + /* maniptype == SRC for postrouting. */ 515 + enum nf_nat_manip_type maniptype = HOOK2MANIP(state->hook); 516 + 517 + ct = nf_ct_get(skb, &ctinfo); 518 + /* Can't track? It's not due to stress, or conntrack would 519 + * have dropped it. Hence it's the user's responsibilty to 520 + * packet filter it out, or implement conntrack/NAT for that 521 + * protocol. 8) --RR 522 + */ 523 + if (!ct) 524 + return NF_ACCEPT; 525 + 526 + nat = nfct_nat(ct); 527 + 528 + switch (ctinfo) { 529 + case IP_CT_RELATED: 530 + case IP_CT_RELATED_REPLY: 531 + /* Only ICMPs can be IP_CT_IS_REPLY. Fallthrough */ 532 + case IP_CT_NEW: 533 + /* Seen it before? This can happen for loopback, retrans, 534 + * or local packets. 535 + */ 536 + if (!nf_nat_initialized(ct, maniptype)) { 537 + struct nf_nat_lookup_hook_priv *lpriv = priv; 538 + struct nf_hook_entries *e = rcu_dereference(lpriv->entries); 539 + unsigned int ret; 540 + int i; 541 + 542 + if (!e) 543 + goto null_bind; 544 + 545 + for (i = 0; i < e->num_hook_entries; i++) { 546 + ret = e->hooks[i].hook(e->hooks[i].priv, skb, 547 + state); 548 + if (ret != NF_ACCEPT) 549 + return ret; 550 + if (nf_nat_initialized(ct, maniptype)) 551 + goto do_nat; 552 + } 553 + null_bind: 554 + ret = nf_nat_alloc_null_binding(ct, state->hook); 555 + if (ret != NF_ACCEPT) 556 + return ret; 557 + } else { 558 + pr_debug("Already setup manip %s for ct %p (status bits 0x%lx)\n", 559 + maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 560 + ct, ct->status); 561 + if (nf_nat_oif_changed(state->hook, ctinfo, nat, 562 + state->out)) 563 + goto oif_changed; 564 + } 565 + break; 566 + default: 567 + /* ESTABLISHED */ 568 + WARN_ON(ctinfo != IP_CT_ESTABLISHED && 569 + ctinfo != IP_CT_ESTABLISHED_REPLY); 570 + if (nf_nat_oif_changed(state->hook, ctinfo, nat, state->out)) 571 + goto oif_changed; 572 + } 573 + do_nat: 574 + return nf_nat_packet(ct, ctinfo, state->hook, skb); 575 + 576 + oif_changed: 577 + nf_ct_kill_acct(ct, ctinfo, skb); 578 + return NF_DROP; 579 + } 580 + EXPORT_SYMBOL_GPL(nf_nat_inet_fn); 552 581 553 582 struct nf_nat_proto_clean { 554 583 u8 l3proto; ··· 904 801 .expectfn = nf_nat_follow_master, 905 802 }; 906 803 804 + int nf_nat_register_fn(struct net *net, const struct nf_hook_ops *ops, 805 + const struct nf_hook_ops *orig_nat_ops, unsigned int ops_count) 806 + { 807 + struct nat_net *nat_net = net_generic(net, nat_net_id); 808 + struct nf_nat_hooks_net *nat_proto_net; 809 + struct nf_nat_lookup_hook_priv *priv; 810 + unsigned int hooknum = ops->hooknum; 811 + struct nf_hook_ops *nat_ops; 812 + int i, ret; 813 + 814 + if (WARN_ON_ONCE(ops->pf >= ARRAY_SIZE(nat_net->nat_proto_net))) 815 + return -EINVAL; 816 + 817 + nat_proto_net = &nat_net->nat_proto_net[ops->pf]; 818 + 819 + for (i = 0; i < ops_count; i++) { 820 + if (WARN_ON(orig_nat_ops[i].pf != ops->pf)) 821 + return -EINVAL; 822 + if (orig_nat_ops[i].hooknum == hooknum) { 823 + hooknum = i; 824 + break; 825 + } 826 + } 827 + 828 + if (WARN_ON_ONCE(i == ops_count)) 829 + return -EINVAL; 830 + 831 + mutex_lock(&nf_nat_proto_mutex); 832 + if (!nat_proto_net->nat_hook_ops) { 833 + WARN_ON(nat_proto_net->users != 0); 834 + 835 + nat_ops = kmemdup(orig_nat_ops, sizeof(*orig_nat_ops) * ops_count, GFP_KERNEL); 836 + if (!nat_ops) { 837 + mutex_unlock(&nf_nat_proto_mutex); 838 + return -ENOMEM; 839 + } 840 + 841 + for (i = 0; i < ops_count; i++) { 842 + priv = kzalloc(sizeof(*priv), GFP_KERNEL); 843 + if (priv) { 844 + nat_ops[i].priv = priv; 845 + continue; 846 + } 847 + mutex_unlock(&nf_nat_proto_mutex); 848 + while (i) 849 + kfree(nat_ops[--i].priv); 850 + kfree(nat_ops); 851 + return -ENOMEM; 852 + } 853 + 854 + ret = nf_register_net_hooks(net, nat_ops, ops_count); 855 + if (ret < 0) { 856 + mutex_unlock(&nf_nat_proto_mutex); 857 + for (i = 0; i < ops_count; i++) 858 + kfree(nat_ops[i].priv); 859 + kfree(nat_ops); 860 + return ret; 861 + } 862 + 863 + nat_proto_net->nat_hook_ops = nat_ops; 864 + } 865 + 866 + nat_ops = nat_proto_net->nat_hook_ops; 867 + priv = nat_ops[hooknum].priv; 868 + if (WARN_ON_ONCE(!priv)) { 869 + mutex_unlock(&nf_nat_proto_mutex); 870 + return -EOPNOTSUPP; 871 + } 872 + 873 + ret = nf_hook_entries_insert_raw(&priv->entries, ops); 874 + if (ret == 0) 875 + nat_proto_net->users++; 876 + 877 + mutex_unlock(&nf_nat_proto_mutex); 878 + return ret; 879 + } 880 + EXPORT_SYMBOL_GPL(nf_nat_register_fn); 881 + 882 + void nf_nat_unregister_fn(struct net *net, const struct nf_hook_ops *ops, 883 + unsigned int ops_count) 884 + { 885 + struct nat_net *nat_net = net_generic(net, nat_net_id); 886 + struct nf_nat_hooks_net *nat_proto_net; 887 + struct nf_nat_lookup_hook_priv *priv; 888 + struct nf_hook_ops *nat_ops; 889 + int hooknum = ops->hooknum; 890 + int i; 891 + 892 + if (ops->pf >= ARRAY_SIZE(nat_net->nat_proto_net)) 893 + return; 894 + 895 + nat_proto_net = &nat_net->nat_proto_net[ops->pf]; 896 + 897 + mutex_lock(&nf_nat_proto_mutex); 898 + if (WARN_ON(nat_proto_net->users == 0)) 899 + goto unlock; 900 + 901 + nat_proto_net->users--; 902 + 903 + nat_ops = nat_proto_net->nat_hook_ops; 904 + for (i = 0; i < ops_count; i++) { 905 + if (nat_ops[i].hooknum == hooknum) { 906 + hooknum = i; 907 + break; 908 + } 909 + } 910 + if (WARN_ON_ONCE(i == ops_count)) 911 + goto unlock; 912 + priv = nat_ops[hooknum].priv; 913 + nf_hook_entries_delete_raw(&priv->entries, ops); 914 + 915 + if (nat_proto_net->users == 0) { 916 + nf_unregister_net_hooks(net, nat_ops, ops_count); 917 + 918 + for (i = 0; i < ops_count; i++) { 919 + priv = nat_ops[i].priv; 920 + kfree_rcu(priv, rcu_head); 921 + } 922 + 923 + nat_proto_net->nat_hook_ops = NULL; 924 + kfree(nat_ops); 925 + } 926 + unlock: 927 + mutex_unlock(&nf_nat_proto_mutex); 928 + } 929 + EXPORT_SYMBOL_GPL(nf_nat_unregister_fn); 930 + 931 + static struct pernet_operations nat_net_ops = { 932 + .id = &nat_net_id, 933 + .size = sizeof(struct nat_net), 934 + }; 935 + 936 + struct nf_nat_hook nat_hook = { 937 + .parse_nat_setup = nfnetlink_parse_nat_setup, 938 + #ifdef CONFIG_XFRM 939 + .decode_session = __nf_nat_decode_session, 940 + #endif 941 + .manip_pkt = nf_nat_manip_pkt, 942 + }; 943 + 907 944 static int __init nf_nat_init(void) 908 945 { 909 946 int ret, i; ··· 1067 824 for (i = 0; i < CONNTRACK_LOCKS; i++) 1068 825 spin_lock_init(&nf_nat_locks[i]); 1069 826 827 + ret = register_pernet_subsys(&nat_net_ops); 828 + if (ret < 0) { 829 + nf_ct_extend_unregister(&nat_extend); 830 + return ret; 831 + } 832 + 1070 833 nf_ct_helper_expectfn_register(&follow_master_nat); 1071 834 1072 - BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); 1073 - RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, 1074 - nfnetlink_parse_nat_setup); 1075 - #ifdef CONFIG_XFRM 1076 - BUG_ON(nf_nat_decode_session_hook != NULL); 1077 - RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session); 1078 - #endif 835 + WARN_ON(nf_nat_hook != NULL); 836 + RCU_INIT_POINTER(nf_nat_hook, &nat_hook); 837 + 1079 838 return 0; 1080 839 } 1081 840 ··· 1090 845 1091 846 nf_ct_extend_unregister(&nat_extend); 1092 847 nf_ct_helper_expectfn_unregister(&follow_master_nat); 1093 - RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); 1094 - #ifdef CONFIG_XFRM 1095 - RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL); 1096 - #endif 848 + RCU_INIT_POINTER(nf_nat_hook, NULL); 849 + 1097 850 synchronize_rcu(); 1098 851 1099 852 for (i = 0; i < NFPROTO_NUMPROTO; i++) 1100 853 kfree(nf_nat_l4protos[i]); 1101 854 synchronize_net(); 1102 855 nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size); 856 + unregister_pernet_subsys(&nat_net_ops); 1103 857 } 1104 858 1105 859 MODULE_LICENSE("GPL");
+17 -70
net/netfilter/nf_tables_api.c
··· 74 74 kfree(trans); 75 75 } 76 76 77 - /* removal requests are queued in the commit_list, but not acted upon 78 - * until after all new rules are in place. 79 - * 80 - * Therefore, nf_register_net_hook(net, &nat_hook) runs before pending 81 - * nf_unregister_net_hook(). 82 - * 83 - * nf_register_net_hook thus fails if a nat hook is already in place 84 - * even if the conflicting hook is about to be removed. 85 - * 86 - * If collision is detected, search commit_log for DELCHAIN matching 87 - * the new nat hooknum; if we find one collision is temporary: 88 - * 89 - * Either transaction is aborted (new/colliding hook is removed), or 90 - * transaction is committed (old hook is removed). 91 - */ 92 - static bool nf_tables_allow_nat_conflict(const struct net *net, 93 - const struct nf_hook_ops *ops) 94 - { 95 - const struct nft_trans *trans; 96 - bool ret = false; 97 - 98 - if (!ops->nat_hook) 99 - return false; 100 - 101 - list_for_each_entry(trans, &net->nft.commit_list, list) { 102 - const struct nf_hook_ops *pending_ops; 103 - const struct nft_chain *pending; 104 - 105 - if (trans->msg_type != NFT_MSG_NEWCHAIN && 106 - trans->msg_type != NFT_MSG_DELCHAIN) 107 - continue; 108 - 109 - pending = trans->ctx.chain; 110 - if (!nft_is_base_chain(pending)) 111 - continue; 112 - 113 - pending_ops = &nft_base_chain(pending)->ops; 114 - if (pending_ops->nat_hook && 115 - pending_ops->pf == ops->pf && 116 - pending_ops->hooknum == ops->hooknum) { 117 - /* other hook registration already pending? */ 118 - if (trans->msg_type == NFT_MSG_NEWCHAIN) 119 - return false; 120 - 121 - ret = true; 122 - } 123 - } 124 - 125 - return ret; 126 - } 127 - 128 77 static int nf_tables_register_hook(struct net *net, 129 78 const struct nft_table *table, 130 79 struct nft_chain *chain) 131 80 { 132 - struct nf_hook_ops *ops; 133 - int ret; 81 + const struct nft_base_chain *basechain; 82 + const struct nf_hook_ops *ops; 134 83 135 84 if (table->flags & NFT_TABLE_F_DORMANT || 136 85 !nft_is_base_chain(chain)) 137 86 return 0; 138 87 139 - ops = &nft_base_chain(chain)->ops; 140 - ret = nf_register_net_hook(net, ops); 141 - if (ret == -EBUSY && nf_tables_allow_nat_conflict(net, ops)) { 142 - ops->nat_hook = false; 143 - ret = nf_register_net_hook(net, ops); 144 - ops->nat_hook = true; 145 - } 88 + basechain = nft_base_chain(chain); 89 + ops = &basechain->ops; 146 90 147 - return ret; 91 + if (basechain->type->ops_register) 92 + return basechain->type->ops_register(net, ops); 93 + 94 + return nf_register_net_hook(net, ops); 148 95 } 149 96 150 97 static void nf_tables_unregister_hook(struct net *net, 151 98 const struct nft_table *table, 152 99 struct nft_chain *chain) 153 100 { 101 + const struct nft_base_chain *basechain; 102 + const struct nf_hook_ops *ops; 103 + 154 104 if (table->flags & NFT_TABLE_F_DORMANT || 155 105 !nft_is_base_chain(chain)) 156 106 return; 107 + basechain = nft_base_chain(chain); 108 + ops = &basechain->ops; 157 109 158 - nf_unregister_net_hook(net, &nft_base_chain(chain)->ops); 110 + if (basechain->type->ops_unregister) 111 + return basechain->type->ops_unregister(net, ops); 112 + 113 + nf_unregister_net_hook(net, ops); 159 114 } 160 115 161 116 static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type) ··· 1246 1291 if (nft_is_base_chain(chain)) { 1247 1292 struct nft_base_chain *basechain = nft_base_chain(chain); 1248 1293 1249 - if (basechain->type->free) 1250 - basechain->type->free(ctx); 1251 1294 module_put(basechain->type->owner); 1252 1295 free_percpu(basechain->stats); 1253 1296 if (basechain->stats) ··· 1378 1425 } 1379 1426 1380 1427 basechain->type = hook.type; 1381 - if (basechain->type->init) 1382 - basechain->type->init(ctx); 1383 - 1384 1428 chain = &basechain->chain; 1385 1429 1386 1430 ops = &basechain->ops; ··· 1387 1437 ops->priv = chain; 1388 1438 ops->hook = hook.type->hooks[ops->hooknum]; 1389 1439 ops->dev = hook.dev; 1390 - 1391 - if (basechain->type->type == NFT_CHAIN_T_NAT) 1392 - ops->nat_hook = true; 1393 1440 1394 1441 chain->flags |= NFT_BASE_CHAIN; 1395 1442 basechain->policy = policy;
+7 -22
net/netfilter/nf_tables_core.c
··· 41 41 42 42 static noinline void __nft_trace_packet(struct nft_traceinfo *info, 43 43 const struct nft_chain *chain, 44 - int rulenum, enum nft_trace_types type) 44 + enum nft_trace_types type) 45 45 { 46 46 const struct nft_pktinfo *pkt = info->pkt; 47 47 ··· 52 52 info->type = type; 53 53 54 54 nft_trace_notify(info); 55 - 56 - nf_log_trace(nft_net(pkt), nft_pf(pkt), nft_hook(pkt), pkt->skb, 57 - nft_in(pkt), nft_out(pkt), &trace_loginfo, 58 - "TRACE: %s:%s:%s:%u ", 59 - chain->table->name, chain->name, comments[type], rulenum); 60 55 } 61 56 62 57 static inline void nft_trace_packet(struct nft_traceinfo *info, 63 58 const struct nft_chain *chain, 64 59 const struct nft_rule *rule, 65 - int rulenum, 66 60 enum nft_trace_types type) 67 61 { 68 62 if (static_branch_unlikely(&nft_trace_enabled)) { 69 63 info->rule = rule; 70 - __nft_trace_packet(info, chain, rulenum, type); 64 + __nft_trace_packet(info, chain, type); 71 65 } 72 66 } 73 67 ··· 134 140 struct nft_jumpstack { 135 141 const struct nft_chain *chain; 136 142 const struct nft_rule *rule; 137 - int rulenum; 138 143 }; 139 144 140 145 unsigned int ··· 146 153 struct nft_regs regs; 147 154 unsigned int stackptr = 0; 148 155 struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; 149 - int rulenum; 150 156 unsigned int gencursor = nft_genmask_cur(net); 151 157 struct nft_traceinfo info; 152 158 ··· 153 161 if (static_branch_unlikely(&nft_trace_enabled)) 154 162 nft_trace_init(&info, pkt, &regs.verdict, basechain); 155 163 do_chain: 156 - rulenum = 0; 157 164 rule = list_entry(&chain->rules, struct nft_rule, list); 158 165 next_rule: 159 166 regs.verdict.code = NFT_CONTINUE; ··· 161 170 /* This rule is not active, skip. */ 162 171 if (unlikely(rule->genmask & gencursor)) 163 172 continue; 164 - 165 - rulenum++; 166 173 167 174 nft_rule_for_each_expr(expr, last, rule) { 168 175 if (expr->ops == &nft_cmp_fast_ops) ··· 179 190 continue; 180 191 case NFT_CONTINUE: 181 192 nft_trace_packet(&info, chain, rule, 182 - rulenum, NFT_TRACETYPE_RULE); 193 + NFT_TRACETYPE_RULE); 183 194 continue; 184 195 } 185 196 break; ··· 191 202 case NF_QUEUE: 192 203 case NF_STOLEN: 193 204 nft_trace_packet(&info, chain, rule, 194 - rulenum, NFT_TRACETYPE_RULE); 205 + NFT_TRACETYPE_RULE); 195 206 return regs.verdict.code; 196 207 } 197 208 ··· 200 211 BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE); 201 212 jumpstack[stackptr].chain = chain; 202 213 jumpstack[stackptr].rule = rule; 203 - jumpstack[stackptr].rulenum = rulenum; 204 214 stackptr++; 205 215 /* fall through */ 206 216 case NFT_GOTO: 207 217 nft_trace_packet(&info, chain, rule, 208 - rulenum, NFT_TRACETYPE_RULE); 218 + NFT_TRACETYPE_RULE); 209 219 210 220 chain = regs.verdict.chain; 211 221 goto do_chain; 212 222 case NFT_CONTINUE: 213 - rulenum++; 214 223 /* fall through */ 215 224 case NFT_RETURN: 216 225 nft_trace_packet(&info, chain, rule, 217 - rulenum, NFT_TRACETYPE_RETURN); 226 + NFT_TRACETYPE_RETURN); 218 227 break; 219 228 default: 220 229 WARN_ON(1); ··· 222 235 stackptr--; 223 236 chain = jumpstack[stackptr].chain; 224 237 rule = jumpstack[stackptr].rule; 225 - rulenum = jumpstack[stackptr].rulenum; 226 238 goto next_rule; 227 239 } 228 240 229 - nft_trace_packet(&info, basechain, NULL, -1, 230 - NFT_TRACETYPE_POLICY); 241 + nft_trace_packet(&info, basechain, NULL, NFT_TRACETYPE_POLICY); 231 242 232 243 if (static_branch_unlikely(&nft_counters_enabled)) 233 244 nft_update_chain_stats(basechain, pkt);
+130 -1
net/netfilter/nft_hash.c
··· 25 25 u32 modulus; 26 26 u32 seed; 27 27 u32 offset; 28 + struct nft_set *map; 28 29 }; 29 30 30 31 static void nft_jhash_eval(const struct nft_expr *expr, ··· 36 35 const void *data = &regs->data[priv->sreg]; 37 36 u32 h; 38 37 39 - h = reciprocal_scale(jhash(data, priv->len, priv->seed), priv->modulus); 38 + h = reciprocal_scale(jhash(data, priv->len, priv->seed), 39 + priv->modulus); 40 + 40 41 regs->data[priv->dreg] = h + priv->offset; 42 + } 43 + 44 + static void nft_jhash_map_eval(const struct nft_expr *expr, 45 + struct nft_regs *regs, 46 + const struct nft_pktinfo *pkt) 47 + { 48 + struct nft_jhash *priv = nft_expr_priv(expr); 49 + const void *data = &regs->data[priv->sreg]; 50 + const struct nft_set *map = priv->map; 51 + const struct nft_set_ext *ext; 52 + u32 result; 53 + bool found; 54 + 55 + result = reciprocal_scale(jhash(data, priv->len, priv->seed), 56 + priv->modulus) + priv->offset; 57 + 58 + found = map->ops->lookup(nft_net(pkt), map, &result, &ext); 59 + if (!found) 60 + return; 61 + 62 + nft_data_copy(&regs->data[priv->dreg], 63 + nft_set_ext_data(ext), map->dlen); 41 64 } 42 65 43 66 struct nft_symhash { 44 67 enum nft_registers dreg:8; 45 68 u32 modulus; 46 69 u32 offset; 70 + struct nft_set *map; 47 71 }; 48 72 49 73 static void nft_symhash_eval(const struct nft_expr *expr, ··· 84 58 regs->data[priv->dreg] = h + priv->offset; 85 59 } 86 60 61 + static void nft_symhash_map_eval(const struct nft_expr *expr, 62 + struct nft_regs *regs, 63 + const struct nft_pktinfo *pkt) 64 + { 65 + struct nft_symhash *priv = nft_expr_priv(expr); 66 + struct sk_buff *skb = pkt->skb; 67 + const struct nft_set *map = priv->map; 68 + const struct nft_set_ext *ext; 69 + u32 result; 70 + bool found; 71 + 72 + result = reciprocal_scale(__skb_get_hash_symmetric(skb), 73 + priv->modulus) + priv->offset; 74 + 75 + found = map->ops->lookup(nft_net(pkt), map, &result, &ext); 76 + if (!found) 77 + return; 78 + 79 + nft_data_copy(&regs->data[priv->dreg], 80 + nft_set_ext_data(ext), map->dlen); 81 + } 82 + 87 83 static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = { 88 84 [NFTA_HASH_SREG] = { .type = NLA_U32 }, 89 85 [NFTA_HASH_DREG] = { .type = NLA_U32 }, ··· 114 66 [NFTA_HASH_SEED] = { .type = NLA_U32 }, 115 67 [NFTA_HASH_OFFSET] = { .type = NLA_U32 }, 116 68 [NFTA_HASH_TYPE] = { .type = NLA_U32 }, 69 + [NFTA_HASH_SET_NAME] = { .type = NLA_STRING, 70 + .len = NFT_SET_MAXNAMELEN - 1 }, 71 + [NFTA_HASH_SET_ID] = { .type = NLA_U32 }, 117 72 }; 118 73 119 74 static int nft_jhash_init(const struct nft_ctx *ctx, ··· 166 115 NFT_DATA_VALUE, sizeof(u32)); 167 116 } 168 117 118 + static int nft_jhash_map_init(const struct nft_ctx *ctx, 119 + const struct nft_expr *expr, 120 + const struct nlattr * const tb[]) 121 + { 122 + struct nft_jhash *priv = nft_expr_priv(expr); 123 + u8 genmask = nft_genmask_next(ctx->net); 124 + 125 + nft_jhash_init(ctx, expr, tb); 126 + priv->map = nft_set_lookup_global(ctx->net, ctx->table, 127 + tb[NFTA_HASH_SET_NAME], 128 + tb[NFTA_HASH_SET_ID], genmask); 129 + if (IS_ERR(priv->map)) 130 + return PTR_ERR(priv->map); 131 + 132 + return 0; 133 + } 134 + 169 135 static int nft_symhash_init(const struct nft_ctx *ctx, 170 136 const struct nft_expr *expr, 171 137 const struct nlattr * const tb[]) ··· 207 139 208 140 return nft_validate_register_store(ctx, priv->dreg, NULL, 209 141 NFT_DATA_VALUE, sizeof(u32)); 142 + } 143 + 144 + static int nft_symhash_map_init(const struct nft_ctx *ctx, 145 + const struct nft_expr *expr, 146 + const struct nlattr * const tb[]) 147 + { 148 + struct nft_jhash *priv = nft_expr_priv(expr); 149 + u8 genmask = nft_genmask_next(ctx->net); 150 + 151 + nft_symhash_init(ctx, expr, tb); 152 + priv->map = nft_set_lookup_global(ctx->net, ctx->table, 153 + tb[NFTA_HASH_SET_NAME], 154 + tb[NFTA_HASH_SET_ID], genmask); 155 + if (IS_ERR(priv->map)) 156 + return PTR_ERR(priv->map); 157 + 158 + return 0; 210 159 } 211 160 212 161 static int nft_jhash_dump(struct sk_buff *skb, ··· 253 168 return -1; 254 169 } 255 170 171 + static int nft_jhash_map_dump(struct sk_buff *skb, 172 + const struct nft_expr *expr) 173 + { 174 + const struct nft_jhash *priv = nft_expr_priv(expr); 175 + 176 + if (nft_jhash_dump(skb, expr) || 177 + nla_put_string(skb, NFTA_HASH_SET_NAME, priv->map->name)) 178 + return -1; 179 + 180 + return 0; 181 + } 182 + 256 183 static int nft_symhash_dump(struct sk_buff *skb, 257 184 const struct nft_expr *expr) 258 185 { ··· 285 188 return -1; 286 189 } 287 190 191 + static int nft_symhash_map_dump(struct sk_buff *skb, 192 + const struct nft_expr *expr) 193 + { 194 + const struct nft_symhash *priv = nft_expr_priv(expr); 195 + 196 + if (nft_symhash_dump(skb, expr) || 197 + nla_put_string(skb, NFTA_HASH_SET_NAME, priv->map->name)) 198 + return -1; 199 + 200 + return 0; 201 + } 202 + 288 203 static struct nft_expr_type nft_hash_type; 289 204 static const struct nft_expr_ops nft_jhash_ops = { 290 205 .type = &nft_hash_type, ··· 306 197 .dump = nft_jhash_dump, 307 198 }; 308 199 200 + static const struct nft_expr_ops nft_jhash_map_ops = { 201 + .type = &nft_hash_type, 202 + .size = NFT_EXPR_SIZE(sizeof(struct nft_jhash)), 203 + .eval = nft_jhash_map_eval, 204 + .init = nft_jhash_map_init, 205 + .dump = nft_jhash_map_dump, 206 + }; 207 + 309 208 static const struct nft_expr_ops nft_symhash_ops = { 310 209 .type = &nft_hash_type, 311 210 .size = NFT_EXPR_SIZE(sizeof(struct nft_symhash)), 312 211 .eval = nft_symhash_eval, 313 212 .init = nft_symhash_init, 314 213 .dump = nft_symhash_dump, 214 + }; 215 + 216 + static const struct nft_expr_ops nft_symhash_map_ops = { 217 + .type = &nft_hash_type, 218 + .size = NFT_EXPR_SIZE(sizeof(struct nft_symhash)), 219 + .eval = nft_symhash_map_eval, 220 + .init = nft_symhash_map_init, 221 + .dump = nft_symhash_map_dump, 315 222 }; 316 223 317 224 static const struct nft_expr_ops * ··· 342 217 type = ntohl(nla_get_be32(tb[NFTA_HASH_TYPE])); 343 218 switch (type) { 344 219 case NFT_HASH_SYM: 220 + if (tb[NFTA_HASH_SET_NAME]) 221 + return &nft_symhash_map_ops; 345 222 return &nft_symhash_ops; 346 223 case NFT_HASH_JENKINS: 224 + if (tb[NFTA_HASH_SET_NAME]) 225 + return &nft_jhash_map_ops; 347 226 return &nft_jhash_ops; 348 227 default: 349 228 break;
+72 -4
net/netfilter/nft_numgen.c
··· 166 166 enum nft_registers dreg:8; 167 167 u32 modulus; 168 168 u32 offset; 169 + struct nft_set *map; 169 170 }; 171 + 172 + static u32 nft_ng_random_gen(struct nft_ng_random *priv) 173 + { 174 + struct rnd_state *state = this_cpu_ptr(&nft_numgen_prandom_state); 175 + 176 + return reciprocal_scale(prandom_u32_state(state), priv->modulus) + 177 + priv->offset; 178 + } 170 179 171 180 static void nft_ng_random_eval(const struct nft_expr *expr, 172 181 struct nft_regs *regs, 173 182 const struct nft_pktinfo *pkt) 174 183 { 175 184 struct nft_ng_random *priv = nft_expr_priv(expr); 176 - struct rnd_state *state = this_cpu_ptr(&nft_numgen_prandom_state); 177 - u32 val; 178 185 179 - val = reciprocal_scale(prandom_u32_state(state), priv->modulus); 180 - regs->data[priv->dreg] = val + priv->offset; 186 + regs->data[priv->dreg] = nft_ng_random_gen(priv); 187 + } 188 + 189 + static void nft_ng_random_map_eval(const struct nft_expr *expr, 190 + struct nft_regs *regs, 191 + const struct nft_pktinfo *pkt) 192 + { 193 + struct nft_ng_random *priv = nft_expr_priv(expr); 194 + const struct nft_set *map = priv->map; 195 + const struct nft_set_ext *ext; 196 + u32 result; 197 + bool found; 198 + 199 + result = nft_ng_random_gen(priv); 200 + found = map->ops->lookup(nft_net(pkt), map, &result, &ext); 201 + if (!found) 202 + return; 203 + 204 + nft_data_copy(&regs->data[priv->dreg], 205 + nft_set_ext_data(ext), map->dlen); 181 206 } 182 207 183 208 static int nft_ng_random_init(const struct nft_ctx *ctx, ··· 229 204 NFT_DATA_VALUE, sizeof(u32)); 230 205 } 231 206 207 + static int nft_ng_random_map_init(const struct nft_ctx *ctx, 208 + const struct nft_expr *expr, 209 + const struct nlattr * const tb[]) 210 + { 211 + struct nft_ng_random *priv = nft_expr_priv(expr); 212 + u8 genmask = nft_genmask_next(ctx->net); 213 + 214 + nft_ng_random_init(ctx, expr, tb); 215 + priv->map = nft_set_lookup_global(ctx->net, ctx->table, 216 + tb[NFTA_NG_SET_NAME], 217 + tb[NFTA_NG_SET_ID], genmask); 218 + if (IS_ERR(priv->map)) 219 + return PTR_ERR(priv->map); 220 + 221 + return 0; 222 + } 223 + 232 224 static int nft_ng_random_dump(struct sk_buff *skb, const struct nft_expr *expr) 233 225 { 234 226 const struct nft_ng_random *priv = nft_expr_priv(expr); 235 227 236 228 return nft_ng_dump(skb, priv->dreg, priv->modulus, NFT_NG_RANDOM, 237 229 priv->offset); 230 + } 231 + 232 + static int nft_ng_random_map_dump(struct sk_buff *skb, 233 + const struct nft_expr *expr) 234 + { 235 + const struct nft_ng_random *priv = nft_expr_priv(expr); 236 + 237 + if (nft_ng_dump(skb, priv->dreg, priv->modulus, 238 + NFT_NG_RANDOM, priv->offset) || 239 + nla_put_string(skb, NFTA_NG_SET_NAME, priv->map->name)) 240 + goto nla_put_failure; 241 + 242 + return 0; 243 + 244 + nla_put_failure: 245 + return -1; 238 246 } 239 247 240 248 static struct nft_expr_type nft_ng_type; ··· 295 237 .dump = nft_ng_random_dump, 296 238 }; 297 239 240 + static const struct nft_expr_ops nft_ng_random_map_ops = { 241 + .type = &nft_ng_type, 242 + .size = NFT_EXPR_SIZE(sizeof(struct nft_ng_random)), 243 + .eval = nft_ng_random_map_eval, 244 + .init = nft_ng_random_map_init, 245 + .dump = nft_ng_random_map_dump, 246 + }; 247 + 298 248 static const struct nft_expr_ops * 299 249 nft_ng_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) 300 250 { ··· 321 255 return &nft_ng_inc_map_ops; 322 256 return &nft_ng_inc_ops; 323 257 case NFT_NG_RANDOM: 258 + if (tb[NFTA_NG_SET_NAME]) 259 + return &nft_ng_random_map_ops; 324 260 return &nft_ng_random_ops; 325 261 } 326 262
+72 -3
net/netfilter/nft_set_rbtree.c
··· 22 22 struct rb_root root; 23 23 rwlock_t lock; 24 24 seqcount_t count; 25 + struct delayed_work gc_work; 25 26 }; 26 27 27 28 struct nft_rbtree_elem { ··· 266 265 struct nft_rbtree_elem *rbe = elem->priv; 267 266 268 267 nft_set_elem_change_active(net, set, &rbe->ext); 268 + nft_set_elem_clear_busy(&rbe->ext); 269 269 } 270 270 271 271 static bool nft_rbtree_flush(const struct net *net, ··· 274 272 { 275 273 struct nft_rbtree_elem *rbe = priv; 276 274 277 - nft_set_elem_change_active(net, set, &rbe->ext); 278 - return true; 275 + if (!nft_set_elem_mark_busy(&rbe->ext) || 276 + !nft_is_active(net, &rbe->ext)) { 277 + nft_set_elem_change_active(net, set, &rbe->ext); 278 + return true; 279 + } 280 + return false; 279 281 } 280 282 281 283 static void *nft_rbtree_deactivate(const struct net *net, ··· 353 347 read_unlock_bh(&priv->lock); 354 348 } 355 349 350 + static void nft_rbtree_gc(struct work_struct *work) 351 + { 352 + struct nft_set_gc_batch *gcb = NULL; 353 + struct rb_node *node, *prev = NULL; 354 + struct nft_rbtree_elem *rbe; 355 + struct nft_rbtree *priv; 356 + struct nft_set *set; 357 + int i; 358 + 359 + priv = container_of(work, struct nft_rbtree, gc_work.work); 360 + set = nft_set_container_of(priv); 361 + 362 + write_lock_bh(&priv->lock); 363 + write_seqcount_begin(&priv->count); 364 + for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) { 365 + rbe = rb_entry(node, struct nft_rbtree_elem, node); 366 + 367 + if (nft_rbtree_interval_end(rbe)) { 368 + prev = node; 369 + continue; 370 + } 371 + if (!nft_set_elem_expired(&rbe->ext)) 372 + continue; 373 + if (nft_set_elem_mark_busy(&rbe->ext)) 374 + continue; 375 + 376 + gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC); 377 + if (!gcb) 378 + goto out; 379 + 380 + atomic_dec(&set->nelems); 381 + nft_set_gc_batch_add(gcb, rbe); 382 + 383 + if (prev) { 384 + rbe = rb_entry(prev, struct nft_rbtree_elem, node); 385 + atomic_dec(&set->nelems); 386 + nft_set_gc_batch_add(gcb, rbe); 387 + } 388 + node = rb_next(node); 389 + } 390 + out: 391 + if (gcb) { 392 + for (i = 0; i < gcb->head.cnt; i++) { 393 + rbe = gcb->elems[i]; 394 + rb_erase(&rbe->node, &priv->root); 395 + } 396 + } 397 + write_seqcount_end(&priv->count); 398 + write_unlock_bh(&priv->lock); 399 + 400 + nft_set_gc_batch_complete(gcb); 401 + 402 + queue_delayed_work(system_power_efficient_wq, &priv->gc_work, 403 + nft_set_gc_interval(set)); 404 + } 405 + 356 406 static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[], 357 407 const struct nft_set_desc *desc) 358 408 { ··· 424 362 rwlock_init(&priv->lock); 425 363 seqcount_init(&priv->count); 426 364 priv->root = RB_ROOT; 365 + 366 + INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rbtree_gc); 367 + if (set->flags & NFT_SET_TIMEOUT) 368 + queue_delayed_work(system_power_efficient_wq, &priv->gc_work, 369 + nft_set_gc_interval(set)); 370 + 427 371 return 0; 428 372 } 429 373 ··· 439 371 struct nft_rbtree_elem *rbe; 440 372 struct rb_node *node; 441 373 374 + cancel_delayed_work_sync(&priv->gc_work); 442 375 while ((node = priv->root.rb_node) != NULL) { 443 376 rb_erase(node, &priv->root); 444 377 rbe = rb_entry(node, struct nft_rbtree_elem, node); ··· 464 395 465 396 static struct nft_set_type nft_rbtree_type __read_mostly = { 466 397 .owner = THIS_MODULE, 467 - .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT, 398 + .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT | NFT_SET_TIMEOUT, 468 399 .ops = { 469 400 .privsize = nft_rbtree_privsize, 470 401 .elemsize = offsetof(struct nft_rbtree_elem, ext),