summaryrefslogtreecommitdiffstats
path: root/dnsdist-svc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dnsdist-svc.cc')
-rw-r--r--dnsdist-svc.cc133
1 files changed, 133 insertions, 0 deletions
diff --git a/dnsdist-svc.cc b/dnsdist-svc.cc
new file mode 100644
index 0000000..ffd42fd
--- /dev/null
+++ b/dnsdist-svc.cc
@@ -0,0 +1,133 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dnsdist-svc.hh"
+#include "dnswriter.hh"
+#include "svc-records.hh"
+
+bool generateSVCPayload(std::vector<uint8_t>& payload, uint16_t priority, const DNSName& target, const std::set<uint16_t>& mandatoryParams, const std::vector<std::string>& alpns, bool noDefaultAlpn, std::optional<uint16_t> port, const std::string& ech, const std::vector<ComboAddress>& ipv4hints, const std::vector<ComboAddress>& ipv6hints, const std::vector<std::pair<uint16_t, std::string>>& additionalParams)
+{
+ // this is an _ordered_ set and the comparison operator is properly defined,
+ // so the parameters will be ordered as defined in the RFC
+ std::set<SvcParam> params;
+
+ if (!mandatoryParams.empty()) {
+ std::set<SvcParam::SvcParamKey> mandatoryKeys;
+ for (const auto& entry : mandatoryParams) {
+ mandatoryKeys.insert(static_cast<SvcParam::SvcParamKey>(entry));
+ }
+ params.insert({SvcParam::SvcParamKey::mandatory, std::move(mandatoryKeys)});
+ }
+
+ if (!alpns.empty()) {
+ params.insert({SvcParam::SvcParamKey::alpn, std::vector<std::string>(alpns)});
+ }
+
+ if (noDefaultAlpn) {
+ params.insert({SvcParam::SvcParamKey::no_default_alpn});
+ }
+
+ if (port) {
+ params.insert({SvcParam::SvcParamKey::port, *port});
+ }
+
+ if (!ipv4hints.empty()) {
+ params.insert({SvcParam::SvcParamKey::ipv4hint, std::vector<ComboAddress>(ipv4hints)});
+ }
+
+ if (!ech.empty()) {
+ params.insert({SvcParam::SvcParamKey::ech, ech});
+ }
+
+ if (!ipv6hints.empty()) {
+ params.insert({SvcParam::SvcParamKey::ipv6hint, std::vector<ComboAddress>(ipv6hints)});
+ }
+
+ for (const auto& param : additionalParams) {
+ params.insert({static_cast<SvcParam::SvcParamKey>(param.first), param.second});
+ }
+
+ if (priority == 0 && params.size() != 0) {
+ return false;
+ }
+
+ payload.clear();
+ /* we will remove the header, question and record header parts later */
+ DNSPacketWriter pw(payload, g_rootdnsname, QType::A, QClass::IN, 0);
+ pw.startRecord(g_rootdnsname, QType::A, 60, QClass::IN, DNSResourceRecord::ANSWER, false);
+ size_t offset = pw.size();
+ pw.xfr16BitInt(priority);
+ pw.xfrName(target, false, true);
+ pw.xfrSvcParamKeyVals(params);
+ pw.commit();
+
+ if (payload.size() <= offset) {
+ return false;
+ }
+
+ payload.erase(payload.begin(), payload.begin() + offset);
+ return true;
+}
+
+bool generateSVCPayload(std::vector<uint8_t>& payload, const SVCRecordParameters& parameters)
+{
+ return generateSVCPayload(payload, parameters.priority, parameters.target, parameters.mandatoryParams, parameters.alpns, parameters.noDefaultAlpn, parameters.port, parameters.ech, parameters.ipv4hints, parameters.ipv6hints, parameters.additionalParams);
+}
+
+struct SVCRecordParameters parseSVCParameters(const svcParamsLua_t& params)
+{
+ struct SVCRecordParameters parameters;
+ for (const auto& p : params) {
+ if (p.first == "mandatory") {
+ for (auto const& entry : boost::get<std::vector<std::pair<int, std::string>>>(p.second)) {
+ parameters.mandatoryParams.insert(SvcParam::keyFromString(entry.second));
+ }
+ }
+ else if (p.first == "alpn") {
+ for (auto const& entry : boost::get<std::vector<std::pair<int, std::string>>>(p.second)) {
+ parameters.alpns.push_back(entry.second);
+ }
+ }
+ else if (p.first == "noDefaultAlpn") {
+ parameters.noDefaultAlpn = boost::get<bool>(p.second);
+ }
+ else if (p.first == "port") {
+ parameters.port = boost::get<uint16_t>(p.second);
+ }
+ else if (p.first == "ipv4hint") {
+ for (auto const& entry : boost::get<std::vector<std::pair<int, std::string>>>(p.second)) {
+ parameters.ipv4hints.push_back(ComboAddress(entry.second));
+ }
+ }
+ else if (p.first == "ech") {
+ parameters.ech = boost::get<std::string>(p.second);
+ }
+ else if (p.first == "ipv6hint") {
+ for (auto const& entry : boost::get<std::vector<std::pair<int, std::string>>>(p.second)) {
+ parameters.ipv6hints.push_back(ComboAddress(entry.second));
+ }
+ }
+ else {
+ parameters.additionalParams.push_back({SvcParam::keyFromString(p.first), boost::get<std::string>(p.second)});
+ }
+ }
+ return parameters;
+}