Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk>
0004  * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
0005  */
0006 
0007 #include <linux/ip.h>
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/netdevice.h>
0011 #include <linux/ipv6.h>
0012 #include <linux/netfilter.h>
0013 #include <linux/netfilter_ipv4.h>
0014 #include <linux/netfilter_ipv6.h>
0015 #include <linux/netfilter/x_tables.h>
0016 #include <net/netfilter/nf_nat.h>
0017 
0018 static unsigned int
0019 netmap_tg6(struct sk_buff *skb, const struct xt_action_param *par)
0020 {
0021     const struct nf_nat_range2 *range = par->targinfo;
0022     struct nf_nat_range2 newrange;
0023     struct nf_conn *ct;
0024     enum ip_conntrack_info ctinfo;
0025     union nf_inet_addr new_addr, netmask;
0026     unsigned int i;
0027 
0028     ct = nf_ct_get(skb, &ctinfo);
0029     for (i = 0; i < ARRAY_SIZE(range->min_addr.ip6); i++)
0030         netmask.ip6[i] = ~(range->min_addr.ip6[i] ^
0031                    range->max_addr.ip6[i]);
0032 
0033     if (xt_hooknum(par) == NF_INET_PRE_ROUTING ||
0034         xt_hooknum(par) == NF_INET_LOCAL_OUT)
0035         new_addr.in6 = ipv6_hdr(skb)->daddr;
0036     else
0037         new_addr.in6 = ipv6_hdr(skb)->saddr;
0038 
0039     for (i = 0; i < ARRAY_SIZE(new_addr.ip6); i++) {
0040         new_addr.ip6[i] &= ~netmask.ip6[i];
0041         new_addr.ip6[i] |= range->min_addr.ip6[i] &
0042                    netmask.ip6[i];
0043     }
0044 
0045     newrange.flags  = range->flags | NF_NAT_RANGE_MAP_IPS;
0046     newrange.min_addr   = new_addr;
0047     newrange.max_addr   = new_addr;
0048     newrange.min_proto  = range->min_proto;
0049     newrange.max_proto  = range->max_proto;
0050 
0051     return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par)));
0052 }
0053 
0054 static int netmap_tg6_checkentry(const struct xt_tgchk_param *par)
0055 {
0056     const struct nf_nat_range2 *range = par->targinfo;
0057 
0058     if (!(range->flags & NF_NAT_RANGE_MAP_IPS))
0059         return -EINVAL;
0060     return nf_ct_netns_get(par->net, par->family);
0061 }
0062 
0063 static void netmap_tg_destroy(const struct xt_tgdtor_param *par)
0064 {
0065     nf_ct_netns_put(par->net, par->family);
0066 }
0067 
0068 static unsigned int
0069 netmap_tg4(struct sk_buff *skb, const struct xt_action_param *par)
0070 {
0071     struct nf_conn *ct;
0072     enum ip_conntrack_info ctinfo;
0073     __be32 new_ip, netmask;
0074     const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
0075     struct nf_nat_range2 newrange;
0076 
0077     WARN_ON(xt_hooknum(par) != NF_INET_PRE_ROUTING &&
0078         xt_hooknum(par) != NF_INET_POST_ROUTING &&
0079         xt_hooknum(par) != NF_INET_LOCAL_OUT &&
0080         xt_hooknum(par) != NF_INET_LOCAL_IN);
0081     ct = nf_ct_get(skb, &ctinfo);
0082 
0083     netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
0084 
0085     if (xt_hooknum(par) == NF_INET_PRE_ROUTING ||
0086         xt_hooknum(par) == NF_INET_LOCAL_OUT)
0087         new_ip = ip_hdr(skb)->daddr & ~netmask;
0088     else
0089         new_ip = ip_hdr(skb)->saddr & ~netmask;
0090     new_ip |= mr->range[0].min_ip & netmask;
0091 
0092     memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
0093     memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
0094     newrange.flags       = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
0095     newrange.min_addr.ip = new_ip;
0096     newrange.max_addr.ip = new_ip;
0097     newrange.min_proto   = mr->range[0].min;
0098     newrange.max_proto   = mr->range[0].max;
0099 
0100     /* Hand modified range to generic setup. */
0101     return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par)));
0102 }
0103 
0104 static int netmap_tg4_check(const struct xt_tgchk_param *par)
0105 {
0106     const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
0107 
0108     if (!(mr->range[0].flags & NF_NAT_RANGE_MAP_IPS)) {
0109         pr_debug("bad MAP_IPS.\n");
0110         return -EINVAL;
0111     }
0112     if (mr->rangesize != 1) {
0113         pr_debug("bad rangesize %u.\n", mr->rangesize);
0114         return -EINVAL;
0115     }
0116     return nf_ct_netns_get(par->net, par->family);
0117 }
0118 
0119 static struct xt_target netmap_tg_reg[] __read_mostly = {
0120     {
0121         .name       = "NETMAP",
0122         .family     = NFPROTO_IPV6,
0123         .revision   = 0,
0124         .target     = netmap_tg6,
0125         .targetsize = sizeof(struct nf_nat_range),
0126         .table      = "nat",
0127         .hooks      = (1 << NF_INET_PRE_ROUTING) |
0128                       (1 << NF_INET_POST_ROUTING) |
0129                       (1 << NF_INET_LOCAL_OUT) |
0130                       (1 << NF_INET_LOCAL_IN),
0131         .checkentry = netmap_tg6_checkentry,
0132         .destroy    = netmap_tg_destroy,
0133         .me         = THIS_MODULE,
0134     },
0135     {
0136         .name       = "NETMAP",
0137         .family     = NFPROTO_IPV4,
0138         .revision   = 0,
0139         .target     = netmap_tg4,
0140         .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
0141         .table      = "nat",
0142         .hooks      = (1 << NF_INET_PRE_ROUTING) |
0143                       (1 << NF_INET_POST_ROUTING) |
0144                       (1 << NF_INET_LOCAL_OUT) |
0145                       (1 << NF_INET_LOCAL_IN),
0146         .checkentry = netmap_tg4_check,
0147         .destroy    = netmap_tg_destroy,
0148         .me         = THIS_MODULE,
0149     },
0150 };
0151 
0152 static int __init netmap_tg_init(void)
0153 {
0154     return xt_register_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg));
0155 }
0156 
0157 static void netmap_tg_exit(void)
0158 {
0159     xt_unregister_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg));
0160 }
0161 
0162 module_init(netmap_tg_init);
0163 module_exit(netmap_tg_exit);
0164 
0165 MODULE_LICENSE("GPL");
0166 MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of subnets");
0167 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
0168 MODULE_ALIAS("ip6t_NETMAP");
0169 MODULE_ALIAS("ipt_NETMAP");