Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
b3d54b3e JE |
2 | /* |
3 | * (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk> | |
4 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | |
b3d54b3e JE |
5 | */ |
6 | ||
7 | #include <linux/ip.h> | |
8 | #include <linux/kernel.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/netdevice.h> | |
11 | #include <linux/ipv6.h> | |
12 | #include <linux/netfilter.h> | |
13 | #include <linux/netfilter_ipv4.h> | |
14 | #include <linux/netfilter_ipv6.h> | |
15 | #include <linux/netfilter/x_tables.h> | |
16 | #include <net/netfilter/nf_nat.h> | |
17 | ||
18 | static unsigned int | |
19 | netmap_tg6(struct sk_buff *skb, const struct xt_action_param *par) | |
20 | { | |
2eb0f624 TDT |
21 | const struct nf_nat_range2 *range = par->targinfo; |
22 | struct nf_nat_range2 newrange; | |
b3d54b3e JE |
23 | struct nf_conn *ct; |
24 | enum ip_conntrack_info ctinfo; | |
25 | union nf_inet_addr new_addr, netmask; | |
26 | unsigned int i; | |
27 | ||
28 | ct = nf_ct_get(skb, &ctinfo); | |
29 | for (i = 0; i < ARRAY_SIZE(range->min_addr.ip6); i++) | |
30 | netmask.ip6[i] = ~(range->min_addr.ip6[i] ^ | |
31 | range->max_addr.ip6[i]); | |
32 | ||
613dbd95 PNA |
33 | if (xt_hooknum(par) == NF_INET_PRE_ROUTING || |
34 | xt_hooknum(par) == NF_INET_LOCAL_OUT) | |
b3d54b3e JE |
35 | new_addr.in6 = ipv6_hdr(skb)->daddr; |
36 | else | |
37 | new_addr.in6 = ipv6_hdr(skb)->saddr; | |
38 | ||
39 | for (i = 0; i < ARRAY_SIZE(new_addr.ip6); i++) { | |
40 | new_addr.ip6[i] &= ~netmask.ip6[i]; | |
41 | new_addr.ip6[i] |= range->min_addr.ip6[i] & | |
42 | netmask.ip6[i]; | |
43 | } | |
44 | ||
45 | newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; | |
46 | newrange.min_addr = new_addr; | |
47 | newrange.max_addr = new_addr; | |
48 | newrange.min_proto = range->min_proto; | |
49 | newrange.max_proto = range->max_proto; | |
50 | ||
613dbd95 | 51 | return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par))); |
b3d54b3e JE |
52 | } |
53 | ||
54 | static int netmap_tg6_checkentry(const struct xt_tgchk_param *par) | |
55 | { | |
2eb0f624 | 56 | const struct nf_nat_range2 *range = par->targinfo; |
b3d54b3e JE |
57 | |
58 | if (!(range->flags & NF_NAT_RANGE_MAP_IPS)) | |
59 | return -EINVAL; | |
a357b3f8 FW |
60 | return nf_ct_netns_get(par->net, par->family); |
61 | } | |
62 | ||
63 | static void netmap_tg_destroy(const struct xt_tgdtor_param *par) | |
64 | { | |
65 | nf_ct_netns_put(par->net, par->family); | |
b3d54b3e JE |
66 | } |
67 | ||
68 | static unsigned int | |
69 | netmap_tg4(struct sk_buff *skb, const struct xt_action_param *par) | |
70 | { | |
71 | struct nf_conn *ct; | |
72 | enum ip_conntrack_info ctinfo; | |
73 | __be32 new_ip, netmask; | |
74 | const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; | |
2eb0f624 | 75 | struct nf_nat_range2 newrange; |
b3d54b3e | 76 | |
44d6e2f2 VR |
77 | WARN_ON(xt_hooknum(par) != NF_INET_PRE_ROUTING && |
78 | xt_hooknum(par) != NF_INET_POST_ROUTING && | |
79 | xt_hooknum(par) != NF_INET_LOCAL_OUT && | |
80 | xt_hooknum(par) != NF_INET_LOCAL_IN); | |
b3d54b3e JE |
81 | ct = nf_ct_get(skb, &ctinfo); |
82 | ||
83 | netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip); | |
84 | ||
613dbd95 PNA |
85 | if (xt_hooknum(par) == NF_INET_PRE_ROUTING || |
86 | xt_hooknum(par) == NF_INET_LOCAL_OUT) | |
b3d54b3e JE |
87 | new_ip = ip_hdr(skb)->daddr & ~netmask; |
88 | else | |
89 | new_ip = ip_hdr(skb)->saddr & ~netmask; | |
90 | new_ip |= mr->range[0].min_ip & netmask; | |
91 | ||
92 | memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); | |
93 | memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); | |
94 | newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS; | |
95 | newrange.min_addr.ip = new_ip; | |
96 | newrange.max_addr.ip = new_ip; | |
97 | newrange.min_proto = mr->range[0].min; | |
98 | newrange.max_proto = mr->range[0].max; | |
99 | ||
100 | /* Hand modified range to generic setup. */ | |
613dbd95 | 101 | return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par))); |
b3d54b3e JE |
102 | } |
103 | ||
104 | static int netmap_tg4_check(const struct xt_tgchk_param *par) | |
105 | { | |
106 | const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; | |
107 | ||
108 | if (!(mr->range[0].flags & NF_NAT_RANGE_MAP_IPS)) { | |
109 | pr_debug("bad MAP_IPS.\n"); | |
110 | return -EINVAL; | |
111 | } | |
112 | if (mr->rangesize != 1) { | |
113 | pr_debug("bad rangesize %u.\n", mr->rangesize); | |
114 | return -EINVAL; | |
115 | } | |
a357b3f8 | 116 | return nf_ct_netns_get(par->net, par->family); |
b3d54b3e JE |
117 | } |
118 | ||
119 | static struct xt_target netmap_tg_reg[] __read_mostly = { | |
120 | { | |
121 | .name = "NETMAP", | |
122 | .family = NFPROTO_IPV6, | |
123 | .revision = 0, | |
124 | .target = netmap_tg6, | |
125 | .targetsize = sizeof(struct nf_nat_range), | |
126 | .table = "nat", | |
127 | .hooks = (1 << NF_INET_PRE_ROUTING) | | |
128 | (1 << NF_INET_POST_ROUTING) | | |
129 | (1 << NF_INET_LOCAL_OUT) | | |
130 | (1 << NF_INET_LOCAL_IN), | |
131 | .checkentry = netmap_tg6_checkentry, | |
a357b3f8 | 132 | .destroy = netmap_tg_destroy, |
b3d54b3e JE |
133 | .me = THIS_MODULE, |
134 | }, | |
135 | { | |
136 | .name = "NETMAP", | |
137 | .family = NFPROTO_IPV4, | |
138 | .revision = 0, | |
139 | .target = netmap_tg4, | |
140 | .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat), | |
141 | .table = "nat", | |
142 | .hooks = (1 << NF_INET_PRE_ROUTING) | | |
143 | (1 << NF_INET_POST_ROUTING) | | |
144 | (1 << NF_INET_LOCAL_OUT) | | |
145 | (1 << NF_INET_LOCAL_IN), | |
146 | .checkentry = netmap_tg4_check, | |
a357b3f8 | 147 | .destroy = netmap_tg_destroy, |
b3d54b3e JE |
148 | .me = THIS_MODULE, |
149 | }, | |
150 | }; | |
151 | ||
152 | static int __init netmap_tg_init(void) | |
153 | { | |
154 | return xt_register_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); | |
155 | } | |
156 | ||
157 | static void netmap_tg_exit(void) | |
158 | { | |
159 | xt_unregister_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); | |
160 | } | |
161 | ||
162 | module_init(netmap_tg_init); | |
163 | module_exit(netmap_tg_exit); | |
164 | ||
165 | MODULE_LICENSE("GPL"); | |
166 | MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of subnets"); | |
167 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | |
168 | MODULE_ALIAS("ip6t_NETMAP"); | |
169 | MODULE_ALIAS("ipt_NETMAP"); |