at v4.17 5.1 kB view raw
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 21static unsigned int 22netmap_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 57static 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 66static void netmap_tg_destroy(const struct xt_tgdtor_param *par) 67{ 68 nf_ct_netns_put(par->net, par->family); 69} 70 71static unsigned int 72netmap_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 107static 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 122static 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 155static int __init netmap_tg_init(void) 156{ 157 return xt_register_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); 158} 159 160static void netmap_tg_exit(void) 161{ 162 xt_unregister_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg)); 163} 164 165module_init(netmap_tg_init); 166module_exit(netmap_tg_exit); 167 168MODULE_LICENSE("GPL"); 169MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of subnets"); 170MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 171MODULE_ALIAS("ip6t_NETMAP"); 172MODULE_ALIAS("ipt_NETMAP");