123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /*
- * (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk>
- * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
- *
- * 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.
- */
- #include <linux/ip.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/netdevice.h>
- #include <linux/ipv6.h>
- #include <linux/netfilter.h>
- #include <linux/netfilter_ipv4.h>
- #include <linux/netfilter_ipv6.h>
- #include <linux/netfilter/x_tables.h>
- #include <net/netfilter/nf_nat.h>
- static unsigned int
- netmap_tg6(struct sk_buff *skb, const struct xt_action_param *par)
- {
- const struct nf_nat_range *range = par->targinfo;
- struct nf_nat_range newrange;
- struct nf_conn *ct;
- enum ip_conntrack_info ctinfo;
- union nf_inet_addr new_addr, netmask;
- unsigned int i;
- ct = nf_ct_get(skb, &ctinfo);
- for (i = 0; i < ARRAY_SIZE(range->min_addr.ip6); i++)
- netmask.ip6[i] = ~(range->min_addr.ip6[i] ^
- range->max_addr.ip6[i]);
- if (par->hooknum == NF_INET_PRE_ROUTING ||
- par->hooknum == NF_INET_LOCAL_OUT)
- new_addr.in6 = ipv6_hdr(skb)->daddr;
- else
- new_addr.in6 = ipv6_hdr(skb)->saddr;
- for (i = 0; i < ARRAY_SIZE(new_addr.ip6); i++) {
- new_addr.ip6[i] &= ~netmask.ip6[i];
- new_addr.ip6[i] |= range->min_addr.ip6[i] &
- netmask.ip6[i];
- }
- newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
- newrange.min_addr = new_addr;
- newrange.max_addr = new_addr;
- newrange.min_proto = range->min_proto;
- newrange.max_proto = range->max_proto;
- return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
- }
- static int netmap_tg6_checkentry(const struct xt_tgchk_param *par)
- {
- const struct nf_nat_range *range = par->targinfo;
- if (!(range->flags & NF_NAT_RANGE_MAP_IPS))
- return -EINVAL;
- return 0;
- }
- static unsigned int
- netmap_tg4(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_ipv4_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;
- memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
- memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
- newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
- newrange.min_addr.ip = new_ip;
- newrange.max_addr.ip = new_ip;
- newrange.min_proto = mr->range[0].min;
- newrange.max_proto = mr->range[0].max;
- /* Hand modified range to generic setup. */
- return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
- }
- static int netmap_tg4_check(const struct xt_tgchk_param *par)
- {
- const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
- if (!(mr->range[0].flags & NF_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 struct xt_target netmap_tg_reg[] __read_mostly = {
- {
- .name = "NETMAP",
- .family = NFPROTO_IPV6,
- .revision = 0,
- .target = netmap_tg6,
- .targetsize = sizeof(struct nf_nat_range),
- .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_tg6_checkentry,
- .me = THIS_MODULE,
- },
- {
- .name = "NETMAP",
- .family = NFPROTO_IPV4,
- .revision = 0,
- .target = netmap_tg4,
- .targetsize = sizeof(struct nf_nat_ipv4_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_tg4_check,
- .me = THIS_MODULE,
- },
- };
- static int __init netmap_tg_init(void)
- {
- return xt_register_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg));
- }
- static void netmap_tg_exit(void)
- {
- xt_unregister_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg));
- }
- module_init(netmap_tg_init);
- module_exit(netmap_tg_exit);
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of subnets");
- MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
- MODULE_ALIAS("ip6t_NETMAP");
- MODULE_ALIAS("ipt_NETMAP");
|