1b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt/* 2b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt * (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk> 3b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> 4b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt * 5b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt * This program is free software; you can redistribute it and/or modify 6b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt * it under the terms of the GNU General Public License version 2 as 7b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt * published by the Free Software Foundation. 8b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt */ 9b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 10b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <linux/ip.h> 11b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <linux/kernel.h> 12b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <linux/module.h> 13b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <linux/netdevice.h> 14b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <linux/ipv6.h> 15b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <linux/netfilter.h> 16b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <linux/netfilter_ipv4.h> 17b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <linux/netfilter_ipv6.h> 18b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <linux/netfilter/x_tables.h> 19b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt#include <net/netfilter/nf_nat.h> 20b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 21b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtstatic unsigned int 22b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtnetmap_tg6(struct sk_buff *skb, const struct xt_action_param *par) 23b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt{ 24b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt const struct nf_nat_range *range = par->targinfo; 25b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt struct nf_nat_range newrange; 26b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt struct nf_conn *ct; 27b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt enum ip_conntrack_info ctinfo; 28b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt union nf_inet_addr new_addr, netmask; 29b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt unsigned int i; 30b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 31b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt ct = nf_ct_get(skb, &ctinfo); 32b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt for (i = 0; i < ARRAY_SIZE(range->min_addr.ip6); i++) 33b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt netmask.ip6[i] = ~(range->min_addr.ip6[i] ^ 34b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt range->max_addr.ip6[i]); 35b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 36b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt if (par->hooknum == NF_INET_PRE_ROUTING || 37b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt par->hooknum == NF_INET_LOCAL_OUT) 38b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt new_addr.in6 = ipv6_hdr(skb)->daddr; 39b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt else 40b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt new_addr.in6 = ipv6_hdr(skb)->saddr; 41b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 42b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt for (i = 0; i < ARRAY_SIZE(new_addr.ip6); i++) { 43b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt new_addr.ip6[i] &= ~netmask.ip6[i]; 44b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt new_addr.ip6[i] |= range->min_addr.ip6[i] & 45b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt netmask.ip6[i]; 46b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt } 47b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 48b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; 49b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.min_addr = new_addr; 50b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.max_addr = new_addr; 51b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.min_proto = range->min_proto; 52b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.max_proto = range->max_proto; 53b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 54b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum)); 55b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt} 56b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 57b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtstatic int netmap_tg6_checkentry(const struct xt_tgchk_param *par) 58b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt{ 59b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt const struct nf_nat_range *range = par->targinfo; 60b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 61b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt if (!(range->flags & NF_NAT_RANGE_MAP_IPS)) 62b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt return -EINVAL; 63b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt return 0; 64b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt} 65b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 66b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtstatic unsigned int 67b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtnetmap_tg4(struct sk_buff *skb, const struct xt_action_param *par) 68b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt{ 69b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt struct nf_conn *ct; 70b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt enum ip_conntrack_info ctinfo; 71b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt __be32 new_ip, netmask; 72b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; 73b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt struct nf_nat_range newrange; 74b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 75b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING || 76b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt par->hooknum == NF_INET_POST_ROUTING || 77b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt par->hooknum == NF_INET_LOCAL_OUT || 78b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt par->hooknum == NF_INET_LOCAL_IN); 79b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt ct = nf_ct_get(skb, &ctinfo); 80b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 81b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip); 82b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 83b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt if (par->hooknum == NF_INET_PRE_ROUTING || 84b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt par->hooknum == NF_INET_LOCAL_OUT) 85b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt new_ip = ip_hdr(skb)->daddr & ~netmask; 86b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt else 87b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt new_ip = ip_hdr(skb)->saddr & ~netmask; 88b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt new_ip |= mr->range[0].min_ip & netmask; 89b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 90b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); 91b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); 92b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS; 93b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.min_addr.ip = new_ip; 94b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.max_addr.ip = new_ip; 95b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.min_proto = mr->range[0].min; 96b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt newrange.max_proto = mr->range[0].max; 97b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 98b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt /* Hand modified range to generic setup. */ 99b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum)); 100b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt} 101b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 102b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtstatic int netmap_tg4_check(const struct xt_tgchk_param *par) 103b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt{ 104b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; 105b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 106b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt if (!(mr->range[0].flags & NF_NAT_RANGE_MAP_IPS)) { 107b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt pr_debug("bad MAP_IPS.\n"); 108b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt return -EINVAL; 109b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt } 110b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt if (mr->rangesize != 1) { 111b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt pr_debug("bad rangesize %u.\n", mr->rangesize); 112b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt return -EINVAL; 113b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt } 114b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt return 0; 115b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt} 116b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 117b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtstatic struct xt_target netmap_tg_reg[] __read_mostly = { 118b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt { 119b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .name = "NETMAP", 120b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .family = NFPROTO_IPV6, 121b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .revision = 0, 122b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .target = netmap_tg6, 123b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .targetsize = sizeof(struct nf_nat_range), 124b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .table = "nat", 125b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .hooks = (1 << NF_INET_PRE_ROUTING) | 126b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt (1 << NF_INET_POST_ROUTING) | 127b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt (1 << NF_INET_LOCAL_OUT) | 128b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt (1 << NF_INET_LOCAL_IN), 129b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .checkentry = netmap_tg6_checkentry, 130b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .me = THIS_MODULE, 131b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt }, 132b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt { 133b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .name = "NETMAP", 134b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .family = NFPROTO_IPV4, 135b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .revision = 0, 136b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .target = netmap_tg4, 137b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat), 138b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .table = "nat", 139b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .hooks = (1 << NF_INET_PRE_ROUTING) | 140b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt (1 << NF_INET_POST_ROUTING) | 141b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt (1 << NF_INET_LOCAL_OUT) | 142b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt (1 << NF_INET_LOCAL_IN), 143b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .checkentry = netmap_tg4_check, 144b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt .me = THIS_MODULE, 145b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt }, 146b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt}; 147b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 148b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtstatic int __init netmap_tg_init(void) 149b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt{ 150b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt return xt_register_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); 151b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt} 152b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 153b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtstatic void netmap_tg_exit(void) 154b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt{ 155b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt xt_unregister_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); 156b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt} 157b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 158b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtmodule_init(netmap_tg_init); 159b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardtmodule_exit(netmap_tg_exit); 160b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan Engelhardt 161b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan EngelhardtMODULE_LICENSE("GPL"); 162b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan EngelhardtMODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of subnets"); 163b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan EngelhardtMODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 164b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan EngelhardtMODULE_ALIAS("ip6t_NETMAP"); 165b3d54b3e406b5d6ac391590bf7524e887e8e13c3Jan EngelhardtMODULE_ALIAS("ipt_NETMAP"); 166