From a0383aada8689ef0a87b15d69352abe456252ca7 Mon Sep 17 00:00:00 2001 From: Fred Morcos Date: Mon, 7 Mar 2022 09:07:23 +0100 Subject: [PATCH] Move most of pdns_stou to Pdns::stoi and Pdns::stou This also creates the Pdns namespace and renames pdns_stou to Pdns::stou and separates signed from unsigned conversion (Pdns::stoi and Pdns::stou) which are now implemented in terms of Pdns::checked_conv and return a generic integer. --- modules/bindbackend/binddnssec.cc | 4 +- modules/geoipbackend/geoipbackend.cc | 16 ++--- modules/ldapbackend/ldapbackend.cc | 2 +- modules/ldapbackend/native.cc | 4 +- modules/pipebackend/pipebackend.cc | 4 +- pdns/backends/gsql/gsqlbackend.cc | 40 +++++------ pdns/credentials.cc | 6 +- pdns/decafsigners.cc | 4 +- pdns/dnsbackend.cc | 10 +-- pdns/dnsdist.cc | 4 +- pdns/dnsdistdist/dnsdist-nghttp2.cc | 2 +- pdns/dnsparser.cc | 2 +- pdns/dnsparser.hh | 2 +- pdns/dnssecinfra.cc | 4 +- pdns/dynloader.cc | 2 +- pdns/iputils.cc | 4 +- pdns/iputils.hh | 2 +- pdns/misc.cc | 30 ++------ pdns/misc.hh | 100 ++++++++++++++++++++++++++- pdns/opensslsigners.cc | 2 +- pdns/packethandler.cc | 2 +- pdns/pdnsutil.cc | 34 ++++----- pdns/pkcs11signers.cc | 4 +- pdns/rcpgenerator.cc | 4 +- pdns/rec_channel_rec.cc | 10 +-- pdns/rec_control.cc | 2 +- pdns/recursordist/rec-main.cc | 2 +- pdns/resolver.cc | 2 +- pdns/sodiumsigners.cc | 2 +- pdns/svc-records.cc | 2 +- pdns/tcpreceiver.cc | 4 +- pdns/test-ueberbackend_cc.cc | 3 +- pdns/test-zoneparser_tng_cc.cc | 2 +- pdns/ws-auth.cc | 2 +- pdns/zone2json.cc | 6 +- pdns/zone2ldap.cc | 2 +- pdns/zone2sql.cc | 4 +- pdns/zoneparser-tng.cc | 2 +- 38 files changed, 205 insertions(+), 128 deletions(-) diff --git a/modules/bindbackend/binddnssec.cc b/modules/bindbackend/binddnssec.cc index 9e8cbefa50d4..8e56319538ef 100644 --- a/modules/bindbackend/binddnssec.cc +++ b/modules/bindbackend/binddnssec.cc @@ -323,8 +323,8 @@ bool Bind2Backend::getDomainKeys(const DNSName& name, std::vector& keys SSqlStatement::row_t row; while (d_getDomainKeysQuery_stmt->hasNextRow()) { d_getDomainKeysQuery_stmt->nextRow(row); - kd.id = pdns_stou(row[0]); - kd.flags = pdns_stou(row[1]); + pdns::checked_stoi_into(kd.id, row[0]); + pdns::checked_stoi_into(kd.flags, row[1]); kd.active = (row[2] == "1"); kd.published = (row[3] == "1"); kd.content = row[4]; diff --git a/modules/geoipbackend/geoipbackend.cc b/modules/geoipbackend/geoipbackend.cc index 68abb293a05d..078e7a893d95 100644 --- a/modules/geoipbackend/geoipbackend.cc +++ b/modules/geoipbackend/geoipbackend.cc @@ -923,10 +923,10 @@ bool GeoIPBackend::getDomainKeys(const DNSName& name, std::vector(glob_result.gl_pathv[i] + regm[3].rm_so); if (kid == id) { if (unlink(glob_result.gl_pathv[i])) { cerr << "Cannot delete key:" << strerror(errno) << endl; @@ -1004,7 +1004,7 @@ bool GeoIPBackend::addDomainKey(const DNSName& name, const KeyData& key, int64_t if (glob(pathname.str().c_str(), GLOB_ERR, NULL, &glob_result) == 0) { for (size_t i = 0; i < glob_result.gl_pathc; i++) { if (regexec(®, glob_result.gl_pathv[i], 5, regm, 0) == 0) { - unsigned int kid = pdns_stou(glob_result.gl_pathv[i] + regm[3].rm_so); + auto kid = pdns::checked_stoi(glob_result.gl_pathv[i] + regm[3].rm_so); if (kid >= nextid) nextid = kid + 1; } @@ -1040,10 +1040,10 @@ bool GeoIPBackend::activateDomainKey(const DNSName& name, unsigned int id) if (glob(pathname.str().c_str(), GLOB_ERR, NULL, &glob_result) == 0) { for (size_t i = 0; i < glob_result.gl_pathc; i++) { if (regexec(®, glob_result.gl_pathv[i], 5, regm, 0) == 0) { - unsigned int kid = pdns_stou(glob_result.gl_pathv[i] + regm[3].rm_so); + auto kid = pdns::checked_stoi(glob_result.gl_pathv[i] + regm[3].rm_so); if (kid == id && !strcmp(glob_result.gl_pathv[i] + regm[4].rm_so, "0")) { ostringstream newpath; - newpath << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "." << pdns_stou(glob_result.gl_pathv[i] + regm[2].rm_so) << "." << kid << ".1.key"; + newpath << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "." << pdns::checked_stoi(glob_result.gl_pathv[i] + regm[2].rm_so) << "." << kid << ".1.key"; if (rename(glob_result.gl_pathv[i], newpath.str().c_str())) { cerr << "Cannot activate key: " << strerror(errno) << endl; } @@ -1075,10 +1075,10 @@ bool GeoIPBackend::deactivateDomainKey(const DNSName& name, unsigned int id) if (glob(pathname.str().c_str(), GLOB_ERR, NULL, &glob_result) == 0) { for (size_t i = 0; i < glob_result.gl_pathc; i++) { if (regexec(®, glob_result.gl_pathv[i], 5, regm, 0) == 0) { - unsigned int kid = pdns_stou(glob_result.gl_pathv[i] + regm[3].rm_so); + auto kid = pdns::checked_stoi(glob_result.gl_pathv[i] + regm[3].rm_so); if (kid == id && !strcmp(glob_result.gl_pathv[i] + regm[4].rm_so, "1")) { ostringstream newpath; - newpath << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "." << pdns_stou(glob_result.gl_pathv[i] + regm[2].rm_so) << "." << kid << ".0.key"; + newpath << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "." << pdns::checked_stoi(glob_result.gl_pathv[i] + regm[2].rm_so) << "." << kid << ".0.key"; if (rename(glob_result.gl_pathv[i], newpath.str().c_str())) { cerr << "Cannot deactivate key: " << strerror(errno) << endl; } diff --git a/modules/ldapbackend/ldapbackend.cc b/modules/ldapbackend/ldapbackend.cc index 175c719ff5b2..35e5e6f2fa16 100644 --- a/modules/ldapbackend/ldapbackend.cc +++ b/modules/ldapbackend/ldapbackend.cc @@ -207,7 +207,7 @@ void LdapBackend::extract_entry_results(const DNSName& domain, const DNSResult& if (qtype2 != QType(local_result.qtype).toString()) continue; - local_result.ttl = pdns_stou(rdata.substr(pos + 1)); + pdns::checked_stoi_into(local_result.ttl, rdata.substr(pos + 1)); } } diff --git a/modules/ldapbackend/native.cc b/modules/ldapbackend/native.cc index 0b24a28411a9..51b2e044b6b1 100644 --- a/modules/ldapbackend/native.cc +++ b/modules/ldapbackend/native.cc @@ -372,12 +372,12 @@ bool LdapBackend::getDomainInfo(const DNSName& domain, DomainInfo& di, bool getS di.zone = DNSName(domain); if (result.count("PdnsDomainLastCheck") && !result["PdnsDomainLastCheck"].empty()) - di.last_check = pdns_stou(result["PdnsDomainLastCheck"][0]); + pdns::checked_stoi_into(di.last_check, result["PdnsDomainLastCheck"][0]); else di.last_check = 0; if (result.count("PdnsDomainNotifiedSerial") && !result["PdnsDomainNotifiedSerial"].empty()) - di.notified_serial = pdns_stou(result["PdnsDomainNotifiedSerial"][0]); + pdns::checked_stoi_into(di.notified_serial, result["PdnsDomainNotifiedSerial"][0]); else di.notified_serial = 0; diff --git a/modules/pipebackend/pipebackend.cc b/modules/pipebackend/pipebackend.cc index 5773adcf0bcc..0f3dcbf5a97e 100644 --- a/modules/pipebackend/pipebackend.cc +++ b/modules/pipebackend/pipebackend.cc @@ -315,8 +315,8 @@ bool PipeBackend::get(DNSResourceRecord& r) } r.qname = DNSName(parts[1 + extraFields]); r.qtype = parts[3 + extraFields]; - r.ttl = pdns_stou(parts[4 + extraFields]); - r.domain_id = std::stoi(parts[5 + extraFields]); + pdns::checked_stoi_into(r.ttl, parts[4 + extraFields]); + pdns::checked_stoi_into(r.domain_id, parts[5 + extraFields]); if (r.qtype.getCode() != QType::MX && r.qtype.getCode() != QType::SRV) { r.content.clear(); diff --git a/pdns/backends/gsql/gsqlbackend.cc b/pdns/backends/gsql/gsqlbackend.cc index bc094a8055ea..dc9a31947848 100644 --- a/pdns/backends/gsql/gsqlbackend.cc +++ b/pdns/backends/gsql/gsqlbackend.cc @@ -70,7 +70,7 @@ GSQLBackend::GSQLBackend(const string &mode, const string &suffix) d_InfoOfAllSlaveDomainsQuery=getArg("info-all-slaves-query"); d_SuperMasterInfoQuery=getArg("supermaster-query"); d_GetSuperMasterIPs=getArg("supermaster-name-to-ips"); - d_AddSuperMaster=getArg("supermaster-add"); + d_AddSuperMaster=getArg("supermaster-add"); d_RemoveAutoPrimaryQuery=getArg("autoprimary-remove"); d_ListAutoPrimariesQuery=getArg("list-autoprimaries"); d_InsertZoneQuery=getArg("insert-zone-query"); @@ -110,7 +110,7 @@ GSQLBackend::GSQLBackend(const string &mode, const string &suffix) d_GetLastInsertedKeyIdQuery = getArg("get-last-inserted-key-id-query"); d_ListDomainKeysQuery = getArg("list-domain-keys-query"); - d_GetAllDomainMetadataQuery = getArg("get-all-domain-metadata-query"); + d_GetAllDomainMetadataQuery = getArg("get-all-domain-metadata-query"); d_GetDomainMetadataQuery = getArg("get-domain-metadata-query"); d_ClearDomainMetadataQuery = getArg("clear-domain-metadata-query"); d_ClearDomainAllMetadataQuery = getArg("clear-domain-all-metadata-query"); @@ -315,7 +315,7 @@ bool GSQLBackend::getDomainInfo(const DNSName &domain, DomainInfo &di, bool getS ASSERT_ROW_COLUMNS("info-zone-query", d_result[0], 7); - di.id=pdns_stou(d_result[0][0]); + pdns::checked_stoi_into(di.id, d_result[0][0]); try { di.zone=DNSName(d_result[0][1]); } catch (...) { @@ -329,8 +329,8 @@ bool GSQLBackend::getDomainInfo(const DNSName &domain, DomainInfo &di, bool getS stringtok(masters, d_result[0][2], " ,\t"); for(const auto& m : masters) di.masters.emplace_back(m, 53); - di.last_check=pdns_stou(d_result[0][3]); - di.notified_serial = pdns_stou(d_result[0][4]); + pdns::checked_stoi_into(di.last_check, d_result[0][3]); + pdns::checked_stoi_into(di.notified_serial, d_result[0][4]); di.backend=this; di.serial = 0; @@ -389,7 +389,7 @@ void GSQLBackend::getUnfreshSlaveInfos(vector *unfreshDomains) } try { - sd.id=pdns_stou(row[0]); + pdns::checked_stoi_into(sd.id, row[0]); } catch (const std::exception &e) { g_log< *unfreshDomains) } try { - sd.last_check=pdns_stou(row[3]); + pdns::checked_stoi_into(sd.last_check, row[3]); } catch (const std::exception &e) { g_log< *updatedDomains) stringtok( parts, d_result[n][3] ); try { - uint32_t serial = parts.size() > 2 ? pdns_stou(parts[2]) : 0; - uint32_t notified_serial = pdns_stou( d_result[n][2] ); + uint32_t serial = parts.size() > 2 ? pdns::checked_stoi(parts[2]) : 0; + auto notified_serial = pdns::checked_stoi(d_result[n][2]); if( serial != notified_serial ) { - di.id = pdns_stou( d_result[n][0] ); + pdns::checked_stoi_into(di.id, d_result[n][0]); di.zone = DNSName( d_result[n][1] ); di.serial = serial; di.notified_serial = notified_serial; @@ -999,8 +999,8 @@ bool GSQLBackend::getDomainKeys(const DNSName& name, std::vector& keys) //~ for(const auto& val: row) { //~ cerr<<"'"<* domains, bool getSerial, boo d_getAllDomainsQuery_stmt->nextRow(row); ASSERT_ROW_COLUMNS("get-all-domains-query", row, 8); DomainInfo di; - di.id = pdns_stou(row[0]); + pdns::checked_stoi_into(di.id, row[0]); try { di.zone = DNSName(row[1]); } catch (...) { @@ -1495,8 +1495,8 @@ void GSQLBackend::getAllDomains(vector* domains, bool getSerial, boo } try { - di.notified_serial = pdns_stou(row[5]); - di.last_check = pdns_stou(row[6]); + pdns::checked_stoi_into(di.notified_serial, row[5]); + pdns::checked_stoi_into(di.last_check, row[6]); } catch(...) { continue; } @@ -1579,7 +1579,7 @@ bool GSQLBackend::feedRecord(const DNSResourceRecord &r, const DNSName &ordernam if (r.qtype == QType::MX || r.qtype == QType::SRV) { string::size_type pos = content.find_first_not_of("0123456789"); if (pos != string::npos) { - prio=pdns_stou(content.substr(0,pos)); + pdns::checked_stoi_into(prio, content.substr(0,pos)); boost::erase_head(content, pos); } boost::trim_left(content); @@ -1929,7 +1929,7 @@ void GSQLBackend::extractRecord(SSqlStatement::row_t& row, DNSResourceRecord& r) if (row[1].empty()) r.ttl = defaultTTL; else - r.ttl=pdns_stou(row[1]); + pdns::checked_stoi_into(r.ttl, row[1]); if(!d_qname.empty()) r.qname=d_qname; @@ -1958,7 +1958,7 @@ void GSQLBackend::extractRecord(SSqlStatement::row_t& row, DNSResourceRecord& r) r.disabled = !row[5].empty() && row[5][0]=='1'; - r.domain_id=pdns_stou(row[4]); + pdns::checked_stoi_into(r.domain_id, row[4]); if (row.size() > 8) { // if column 8 exists, it holds an ordername if (!row.at(8).empty()) { @@ -1975,10 +1975,10 @@ void GSQLBackend::extractRecord(SSqlStatement::row_t& row, DNSResourceRecord& r) void GSQLBackend::extractComment(SSqlStatement::row_t& row, Comment& comment) { - comment.domain_id = pdns_stou(row[0]); + pdns::checked_stoi_into(comment.domain_id, row[0]); comment.qname = DNSName(row[1]); comment.qtype = row[2]; - comment.modified_at = pdns_stou(row[3]); + pdns::checked_stoi_into(comment.modified_at, row[3]); comment.account = std::move(row[4]); comment.content = std::move(row[5]); } diff --git a/pdns/credentials.cc b/pdns/credentials.cc index d058a948ac1c..3a7534f75705 100644 --- a/pdns/credentials.cc +++ b/pdns/credentials.cc @@ -246,14 +246,14 @@ static void parseHashed(const std::string& hash, std::string& salt, std::string& } try { - workFactor = pdns_stou(parameters.at(0).substr(3)); + workFactor = pdns::checked_stoi(parameters.at(0).substr(3)); workFactor = static_cast(1) << workFactor; if (workFactor > pwhash_max_work_factor) { throw std::runtime_error("Invalid work factor of " + std::to_string(workFactor) + " in hashed password string, maximum is " + std::to_string(pwhash_max_work_factor)); } - parallelFactor = pdns_stou(parameters.at(1).substr(2)); - blockSize = pdns_stou(parameters.at(2).substr(2)); + parallelFactor = pdns::checked_stoi(parameters.at(1).substr(2)); + blockSize = pdns::checked_stoi(parameters.at(2).substr(2)); auto b64Salt = hash.substr(saltPos, saltEnd - saltPos); salt.reserve(pwhash_salt_size); diff --git a/pdns/decafsigners.cc b/pdns/decafsigners.cc index 3b348e3c8409..93585815a9d9 100644 --- a/pdns/decafsigners.cc +++ b/pdns/decafsigners.cc @@ -81,7 +81,7 @@ void DecafED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::m PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI= */ - drc.d_algorithm = pdns_stou(stormap["algorithm"]); + pdns::checked_stoi_into(drc.d_algorithm, stormap["algorithm"]); string privateKey = stormap["privatekey"]; if (privateKey.length() != DECAF_EDDSA_25519_PRIVATE_BYTES) @@ -217,7 +217,7 @@ void DecafED448DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA */ - drc.d_algorithm = pdns_stou(stormap["algorithm"]); + pdns::checked_stoi_into(drc.d_algorithm, stormap["algorithm"]); string privateKey = stormap["privatekey"]; if (privateKey.length() != DECAF_EDDSA_448_PRIVATE_BYTES) diff --git a/pdns/dnsbackend.cc b/pdns/dnsbackend.cc index 991ab6f3d119..f0ae76a896c0 100644 --- a/pdns/dnsbackend.cc +++ b/pdns/dnsbackend.cc @@ -347,11 +347,11 @@ void fillSOAData(const string &content, SOAData &data) try { data.nameserver = DNSName(parts.at(0)); data.hostmaster = DNSName(parts.at(1)); - data.serial = pdns_stou(parts.at(2).c_str()); - data.refresh = pdns_stou(parts.at(3).c_str()); - data.retry = pdns_stou(parts.at(4).c_str()); - data.expire = pdns_stou(parts.at(5).c_str()); - data.minimum = pdns_stou(parts.at(6).c_str()); + pdns::checked_stoi_into(data.serial, parts.at(2)); + pdns::checked_stoi_into(data.refresh, parts.at(3)); + pdns::checked_stoi_into(data.retry, parts.at(4)); + pdns::checked_stoi_into(data.expire, parts.at(5)); + pdns::checked_stoi_into(data.minimum, parts.at(6)); } catch(const std::out_of_range& oor) { throw PDNSException("Out of range exception parsing '" + content + "'"); diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 24a5c5bd2bb6..b3b018595913 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -434,7 +434,7 @@ static bool applyRulesToResponse(LocalStateHolder(pdns_stou(ruleresult)); // sorry + pdns::checked_stoi_into(dr.delayMsec, ruleresult); // sorry break; case DNSResponseAction::Action::None: break; @@ -833,7 +833,7 @@ bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::s break; /* non-terminal actions follow */ case DNSAction::Action::Delay: - dq.delayMsec = static_cast(pdns_stou(ruleresult)); // sorry + pdns::checked_stoi_into(dq.delayMsec, ruleresult); // sorry break; case DNSAction::Action::None: /* fall-through */ diff --git a/pdns/dnsdistdist/dnsdist-nghttp2.cc b/pdns/dnsdistdist/dnsdist-nghttp2.cc index 42ad2bc656fe..573319a46ca0 100644 --- a/pdns/dnsdistdist/dnsdist-nghttp2.cc +++ b/pdns/dnsdistdist/dnsdist-nghttp2.cc @@ -753,7 +753,7 @@ int DoHConnectionToBackend::on_header_callback(nghttp2_session* session, const n return NGHTTP2_ERR_CALLBACK_FAILURE; } try { - stream->second.d_responseCode = pdns_stou(std::string(reinterpret_cast(value), valuelen)); + pdns::checked_stoi_into(stream->second.d_responseCode, std::string(reinterpret_cast(value), valuelen)); } catch (...) { vinfolog("Error parsing the status header for stream ID %d", frame->hd.stream_id); diff --git a/pdns/dnsparser.cc b/pdns/dnsparser.cc index 145e4943ebba..2e2146120837 100644 --- a/pdns/dnsparser.cc +++ b/pdns/dnsparser.cc @@ -41,7 +41,7 @@ UnknownRecordContent::UnknownRecordContent(const string& zone) } const string& relevant = (parts.size() > 2) ? parts.at(2) : ""; - unsigned int total = pdns_stou(parts.at(1)); + auto total = pdns::checked_stoi(parts.at(1)); if (relevant.size() % 2 || (relevant.size() / 2) != total) { throw MOADNSException((boost::format("invalid unknown record length: size not equal to length field (%d != 2 * %d)") % relevant.size() % total).str()); } diff --git a/pdns/dnsparser.hh b/pdns/dnsparser.hh index b8b612dc627e..980e327e441e 100644 --- a/pdns/dnsparser.hh +++ b/pdns/dnsparser.hh @@ -259,7 +259,7 @@ public: return iter->second.second; if (isUnknownType(name)) { - return (uint16_t)pdns_stou(name.substr(4)); + return pdns::checked_stoi(name.substr(4)); } throw runtime_error("Unknown DNS type '"+name+"'"); diff --git a/pdns/dnssecinfra.cc b/pdns/dnssecinfra.cc index 8599058dda23..198bb791aab0 100644 --- a/pdns/dnssecinfra.cc +++ b/pdns/dnssecinfra.cc @@ -123,7 +123,7 @@ std::unique_ptr DNSCryptoKeyEngine::makeFromISCString(DNSKEY } else if (it->second == KeyTypes::numeric) { try { - unsigned int num = pdns_stou(value); + auto num = pdns::checked_stoi(value); stormap[key] = std::to_string(num); if (key == "algorithm") { algorithm = num; @@ -306,7 +306,7 @@ void DNSCryptoKeyEngine::testMakers(unsigned int algo, maker_t* creator, maker_t std::tie(key,value)=splitField(sline, ':'); boost::trim(value); if(pdns_iequals(key,"algorithm")) { - algorithm = pdns_stou(value); + pdns::checked_stoi_into(algorithm, value); stormap["algorithm"]=std::to_string(algorithm); continue; } else if (pdns_iequals(key,"pin")) { diff --git a/pdns/dynloader.cc b/pdns/dynloader.cc index 877d445354ba..e04f84b0eefd 100644 --- a/pdns/dynloader.cc +++ b/pdns/dynloader.cc @@ -114,7 +114,7 @@ int main(int argc, char **argv) else { uint16_t port; try { - port = static_cast(pdns_stou(::arg()["remote-port"])); + pdns::checked_stoi_into(port, ::arg()["remote-port"]); } catch(...) { cerr<<"Unable to convert '"<<::arg()["remote-port"]<<"' to a port number for connecting to remote PowerDNS\n"; diff --git a/pdns/iputils.cc b/pdns/iputils.cc index 449a6804247d..42522bdebaa7 100644 --- a/pdns/iputils.cc +++ b/pdns/iputils.cc @@ -506,7 +506,7 @@ ComboAddress parseIPAndPort(const std::string& input, uint16_t port) { if (input[0] == '[') { // case 1 auto both = splitField(input.substr(1), ']'); - return ComboAddress(both.first, both.second.empty() ? port : static_cast(pdns_stou(both.second.substr(1)))); + return ComboAddress(both.first, both.second.empty() ? port : pdns::checked_stoi(both.second.substr(1))); } string::size_type count = 0; @@ -527,7 +527,7 @@ ComboAddress parseIPAndPort(const std::string& input, uint16_t port) both.first = input.substr(0, cpos); both.second = input.substr(cpos + 1); - uint16_t newport = static_cast(pdns_stou(both.second)); + auto newport = pdns::checked_stoi(both.second); return ComboAddress(both.first, newport); } default: // case 4 diff --git a/pdns/iputils.hh b/pdns/iputils.hh index ab948b0298a6..225532cb7c8e 100644 --- a/pdns/iputils.hh +++ b/pdns/iputils.hh @@ -498,7 +498,7 @@ public: d_network = makeComboAddress(split.first); if (!split.second.empty()) { - setBits(static_cast(pdns_stou(split.second))); + setBits(pdns::checked_stoi(split.second)); } else if (d_network.sin4.sin_family == AF_INET) { setBits(32); diff --git a/pdns/misc.cc b/pdns/misc.cc index bb62fb40df94..38a30eaae20c 100644 --- a/pdns/misc.cc +++ b/pdns/misc.cc @@ -290,7 +290,7 @@ static void parseService4(const string& descr, ServiceTuple& st) } st.host = parts[0]; if (parts.size() > 1) { - st.port = pdns_stou(parts[1]); + pdns::checked_stoi_into(st.port, parts[1]); } } @@ -303,7 +303,7 @@ static void parseService6(const string& descr, ServiceTuple& st) st.host = descr.substr(1, pos - 1); if (pos + 2 < descr.length()) { - st.port = pdns_stou(descr.substr(pos + 2)); + pdns::checked_stoi_into(st.port, descr.substr(pos + 2)); } } @@ -693,7 +693,7 @@ int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret) if (pos + 2 > addr.size() || addr[pos+1]!=':') return -1; try { - port = pdns_stou(addr.substr(pos+2)); + pdns::checked_stoi_into(port, addr.substr(pos + 2)); portSet = true; } catch(const std::out_of_range&) { @@ -1357,7 +1357,7 @@ uint64_t getOpenFileDescriptors(const std::string&) while((entry = readdir(dirhdl))) { uint32_t num; try { - num = pdns_stou(entry->d_name); + pdns::checked_stoi_into(num, entry->d_name); } catch (...) { continue; // was not a number. } @@ -1513,28 +1513,6 @@ gid_t strToGID(const string &str) return result; } -unsigned int pdns_stou(const std::string& str, size_t* idx, int base) -{ - if (str.empty()) { - return 0; // compatibility - } - - unsigned long result; - try { - result = std::stoul(str, idx, base); - } - catch (std::invalid_argument& e) { - throw std::invalid_argument(string(e.what()) + "; (invalid argument during std::stoul); data was \"" + str + "\""); - } - catch (std::out_of_range& e) { - throw std::out_of_range(string(e.what()) + "; (out of range during std::stoul); data was \"" + str + "\""); - } - if (result > std::numeric_limits::max()) { - throw std::out_of_range("stoul returned result out of unsigned int range; data was \"" + str + "\""); - } - return static_cast(result); -} - bool isSettingThreadCPUAffinitySupported() { #ifdef HAVE_PTHREAD_SETAFFINITY_NP diff --git a/pdns/misc.hh b/pdns/misc.hh index 595f119b4321..05aa87d4e72b 100644 --- a/pdns/misc.hh +++ b/pdns/misc.hh @@ -617,7 +617,105 @@ double DiffTime(const struct timeval& first, const struct timeval& second); uid_t strToUID(const string &str); gid_t strToGID(const string &str); -unsigned int pdns_stou(const std::string& str, size_t* idx = 0, int base = 10); +namespace pdns +{ +/** + * \brief Does a checked conversion from one integer type to another. + * + * \warning The source type `F` and target type `T` must have the same + * signedness, otherwise a compilation error is thrown. + * + * \exception std::out_of_range Thrown if the source value does not fit + * in the target type. + * + * \param[in] from The source value of type `F`. + * + * \return The target value of type `T`. + */ +template +auto checked_conv(F from) -> T +{ + static_assert(std::numeric_limits::is_integer, "checked_conv: The `F` type must be an integer"); + static_assert(std::numeric_limits::is_integer, "checked_conv: The `T` type must be an integer"); + static_assert((std::numeric_limits::is_signed && std::numeric_limits::is_signed) || (!std::numeric_limits::is_signed && !std::numeric_limits::is_signed), + "checked_conv: The `T` and `F` types must either both be signed or unsigned"); + + if (from < std::numeric_limits::min() || from > std::numeric_limits::max()) { + throw std::out_of_range("checked_conv: conversion from value that is out of range for target type"); + } + + return static_cast(from); +} + +/** + * \brief Performs a conversion from `std::string&` to integer. + * + * This function internally calls `std::stoll` and `std::stoull` to do + * the conversion from `std::string&` and calls `pdns::checked_conv` to + * do the checked conversion from `long long`/`unsigned long long` to + * `T`. + * + * \warning The target type `T` must be an integer, otherwise a + * compilation error is thrown. + * + * \exception std:stoll Throws what std::stoll throws. + * + * \exception std::stoull Throws what std::stoull throws. + * + * \exception pdns::checked_conv Throws what pdns::checked_conv throws. + * + * \param[in] str The input string to be converted. + * + * \param[in] idx Location to store the index at which processing + * stopped. + * + * \param[in] base The numerical base for conversion. + * + * \return `str` converted to integer `T`, or 0 if `str` is empty. + */ +template +auto checked_stoi(const std::string& str, size_t* idx = nullptr, int base = 10) -> T +{ + static_assert(std::numeric_limits::is_integer, "checked_stoi: The `T` type must be an integer"); + + if (str.empty()) { + return 0; // compatibility + } + + if constexpr (std::is_unsigned_v) { + return pdns::checked_conv(std::stoull(str, idx, base)); + } + else { + return pdns::checked_conv(std::stoll(str, idx, base)); + } +} + +/** + * \brief Performs a conversion from `std::string&` to integer. + * + * This function internally calls `pdns::checked_stoi` and stores its + * result in `out`. + * + * \exception pdns::checked_stoi Throws what pdns::checked_stoi throws. + * + * \param[out] out `str` converted to integer `T`, or 0 if `str` is + * empty. + * + * \param[in] str The input string to be converted. + * + * \param[in] idx Location to store the index at which processing + * stopped. + * + * \param[in] base The numerical base for conversion. + * + * \return `str` converted to integer `T`, or 0 if `str` is empty. + */ +template +auto checked_stoi_into(T& out, const std::string& str, size_t* idx = nullptr, int base = 10) +{ + out = checked_stoi(str, idx, base); +} +} bool isSettingThreadCPUAffinitySupported(); int mapThreadToCPUList(pthread_t tid, const std::set& cpus); diff --git a/pdns/opensslsigners.cc b/pdns/opensslsigners.cc index 7138f9705285..2b7a863d3c14 100644 --- a/pdns/opensslsigners.cc +++ b/pdns/opensslsigners.cc @@ -459,7 +459,7 @@ void OpenSSLRSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map auto dmq1 = parse(stormap, "exponent2"); auto iqmp = parse(stormap, "coefficient"); - drc.d_algorithm = pdns_stou(stormap["algorithm"]); + pdns::checked_stoi_into(drc.d_algorithm, stormap["algorithm"]); if (drc.d_algorithm != d_algorithm) { throw runtime_error(getName() + " tried to feed an algorithm " + std::to_string(drc.d_algorithm) + " to a " + std::to_string(d_algorithm) + " key"); diff --git a/pdns/packethandler.cc b/pdns/packethandler.cc index 59e205c27c79..efb5f0793686 100644 --- a/pdns/packethandler.cc +++ b/pdns/packethandler.cc @@ -229,7 +229,7 @@ bool PacketHandler::addCDS(DNSPacket& p, std::unique_ptr& r) continue; } for(auto const &digestAlgo : digestAlgos){ - rr.dr.d_content=std::make_shared(makeDSFromDNSKey(p.qdomain, value.first.getDNSKEY(), pdns_stou(digestAlgo))); + rr.dr.d_content=std::make_shared(makeDSFromDNSKey(p.qdomain, value.first.getDNSKEY(), pdns::checked_stoi(digestAlgo))); r->addRecord(DNSZoneRecord(rr)); haveOne=true; } diff --git a/pdns/pdnsutil.cc b/pdns/pdnsutil.cc index a64abd0e5c64..0c343c7652b1 100644 --- a/pdns/pdnsutil.cc +++ b/pdns/pdnsutil.cc @@ -2490,7 +2490,7 @@ try cerr << "Syntax: pdnsutil test-algorithm algonum"<(cmds.at(1)))) return 0; return 1; } @@ -2587,7 +2587,7 @@ try uint64_t workFactor = CredentialsHolder::s_defaultWorkFactor; if (cmds.size() > 1) { try { - workFactor = pdns_stou(cmds.at(1)); + pdns::checked_stoi_into(workFactor, cmds.at(1)); } catch (const std::exception& e) { cerr<<"Unable to parse the supplied work factor: "< 3) ? cmds.at(3) : "", pdns_stou(cmds.at(2))); + testSpeed(dk, DNSName(cmds.at(1)), (cmds.size() > 3) ? cmds.at(3) : "", pdns::checked_stoi(cmds.at(2))); } else if (cmds.at(0) == "verify-crypto") { if(cmds.size() != 2) { @@ -2734,7 +2734,7 @@ try return 0; } DNSName zone(cmds.at(1)); - unsigned int id = atoi(cmds.at(2).c_str()); // if you make this pdns_stou, the error gets worse + unsigned int id = atoi(cmds.at(2).c_str()); // if you make this pdns::checked_stoi, the error gets worse if(!id) { cerr << "Invalid KEY-ID '" << cmds.at(2) << "'" << endl; @@ -2758,7 +2758,7 @@ try return 0; } DNSName zone(cmds.at(1)); - unsigned int id = pdns_stou(cmds.at(2)); + auto id = pdns::checked_stoi(cmds.at(2)); if(!id) { cerr<<"Invalid KEY-ID"<(cmds.at(n)) != 0) { + pdns::checked_stoi_into(bits, cmds.at(n)); } else { cerr << "Unknown algorithm, key flag or size '" << cmds.at(n) << "'" << endl; @@ -2907,7 +2907,7 @@ try return 0; } DNSName zone(cmds.at(1)); - unsigned int id = pdns_stou(cmds.at(2)); + auto id = pdns::checked_stoi(cmds.at(2)); if (!dk.removeKey(zone, id)) { cerr<<"Cannot remove key " << id << " from " << zone <(cmds.at(2)); DNSSECPrivateKey dpk=dk.getKeyById(DNSName(zone), id); cout << dpk.getKey()->convertToISC() <(cmds.at(2)); DNSSECPrivateKey dpk=dk.getKeyById(zone, id); cout << zone<<" IN DNSKEY "< 0) { algorithm = tmp_algo; } - else if (pdns_stou(cmds.at(n))) - bits = pdns_stou(cmds.at(n)); + else if (pdns::checked_stoi(cmds.at(n)) != 0) + pdns::checked_stoi_into(bits, cmds.at(n)); else { cerr << "Unknown algorithm, key flag or size '" << cmds.at(n) << "'" << endl; return 0; @@ -3779,7 +3779,7 @@ try return 1; } - id = pdns_stou(cmds.at(3)); + pdns::checked_stoi_into(id, cmds.at(3)); std::vector keys; if (!B.getDomainKeys(zone, keys)) { cerr << "No keys found for zone " << zone << std::endl; @@ -3801,7 +3801,7 @@ try return 1; } if (cmds.size() > 4) { - bits = pdns_stou(cmds.at(4)); + pdns::checked_stoi_into(bits, cmds.at(4)); } if (bits < 1) { cerr << "Invalid bit size " << bits << "given, must be positive integer"; diff --git a/pdns/pkcs11signers.cc b/pdns/pkcs11signers.cc index 3024fc435a72..2ea2f6894420 100644 --- a/pdns/pkcs11signers.cc +++ b/pdns/pkcs11signers.cc @@ -327,7 +327,7 @@ class Pkcs11Token { } public: - Pkcs11Token(const std::shared_ptr>& slot, const std::string& label, const std::string& pub_label); + Pkcs11Token(const std::shared_ptr>& slot, const std::string& label, const std::string& pub_label); ~Pkcs11Token(); bool Login(const std::string& pin) { @@ -984,7 +984,7 @@ DNSCryptoKeyEngine::storvector_t PKCS11DNSCryptoKeyEngine::convertToISCVector() }; void PKCS11DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, stormap_t& stormap) { - drc.d_algorithm = pdns_stou(stormap["algorithm"]); + pdns::checked_stoi_into(drc.d_algorithm, stormap["algorithm"]); d_module = stormap["engine"]; d_slot_id = stormap["slot"]; boost::trim(d_slot_id); diff --git a/pdns/rcpgenerator.cc b/pdns/rcpgenerator.cc index 6340b55b7a34..9204773d379a 100644 --- a/pdns/rcpgenerator.cc +++ b/pdns/rcpgenerator.cc @@ -93,8 +93,8 @@ void RecordTextReader::xfr32BitInt(uint32_t &val) throw RecordTextException("expected digits at position "+std::to_string(d_pos)+" in '"+d_string+"'"); size_t pos; - val=pdns_stou(d_string.c_str()+d_pos, &pos); - + val = pdns::checked_stoi(d_string.c_str() + d_pos, &pos); + d_pos += pos; } diff --git a/pdns/rec_channel_rec.cc b/pdns/rec_channel_rec.cc index b5d41b77dd51..8ed79f3b10a8 100644 --- a/pdns/rec_channel_rec.cc +++ b/pdns/rec_channel_rec.cc @@ -809,7 +809,7 @@ static string setMinimumTTL(T begin, T end) if (end - begin != 1) return "Need to supply new minimum TTL number\n"; try { - SyncRes::s_minimumTTL = pdns_stou(*begin); + pdns::checked_stoi_into(SyncRes::s_minimumTTL, *begin); return "New minimum TTL: " + std::to_string(SyncRes::s_minimumTTL) + "\n"; } catch (const std::exception& e) { @@ -823,7 +823,7 @@ static string setMinimumECSTTL(T begin, T end) if (end - begin != 1) return "Need to supply new ECS minimum TTL number\n"; try { - SyncRes::s_minimumECSTTL = pdns_stou(*begin); + pdns::checked_stoi_into(SyncRes::s_minimumECSTTL, *begin); return "New minimum ECS TTL: " + std::to_string(SyncRes::s_minimumECSTTL) + "\n"; } catch (const std::exception& e) { @@ -837,7 +837,7 @@ static string setMaxCacheEntries(T begin, T end) if (end - begin != 1) return "Need to supply new cache size\n"; try { - g_maxCacheEntries = pdns_stou(*begin); + g_maxCacheEntries = pdns::checked_stoi(*begin); return "New max cache entries: " + std::to_string(g_maxCacheEntries) + "\n"; } catch (const std::exception& e) { @@ -851,7 +851,7 @@ static string setMaxPacketCacheEntries(T begin, T end) if (end - begin != 1) return "Need to supply new packet cache size\n"; try { - g_maxPacketCacheEntries = pdns_stou(*begin); + g_maxPacketCacheEntries = pdns::checked_stoi(*begin); return "New max packetcache entries: " + std::to_string(g_maxPacketCacheEntries) + "\n"; } catch (const std::exception& e) { @@ -1865,7 +1865,7 @@ static string setEventTracing(T begin, T end) return "No event trace enabled value specified\n"; } try { - SyncRes::s_event_trace_enabled = pdns_stou(*begin); + pdns::checked_stoi_into(SyncRes::s_event_trace_enabled, *begin); return "New event trace enabled value: " + std::to_string(SyncRes::s_event_trace_enabled) + "\n"; } catch (const std::exception& e) { diff --git a/pdns/rec_control.cc b/pdns/rec_control.cc index 75d99c9813c6..fdb68179026e 100644 --- a/pdns/rec_control.cc +++ b/pdns/rec_control.cc @@ -114,7 +114,7 @@ int main(int argc, char** argv) uint64_t workFactor = CredentialsHolder::s_defaultWorkFactor; if (commands.size() > 1) { try { - workFactor = pdns_stou(commands.at(1)); + pdns::checked_stoi_into(workFactor, commands.at(1)); } catch (const std::exception& e) { cerr << "Unable to parse the supplied work factor: " << e.what() << endl; diff --git a/pdns/recursordist/rec-main.cc b/pdns/recursordist/rec-main.cc index cd1116d75f03..3ade92299f86 100644 --- a/pdns/recursordist/rec-main.cc +++ b/pdns/recursordist/rec-main.cc @@ -132,7 +132,7 @@ static std::map> parseCPUMap() boost::trim(headers.first); boost::trim(headers.second); - unsigned int threadId = pdns_stou(headers.first); + auto threadId = pdns::checked_stoi(headers.first); std::vector cpus; stringtok(cpus, headers.second, ","); diff --git a/pdns/resolver.cc b/pdns/resolver.cc index 065d8226bf03..d09976108d9f 100644 --- a/pdns/resolver.cc +++ b/pdns/resolver.cc @@ -361,7 +361,7 @@ void Resolver::getSoaSerial(const ComboAddress& ipport, const DNSName &domain, u throw ResolverException("Query to '" + ipport.toLogString() + "' for SOA of '" + domain.toLogString() + "' produced an unparseable response"); try { - *serial=pdns_stou(parts[2]); + *serial = pdns::checked_stoi(parts[2]); } catch(const std::out_of_range& oor) { throw ResolverException("Query to '" + ipport.toLogString() + "' for SOA of '" + domain.toLogString() + "' produced an unparseable serial"); diff --git a/pdns/sodiumsigners.cc b/pdns/sodiumsigners.cc index ee142a6c1c01..f50c02e7881d 100644 --- a/pdns/sodiumsigners.cc +++ b/pdns/sodiumsigners.cc @@ -71,7 +71,7 @@ void SodiumED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std:: PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ= */ - drc.d_algorithm = pdns_stou(stormap["algorithm"]); + pdns::checked_stoi_into(drc.d_algorithm, stormap["algorithm"]); string privateKey = stormap["privatekey"]; if (privateKey.length() != crypto_sign_ed25519_SEEDBYTES) diff --git a/pdns/svc-records.cc b/pdns/svc-records.cc index 666064a49bc8..73b112f47024 100644 --- a/pdns/svc-records.cc +++ b/pdns/svc-records.cc @@ -47,7 +47,7 @@ SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k, bool &generi if (k.substr(0, 3) == "key") { try { generic = true; - return SvcParam::SvcParamKey(pdns_stou(k.substr(3))); + return SvcParam::SvcParamKey(pdns::checked_stoi(k.substr(3))); } catch (...) { } diff --git a/pdns/tcpreceiver.cc b/pdns/tcpreceiver.cc index 71c00d633a50..30cc46109655 100644 --- a/pdns/tcpreceiver.cc +++ b/pdns/tcpreceiver.cc @@ -707,7 +707,7 @@ int TCPNameserver::doAXFR(const DNSName &target, std::unique_ptr& q, zrrs.push_back(zrr); } else { for(auto const &digestAlgo : digestAlgos) { - zrr.dr.d_content=std::make_shared(makeDSFromDNSKey(target, value.first.getDNSKEY(), pdns_stou(digestAlgo))); + zrr.dr.d_content=std::make_shared(makeDSFromDNSKey(target, value.first.getDNSKEY(), pdns::checked_stoi(digestAlgo))); zrrs.push_back(zrr); } } @@ -1100,7 +1100,7 @@ int TCPNameserver::doIXFR(std::unique_ptr& q, int outsock) stringtok(parts, rr->d_content->getZoneRepresentation()); if (parts.size() >= 3) { try { - serial=pdns_stou(parts[2]); + pdns::checked_stoi_into(serial, parts[2]); } catch(const std::out_of_range& oor) { g_log< MetaDataStorage; // Initialize our backend ID from the suffix, skipping the '-' that DNSBackend adds there - SimpleBackend(const std::string& suffix): d_suffix(suffix), d_backendId(pdns_stou(suffix.substr(1))) + SimpleBackend(const std::string& suffix) : + d_suffix(suffix), d_backendId(pdns::checked_stoi(suffix.substr(1))) { } diff --git a/pdns/test-zoneparser_tng_cc.cc b/pdns/test-zoneparser_tng_cc.cc index 2b579d5c6966..78f273162fc8 100644 --- a/pdns/test-zoneparser_tng_cc.cc +++ b/pdns/test-zoneparser_tng_cc.cc @@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(test_tng_record_types) { unsigned int ttl; std::getline(ifs, host, ' '); std::getline(ifs, type, ' '); - ttl = pdns_stou(type); + pdns::checked_stoi_into(ttl, type); std::getline(ifs, type, ' '); std::getline(ifs, type, ' '); std::getline(ifs, data, '\n'); diff --git a/pdns/ws-auth.cc b/pdns/ws-auth.cc index e3c9274e7f4a..883cb0618de3 100644 --- a/pdns/ws-auth.cc +++ b/pdns/ws-auth.cc @@ -1124,7 +1124,7 @@ static void apiZoneCryptokeysGET(const DNSName& zonename, int inquireKeyId, Http std::set CDSalgos; for(auto const &digestAlgo : digestAlgos) { - CDSalgos.insert(pdns_stou(digestAlgo)); + CDSalgos.insert(pdns::checked_stoi(digestAlgo)); } if (value.second.keyType == DNSSECKeeper::KSK || value.second.keyType == DNSSECKeeper::CSK) { diff --git a/pdns/zone2json.cc b/pdns/zone2json.cc index b365982b188e..788f9e00124a 100644 --- a/pdns/zone2json.cc +++ b/pdns/zone2json.cc @@ -59,9 +59,9 @@ static Json::object emitRecord(const string& zoneName, const DNSName &DNSqname, string retval; g_numRecords++; string content(ocontent); - if(qtype == "MX" || qtype == "SRV") { - prio=pdns_stou(content); - + if(qtype == "MX" || qtype == "SRV") { + pdns::checked_stoi_into(prio, content); + string::size_type pos = content.find_first_not_of("0123456789"); if(pos != string::npos) boost::erase_head(content, pos); diff --git a/pdns/zone2ldap.cc b/pdns/zone2ldap.cc index 28039bf48e37..38c3b7e72808 100644 --- a/pdns/zone2ldap.cc +++ b/pdns/zone2ldap.cc @@ -294,7 +294,7 @@ int main( int argc, char* argv[] ) } if ( !args["domainid"].empty() ) - g_domainid = pdns_stou( args["domainid"] ); + pdns::checked_stoi_into(g_domainid, args["domainid"]); else g_domainid = 1; diff --git a/pdns/zone2sql.cc b/pdns/zone2sql.cc index d6c1c5e32abe..d6e61b4f89bf 100644 --- a/pdns/zone2sql.cc +++ b/pdns/zone2sql.cc @@ -162,8 +162,8 @@ static void emitRecord(const DNSName& zoneName, const DNSName &DNSqname, const s return; // NSECs do not go in the database if((qtype == "MX" || qtype == "SRV")) { - prio=pdns_stou(content); - + pdns::checked_stoi_into(prio, content); + string::size_type pos = content.find_first_not_of("0123456789"); if(pos != string::npos) boost::erase_head(content, pos); diff --git a/pdns/zoneparser-tng.cc b/pdns/zoneparser-tng.cc index 9c6cc2801ad6..d9c1594763f7 100644 --- a/pdns/zoneparser-tng.cc +++ b/pdns/zoneparser-tng.cc @@ -129,7 +129,7 @@ unsigned int ZoneParserTNG::makeTTLFromZone(const string& str) unsigned int val; try { - val=pdns_stou(str); + pdns::checked_stoi_into(val, str); } catch (const std::out_of_range& oor) { throw PDNSException("Unable to parse time specification '"+str+"' "+getLineOfFile());