1 /* 2 * (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk> 3 * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> 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 36 if (par->hooknum == NF_INET_PRE_ROUTING || 37 par->hooknum == NF_INET_LOCAL_OUT) 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 54 return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum)); 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; 63 return 0; 64 } 65 66 static unsigned int 67 netmap_tg4(struct sk_buff *skb, const struct xt_action_param *par) 68 { 69 struct nf_conn *ct; 70 enum ip_conntrack_info ctinfo; 71 __be32 new_ip, netmask; 72 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; 73 struct nf_nat_range newrange; 74 75 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING || 76 par->hooknum == NF_INET_POST_ROUTING || 77 par->hooknum == NF_INET_LOCAL_OUT || 78 par->hooknum == NF_INET_LOCAL_IN); 79 ct = nf_ct_get(skb, &ctinfo); 80 81 netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip); 82 83 if (par->hooknum == NF_INET_PRE_ROUTING || 84 par->hooknum == NF_INET_LOCAL_OUT) 85 new_ip = ip_hdr(skb)->daddr & ~netmask; 86 else 87 new_ip = ip_hdr(skb)->saddr & ~netmask; 88 new_ip |= mr->range[0].min_ip & netmask; 89 90 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); 91 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); 92 newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS; 93 newrange.min_addr.ip = new_ip; 94 newrange.max_addr.ip = new_ip; 95 newrange.min_proto = mr->range[0].min; 96 newrange.max_proto = mr->range[0].max; 97 98 /* Hand modified range to generic setup. */ 99 return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum)); 100 } 101 102 static int netmap_tg4_check(const struct xt_tgchk_param *par) 103 { 104 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; 105 106 if (!(mr->range[0].flags & NF_NAT_RANGE_MAP_IPS)) { 107 pr_debug("bad MAP_IPS.\n"); 108 return -EINVAL; 109 } 110 if (mr->rangesize != 1) { 111 pr_debug("bad rangesize %u.\n", mr->rangesize); 112 return -EINVAL; 113 } 114 return 0; 115 } 116 117 static struct xt_target netmap_tg_reg[] __read_mostly = { 118 { 119 .name = "NETMAP", 120 .family = NFPROTO_IPV6, 121 .revision = 0, 122 .target = netmap_tg6, 123 .targetsize = sizeof(struct nf_nat_range), 124 .table = "nat", 125 .hooks = (1 << NF_INET_PRE_ROUTING) | 126 (1 << NF_INET_POST_ROUTING) | 127 (1 << NF_INET_LOCAL_OUT) | 128 (1 << NF_INET_LOCAL_IN), 129 .checkentry = netmap_tg6_checkentry, 130 .me = THIS_MODULE, 131 }, 132 { 133 .name = "NETMAP", 134 .family = NFPROTO_IPV4, 135 .revision = 0, 136 .target = netmap_tg4, 137 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat), 138 .table = "nat", 139 .hooks = (1 << NF_INET_PRE_ROUTING) | 140 (1 << NF_INET_POST_ROUTING) | 141 (1 << NF_INET_LOCAL_OUT) | 142 (1 << NF_INET_LOCAL_IN), 143 .checkentry = netmap_tg4_check, 144 .me = THIS_MODULE, 145 }, 146 }; 147 148 static int __init netmap_tg_init(void) 149 { 150 return xt_register_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); 151 } 152 153 static void netmap_tg_exit(void) 154 { 155 xt_unregister_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); 156 } 157 158 module_init(netmap_tg_init); 159 module_exit(netmap_tg_exit); 160 161 MODULE_LICENSE("GPL"); 162 MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of subnets"); 163 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 164 MODULE_ALIAS("ip6t_NETMAP"); 165 MODULE_ALIAS("ipt_NETMAP"); 166