You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

133 lines
4.0 KiB

  1. /*
  2. * This file is part of PowerDNS or dnsdist.
  3. * Copyright -- PowerDNS.COM B.V. and its contributors
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of version 2 of the GNU General Public License as
  7. * published by the Free Software Foundation.
  8. *
  9. * In addition, for the avoidance of any doubt, permission is granted to
  10. * link this program with OpenSSL and to (re)distribute the binaries
  11. * produced as the result of such linking.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. #ifdef HAVE_CONFIG_H
  23. #include "config.h"
  24. #endif
  25. #include <string>
  26. #include "shuffle.hh"
  27. #include "dns_random.hh"
  28. #include "dnsparser.hh"
  29. // shuffle, maintaining some semblance of order
  30. void pdns::shuffle(std::vector<DNSZoneRecord>& rrs)
  31. {
  32. std::vector<DNSZoneRecord>::iterator first, second;
  33. // We assume the CNAMES are listed first in the ANSWER section and the the other records
  34. // and we want to shuffle the other records only
  35. // First we scan for the first non-CNAME ANSWER record
  36. for (first = rrs.begin(); first != rrs.end(); ++first) {
  37. if (first->dr.d_place == DNSResourceRecord::ANSWER && first->dr.d_type != QType::CNAME) {
  38. break;
  39. }
  40. }
  41. // And then for one past the last ANSWER record
  42. for (second = first; second != rrs.end(); ++second)
  43. if (second->dr.d_place != DNSResourceRecord::ANSWER)
  44. break;
  45. // Now shuffle the non-CNAME ANSWER records
  46. dns_random_engine r;
  47. if (second - first > 1) {
  48. shuffle(first, second, r);
  49. }
  50. // now shuffle the ADDITIONAL records in the same manner as the ANSWER records
  51. for (first = second; first != rrs.end(); ++first) {
  52. if (first->dr.d_place == DNSResourceRecord::ADDITIONAL && first->dr.d_type != QType::CNAME) {
  53. break;
  54. }
  55. }
  56. for (second = first; second != rrs.end(); ++second) {
  57. if (second->dr.d_place != DNSResourceRecord::ADDITIONAL) {
  58. break;
  59. }
  60. }
  61. if (second - first > 1) {
  62. shuffle(first, second, r);
  63. }
  64. // we don't shuffle the rest
  65. }
  66. // shuffle, maintaining some semblance of order
  67. static void shuffle(std::vector<DNSRecord>& rrs)
  68. {
  69. // This shuffles in the same style as the above method, keeping CNAME in the front and RRSIGs at the end
  70. std::vector<DNSRecord>::iterator first, second;
  71. for (first = rrs.begin(); first != rrs.end(); ++first) {
  72. if (first->d_place == DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) {
  73. break;
  74. }
  75. }
  76. for (second = first; second != rrs.end(); ++second) {
  77. if (second->d_place != DNSResourceRecord::ANSWER || second->d_type == QType::RRSIG) {
  78. break;
  79. }
  80. }
  81. pdns::dns_random_engine r;
  82. if (second - first > 1) {
  83. shuffle(first, second, r);
  84. }
  85. // now shuffle the additional records
  86. for (first = second; first != rrs.end(); ++first) {
  87. if (first->d_place == DNSResourceRecord::ADDITIONAL && first->d_type != QType::CNAME) {
  88. break;
  89. }
  90. }
  91. for (second = first; second != rrs.end(); ++second) {
  92. if (second->d_place != DNSResourceRecord::ADDITIONAL) {
  93. break;
  94. }
  95. }
  96. if (second - first > 1) {
  97. shuffle(first, second, r);
  98. }
  99. // we don't shuffle the rest
  100. }
  101. static uint16_t mapTypesToOrder(uint16_t type)
  102. {
  103. if (type == QType::CNAME)
  104. return 0;
  105. if (type == QType::RRSIG)
  106. return 65535;
  107. else
  108. return 1;
  109. }
  110. // make sure rrs is sorted in d_place order to avoid surprises later
  111. // then shuffle the parts that desire shuffling
  112. void pdns::orderAndShuffle(vector<DNSRecord>& rrs)
  113. {
  114. std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord& a, const DNSRecord& b) {
  115. return std::make_tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::make_tuple(b.d_place, mapTypesToOrder(b.d_type));
  116. });
  117. shuffle(rrs);
  118. }