![Patrick McHardy](/assets/img/avatar_default.png)
2.6.34 introduced 'conntrack zones' to deal with cases where packets from multiple identical networks are handled by conntrack/NAT. Packets are looped through veth devices, during which they are NATed to private addresses, after which they can continue normally through the stack and possibly have NAT rules applied a second time. This works well, but is needlessly complicated for cases where only a single SNAT/DNAT mapping needs to be applied to these packets. In that case, all that needs to be done is to assign each network to a seperate zone and perform NAT as usual. However this doesn't work for packets destined for the machine performing NAT itself since its corrently not possible to configure SNAT mappings for the LOCAL_IN chain. This patch adds a new INPUT chain to the NAT table and changes the targets performing SNAT to be usable in that chain. Example usage with two identical networks (192.168.0.0/24) on eth0/eth1: iptables -t raw -A PREROUTING -i eth0 -j CT --zone 1 iptables -t raw -A PREROUTING -i eth0 -j MARK --set-mark 1 iptables -t raw -A PREROUTING -i eth1 -j CT --zone 2 iptabels -t raw -A PREROUTING -i eth1 -j MARK --set-mark 2 iptables -t nat -A INPUT -m mark --mark 1 -j NETMAP --to 10.0.0.0/24 iptables -t nat -A POSTROUTING -m mark --mark 1 -j NETMAP --to 10.0.0.0/24 iptables -t nat -A INPUT -m mark --mark 2 -j NETMAP --to 10.0.1.0/24 iptables -t nat -A POSTROUTING -m mark --mark 2 -j NETMAP --to 10.0.1.0/24 iptables -t raw -A PREROUTING -d 10.0.0.0/24 -j CT --zone 1 iptables -t raw -A OUTPUT -d 10.0.0.0/24 -j CT --zone 1 iptables -t raw -A PREROUTING -d 10.0.1.0/24 -j CT --zone 2 iptables -t raw -A OUTPUT -d 10.0.1.0/24 -j CT --zone 2 iptables -t nat -A PREROUTING -d 10.0.0.0/24 -j NETMAP --to 192.168.0.0/24 iptables -t nat -A OUTPUT -d 10.0.0.0/24 -j NETMAP --to 192.168.0.0/24 iptables -t nat -A PREROUTING -d 10.0.1.0/24 -j NETMAP --to 192.168.0.0/24 iptables -t nat -A OUTPUT -d 10.0.1.0/24 -j NETMAP --to 192.168.0.0/24 Signed-off-by: Patrick McHardy <kaber@trash.net>
99 lines
2.8 KiB
C
99 lines
2.8 KiB
C
/* NETMAP - static NAT mapping of IP network addresses (1:1).
|
|
* The mapping can be applied to source (POSTROUTING),
|
|
* destination (PREROUTING), or both (with separate rules).
|
|
*/
|
|
|
|
/* (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
#include <linux/ip.h>
|
|
#include <linux/module.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/netfilter.h>
|
|
#include <linux/netfilter_ipv4.h>
|
|
#include <linux/netfilter/x_tables.h>
|
|
#include <net/netfilter/nf_nat_rule.h>
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>");
|
|
MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of IPv4 subnets");
|
|
|
|
static int netmap_tg_check(const struct xt_tgchk_param *par)
|
|
{
|
|
const struct nf_nat_multi_range_compat *mr = par->targinfo;
|
|
|
|
if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
|
|
pr_debug("bad MAP_IPS.\n");
|
|
return -EINVAL;
|
|
}
|
|
if (mr->rangesize != 1) {
|
|
pr_debug("bad rangesize %u.\n", mr->rangesize);
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static unsigned int
|
|
netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
|
|
{
|
|
struct nf_conn *ct;
|
|
enum ip_conntrack_info ctinfo;
|
|
__be32 new_ip, netmask;
|
|
const struct nf_nat_multi_range_compat *mr = par->targinfo;
|
|
struct nf_nat_range newrange;
|
|
|
|
NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
|
|
par->hooknum == NF_INET_POST_ROUTING ||
|
|
par->hooknum == NF_INET_LOCAL_OUT ||
|
|
par->hooknum == NF_INET_LOCAL_IN);
|
|
ct = nf_ct_get(skb, &ctinfo);
|
|
|
|
netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
|
|
|
|
if (par->hooknum == NF_INET_PRE_ROUTING ||
|
|
par->hooknum == NF_INET_LOCAL_OUT)
|
|
new_ip = ip_hdr(skb)->daddr & ~netmask;
|
|
else
|
|
new_ip = ip_hdr(skb)->saddr & ~netmask;
|
|
new_ip |= mr->range[0].min_ip & netmask;
|
|
|
|
newrange = ((struct nf_nat_range)
|
|
{ mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
|
|
new_ip, new_ip,
|
|
mr->range[0].min, mr->range[0].max });
|
|
|
|
/* Hand modified range to generic setup. */
|
|
return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
|
|
}
|
|
|
|
static struct xt_target netmap_tg_reg __read_mostly = {
|
|
.name = "NETMAP",
|
|
.family = NFPROTO_IPV4,
|
|
.target = netmap_tg,
|
|
.targetsize = sizeof(struct nf_nat_multi_range_compat),
|
|
.table = "nat",
|
|
.hooks = (1 << NF_INET_PRE_ROUTING) |
|
|
(1 << NF_INET_POST_ROUTING) |
|
|
(1 << NF_INET_LOCAL_OUT) |
|
|
(1 << NF_INET_LOCAL_IN),
|
|
.checkentry = netmap_tg_check,
|
|
.me = THIS_MODULE
|
|
};
|
|
|
|
static int __init netmap_tg_init(void)
|
|
{
|
|
return xt_register_target(&netmap_tg_reg);
|
|
}
|
|
|
|
static void __exit netmap_tg_exit(void)
|
|
{
|
|
xt_unregister_target(&netmap_tg_reg);
|
|
}
|
|
|
|
module_init(netmap_tg_init);
|
|
module_exit(netmap_tg_exit);
|