nf_nat_redirect.c 3.3 KB

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