2 * (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk>
3 * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
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.
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>
22 netmap_tg6(struct sk_buff
*skb
, const struct xt_action_param
*par
)
24 const struct nf_nat_range
*range
= par
->targinfo
;
25 struct nf_nat_range newrange
;
27 enum ip_conntrack_info ctinfo
;
28 union nf_inet_addr new_addr
, netmask
;
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
]);
36 if (xt_hooknum(par
) == NF_INET_PRE_ROUTING
||
37 xt_hooknum(par
) == NF_INET_LOCAL_OUT
)
38 new_addr
.in6
= ipv6_hdr(skb
)->daddr
;
40 new_addr
.in6
= ipv6_hdr(skb
)->saddr
;
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
] &
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
;
54 return nf_nat_setup_info(ct
, &newrange
, HOOK2MANIP(xt_hooknum(par
)));
57 static int netmap_tg6_checkentry(const struct xt_tgchk_param
*par
)
59 const struct nf_nat_range
*range
= par
->targinfo
;
61 if (!(range
->flags
& NF_NAT_RANGE_MAP_IPS
))
63 return nf_ct_netns_get(par
->net
, par
->family
);
66 static void netmap_tg_destroy(const struct xt_tgdtor_param
*par
)
68 nf_ct_netns_put(par
->net
, par
->family
);
72 netmap_tg4(struct sk_buff
*skb
, const struct xt_action_param
*par
)
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
;
80 WARN_ON(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
);
84 ct
= nf_ct_get(skb
, &ctinfo
);
86 netmask
= ~(mr
->range
[0].min_ip
^ mr
->range
[0].max_ip
);
88 if (xt_hooknum(par
) == NF_INET_PRE_ROUTING
||
89 xt_hooknum(par
) == NF_INET_LOCAL_OUT
)
90 new_ip
= ip_hdr(skb
)->daddr
& ~netmask
;
92 new_ip
= ip_hdr(skb
)->saddr
& ~netmask
;
93 new_ip
|= mr
->range
[0].min_ip
& netmask
;
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
;
103 /* Hand modified range to generic setup. */
104 return nf_nat_setup_info(ct
, &newrange
, HOOK2MANIP(xt_hooknum(par
)));
107 static int netmap_tg4_check(const struct xt_tgchk_param
*par
)
109 const struct nf_nat_ipv4_multi_range_compat
*mr
= par
->targinfo
;
111 if (!(mr
->range
[0].flags
& NF_NAT_RANGE_MAP_IPS
)) {
112 pr_debug("bad MAP_IPS.\n");
115 if (mr
->rangesize
!= 1) {
116 pr_debug("bad rangesize %u.\n", mr
->rangesize
);
119 return nf_ct_netns_get(par
->net
, par
->family
);
122 static struct xt_target netmap_tg_reg
[] __read_mostly
= {
125 .family
= NFPROTO_IPV6
,
127 .target
= netmap_tg6
,
128 .targetsize
= sizeof(struct nf_nat_range
),
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
,
135 .destroy
= netmap_tg_destroy
,
140 .family
= NFPROTO_IPV4
,
142 .target
= netmap_tg4
,
143 .targetsize
= sizeof(struct nf_nat_ipv4_multi_range_compat
),
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
,
150 .destroy
= netmap_tg_destroy
,
155 static int __init
netmap_tg_init(void)
157 return xt_register_targets(netmap_tg_reg
, ARRAY_SIZE(netmap_tg_reg
));
160 static void netmap_tg_exit(void)
162 xt_unregister_targets(netmap_tg_reg
, ARRAY_SIZE(netmap_tg_reg
));
165 module_init(netmap_tg_init
);
166 module_exit(netmap_tg_exit
);
168 MODULE_LICENSE("GPL");
169 MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of subnets");
170 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
171 MODULE_ALIAS("ip6t_NETMAP");
172 MODULE_ALIAS("ipt_NETMAP");