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

netfilter: nf_nat: add nat hook register functions to nf_nat

This adds the infrastructure to register nat hooks with the nat core
instead of the netfilter core.

nat hooks are used to configure nat bindings. Such hooks are registered
from ip(6)table_nat or by the nftables core when a nat chain is added.

After next patch, nat hooks will be registered with nf_nat instead of
netfilter core. This allows to use many nat lookup functions at the
same time while doing the real packet rewrite (nat transformation) in
one place.

This change doesn't convert the intended users yet to ease review.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
1cd472bf 06cad3ac

+161
+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
+157
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) ··· 889 871 .expectfn = nf_nat_follow_master, 890 872 }; 891 873 874 + int nf_nat_register_fn(struct net *net, const struct nf_hook_ops *ops, 875 + const struct nf_hook_ops *orig_nat_ops, unsigned int ops_count) 876 + { 877 + struct nat_net *nat_net = net_generic(net, nat_net_id); 878 + struct nf_nat_hooks_net *nat_proto_net; 879 + struct nf_nat_lookup_hook_priv *priv; 880 + unsigned int hooknum = ops->hooknum; 881 + struct nf_hook_ops *nat_ops; 882 + int i, ret; 883 + 884 + if (WARN_ON_ONCE(ops->pf >= ARRAY_SIZE(nat_net->nat_proto_net))) 885 + return -EINVAL; 886 + 887 + nat_proto_net = &nat_net->nat_proto_net[ops->pf]; 888 + 889 + for (i = 0; i < ops_count; i++) { 890 + if (WARN_ON(orig_nat_ops[i].pf != ops->pf)) 891 + return -EINVAL; 892 + if (orig_nat_ops[i].hooknum == hooknum) { 893 + hooknum = i; 894 + break; 895 + } 896 + } 897 + 898 + if (WARN_ON_ONCE(i == ops_count)) 899 + return -EINVAL; 900 + 901 + mutex_lock(&nf_nat_proto_mutex); 902 + if (!nat_proto_net->nat_hook_ops) { 903 + WARN_ON(nat_proto_net->users != 0); 904 + 905 + nat_ops = kmemdup(orig_nat_ops, sizeof(*orig_nat_ops) * ops_count, GFP_KERNEL); 906 + if (!nat_ops) { 907 + mutex_unlock(&nf_nat_proto_mutex); 908 + return -ENOMEM; 909 + } 910 + 911 + for (i = 0; i < ops_count; i++) { 912 + priv = kzalloc(sizeof(*priv), GFP_KERNEL); 913 + if (priv) { 914 + nat_ops[i].priv = priv; 915 + continue; 916 + } 917 + mutex_unlock(&nf_nat_proto_mutex); 918 + while (i) 919 + kfree(nat_ops[--i].priv); 920 + kfree(nat_ops); 921 + return -ENOMEM; 922 + } 923 + 924 + ret = nf_register_net_hooks(net, nat_ops, ops_count); 925 + if (ret < 0) { 926 + mutex_unlock(&nf_nat_proto_mutex); 927 + for (i = 0; i < ops_count; i++) 928 + kfree(nat_ops[i].priv); 929 + kfree(nat_ops); 930 + return ret; 931 + } 932 + 933 + nat_proto_net->nat_hook_ops = nat_ops; 934 + } 935 + 936 + nat_ops = nat_proto_net->nat_hook_ops; 937 + priv = nat_ops[hooknum].priv; 938 + if (WARN_ON_ONCE(!priv)) { 939 + mutex_unlock(&nf_nat_proto_mutex); 940 + return -EOPNOTSUPP; 941 + } 942 + 943 + ret = nf_hook_entries_insert_raw(&priv->entries, ops); 944 + if (ret == 0) 945 + nat_proto_net->users++; 946 + 947 + mutex_unlock(&nf_nat_proto_mutex); 948 + return ret; 949 + } 950 + EXPORT_SYMBOL_GPL(nf_nat_register_fn); 951 + 952 + void nf_nat_unregister_fn(struct net *net, const struct nf_hook_ops *ops, 953 + unsigned int ops_count) 954 + { 955 + struct nat_net *nat_net = net_generic(net, nat_net_id); 956 + struct nf_nat_hooks_net *nat_proto_net; 957 + struct nf_nat_lookup_hook_priv *priv; 958 + struct nf_hook_ops *nat_ops; 959 + int hooknum = ops->hooknum; 960 + int i; 961 + 962 + if (ops->pf >= ARRAY_SIZE(nat_net->nat_proto_net)) 963 + return; 964 + 965 + nat_proto_net = &nat_net->nat_proto_net[ops->pf]; 966 + 967 + mutex_lock(&nf_nat_proto_mutex); 968 + if (WARN_ON(nat_proto_net->users == 0)) 969 + goto unlock; 970 + 971 + nat_proto_net->users--; 972 + 973 + nat_ops = nat_proto_net->nat_hook_ops; 974 + for (i = 0; i < ops_count; i++) { 975 + if (nat_ops[i].hooknum == hooknum) { 976 + hooknum = i; 977 + break; 978 + } 979 + } 980 + if (WARN_ON_ONCE(i == ops_count)) 981 + goto unlock; 982 + priv = nat_ops[hooknum].priv; 983 + nf_hook_entries_delete_raw(&priv->entries, ops); 984 + 985 + if (nat_proto_net->users == 0) { 986 + nf_unregister_net_hooks(net, nat_ops, ops_count); 987 + 988 + for (i = 0; i < ops_count; i++) { 989 + priv = nat_ops[i].priv; 990 + kfree_rcu(priv, rcu_head); 991 + } 992 + 993 + nat_proto_net->nat_hook_ops = NULL; 994 + kfree(nat_ops); 995 + } 996 + unlock: 997 + mutex_unlock(&nf_nat_proto_mutex); 998 + } 999 + EXPORT_SYMBOL_GPL(nf_nat_unregister_fn); 1000 + 1001 + static struct pernet_operations nat_net_ops = { 1002 + .id = &nat_net_id, 1003 + .size = sizeof(struct nat_net), 1004 + }; 1005 + 892 1006 static int __init nf_nat_init(void) 893 1007 { 894 1008 int ret, i; ··· 1043 893 1044 894 for (i = 0; i < CONNTRACK_LOCKS; i++) 1045 895 spin_lock_init(&nf_nat_locks[i]); 896 + 897 + ret = register_pernet_subsys(&nat_net_ops); 898 + if (ret < 0) { 899 + nf_ct_extend_unregister(&nat_extend); 900 + return ret; 901 + } 1046 902 1047 903 nf_ct_helper_expectfn_register(&follow_master_nat); 1048 904 ··· 1081 925 kfree(nf_nat_l4protos[i]); 1082 926 synchronize_net(); 1083 927 nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size); 928 + unregister_pernet_subsys(&nat_net_ops); 1084 929 } 1085 930 1086 931 MODULE_LICENSE("GPL");