linux/net/netfilter/xt_NETMAP.c
<<
>>
Prefs
   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");
 170