origin git://computergmbh.de/linux patchomatic commit df4f8a4974253e72ccf806c532c7d04daa514474 Author: Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx> Date: Sun Jan 13 17:03:25 2008 +0100 [NETFILTER]: xt_RAWNAT target xt_RAWNAT can be used to do static network address translation without depending on connection tracking. Together with the previous patch to add a POSTROUTING chain to the "raw" table, it is possible to use xt_RAWNAT even when conntrack is enabled. Signed-off-by: Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx> diff --git a/include/linux/netfilter/xt_RAWNAT.h b/include/linux/netfilter/xt_RAWNAT.h new file mode 100644 index 0000000..f948166 --- /dev/null +++ b/include/linux/netfilter/xt_RAWNAT.h @@ -0,0 +1,9 @@ +#ifndef _LINUX_NETFILTER_XT_TARGET_RAWNAT +#define _LINUX_NETFILTER_XT_TARGET_RAWNAT 1 + +struct xt_rawnat_tginfo { + union nf_inet_addr addr; + uint8_t mask; +}; + +#endif /* _LINUX_NETFILTER_XT_TARGET_RAWNAT */ diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index eec3d24..7611e1b 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -385,6 +385,15 @@ config NETFILTER_XT_TARGET_RATEEST To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_TARGET_RAWNAT + tristate '"RAWNAT" raw address translation w/o conntrack' + depends on NETFILTER_XTABLES + depends on IP_NF_RAW || IP_NF6_RAW + ---help--- + This option adds the RAWSNAT and RAWDNAT targets which can do Network + Address Translation (no port translation) without requiring Netfilter + connection tracking. + config NETFILTER_XT_TARGET_REJECT tristate '"REJECT" target support' depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index b170ef1..e5132fd 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o obj-$(CONFIG_NETFILTER_XT_TARGET_RATEEST) += xt_RATEEST.o +obj-$(CONFIG_NETFILTER_XT_TARGET_RAWNAT) += xt_RAWNAT.o obj-$(CONFIG_NETFILTER_XT_TARGET_REJECT) += xt_REJECT.o obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_STEAL) += xt_STEAL.o diff --git a/net/netfilter/xt_RAWNAT.c b/net/netfilter/xt_RAWNAT.c new file mode 100644 index 0000000..a5a68da --- /dev/null +++ b/net/netfilter/xt_RAWNAT.c @@ -0,0 +1,195 @@ +/* + * xt_RAWNAT - Netfilter module to do untracked NAT + * + * Copyright © CC Computer Consultants GmbH, 2008 + * Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx> + */ +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/netfilter.h> +#include <linux/netfilter/nf_conntrack_common.h> +#include <linux/netfilter/x_tables.h> +#include <linux/netfilter/xt_RAWNAT.h> +#include <net/netfilter/nf_conntrack.h> + +static inline u_int32_t +remask(u_int32_t addr, u_int32_t repl, unsigned int shift) +{ + u_int32_t mask = (left == 32) ? 0 : (~(u_int32_t)0 >> shift); + return htonl((ntohl(addr) & ~mask) | ntohl(repl)); +} + +static void +rawnat_ipv6_mask(__be32 *addr, const __be32 *repl, unsigned int mask) +{ + switch (mask) { + case 0: + break; + case 1 ... 31: + addr[0] = remask(addr[0], repl[0], mask); + break; + case 32: + addr[0] = repl[0]; + break; + case 33 ... 63: + addr[0] = repl[0]; + addr[1] = remask(addr[1], repl[1], mask - 64); + break; + case 64: + addr[0] = repl[0]; + addr[1] = repl[1]; + break; + case 65 ... 95: + addr[0] = repl[0]; + addr[1] = repl[1]; + addr[2] = remask(addr[2], repl[2], mask - 96); + case 96: + addr[0] = repl[0]; + addr[1] = repl[1]; + addr[2] = repl[2]; + break; + case 97 ... 127: + addr[0] = repl[0]; + addr[1] = repl[1]; + addr[2] = repl[2]; + addr[3] = remask(addr[3], repl[3], mask - 128); + break; + case 128: + addr[0] = repl[0]; + addr[1] = repl[1]; + addr[2] = repl[2]; + addr[3] = repl[3]; + break; + } +} + +static unsigned int +rawsnat_tg4(struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, unsigned int hooknum, + const struct xt_target *target, const void *targinfo) +{ + const struct xt_rawnat_tginfo *info = targinfo; + struct iphdr *iph; + u_int32_t na; + + if (!skb_make_writable(skb, sizeof(struct iphdr))) + return NF_DROP; + + iph = ip_hdr(skb); + na = remask(iph->saddr, info->addr.ip, info->mask); + csum_replace4(&iph->check, iph->saddr, na); + iph->saddr = na; + return XT_CONTINUE; +} + +static unsigned int +rawdnat_tg4(struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, unsigned int hooknum, + const struct xt_target *target, const void *targinfo) +{ + const struct xt_rawnat_tginfo *info = targinfo; + struct iphdr *iph; + u_int32_t na; + + if (!skb_make_writable(skb, sizeof(struct iphdr))) + return NF_DROP; + + iph = ip_hdr(skb); + na = remask(iph->daddr, info->addr.ip, info->mask); + csum_replace4(&iph->check, iph->daddr, na); + iph->daddr = na; + return XT_CONTINUE; +} + +static unsigned int +rawsnat_tg6(struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, unsigned int hooknum, + const struct xt_target *target, const void *targinfo) +{ + const struct xt_rawnat_tginfo *info = targinfo; + struct ipv6hdr *iph; + + if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) + return NF_DROP; + + iph = ipv6_hdr(skb); + rawnat_ipv6_mask(iph->saddr.s6_addr32, info->addr.ip6, info->mask); + return XT_CONTINUE; +} + +static unsigned int +rawdnat_tg6(struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, unsigned int hooknum, + const struct xt_target *target, const void *targinfo) +{ + const struct xt_rawnat_tginfo *info = targinfo; + struct ipv6hdr *iph; + + if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) + return NF_DROP; + + iph = ipv6_hdr(skb); + rawnat_ipv6_mask(iph->daddr.s6_addr32, info->addr.ip6, info->mask); + return XT_CONTINUE; +} + +static struct xt_target rawnat_tg_reg[] __read_mostly = { + { + .name = "RAWSNAT", + .revision = 0, + .family = AF_INET, + .table = "raw", + .target = rawsnat_tg4, + .targetsize = sizeof(struct xt_rawnat_tginfo), + .me = THIS_MODULE, + }, + { + .name = "RAWSNAT", + .revision = 0, + .family = AF_INET6, + .table = "raw", + .target = rawsnat_tg6, + .targetsize = sizeof(struct xt_rawnat_tginfo), + .me = THIS_MODULE, + }, + { + .name = "RAWDNAT", + .revision = 0, + .family = AF_INET, + .table = "raw", + .target = rawdnat_tg4, + .targetsize = sizeof(struct xt_rawnat_tginfo), + .me = THIS_MODULE, + }, + { + .name = "RAWDNAT", + .revision = 0, + .family = AF_INET6, + .table = "raw", + .target = rawdnat_tg6, + .targetsize = sizeof(struct xt_rawnat_tginfo), + .me = THIS_MODULE, + }, +}; + +static int __init rawnat_tg_init(void) +{ + return xt_register_targets(rawnat_tg_reg, ARRAY_SIZE(rawnat_tg_reg)); +} + +static void __exit rawnat_tg_exit(void) +{ + xt_unregister_targets(rawnat_tg_reg, ARRAY_SIZE(rawnat_tg_reg)); +} + +module_init(rawnat_tg_init); +module_exit(rawnat_tg_exit); +MODULE_AUTHOR("Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx>"); +MODULE_DESCRIPTION("Netfilter: conntrack-less raw NAT"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_RAWSNAT"); +MODULE_ALIAS("ipt_RAWDNAT"); +MODULE_ALIAS("ip6t_RAWSNAT"); +MODULE_ALIAS("ip6t_RAWDNAT"); - To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html