From: Miod Vallat Date: Fri, 5 Sep 2025 13:00:19 +0000 (+0200) Subject: Allow multiple word text record contents to not use quotes. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=63f7450b92590138ca4693aa820b2edae9615fc0;p=thirdparty%2Fpdns.git Allow multiple word text record contents to not use quotes. The existing logic would only accept a record not starting with a quote if it was containing a single word, but there is no such requirement. Signed-off-by: Miod Vallat --- diff --git a/pdns/rcpgenerator.cc b/pdns/rcpgenerator.cc index 2ec0d739a..bb1b704aa 100644 --- a/pdns/rcpgenerator.cc +++ b/pdns/rcpgenerator.cc @@ -613,28 +613,27 @@ void RecordTextReader::xfrText(string& val, bool multi, bool /* lenField */) val.clear(); val.reserve(d_end - d_pos); - while(d_pos != d_end) { - if(!val.empty()) + while (d_pos != d_end) { + if (!val.empty()) { val.append(1, ' '); + } skipSpaces(); - if(d_string[d_pos]!='"') { // special case 'plenus' - without quotes - string::size_type pos = d_pos; - while(pos != d_end && isalnum(d_string[pos])) - pos++; - if(pos == d_end) { - val.append(1, '"'); - val.append(d_string.c_str() + d_pos, d_end - d_pos); - val.append(1, '"'); - d_pos = d_end; - break; - } - throw RecordTextException("Data field in DNS should start with quote (\") at position "+std::to_string(d_pos)+" of '"+d_string+"'"); - } + char delimiter{'"'}; + bool quoted = d_string[d_pos] == '"'; + // If the word is quoted, process up to the next quote; otherwise, + // process up to the next whitespace (but output it in quotes). val.append(1, '"'); - while(++d_pos < d_end && d_string[d_pos]!='"') { - if(d_string[d_pos]=='\\' && d_pos+1!=d_end) { - val.append(1, d_string[d_pos++]); + if (quoted) { + ++d_pos; + } + else { + // RFC1035: ``a contiguous set of characters without interior spaces'' + delimiter = ' '; + } + while (d_pos != d_end && d_string[d_pos] != delimiter) { + if (d_string[d_pos] == '\\' && d_pos + 1 != d_end) { + val.append(1, d_string[d_pos++]); // copy escape slash char chr = d_string[d_pos]; if (chr >= '0' && chr <= '9') { bool valid{false}; @@ -654,13 +653,20 @@ void RecordTextReader::xfrText(string& val, bool multi, bool /* lenField */) // part of the regular case. } val.append(1, d_string[d_pos]); + ++d_pos; } val.append(1,'"'); - if(d_pos == d_end) - throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'"); - d_pos++; - if(!multi) + if (quoted) { + // If we reached the end in a quoted section, the closing quote is missing. + if (d_pos == d_end) { + throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'"); + } + // Skip closing quote + ++d_pos; + } + if (!multi) { break; + } } } diff --git a/pdns/test-dnsrecords_cc.cc b/pdns/test-dnsrecords_cc.cc index bbe176155..cdb0e6245 100644 --- a/pdns/test-dnsrecords_cc.cc +++ b/pdns/test-dnsrecords_cc.cc @@ -84,9 +84,9 @@ BOOST_AUTO_TEST_CASE(test_record_types) { // non-local name (CASE_S(QType::PTR, "ptr.example.com.", "\x03ptr\x07""example\x03""com\x00")) (CASE_S(QType::HINFO, "\"i686\" \"Linux\"", "\x04i686\x05Linux")) - (BROKEN_CASE_L(QType::HINFO, "i686 \"Linux\"", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) + (CASE_L(QType::HINFO, "i686 \"Linux\"", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) (CASE_L(QType::HINFO, "\"i686\" Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) - (BROKEN_CASE_L(QType::HINFO, "i686 Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) + (CASE_L(QType::HINFO, "i686 Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) // local name (CASE_S(QType::MX, "10 mx.rec.test.", "\x00\x0a\x02mx\xc0\x11")) // non-local name