Coverage Report

Created: 2025-11-05 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}