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 (xt_hooknum(par) == NF_INET_PRE_ROUTING || 37 xt_hooknum(par) == 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(xt_hooknum(par))); 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 nf_ct_netns_get(par->net, par->family); 64 } 65 66 static void netmap_tg_destroy(const struct xt_tgdtor_param *par) 67 { 68 nf_ct_netns_put(par->net, par->family); 69 } 70 71 static unsigned int 72 netmap_tg4(struct sk_buff *skb, const struct xt_action_param *par) 73 { 74 struct nf_conn *ct; 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; 79 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); 85 86 netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip); 87 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; 91 else 92 new_ip = ip_hdr(skb)->saddr & ~netmask; 93 new_ip |= mr->range[0].min_ip & netmask; 94 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; 102 103 /* Hand modified range to generic setup. */ 104 return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par))); 105 } 106 107 static int netmap_tg4_check(const struct xt_tgchk_param *par) 108 { 109 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; 110 111 if (!(mr->range[0].flags & NF_NAT_RANGE_MAP_IPS)) { 112 pr_debug("bad MAP_IPS.\n"); 113 return -EINVAL; 114 } 115 if (mr->rangesize != 1) { 116 pr_debug("bad rangesize %u.\n", mr->rangesize); 117 return -EINVAL; 118 } 119 return nf_ct_netns_get(par->net, par->family); 120 } 121 122 static struct xt_target netmap_tg_reg[] __read_mostly = { 123 { 124 .name = "NETMAP", 125 .family = NFPROTO_IPV6, 126 .revision = 0, 127 .target = netmap_tg6, 128 .targetsize = sizeof(struct nf_nat_range), 129 .table = "nat", 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, 136 .me = THIS_MODULE, 137 }, 138 { 139 .name = "NETMAP", 140 .family = NFPROTO_IPV4, 141 .revision = 0, 142 .target = netmap_tg4, 143 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat), 144 .table = "nat", 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, 151 .me = THIS_MODULE, 152 }, 153 }; 154 155 static int __init netmap_tg_init(void) 156 { 157 return xt_register_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); 158 } 159 160 static void netmap_tg_exit(void) 161 { 162 xt_unregister_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); 163 } 164 165 module_init(netmap_tg_init); 166 module_exit(netmap_tg_exit); 167 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"); 173