root/net/netfilter/nf_nat_redirect.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nf_nat_redirect_ipv4
  2. nf_nat_redirect_ipv6

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * (C) 1999-2001 Paul `Rusty' Russell
   4  * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
   5  * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
   6  *
   7  * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6
   8  * NAT funded by Astaro.
   9  */
  10 
  11 #include <linux/if.h>
  12 #include <linux/inetdevice.h>
  13 #include <linux/ip.h>
  14 #include <linux/kernel.h>
  15 #include <linux/netdevice.h>
  16 #include <linux/netfilter.h>
  17 #include <linux/types.h>
  18 #include <linux/netfilter_ipv4.h>
  19 #include <linux/netfilter_ipv6.h>
  20 #include <linux/netfilter/x_tables.h>
  21 #include <net/addrconf.h>
  22 #include <net/checksum.h>
  23 #include <net/protocol.h>
  24 #include <net/netfilter/nf_nat.h>
  25 #include <net/netfilter/nf_nat_redirect.h>
  26 
  27 unsigned int
  28 nf_nat_redirect_ipv4(struct sk_buff *skb,
  29                      const struct nf_nat_ipv4_multi_range_compat *mr,
  30                      unsigned int hooknum)
  31 {
  32         struct nf_conn *ct;
  33         enum ip_conntrack_info ctinfo;
  34         __be32 newdst;
  35         struct nf_nat_range2 newrange;
  36 
  37         WARN_ON(hooknum != NF_INET_PRE_ROUTING &&
  38                 hooknum != NF_INET_LOCAL_OUT);
  39 
  40         ct = nf_ct_get(skb, &ctinfo);
  41         WARN_ON(!(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
  42 
  43         /* Local packets: make them go to loopback */
  44         if (hooknum == NF_INET_LOCAL_OUT) {
  45                 newdst = htonl(0x7F000001);
  46         } else {
  47                 const struct in_device *indev;
  48 
  49                 newdst = 0;
  50 
  51                 indev = __in_dev_get_rcu(skb->dev);
  52                 if (indev) {
  53                         const struct in_ifaddr *ifa;
  54 
  55                         ifa = rcu_dereference(indev->ifa_list);
  56                         if (ifa)
  57                                 newdst = ifa->ifa_local;
  58                 }
  59 
  60                 if (!newdst)
  61                         return NF_DROP;
  62         }
  63 
  64         /* Transfer from original range. */
  65         memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
  66         memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
  67         newrange.flags       = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
  68         newrange.min_addr.ip = newdst;
  69         newrange.max_addr.ip = newdst;
  70         newrange.min_proto   = mr->range[0].min;
  71         newrange.max_proto   = mr->range[0].max;
  72 
  73         /* Hand modified range to generic setup. */
  74         return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
  75 }
  76 EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv4);
  77 
  78 static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
  79 
  80 unsigned int
  81 nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range,
  82                      unsigned int hooknum)
  83 {
  84         struct nf_nat_range2 newrange;
  85         struct in6_addr newdst;
  86         enum ip_conntrack_info ctinfo;
  87         struct nf_conn *ct;
  88 
  89         ct = nf_ct_get(skb, &ctinfo);
  90         if (hooknum == NF_INET_LOCAL_OUT) {
  91                 newdst = loopback_addr;
  92         } else {
  93                 struct inet6_dev *idev;
  94                 struct inet6_ifaddr *ifa;
  95                 bool addr = false;
  96 
  97                 idev = __in6_dev_get(skb->dev);
  98                 if (idev != NULL) {
  99                         read_lock_bh(&idev->lock);
 100                         list_for_each_entry(ifa, &idev->addr_list, if_list) {
 101                                 newdst = ifa->addr;
 102                                 addr = true;
 103                                 break;
 104                         }
 105                         read_unlock_bh(&idev->lock);
 106                 }
 107 
 108                 if (!addr)
 109                         return NF_DROP;
 110         }
 111 
 112         newrange.flags          = range->flags | NF_NAT_RANGE_MAP_IPS;
 113         newrange.min_addr.in6   = newdst;
 114         newrange.max_addr.in6   = newdst;
 115         newrange.min_proto      = range->min_proto;
 116         newrange.max_proto      = range->max_proto;
 117 
 118         return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
 119 }
 120 EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv6);

/* [<][>][^][v][top][bottom][index][help] */