Skip to content

Commit 1cd472b

Browse files
Florian Westphalummakynes
authored andcommitted
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 <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 06cad3a commit 1cd472b

File tree

2 files changed

+161
-0
lines changed

2 files changed

+161
-0
lines changed

include/net/netfilter/nf_nat.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,8 @@ static inline bool nf_nat_oif_changed(unsigned int hooknum,
7575
#endif
7676
}
7777

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);
7882
#endif

net/netfilter/nf_nat_core.c

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,36 @@
3232
#include <net/netfilter/nf_conntrack_zones.h>
3333
#include <linux/netfilter/nf_nat.h>
3434

35+
#include "nf_internals.h"
36+
3537
static spinlock_t nf_nat_locks[CONNTRACK_LOCKS];
3638

3739
static DEFINE_MUTEX(nf_nat_proto_mutex);
3840
static const struct nf_nat_l3proto __rcu *nf_nat_l3protos[NFPROTO_NUMPROTO]
3941
__read_mostly;
4042
static const struct nf_nat_l4proto __rcu **nf_nat_l4protos[NFPROTO_NUMPROTO]
4143
__read_mostly;
44+
static unsigned int nat_net_id __read_mostly;
4245

4346
static struct hlist_head *nf_nat_bysource __read_mostly;
4447
static unsigned int nf_nat_htable_size __read_mostly;
4548
static unsigned int nf_nat_hash_rnd __read_mostly;
4649

