]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
SVCB: use proper escaping when writing text format
authorPieter Lexis <pieter.lexis@powerdns.com>
Mon, 8 Feb 2021 20:22:57 +0000 (21:22 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Mon, 29 Mar 2021 17:10:31 +0000 (19:10 +0200)
pdns/rcpgenerator.cc
pdns/rcpgenerator.hh
pdns/test-dnsrecords_cc.cc

index d249cabee75b0b734e8d1c0ab2a9cc2450591c86..e84a6588b0fc6dca88627bbeda2f33062b726c2b 100644 (file)
@@ -29,6 +29,7 @@
 #include "utility.hh"
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/replace.hpp>
 
 #include <iostream>
 #include "base32.hh"
@@ -742,6 +743,27 @@ static string txtEscape(const string &name)
   return ret;
 }
 
+void RecordTextWriter::xfrSVCBValueList(const vector<string> &val) {
+  bool shouldQuote{false};
+  vector<string> escaped;
+  escaped.reserve(val.size());
+  for (auto const &v : val) {
+    if (v.find_first_of(' ') != string::npos) {
+      shouldQuote = true;
+    }
+    string tmp = txtEscape(v);
+    boost::replace_all(tmp, ",", "\\,");
+    escaped.push_back(tmp);
+  }
+  if (shouldQuote) {
+    d_string.append(1, '"');
+  }
+  d_string.append(boost::join(escaped, ","));
+  if (shouldQuote) {
+    d_string.append(1, '"');
+  }
+}
+
 void RecordTextWriter::xfrSvcParamKeyVals(const set<SvcParam>& val) {
   for (auto const &param : val) {
     if (!d_string.empty())
@@ -762,8 +784,7 @@ void RecordTextWriter::xfrSvcParamKeyVals(const set<SvcParam>& val) {
       d_string.append(ComboAddress::caContainerToString(param.getIPHints(), false));
       break;
     case SvcParam::alpn:
-      // This is safe, as this value needs no quotes
-      d_string.append(boost::join(param.getALPN(), ","));
+      xfrSVCBValueList(param.getALPN());
       break;
     case SvcParam::mandatory:
     {
index 22b79ce87e6c3e547703cbdbe595de8605897e22..099417b31b80148eef1cebb405184faecd393e2e 100644 (file)
@@ -105,6 +105,8 @@ public:
   void xfrSvcParamKeyVals(const set<SvcParam>& val);
   bool eof() { return true; };
 
+  void xfrSVCBValueList(const vector<string> &val);
+
   const string getRemaining() const {
      return "";
   }
index 22f87700efe290708c5901c24239f2dcb2d2eccb..9404e2fc145194ff8d8b08f84304f1039bc27f5b 100644 (file)
@@ -229,6 +229,13 @@ BOOST_AUTO_TEST_CASE(test_record_types) {
      (CASE_S(QType::SVCB, "16 foo.powerdns.org. mandatory=alpn alpn=h2,h3 ipv4hint=192.0.2.1", "\0\x10\3foo\x08powerdns\x03org\x00\x00\x00\x00\x02\x00\x01\x00\x01\x00\x06\x02h2\x02h3\x00\x04\x00\x04\xc0\x00\x02\x01"))
      (CASE_L(QType::SVCB, "16 foo.powerdns.org. alpn=h2,h3 mandatory=alpn ipv4hint=192.0.2.1", "16 foo.powerdns.org. mandatory=alpn alpn=h2,h3 ipv4hint=192.0.2.1", "\0\x10\3foo\x08powerdns\x03org\x00\x00\x00\x00\x02\x00\x01\x00\x01\x00\x06\x02h2\x02h3\x00\x04\x00\x04\xc0\x00\x02\x01"))
 
+     // IPv4hint is quoted
+     (CASE_L(QType::SVCB, "16 foo.powerdns.org. alpn=h2,h3 mandatory=alpn ipv4hint=\"192.0.2.1\"", "16 foo.powerdns.org. mandatory=alpn alpn=h2,h3 ipv4hint=192.0.2.1", "\0\x10\3foo\x08powerdns\x03org\x00\x00\x00\x00\x02\x00\x01\x00\x01\x00\x06\x02h2\x02h3\x00\x04\x00\x04\xc0\x00\x02\x01"))
+     // Escaped ALPN value
+     (CASE_S(QType::SVCB, "1 foo.powerdns.org. alpn=h3\\,cool,h2", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x01\x00\x0b\x07h3,cool\x02h2"))
+     // Escaped _and_ spaced ALPN value
+     (CASE_S(QType::SVCB, "1 foo.powerdns.org. alpn=\"h3\\,co ol,h2\"", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x01\x00\x0c\x08h3,co ol\x02h2"))
+
      (CASE_S(QType::SPF, "\"v=spf1 a:mail.rec.test ~all\"", "\x1bv=spf1 a:mail.rec.test ~all"))
      (CASE_S(QType::EUI48, "00-11-22-33-44-55", "\x00\x11\x22\x33\x44\x55"))
      (CASE_S(QType::EUI64, "00-11-22-33-44-55-66-77", "\x00\x11\x22\x33\x44\x55\x66\x77"))