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