]>
Commit | Line | Data |
---|---|---|
12c86877 | 1 | /* |
12471842 PL |
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 | */ | |
12c86877 BH |
22 | #ifndef PACKETCACHE_HH |
23 | #define PACKETCACHE_HH | |
24 | ||
bf269e28 RG |
25 | #include "ednsoptions.hh" |
26 | #include "misc.hh" | |
27 | #include "iputils.hh" | |
ba45c866 | 28 | |
3dbfa51e | 29 | class PacketCache : public boost::noncopyable |
12c86877 | 30 | { |
08b02366 RG |
31 | public: |
32 | static uint32_t canHashPacket(const std::string& packet, uint16_t* ecsBegin, uint16_t* ecsEnd) | |
12c86877 | 33 | { |
bf269e28 | 34 | uint32_t ret = 0; |
08b02366 | 35 | ret = burtle(reinterpret_cast<const unsigned char*>(packet.c_str()) + 2, sizeof(dnsheader) - 2, ret); // rest of dnsheader, skip id |
bf269e28 | 36 | size_t packetSize = packet.size(); |
08b02366 | 37 | size_t pos = sizeof(dnsheader); |
bf269e28 RG |
38 | const char* end = packet.c_str() + packetSize; |
39 | const char* p = packet.c_str() + pos; | |
40 | ||
010b2e48 | 41 | for(; p < end && *p; ++p, ++pos) { // XXX if you embed a 0 in your qname we'll stop lowercasing there |
bf269e28 RG |
42 | const unsigned char l = dns_tolower(*p); // label lengths can safely be lower cased |
43 | ret=burtle(&l, 1, ret); | |
44 | } // XXX the embedded 0 in the qname will break the subnet stripping | |
45 | ||
08b02366 | 46 | const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.c_str()); |
bf269e28 RG |
47 | const char* skipBegin = p; |
48 | const char* skipEnd = p; | |
08b02366 RG |
49 | if (ecsBegin != nullptr && ecsEnd != nullptr) { |
50 | *ecsBegin = 0; | |
51 | *ecsEnd = 0; | |
52 | } | |
bf269e28 RG |
53 | /* we need at least 1 (final empty label) + 2 (QTYPE) + 2 (QCLASS) |
54 | + OPT root label (1), type (2), class (2) and ttl (4) | |
55 | + the OPT RR rdlen (2) | |
56 | = 16 | |
57 | */ | |
08b02366 | 58 | if(ntohs(dh->arcount)==1 && (pos+16) < packetSize) { |
bf269e28 RG |
59 | char* optionBegin = nullptr; |
60 | size_t optionLen = 0; | |
61 | /* skip the final empty label (1), the qtype (2), qclass (2) */ | |
62 | /* root label (1), type (2), class (2) and ttl (4) */ | |
08b02366 | 63 | int res = getEDNSOption(const_cast<char*>(reinterpret_cast<const char*>(p)) + 14, end - (p + 14), EDNSOptionCode::ECS, &optionBegin, &optionLen); |
bf269e28 RG |
64 | if (res == 0) { |
65 | skipBegin = optionBegin; | |
66 | skipEnd = optionBegin + optionLen; | |
08b02366 RG |
67 | if (ecsBegin != nullptr && ecsEnd != nullptr) { |
68 | *ecsBegin = optionBegin - packet.c_str(); | |
69 | *ecsEnd = *ecsBegin + optionLen; | |
70 | } | |
bf269e28 RG |
71 | } |
72 | } | |
73 | if (skipBegin > p) { | |
08b02366 | 74 | ret = burtle(reinterpret_cast<const unsigned char*>(p), skipBegin-p, ret); |
bf269e28 RG |
75 | } |
76 | if (skipEnd < end) { | |
08b02366 | 77 | ret = burtle(reinterpret_cast<const unsigned char*>(skipEnd), end-skipEnd, ret); |
bf269e28 RG |
78 | } |
79 | ||
80 | return ret; | |
908c1491 | 81 | } |
08b02366 RG |
82 | |
83 | static uint32_t canHashPacket(const std::string& packet) | |
84 | { | |
85 | uint32_t ret = 0; | |
86 | ret = burtle(reinterpret_cast<const unsigned char*>(packet.c_str()) + 2, sizeof(dnsheader) - 2, ret); // rest of dnsheader, skip id | |
87 | size_t packetSize = packet.size(); | |
88 | size_t pos = sizeof(dnsheader); | |
89 | const char* end = packet.c_str() + packetSize; | |
90 | const char* p = packet.c_str() + pos; | |
91 | ||
92 | for(; p < end && *p; ++p) { // XXX if you embed a 0 in your qname we'll stop lowercasing there | |
93 | const unsigned char l = dns_tolower(*p); // label lengths can safely be lower cased | |
94 | ret=burtle(&l, 1, ret); | |
95 | } // XXX the embedded 0 in the qname will break the subnet stripping | |
96 | ||
97 | if (p < end) { | |
98 | ret = burtle(reinterpret_cast<const unsigned char*>(p), end-p, ret); | |
99 | } | |
100 | ||
101 | return ret; | |
102 | } | |
103 | ||
104 | static bool queryHeaderMatches(const std::string& cachedQuery, const std::string& query) | |
105 | { | |
106 | if (cachedQuery.size() != query.size()) { | |
107 | return false; | |
108 | } | |
109 | ||
110 | return (cachedQuery.compare(/* skip the ID */ 2, sizeof(dnsheader) - 2, query, 2, sizeof(dnsheader) - 2) == 0); | |
111 | } | |
112 | ||
113 | static bool queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname) | |
114 | { | |
115 | if (!queryHeaderMatches(cachedQuery, query)) { | |
116 | return false; | |
117 | } | |
118 | ||
119 | size_t pos = sizeof(dnsheader) + qname.wirelength(); | |
120 | ||
121 | return (cachedQuery.compare(pos, cachedQuery.size() - pos, query, pos, query.size() - pos) == 0); | |
122 | } | |
123 | ||
124 | static bool queryMatches(const std::string& cachedQuery, const std::string& query, const DNSName& qname, uint16_t ecsBegin, uint16_t ecsEnd) | |
125 | { | |
126 | if (!queryHeaderMatches(cachedQuery, query)) { | |
127 | return false; | |
128 | } | |
129 | ||
130 | size_t pos = sizeof(dnsheader) + qname.wirelength(); | |
131 | ||
132 | if (ecsBegin != 0 && ecsBegin >= pos && ecsEnd > ecsBegin) { | |
133 | if (cachedQuery.compare(pos, ecsBegin - pos, query, pos, ecsBegin - pos) != 0) { | |
134 | return false; | |
135 | } | |
136 | ||
137 | if (cachedQuery.compare(ecsEnd, cachedQuery.size() - ecsEnd, query, ecsEnd, query.size() - ecsEnd) != 0) { | |
138 | return false; | |
139 | } | |
140 | } | |
141 | else { | |
142 | if (cachedQuery.compare(pos, cachedQuery.size() - pos, query, pos, query.size() - pos) != 0) { | |
143 | return false; | |
144 | } | |
145 | } | |
146 | ||
147 | return true; | |
148 | } | |
149 | ||
12c86877 BH |
150 | }; |
151 | ||
12c86877 | 152 | #endif /* PACKETCACHE_HH */ |