50+
struct nf_nat_lookup_hook_priv {
51+
struct nf_hook_entries __rcu *entries;
52+
53+
struct rcu_head rcu_head;
54+
};
55+
56+
struct nf_nat_hooks_net {
57+
struct nf_hook_ops *nat_hook_ops;
58+
unsigned int users;
59+
};
60+
61+
struct nat_net {
62+
struct nf_nat_hooks_net nat_proto_net[NFPROTO_NUMPROTO];
63+
};
64+
4765
inline const struct nf_nat_l3proto *
4866
__nf_nat_l3proto_find(u8 family)
4967
{
@@ -871,6 +889,138 @@ static struct nf_ct_helper_expectfn follow_master_nat = {
871889
.expectfn = nf_nat_follow_master,
872890
};
873891

892+
int nf_nat_register_fn(struct net *net, const struct nf_hook_ops *ops,
893+
const struct nf_hook_ops *orig_nat_ops, unsigned int ops_count)
894+
{
895+
struct nat_net *nat_net = net_generic(net, nat_net_id);
896+
struct nf_nat_hooks_net *nat_proto_net;
897+
struct nf_nat_lookup_hook_priv *priv;
898+
unsigned int hooknum = ops->hooknum;
899+
struct nf_hook_ops *nat_ops;
900+
int i, ret;
901+
902+
if (WARN_ON_ONCE(ops->pf >= ARRAY_SIZE(nat_net->nat_proto_net)))
903+
return -EINVAL;
904+
905+
nat_proto_net = &nat_net->nat_proto_net[ops->pf];
906+
907+
for (i = 0; i < ops_count; i++) {
908+
if (WARN_ON(orig_nat_ops[i].pf != ops->pf))
909+
return -EINVAL;
910+
if (orig_nat_ops[i].hooknum == hooknum) {
911+
hooknum = i;
912+
break;
913+
}
914+
}
915+
916+
if (WARN_ON_ONCE(i == ops_count))
917+
return -EINVAL;
918+
919+
mutex_lock(&nf_nat_proto_mutex);
920+
if (!nat_proto_net->nat_hook_ops) {
921+
WARN_ON(nat_proto_net->users != 0);
922+
923+
nat_ops = kmemdup(orig_nat_ops, sizeof(*orig_nat_ops) * ops_count, GFP_KERNEL);
924+
if (!nat_ops) {
925+
mutex_unlock(&nf_nat_proto_mutex);
926+
return -ENOMEM;
927+
}
928+
929+
for (i = 0; i < ops_count; i++) {
930+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
931+
if (priv) {
932+
nat_ops[i].priv = priv;
933+
continue;
934+
}
935+
mutex_unlock(&nf_nat_proto_mutex);
936+
while (i)
937+
kfree(nat_ops[--i].priv);
938+
kfree(nat_ops);
939+
return -ENOMEM;
940+
}
941+
942+
ret = nf_register_net_hooks(net, nat_ops, ops_count);
943+
if (ret < 0) {
944+
mutex_unlock(&nf_nat_proto_mutex);
945+
for (i = 0; i < ops_count; i++)
946+
kfree(nat_ops[i].priv);
947+
kfree(nat_ops);
948+
return ret;
949+
}
950+
951+
nat_proto_net->nat_hook_ops = nat_ops;
952+
}
953+
954+
nat_ops = nat_proto_net->nat_hook_ops;
955+
priv = nat_ops[hooknum].priv;
956+
if (WARN_ON_ONCE(!priv)) {
957+
mutex_unlock(&nf_nat_proto_mutex);
958+
return -EOPNOTSUPP;
959+
}
960+
961+
ret = nf_hook_entries_insert_raw(&priv->entries, ops);
962+
if (ret == 0)
963+
nat_proto_net->users++;
964+
965+
mutex_unlock(&nf_nat_proto_mutex);
966+
return ret;
967+
}
968+
EXPORT_SYMBOL_GPL(nf_nat_register_fn);
969+
970+
void nf_nat_unregister_fn(struct net *net, const struct nf_hook_ops *ops,
971+
unsigned int ops_count)
972+
{
973+
struct nat_net *nat_net = net_generic(net, nat_net_id);
974+
struct nf_nat_hooks_net *nat_proto_net;
975+
struct nf_nat_lookup_hook_priv *priv;
976+
struct nf_hook_ops *nat_ops;
977+
int hooknum = ops->hooknum;
978+
int i;
979+
980+
if (ops->pf >= ARRAY_SIZE(nat_net->nat_proto_net))
981+
return;
982+
983+
nat_proto_net = &nat_net->nat_proto_net[ops->pf];
984+
985+
mutex_lock(&nf_nat_proto_mutex);
986+
if (WARN_ON(nat_proto_net->users == 0))
987+
goto unlock;
988+
989+
nat_proto_net->users--;
990+
991+
nat_ops = nat_proto_net->nat_hook_ops;
992+
for (i = 0; i < ops_count; i++) {
993+
if (nat_ops[i].hooknum == hooknum) {
994+
hooknum = i;
995+
break;
996+
}
997+
}
998+
if (WARN_ON_ONCE(i == ops_count))
999+
goto unlock;
1000+
priv = nat_ops[hooknum].priv;
1001+
nf_hook_entries_delete_raw(&priv->entries, ops);
1002+
1003+
if (nat_proto_net->users == 0) {
1004+
nf_unregister_net_hooks(net, nat_ops, ops_count);
1005+
1006+
for (i = 0; i < ops_count; i++) {
1007+
priv = nat_ops[i].priv;
1008+
kfree_rcu(priv, rcu_head);
1009+
}
1010+
1011+
nat_proto_net->nat_hook_ops = NULL;
1012+
kfree(nat_ops);
1013+
}
1014+
unlock:
1015+
mutex_unlock(&nf_nat_proto_mutex);
1016+
}
1017+
EXPORT_SYMBOL_GPL(nf_nat_unregister_fn);
1018+
1019+
static struct pernet_operations nat_net_ops = {
1020+
.id = &nat_net_id,
1021+
.size = sizeof(struct nat_net),
1022+
};
1023+
8741024
static int __init nf_nat_init(void)
8751025
{
8761026
int ret, i;
@@ -894,6 +1044,12 @@ static int __init nf_nat_init(void)
8941044
for (i = 0; i < CONNTRACK_LOCKS; i++)
8951045
spin_lock_init(&nf_nat_locks[i]);
8961046

1047+
ret = register_pernet_subsys(&nat_net_ops);
1048+
if (ret < 0) {
1049+
nf_ct_extend_unregister(&nat_extend);
1050+
return ret;
1051+
}
1052+
8971053
nf_ct_helper_expectfn_register(&follow_master_nat);
8981054

8991055
BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
@@ -925,6 +1081,7 @@ static void __exit nf_nat_cleanup(void)
9251081
kfree(nf_nat_l4protos[i]);
9261082
synchronize_net();
9271083
nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size);
1084+
unregister_pernet_subsys(&nat_net_ops);
9281085
}
9291086

9301087
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)