/src/pdns/pdns/svc-records.cc
Line | Count | Source |
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 "svc-records.hh" |
23 | | #include "misc.hh" |
24 | | #include "base64.hh" |
25 | | |
26 | | const std::map<std::string, SvcParam::SvcParamKey> SvcParam::SvcParams = { |
27 | | {"mandatory", SvcParam::SvcParamKey::mandatory}, |
28 | | {"alpn", SvcParam::SvcParamKey::alpn}, |
29 | | {"no-default-alpn", SvcParam::SvcParamKey::no_default_alpn}, |
30 | | {"port", SvcParam::SvcParamKey::port}, |
31 | | {"ipv4hint", SvcParam::SvcParamKey::ipv4hint}, |
32 | | {"ech", SvcParam::SvcParamKey::ech}, |
33 | | {"ipv6hint", SvcParam::SvcParamKey::ipv6hint}, |
34 | | {"dohpath", SvcParam::SvcParamKey::dohpath}, |
35 | | {"ohttp", SvcParam::SvcParamKey::ohttp}, |
36 | | {"tls-supported-groups", SvcParam::SvcParamKey::tls_supported_groups}, |
37 | | }; |
38 | | |
39 | | SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k) |
40 | 0 | { |
41 | 0 | bool ignored; |
42 | 0 | return SvcParam::keyFromString(k, ignored); |
43 | 0 | } |
44 | | |
45 | | SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k, bool& generic) |
46 | 0 | { |
47 | 0 | auto it = SvcParams.find(k); |
48 | 0 | if (it != SvcParams.end()) { |
49 | 0 | generic = false; |
50 | 0 | return it->second; |
51 | 0 | } |
52 | 0 | if (k.substr(0, 3) == "key") { |
53 | 0 | try { |
54 | 0 | generic = true; |
55 | 0 | return SvcParam::SvcParamKey(pdns::checked_stoi<uint16_t>(k.substr(3))); |
56 | 0 | } |
57 | 0 | catch (...) { |
58 | 0 | } |
59 | 0 | } |
60 | 0 | throw std::invalid_argument("SvcParam '" + k + "' is not recognized or in keyNNNN format"); |
61 | 0 | } |
62 | | |
63 | | std::string SvcParam::keyToString(const SvcParam::SvcParamKey& k) |
64 | 9 | { |
65 | 57 | auto ret = std::find_if(SvcParams.begin(), SvcParams.end(), [&](const std::pair<std::string, SvcParam::SvcParamKey>& e) { return e.second == k; }); |
66 | 9 | if (ret != SvcParams.end()) { |
67 | 9 | return ret->first; |
68 | 9 | } |
69 | 0 | return "key" + std::to_string(k); |
70 | 9 | } |
71 | | |
72 | | SvcParam::SvcParam(const SvcParamKey& key) |
73 | 413 | { |
74 | 413 | d_key = key; |
75 | 413 | if (d_key != SvcParamKey::no_default_alpn && d_key != SvcParamKey::ohttp) { |
76 | 0 | throw std::invalid_argument("can not create non-empty SvcParam for key '" + keyToString(key) + "'"); |
77 | 0 | } |
78 | 413 | } |
79 | | |
80 | | SvcParam::SvcParam(const SvcParamKey& key, const std::string& value) |
81 | 3.10k | { |
82 | 3.10k | d_key = key; |
83 | 3.10k | if (d_key != SvcParamKey::ech && d_key != SvcParamKey::dohpath && d_key < 10) { |
84 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string value"); |
85 | 0 | } |
86 | 3.10k | if (d_key == SvcParamKey::ech) { |
87 | 588 | std::string d; |
88 | | // TODO check Base64 decode |
89 | 588 | d_ech = value; |
90 | 588 | return; |
91 | 588 | } |
92 | 2.52k | d_value = value; |
93 | 2.52k | } |
94 | | |
95 | | SvcParam::SvcParam(const SvcParamKey& key, std::vector<std::string>&& value) |
96 | 1.11k | { |
97 | 1.11k | d_key = key; |
98 | 1.11k | if (d_key != SvcParamKey::alpn) { |
99 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value"); |
100 | 0 | } |
101 | 1.11k | if (d_key == SvcParamKey::alpn) { |
102 | 1.11k | d_alpn = std::move(value); |
103 | 1.11k | } |
104 | 1.11k | } |
105 | | |
106 | | SvcParam::SvcParam(const SvcParamKey& key, std::set<std::string>&& value) |
107 | 0 | { |
108 | 0 | d_key = key; |
109 | 0 | if (d_key != SvcParamKey::mandatory) { |
110 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value"); |
111 | 0 | } |
112 | 0 | if (d_key == SvcParamKey::mandatory) { |
113 | 0 | for (auto const& v : value) { |
114 | 0 | d_mandatory.insert(keyFromString(v)); |
115 | 0 | } |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | | SvcParam::SvcParam(const SvcParamKey& key, std::set<SvcParam::SvcParamKey>&& value) |
120 | 305 | { |
121 | 305 | d_key = key; |
122 | 305 | if (d_key != SvcParamKey::mandatory) { |
123 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a SvcParamKey-set value"); |
124 | 0 | } |
125 | 305 | d_mandatory = std::move(value); |
126 | 305 | } |
127 | | |
128 | | SvcParam::SvcParam(const SvcParamKey& key, std::vector<ComboAddress>&& value) |
129 | 1.10k | { |
130 | 1.10k | d_key = key; |
131 | 1.10k | if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) { |
132 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with an IP address value"); |
133 | 0 | } |
134 | 5.77k | for (auto const& addr : value) { |
135 | 5.77k | if (d_key == SvcParam::ipv6hint && !addr.isIPv6()) { |
136 | 0 | throw std::invalid_argument("non-IPv6 address ('" + addr.toString() + "') passed for " + keyToString(key)); |
137 | 0 | } |
138 | 5.77k | if (d_key == SvcParam::ipv4hint && !addr.isIPv4()) { |
139 | 0 | throw std::invalid_argument("non-IPv4 address ('" + addr.toString() + "') passed for " + keyToString(key)); |
140 | 0 | } |
141 | 5.77k | } |
142 | 1.10k | d_ipHints = std::move(value); |
143 | 1.10k | } |
144 | | |
145 | | SvcParam::SvcParam(const SvcParamKey& key, std::vector<uint16_t>&& value) : |
146 | 663 | d_key(key) |
147 | 663 | { |
148 | 663 | if (d_key != SvcParamKey::tls_supported_groups) { |
149 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a uint16 value-vector"); |
150 | 0 | } |
151 | 663 | d_tls_supported_groups = std::move(value); |
152 | 663 | } |
153 | | |
154 | | SvcParam::SvcParam(const SvcParamKey& key, const uint16_t value) |
155 | 1.33k | { |
156 | 1.33k | d_key = key; |
157 | 1.33k | if (d_key != SvcParamKey::port) { |
158 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a port value"); |
159 | 0 | } |
160 | 1.33k | d_port = value; |
161 | 1.33k | } |
162 | | |
163 | | //! This ensures an std::set<SvcParam> will be sorted by key (section 2.2 mandates this for wire format) |
164 | | bool SvcParam::operator<(const SvcParam& other) const |
165 | 5.94k | { |
166 | 5.94k | return this->d_key < other.getKey(); |
167 | 5.94k | } |
168 | | |
169 | | bool SvcParam::operator==(const SvcParam& other) const |
170 | 0 | { |
171 | 0 | if (this->getKey() != other.getKey()) { |
172 | 0 | return false; |
173 | 0 | } |
174 | 0 | switch (this->d_key) { |
175 | 0 | case SvcParamKey::mandatory: |
176 | 0 | return this->getMandatory() == other.getMandatory(); |
177 | 0 | case SvcParamKey::alpn: |
178 | 0 | return this->getALPN() == other.getALPN(); |
179 | 0 | case SvcParamKey::no_default_alpn: /* fallthrough */ |
180 | 0 | case SvcParamKey::ohttp: |
181 | 0 | return true; |
182 | 0 | case SvcParamKey::port: |
183 | 0 | return this->getPort() == other.getPort(); |
184 | 0 | case SvcParamKey::ipv4hint: /* fallthrough */ |
185 | 0 | case SvcParamKey::ipv6hint: |
186 | 0 | return (this->getIPHints() == other.getIPHints() && this->getAutoHint() == other.getAutoHint()); |
187 | 0 | case SvcParamKey::ech: |
188 | 0 | return this->getECH() == other.getECH(); |
189 | 0 | case SvcParamKey::dohpath: |
190 | 0 | return this->getValue() == other.getValue(); |
191 | 0 | case SvcParamKey::tls_supported_groups: |
192 | 0 | return this->getTLSSupportedGroups() == other.getTLSSupportedGroups(); |
193 | 0 | default: |
194 | 0 | return this->getValue() == other.getValue(); |
195 | 0 | } |
196 | 0 | } |
197 | | |
198 | | bool SvcParam::operator!=(const SvcParam& other) const |
199 | 0 | { |
200 | 0 | return !(*this == other); |
201 | 0 | } |
202 | | |
203 | | const std::vector<ComboAddress>& SvcParam::getIPHints() const |
204 | 0 | { |
205 | 0 | if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) { |
206 | 0 | throw std::invalid_argument("getIPHints called for non-IP address key '" + keyToString(d_key) + "'"); |
207 | 0 | } |
208 | 0 | return d_ipHints; |
209 | 0 | } |
210 | | |
211 | | uint16_t SvcParam::getPort() const |
212 | 0 | { |
213 | 0 | if (d_key != SvcParam::port) { |
214 | 0 | throw std::invalid_argument("getPort called for non-port key '" + keyToString(d_key) + "'"); |
215 | 0 | } |
216 | 0 | return d_port; |
217 | 0 | } |
218 | | |
219 | | const std::vector<std::string>& SvcParam::getALPN() const |
220 | 0 | { |
221 | 0 | if (d_key != SvcParam::alpn) { |
222 | 0 | throw std::invalid_argument("getALPN called for non-alpn key '" + keyToString(d_key) + "'"); |
223 | 0 | } |
224 | 0 | return d_alpn; |
225 | 0 | } |
226 | | |
227 | | const std::set<SvcParam::SvcParamKey>& SvcParam::getMandatory() const |
228 | 0 | { |
229 | 0 | if (d_key != SvcParam::mandatory) { |
230 | 0 | throw std::invalid_argument("getMandatory called for non-mandatory key '" + keyToString(d_key) + "'"); |
231 | 0 | } |
232 | 0 | return d_mandatory; |
233 | 0 | } |
234 | | |
235 | | const std::string& SvcParam::getECH() const |
236 | 0 | { |
237 | 0 | if (d_key != SvcParam::ech) { |
238 | 0 | throw std::invalid_argument("getECH called for non-ech key '" + keyToString(d_key) + "'"); |
239 | 0 | } |
240 | 0 | return d_ech; |
241 | 0 | } |
242 | | |
243 | | const std::string& SvcParam::getValue() const |
244 | 0 | { |
245 | 0 | if (d_key != SvcParamKey::dohpath && d_key < 10) { |
246 | 0 | throw std::invalid_argument("getValue called for non-single value key '" + keyToString(d_key) + "'"); |
247 | 0 | } |
248 | 0 | return d_value; |
249 | 0 | } |
250 | | |
251 | | const std::vector<uint16_t>& SvcParam::getTLSSupportedGroups() const |
252 | 0 | { |
253 | 0 | if (d_key != SvcParam::tls_supported_groups) { |
254 | 0 | throw std::invalid_argument("getTLSSupportedGroups called for non-tls-supported-groups key '" + keyToString(d_key) + "'"); |
255 | 0 | } |
256 | 0 | return d_tls_supported_groups; |
257 | 0 | } |