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