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.
 
 
 
 
 
 

139 lines
4.9 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. #include "dns.hh"
  23. #include "ednsoptions.hh"
  24. #include "iputils.hh"
  25. /* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
  26. int getEDNSOption(char* optRR, const size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize)
  27. {
  28. assert(optRR != NULL);
  29. assert(optionValue != NULL);
  30. assert(optionValueSize != NULL);
  31. size_t pos = 0;
  32. if (len < DNS_RDLENGTH_SIZE)
  33. return EINVAL;
  34. const uint16_t rdLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
  35. size_t rdPos = 0;
  36. pos += DNS_RDLENGTH_SIZE;
  37. if ((pos + rdLen) > len) {
  38. return EINVAL;
  39. }
  40. while(len >= (pos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE) &&
  41. rdLen >= (rdPos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE)) {
  42. const uint16_t optionCode = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
  43. pos += EDNS_OPTION_CODE_SIZE;
  44. rdPos += EDNS_OPTION_CODE_SIZE;
  45. const uint16_t optionLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
  46. pos += EDNS_OPTION_LENGTH_SIZE;
  47. rdPos += EDNS_OPTION_LENGTH_SIZE;
  48. if (optionLen > (rdLen - rdPos) || optionLen > (len - pos))
  49. return EINVAL;
  50. if (optionCode == wantedOption) {
  51. *optionValue = optRR + pos - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE);
  52. *optionValueSize = optionLen + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE;
  53. return 0;
  54. }
  55. else {
  56. /* skip this option */
  57. pos += optionLen;
  58. rdPos += optionLen;
  59. }
  60. }
  61. return ENOENT;
  62. }
  63. /* extract all EDNS0 options from a pointer on the beginning rdLen of the OPT RR */
  64. int getEDNSOptions(const char* optRR, const size_t len, EDNSOptionViewMap& options)
  65. {
  66. assert(optRR != NULL);
  67. size_t pos = 0;
  68. if (len < DNS_RDLENGTH_SIZE)
  69. return EINVAL;
  70. const uint16_t rdLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
  71. size_t rdPos = 0;
  72. pos += DNS_RDLENGTH_SIZE;
  73. if ((pos + rdLen) > len) {
  74. return EINVAL;
  75. }
  76. while(len >= (pos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE) &&
  77. rdLen >= (rdPos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE)) {
  78. const uint16_t optionCode = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
  79. pos += EDNS_OPTION_CODE_SIZE;
  80. rdPos += EDNS_OPTION_CODE_SIZE;
  81. const uint16_t optionLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
  82. pos += EDNS_OPTION_LENGTH_SIZE;
  83. rdPos += EDNS_OPTION_LENGTH_SIZE;
  84. if (optionLen > (rdLen - rdPos) || optionLen > (len - pos))
  85. return EINVAL;
  86. EDNSOptionViewValue value;
  87. value.content = optRR + pos;
  88. value.size = optionLen;
  89. options[optionCode].values.push_back(std::move(value));
  90. /* skip this option */
  91. pos += optionLen;
  92. rdPos += optionLen;
  93. }
  94. return 0;
  95. }
  96. bool getEDNSOptionsFromContent(const std::string& content, std::vector<std::pair<uint16_t, std::string>>& options)
  97. {
  98. size_t pos = 0;
  99. uint16_t code, len;
  100. const size_t contentLength = content.size();
  101. while (pos < contentLength && (contentLength - pos) >= (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE)) {
  102. code = (static_cast<unsigned char>(content.at(pos)) * 256) + static_cast<unsigned char>(content.at(pos+1));
  103. pos += EDNS_OPTION_CODE_SIZE;
  104. len = (static_cast<unsigned char>(content.at(pos)) * 256) + static_cast<unsigned char>(content.at(pos+1));
  105. pos += EDNS_OPTION_LENGTH_SIZE;
  106. if (pos > contentLength || len > (contentLength - pos)) {
  107. return false;
  108. }
  109. options.emplace_back(code, std::string(&content.at(pos), len));
  110. pos += len;
  111. }
  112. return true;
  113. }
  114. void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res)
  115. {
  116. const uint16_t ednsOptionCode = htons(optionCode);
  117. const uint16_t payloadLen = htons(payload.length());
  118. res.append((const char *) &ednsOptionCode, sizeof ednsOptionCode);
  119. res.append((const char *) &payloadLen, sizeof payloadLen);
  120. res.append(payload);
  121. }