nf_nat_masquerade_ipv6.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6
  9. * NAT funded by Astaro.
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/module.h>
  13. #include <linux/atomic.h>
  14. #include <linux/netdevice.h>
  15. #include <linux/ipv6.h>
  16. #include <linux/netfilter.h>
  17. #include <linux/netfilter_ipv6.h>
  18. #include <net/netfilter/nf_nat.h>
  19. #include <net/addrconf.h>
  20. #include <net/ipv6.h>
  21. #include <net/netfilter/ipv6/nf_nat_masquerade.h>
  22. unsigned int
  23. nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range *range,
  24. const struct net_device *out)
  25. {
  26. enum ip_conntrack_info ctinfo;
  27. struct in6_addr src;
  28. struct nf_conn *ct;
  29. struct nf_nat_range newrange;
  30. ct = nf_ct_get(skb, &ctinfo);
  31. NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
  32. ctinfo == IP_CT_RELATED_REPLY));
  33. if (ipv6_dev_get_saddr(nf_ct_net(ct), out,
  34. &ipv6_hdr(skb)->daddr, 0, &src) < 0)
  35. return NF_DROP;
  36. nfct_nat(ct)->masq_index = out->ifindex;
  37. newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
  38. newrange.min_addr.in6 = src;
  39. newrange.max_addr.in6 = src;
  40. newrange.min_proto = range->min_proto;
  41. newrange.max_proto = range->max_proto;
  42. return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
  43. }
  44. EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6);
  45. static int device_cmp(struct nf_conn *ct, void *ifindex)
  46. {
  47. const struct nf_conn_nat *nat = nfct_nat(ct);
  48. if (!nat)
  49. return 0;
  50. if (nf_ct_l3num(ct) != NFPROTO_IPV6)
  51. return 0;
  52. return nat->masq_index == (int)(long)ifindex;
  53. }
  54. static int masq_device_event(struct notifier_block *this,
  55. unsigned long event, void *ptr)
  56. {
  57. const struct net_device *dev = netdev_notifier_info_to_dev(ptr);
  58. struct net *net = dev_net(dev);
  59. if (event == NETDEV_DOWN)
  60. nf_ct_iterate_cleanup(net, device_cmp,
  61. (void *)(long)dev->ifindex, 0, 0);
  62. return NOTIFY_DONE;
  63. }
  64. static struct notifier_block masq_dev_notifier = {
  65. .notifier_call = masq_device_event,
  66. };
  67. static int masq_inet_event(struct notifier_block *this,
  68. unsigned long event, void *ptr)
  69. {
  70. struct inet6_ifaddr *ifa = ptr;
  71. struct netdev_notifier_info info;
  72. netdev_notifier_info_init(&info, ifa->idev->dev);
  73. return masq_device_event(this, event, &info);
  74. }
  75. static struct notifier_block masq_inet_notifier = {
  76. .notifier_call = masq_inet_event,
  77. };
  78. static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0);
  79. void nf_nat_masquerade_ipv6_register_notifier(void)
  80. {
  81. /* check if the notifier is already set */
  82. if (atomic_inc_return(&masquerade_notifier_refcount) > 1)
  83. return;
  84. register_netdevice_notifier(&masq_dev_notifier);
  85. register_inet6addr_notifier(&masq_inet_notifier);
  86. }
  87. EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_register_notifier);
  88. void nf_nat_masquerade_ipv6_unregister_notifier(void)
  89. {
  90. /* check if the notifier still has clients */
  91. if (atomic_dec_return(&masquerade_notifier_refcount) > 0)
  92. return;
  93. unregister_inet6addr_notifier(&masq_inet_notifier);
  94. unregister_netdevice_notifier(&masq_dev_notifier);
  95. }
  96. EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_unregister_notifier);
  97. MODULE_LICENSE("GPL");
  98. MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");