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