|
24 | 24 | #include <boost/algorithm/string.hpp>
|
25 | 25 | #include <boost/format.hpp>
|
26 | 26 |
|
| 27 | +#include "dns_random.hh" |
27 | 28 | #include "namespaces.hh"
|
28 | 29 | #include "noinitvector.hh"
|
29 | 30 |
|
@@ -985,6 +986,86 @@ void ageDNSPacket(std::string& packet, uint32_t seconds, const dnsheader_aligned
|
985 | 986 | ageDNSPacket(packet.data(), packet.length(), seconds, aligned_dh);
|
986 | 987 | }
|
987 | 988 |
|
| 989 | +void shuffleDNSPacket(char* packet, size_t length, const dnsheader_aligned& aligned_dh) |
| 990 | +{ |
| 991 | + if (length < sizeof(dnsheader)) { |
| 992 | + return; |
| 993 | + } |
| 994 | + try { |
| 995 | + DNSPacketMangler dpm(packet, length); |
| 996 | + const dnsheader* dhp = aligned_dh.get(); |
| 997 | + const uint16_t ancount = ntohs(dhp->ancount); |
| 998 | + if (ancount == 1) { |
| 999 | + // quick exit, nothing to shuffle |
| 1000 | + return; |
| 1001 | + } |
| 1002 | + |
| 1003 | + const uint16_t qdcount = ntohs(dhp->qdcount); |
| 1004 | + |
| 1005 | + for(size_t iter = 0; iter < qdcount; ++iter) { |
| 1006 | + dpm.skipDomainName(); |
| 1007 | + /* type and class */ |
| 1008 | + dpm.skipBytes(4); |
| 1009 | + } |
| 1010 | + |
| 1011 | + // for now shuffle only first rrset, only As and AAAAs |
| 1012 | + uint16_t rrset_type = 0; |
| 1013 | + DNSName rrset_dnsname = DNSName(); |
| 1014 | + std::vector<std::pair<uint32_t, uint32_t>> rrdata_indexes; |
| 1015 | + rrdata_indexes.reserve(ancount); |
| 1016 | + |
| 1017 | + for(size_t iter = 0; iter < ancount; ++iter) { |
| 1018 | + auto domain_start = dpm.getOffset(); |
| 1019 | + dpm.skipDomainName(); |
| 1020 | + const uint16_t dnstype = dpm.get16BitInt(); |
| 1021 | + if (dnstype == QType::A || dnstype == QType::AAAA) { |
| 1022 | + if (rrdata_indexes.size() == 0) { |
| 1023 | + rrset_type = dnstype; |
| 1024 | + rrset_dnsname = DNSName(packet, length, domain_start, true); |
| 1025 | + } else { |
| 1026 | + if (dnstype != rrset_type) { |
| 1027 | + break; |
| 1028 | + } |
| 1029 | + if (DNSName(packet, length, domain_start, true) != rrset_dnsname) { |
| 1030 | + break; |
| 1031 | + } |
| 1032 | + } |
| 1033 | + /* class */ |
| 1034 | + dpm.skipBytes(2); |
| 1035 | + |
| 1036 | + /* ttl */ |
| 1037 | + dpm.skipBytes(4); |
| 1038 | + rrdata_indexes.push_back(dpm.skipAndReturnIndexesRData()); |
| 1039 | + } else { |
| 1040 | + if (rrdata_indexes.size() != 0) { |
| 1041 | + break; |
| 1042 | + } |
| 1043 | + /* class */ |
| 1044 | + dpm.skipBytes(2); |
| 1045 | + |
| 1046 | + /* ttl */ |
| 1047 | + dpm.skipBytes(4); |
| 1048 | + dpm.skipRData(); |
| 1049 | + } |
| 1050 | + } |
| 1051 | + |
| 1052 | + if (rrdata_indexes.size() >= 2) { |
| 1053 | + using uid = std::uniform_int_distribution<std::vector<std::pair<uint32_t, uint32_t>>::size_type>; |
| 1054 | + uid dist; |
| 1055 | + |
| 1056 | + pdns::dns_random_engine randomEngine; |
| 1057 | + for (auto swapped = rrdata_indexes.size() - 1; swapped > 0; --swapped) { |
| 1058 | + auto swapped_with = dist(randomEngine, uid::param_type(0, swapped)); |
| 1059 | + if (swapped != swapped_with) { |
| 1060 | + dpm.swapInPlace(rrdata_indexes[swapped], rrdata_indexes[swapped_with]); |
| 1061 | + } |
| 1062 | + } |
| 1063 | + } |
| 1064 | + } |
| 1065 | + catch(...) { |
| 1066 | + } |
| 1067 | +} |
| 1068 | + |
988 | 1069 | uint32_t getDNSPacketMinTTL(const char* packet, size_t length, bool* seenAuthSOA)
|
989 | 1070 | {
|
990 | 1071 | uint32_t result = std::numeric_limits<uint32_t>::max();
|
|
0 commit comments