nf_nat_proto_icmpv6.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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 IPv4 ICMP NAT code. Development of IPv6
  9. * NAT funded by Astaro.
  10. */
  11. #include <linux/types.h>
  12. #include <linux/init.h>
  13. #include <linux/icmpv6.h>
  14. #include <linux/netfilter.h>
  15. #include <net/netfilter/nf_nat.h>
  16. #include <net/netfilter/nf_nat_core.h>
  17. #include <net/netfilter/nf_nat_l3proto.h>
  18. #include <net/netfilter/nf_nat_l4proto.h>
  19. static bool
  20. icmpv6_in_range(const struct nf_conntrack_tuple *tuple,
  21. enum nf_nat_manip_type maniptype,
  22. const union nf_conntrack_man_proto *min,
  23. const union nf_conntrack_man_proto *max)
  24. {
  25. return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) &&
  26. ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id);
  27. }
  28. static void
  29. icmpv6_unique_tuple(const struct nf_nat_l3proto *l3proto,
  30. struct nf_conntrack_tuple *tuple,
  31. const struct nf_nat_range *range,
  32. enum nf_nat_manip_type maniptype,
  33. const struct nf_conn *ct)
  34. {
  35. static u16 id;
  36. unsigned int range_size;
  37. unsigned int i;
  38. range_size = ntohs(range->max_proto.icmp.id) -
  39. ntohs(range->min_proto.icmp.id) + 1;
  40. if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED))
  41. range_size = 0xffff;
  42. for (i = 0; ; ++id) {
  43. tuple->src.u.icmp.id = htons(ntohs(range->min_proto.icmp.id) +
  44. (id % range_size));
  45. if (++i == range_size || !nf_nat_used_tuple(tuple, ct))
  46. return;
  47. }
  48. }
  49. static bool
  50. icmpv6_manip_pkt(struct sk_buff *skb,
  51. const struct nf_nat_l3proto *l3proto,
  52. unsigned int iphdroff, unsigned int hdroff,
  53. const struct nf_conntrack_tuple *tuple,
  54. enum nf_nat_manip_type maniptype)
  55. {
  56. struct icmp6hdr *hdr;
  57. if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
  58. return false;
  59. hdr = (struct icmp6hdr *)(skb->data + hdroff);
  60. l3proto->csum_update(skb, iphdroff, &hdr->icmp6_cksum,
  61. tuple, maniptype);
  62. if (hdr->icmp6_type == ICMPV6_ECHO_REQUEST ||
  63. hdr->icmp6_type == ICMPV6_ECHO_REPLY) {
  64. inet_proto_csum_replace2(&hdr->icmp6_cksum, skb,
  65. hdr->icmp6_identifier,
  66. tuple->src.u.icmp.id, false);
  67. hdr->icmp6_identifier = tuple->src.u.icmp.id;
  68. }
  69. return true;
  70. }
  71. const struct nf_nat_l4proto nf_nat_l4proto_icmpv6 = {
  72. .l4proto = IPPROTO_ICMPV6,
  73. .manip_pkt = icmpv6_manip_pkt,
  74. .in_range = icmpv6_in_range,
  75. .unique_tuple = icmpv6_unique_tuple,
  76. #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  77. .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
  78. #endif
  79. };