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