/src/pdns/pdns/dnsdistdist/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 | 0 | SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k) { |
40 | 0 | bool ignored; |
41 | 0 | return SvcParam::keyFromString(k, ignored); |
42 | 0 | } |
43 | | |
44 | 0 | SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k, bool &generic) { |
45 | 0 | auto it = SvcParams.find(k); |
46 | 0 | if (it != SvcParams.end()) { |
47 | 0 | generic = false; |
48 | 0 | return it->second; |
49 | 0 | } |
50 | 0 | if (k.substr(0, 3) == "key") { |
51 | 0 | try { |
52 | 0 | generic = true; |
53 | 0 | return SvcParam::SvcParamKey(pdns::checked_stoi<uint16_t>(k.substr(3))); |
54 | 0 | } |
55 | 0 | catch (...) { |
56 | 0 | } |
57 | 0 | } |
58 | 0 | throw std::invalid_argument("SvcParam '" + k + "' is not recognized or in keyNNNN format"); |
59 | 0 | } |
60 | | |
61 | 33 | std::string SvcParam::keyToString(const SvcParam::SvcParamKey& k) { |
62 | 236 | auto ret = std::find_if(SvcParams.begin(), SvcParams.end(), [&](const std::pair<std::string, SvcParam::SvcParamKey>& e) { return e.second == k; }); |
63 | 33 | if (ret != SvcParams.end()) { |
64 | 33 | return ret->first; |
65 | 33 | } |
66 | 0 | return "key" + std::to_string(k); |
67 | 33 | } |
68 | | |
69 | 781 | SvcParam::SvcParam(const SvcParamKey &key) { |
70 | 781 | d_key = key; |
71 | 781 | if (d_key != SvcParamKey::no_default_alpn && d_key != SvcParamKey::ohttp) { |
72 | 0 | throw std::invalid_argument("can not create non-empty SvcParam for key '" + keyToString(key) + "'"); |
73 | 0 | } |
74 | 781 | } |
75 | | |
76 | 8.11k | SvcParam::SvcParam(const SvcParamKey &key, const std::string &value) { |
77 | 8.11k | d_key = key; |
78 | 8.11k | if (d_key != SvcParamKey::ech && d_key != SvcParamKey::dohpath && d_key < 10) { |
79 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string value"); |
80 | 0 | } |
81 | 8.11k | if (d_key == SvcParamKey::ech) { |
82 | 754 | std::string d; |
83 | | // TODO check Base64 decode |
84 | 754 | d_ech = value; |
85 | 754 | return; |
86 | 754 | } |
87 | 7.36k | d_value = value; |
88 | 7.36k | } |
89 | | |
90 | 660 | SvcParam::SvcParam(const SvcParamKey &key, std::vector<std::string> &&value) { |
91 | 660 | d_key = key; |
92 | 660 | if (d_key != SvcParamKey::alpn) { |
93 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value"); |
94 | 0 | } |
95 | 660 | if (d_key == SvcParamKey::alpn) { |
96 | 660 | d_alpn = std::move(value); |
97 | 660 | } |
98 | 660 | } |
99 | | |
100 | 0 | SvcParam::SvcParam(const SvcParamKey &key, std::set<std::string> &&value) { |
101 | 0 | d_key = key; |
102 | 0 | if (d_key != SvcParamKey::mandatory) { |
103 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value"); |
104 | 0 | } |
105 | 0 | if (d_key == SvcParamKey::mandatory) { |
106 | 0 | for (auto const &v: value) { |
107 | 0 | d_mandatory.insert(keyFromString(v)); |
108 | 0 | } |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | 558 | SvcParam::SvcParam(const SvcParamKey &key, std::set<SvcParam::SvcParamKey> &&value) { |
113 | 558 | d_key = key; |
114 | 558 | if (d_key != SvcParamKey::mandatory) { |
115 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a SvcParamKey-set value"); |
116 | 0 | } |
117 | 558 | d_mandatory = std::move(value); |
118 | 558 | } |
119 | | |
120 | 1.09k | SvcParam::SvcParam(const SvcParamKey &key, std::vector<ComboAddress> &&value) { |
121 | 1.09k | d_key = key; |
122 | 1.09k | if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) { |
123 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with an IP address value"); |
124 | 0 | } |
125 | 5.62k | for (auto const &addr : value) { |
126 | 5.62k | if (d_key == SvcParam::ipv6hint && !addr.isIPv6()) { |
127 | 0 | throw std::invalid_argument("non-IPv6 address ('" + addr.toString() + "') passed for " + keyToString(key)); |
128 | 0 | } |
129 | 5.62k | if (d_key == SvcParam::ipv4hint && !addr.isIPv4()) { |
130 | 0 | throw std::invalid_argument("non-IPv4 address ('" + addr.toString() + "') passed for " + keyToString(key)); |
131 | 0 | } |
132 | 5.62k | } |
133 | 1.09k | d_ipHints = std::move(value); |
134 | 1.09k | } |
135 | | |
136 | 925 | SvcParam::SvcParam(const SvcParamKey &key, std::vector<uint16_t> &&value) : d_key(key) { |
137 | 925 | if (d_key != SvcParamKey::tls_supported_groups) { |
138 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a uint16 value-vector"); |
139 | 0 | } |
140 | 925 | d_tls_supported_groups = std::move(value); |
141 | 925 | } |
142 | | |
143 | 827 | SvcParam::SvcParam(const SvcParamKey &key, const uint16_t value) { |
144 | 827 | d_key = key; |
145 | 827 | if (d_key != SvcParamKey::port) { |
146 | 0 | throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with an port value"); |
147 | 0 | } |
148 | 827 | d_port = value; |
149 | 827 | } |
150 | | |
151 | | //! This ensures an std::set<SvcParam> will be sorted by key (section 2.2 mandates this for wire format) |
152 | 57.9k | bool SvcParam::operator<(const SvcParam& other) const { |
153 | 57.9k | return this->d_key < other.getKey(); |
154 | 57.9k | } |
155 | | |
156 | 0 | const std::vector<ComboAddress>& SvcParam::getIPHints() const { |
157 | 0 | if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) { |
158 | 0 | throw std::invalid_argument("getIPHints called for non-IP address key '" + keyToString(d_key) + "'"); |
159 | 0 | } |
160 | 0 | return d_ipHints; |
161 | 0 | } |
162 | | |
163 | 0 | uint16_t SvcParam::getPort() const { |
164 | 0 | if (d_key != SvcParam::port) { |
165 | 0 | throw std::invalid_argument("getPort called for non-port key '" + keyToString(d_key) + "'"); |
166 | 0 | } |
167 | 0 | return d_port; |
168 | 0 | } |
169 | | |
170 | 0 | const std::vector<std::string>& SvcParam::getALPN() const { |
171 | 0 | if (d_key != SvcParam::alpn) { |
172 | 0 | throw std::invalid_argument("getALPN called for non-alpn key '" + keyToString(d_key) + "'"); |
173 | 0 | } |
174 | 0 | return d_alpn; |
175 | 0 | } |
176 | | |
177 | 0 | const std::set<SvcParam::SvcParamKey>& SvcParam::getMandatory() const { |
178 | 0 | if (d_key != SvcParam::mandatory) { |
179 | 0 | throw std::invalid_argument("getMandatory called for non-mandatory key '" + keyToString(d_key) + "'"); |
180 | 0 | } |
181 | 0 | return d_mandatory; |
182 | 0 | } |
183 | | |
184 | 0 | const std::string& SvcParam::getECH() const { |
185 | 0 | if (d_key != SvcParam::ech) { |
186 | 0 | throw std::invalid_argument("getECH called for non-ech key '" + keyToString(d_key) + "'"); |
187 | 0 | } |
188 | 0 | return d_ech; |
189 | 0 | } |
190 | | |
191 | 0 | const std::string& SvcParam::getValue() const { |
192 | 0 | if (d_key != SvcParamKey::dohpath && d_key < 10) { |
193 | 0 | throw std::invalid_argument("getValue called for non-single value key '" + keyToString(d_key) + "'"); |
194 | 0 | } |
195 | 0 | return d_value; |
196 | 0 | } |
197 | | |
198 | 0 | const std::vector<uint16_t>& SvcParam::getTLSSupportedGroups() const { |
199 | 0 | if (d_key != SvcParam::tls_supported_groups) { |
200 | 0 | throw std::invalid_argument("getTLSSupportedGroups called for non-tls-supported-groups key '" + keyToString(d_key) + "'"); |
201 | 0 | } |
202 | 0 | return d_tls_supported_groups; |
203 | 0 | } |