/* * 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& payload, uint16_t priority, const DNSName& target, const std::set& mandatoryParams, const std::vector& alpns, bool noDefaultAlpn, std::optional port, const std::string& ech, const std::vector& ipv4hints, const std::vector& ipv6hints, const std::vector>& 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 params; if (!mandatoryParams.empty()) { std::set mandatoryKeys; for (const auto& entry : mandatoryParams) { mandatoryKeys.insert(static_cast(entry)); } params.insert({SvcParam::SvcParamKey::mandatory, std::move(mandatoryKeys)}); } if (!alpns.empty()) { params.insert({SvcParam::SvcParamKey::alpn, std::vector(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(ipv4hints)}); } if (!ech.empty()) { params.insert({SvcParam::SvcParamKey::ech, ech}); } if (!ipv6hints.empty()) { params.insert({SvcParam::SvcParamKey::ipv6hint, std::vector(ipv6hints)}); } for (const auto& param : additionalParams) { params.insert({static_cast(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& 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>>(p.second)) { parameters.mandatoryParams.insert(SvcParam::keyFromString(entry.second)); } } else if (p.first == "alpn") { for (auto const& entry : boost::get>>(p.second)) { parameters.alpns.push_back(entry.second); } } else if (p.first == "noDefaultAlpn") { parameters.noDefaultAlpn = boost::get(p.second); } else if (p.first == "port") { parameters.port = boost::get(p.second); } else if (p.first == "ipv4hint") { for (auto const& entry : boost::get>>(p.second)) { parameters.ipv4hints.push_back(ComboAddress(entry.second)); } } else if (p.first == "ech") { parameters.ech = boost::get(p.second); } else if (p.first == "ipv6hint") { for (auto const& entry : boost::get>>(p.second)) { parameters.ipv6hints.push_back(ComboAddress(entry.second)); } } else { parameters.additionalParams.push_back({SvcParam::keyFromString(p.first), boost::get(p.second)}); } } return parameters; }