Skip site navigation (1)Skip section navigation (2)
Date:      Sun,  2 Sep 2007 22:41:23 +0200 (CEST)
From:      Sten Spans <sten@blinkenlights.nl>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   ports/116029: backport multiline txt records support
Message-ID:  <20070902204123.B7BB973033@mx0.blinkenlights.nl>
Resent-Message-ID: <200709022050.l82Ko2HQ021064@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         116029
>Category:       ports
>Synopsis:       backport multiline txt records support
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          maintainer-update
>Submitter-Id:   current-users
>Arrival-Date:   Sun Sep 02 20:50:01 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Sten Spans
>Release:        FreeBSD 6.2-RELEASE i386
>Organization:
>Environment:
System: FreeBSD earth.blinkenlights.nl 6.2-RELEASE FreeBSD 6.2-RELEASE #0: Sun Jan 28 15:02:12 CET 2007 root@earth.blinkenlights.nl:/usr/obj/usr/src/sys/1650 i386


	
>Description:
powerdns-recursor 3.1.4 doesn't support multiline txt records, which 
are used by various dns information systems. 3.1.5 does have support
for this.
A backport of the code changes is relatively risk-free, and has been
requested by users and port maintainers.

http://www.nabble.com/recursor-unable-to-resolve-asn.routeviews.org-data-t4252567.html
>How-To-Repeat:
	
>Fix:

--- Makefile.orig	Thu Jun  7 04:24:04 2007
+++ Makefile	Sun Sep  2 22:25:53 2007
@@ -7,7 +7,7 @@
 
 PORTNAME=	powerdns-recursor
 PORTVERSION=	3.1.4
-PORTREVISION=	5
+PORTREVISION=	6
 CATEGORIES=	dns ipv6
 MASTER_SITES=	http://downloads.powerdns.com/releases/ \
 		http://mirrors.evolva.ro/powerdns.com/releases/
--- files/patch-multiline_txt_records	Thu Jan  1 01:00:00 1970
+++ files/patch-multiline_txt_records	Sun Sep  2 22:23:43 2007
@@ -0,0 +1,398 @@
+Index: dnswriter.hh
+===================================================================
+--- dnswriter.hh (revision 962)
++++ dnswriter.hh (revision 996)
+@@ -84,5 +84,5 @@
+ 
+   void xfrLabel(const string& label, bool compress=false);
+-  void xfrText(const string& text);
++  void xfrText(const string& text, bool multi=false);
+   void xfrBlob(const string& blob);
+   void xfrHexBlob(const string& blob);
+Index: dnsparser.hh
+===================================================================
+--- dnsparser.hh (revision 972)
++++ dnsparser.hh (revision 996)
+@@ -110,7 +110,7 @@
+   }
+ 
+-  void xfrText(string &text)
+-  {
+-    text=getText();
++  void xfrText(string &text, bool multi=false)
++  {
++    text=getText(multi);
+   }
+ 
+@@ -126,5 +126,5 @@
+ 
+   string getLabel(unsigned int recurs=0);
+-  string getText();
++  string getText(bool multi);
+ 
+   uint16_t d_pos;
+Index: zoneparser-tng.cc
+===================================================================
+--- zoneparser-tng.cc (revision 989)
++++ zoneparser-tng.cc (revision 996)
+@@ -281,6 +281,5 @@
+     }
+     catch(...) {
+-      cerr<<"Oops, this doesn't look like a qtype, stopping loop\n";
+-      break;
++      throw runtime_error("Parsing zone content line: '"+nextpart+"' doesn't look like a qtype, stopping loop");
+     }
+   }
+Index: dnswriter.cc
+===================================================================
+--- dnswriter.cc (revision 962)
++++ dnswriter.cc (revision 996)
+@@ -2,4 +2,5 @@
+ #include "misc.hh"
+ #include "dnsparser.hh"
++#include <boost/tokenizer.hpp>
+ 
+ DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& content, const string& qname, uint16_t  qtype, uint16_t qclass, uint8_t opcode)
+@@ -116,9 +117,20 @@
+ }
+ 
+-void DNSPacketWriter::xfrText(const string& text)
+-{
+-  d_record.push_back(text.length());
+-  const uint8_t* ptr=(uint8_t*)(text.c_str());
+-  d_record.insert(d_record.end(), ptr, ptr+text.size());
++void DNSPacketWriter::xfrText(const string& text, bool)
++{
++  escaped_list_separator<char> sep('\\', ' ' , '"');
++  tokenizer<escaped_list_separator<char> > tok(text, sep);
++
++  tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin();
++
++  if(beg==tok.end()) {
++    d_record.push_back(0);
++  }
++  else 
++    for(; beg!=tok.end(); ++beg){
++      d_record.push_back(beg->length());
++      const uint8_t* ptr=(uint8_t*)(beg->c_str());
++      d_record.insert(d_record.end(), ptr, ptr+beg->length());
++    }
+ }
+ 
+Index: dnsparser.cc
+===================================================================
+--- dnsparser.cc (revision 972)
++++ dnsparser.cc (revision 996)
+@@ -359,14 +359,42 @@
+ }
+ 
+-string PacketReader::getText()
++static string txtEscape(const string &name)
++{
++  string ret;
++
++  for(string::const_iterator i=name.begin();i!=name.end();++i)
++    if(*i=='"' || *i=='\\'){
++      ret += '\\';
++      ret += *i;
++    }
++    else
++      ret += *i;
++  return ret;
++}
++
++// exceptions thrown here do not result in logging in the main pdns auth server - just so you know!
++string PacketReader::getText(bool multi)
+ {
+   string ret;
+   ret.reserve(40);
+-
+-  unsigned char labellen=d_content.at(d_pos++);
+-  ret.append(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1); // the end is one beyond the packet
+-  d_pos+=labellen;
+-  return ret;
+-}
++  while(d_pos < d_startrecordpos + d_recordlen ) {
++    if(!ret.empty()) {
++      ret.append(1,' ');
++    }
++    unsigned char labellen=d_content.at(d_pos++);
++    
++    ret.append(1,'"');
++    string val(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1);
++    
++    ret.append(txtEscape(val)); // the end is one beyond the packet
++    ret.append(1,'"');
++    d_pos+=labellen;
++    if(!multi)
++      break;
++  }
++
++  return ret;
++}
++
+ 
+ void PacketReader::getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs) 
+Index: rcpgenerator.hh
+===================================================================
+--- rcpgenerator.hh (revision 802)
++++ rcpgenerator.hh (revision 996)
+@@ -51,5 +51,5 @@
+ 
+   void xfrLabel(string& val, bool compress=false);
+-  void xfrText(string& val);
++  void xfrText(string& val, bool multi=false);
+   void xfrHexBlob(string& val);
+   void xfrBlob(string& val);
+@@ -76,5 +76,5 @@
+   void xfrType(const uint16_t& val);
+   void xfrLabel(const string& val, bool compress=false);
+-  void xfrText(const string& val);
++  void xfrText(const string& val, bool multi=false);
+   void xfrBlob(const string& val);
+   void xfrHexBlob(const string& val);
+Index: dnsrecords.cc
+===================================================================
+--- dnsrecords.cc (revision 823)
++++ dnsrecords.cc (revision 996)
+@@ -1,5 +1,5 @@
+ /*
+     PowerDNS Versatile Database Driven Nameserver
+-    Copyright (C) 2005 - 2006  PowerDNS.COM BV
++    Copyright (C) 2005 - 2007  PowerDNS.COM BV
+ 
+     This program is free software; you can redistribute it and/or modify
+@@ -178,6 +178,6 @@
+ boilerplate_conv(PTR, ns_t_ptr, conv.xfrLabel(d_content, true));
+ boilerplate_conv(CNAME, ns_t_cname, conv.xfrLabel(d_content, true));
+-boilerplate_conv(TXT, ns_t_txt, conv.xfrText(d_text));
+-boilerplate_conv(SPF, 99, conv.xfrText(d_text));
++boilerplate_conv(TXT, ns_t_txt, conv.xfrText(d_text, true));
++boilerplate_conv(SPF, 99, conv.xfrText(d_text, true));
+ boilerplate_conv(HINFO, ns_t_hinfo,  conv.xfrText(d_cpu);   conv.xfrText(d_host));
+ 
+@@ -199,4 +199,9 @@
+ 		 conv.xfr16BitInt(d_preference);
+ 		 conv.xfrLabel(d_mxname, true);
++		 )
++
++boilerplate_conv(AFSDB, ns_t_afsdb, 
++		 conv.xfr16BitInt(d_subtype);
++		 conv.xfrLabel(d_hostname);
+ 		 )
+ 
+@@ -235,4 +240,11 @@
+ 		 conv.xfr32BitInt(d_st.expire);
+ 		 conv.xfr32BitInt(d_st.minimum);
++		 );
++#undef KEY
++boilerplate_conv(KEY, ns_t_key, 
++		 conv.xfr16BitInt(d_flags); 
++		 conv.xfr8BitInt(d_protocol); 
++		 conv.xfr8BitInt(d_algorithm); 
++		 conv.xfrBlob(d_certificate);
+ 		 );
+ 
+@@ -294,7 +306,9 @@
+ void reportOtherTypes()
+ {
++   AFSDBRecordContent::report();
+    SPFRecordContent::report();
+    NAPTRRecordContent::report();
+    RPRecordContent::report();
++   KEYRecordContent::report();
+    DNSKEYRecordContent::report();
+    RRSIGRecordContent::report();
+Index: dnsrecords.hh
+===================================================================
+--- dnsrecords.hh (revision 823)
++++ dnsrecords.hh (revision 978)
+@@ -196,4 +196,26 @@
+   string d_fingerprint;
+ };
++
++class KEYRecordContent : public DNSRecordContent
++{
++public:
++  includeboilerplate(KEY)
++
++private:
++  uint16_t d_flags;
++  uint8_t d_protocol, d_algorithm;
++  string d_certificate;
++};
++
++class AFSDBRecordContent : public DNSRecordContent
++{
++public:
++  includeboilerplate(AFSDB)
++
++private:
++  uint16_t d_subtype;
++  string d_hostname;
++};
++
+ 
+ class CERTRecordContent : public DNSRecordContent
+Index: rcpgenerator.cc
+===================================================================
+--- rcpgenerator.cc (revision 850)
++++ rcpgenerator.cc (revision 996)
+@@ -67,9 +67,38 @@
+   if(!isdigit(d_string.at(d_pos)))
+     throw RecordTextException("while parsing IP address, expected digits at position "+lexical_cast<string>(d_pos)+" in '"+d_string+"'");
+-  
+-  string ip;
+-  xfrLabel(ip);
+-  if(!IpToU32(ip, &val))
+-    throw RecordTextException("unable to parse IP address '"+ip+"'");
++
++  uint32_t octet=0;
++  val=0;
++  char count=0;
++  
++  for(;;) {
++    if(d_string.at(d_pos)=='.') {
++      val<<=8;
++      val+=octet;
++      octet=0;
++      count++;
++      if(count > 3)
++	break;
++    }
++    else if(isdigit(d_string.at(d_pos))) {
++      octet*=10;
++      octet+=d_string.at(d_pos) - '0';
++      if(octet > 255)
++	throw RecordTextException("unable to parse IP address");
++    }
++    else if(dns_isspace(d_string.at(d_pos))) 
++      break;
++    else
++      throw RecordTextException("unable to parse IP address, strange character: "+d_string.at(d_pos));
++
++    d_pos++;
++    if(d_pos == d_string.length())
++      break;
++  }
++  if(count<=3) {
++    val<<=8;
++    val+=octet;
++  }
++  val=ntohl(val);
+ }
+ 
+@@ -178,23 +207,31 @@
+ }
+ 
+-
+-void RecordTextReader::xfrText(string& val)
+-{
+-  skipSpaces();
+-  if(d_string[d_pos]!='"')
+-    throw RecordTextException("Data field in DNS should start with quote (\") at position "+lexical_cast<string>(d_pos)+" of '"+d_string+"'");
+-
++void RecordTextReader::xfrText(string& val, bool multi)
++{
+   val.clear();
+   val.reserve(d_end - d_pos);
+-  
+-  while(++d_pos < d_end && d_string[d_pos]!='"') {
+-    if(d_string[d_pos]=='\\' && d_pos+1!=d_end) {
+-      ++d_pos;
++
++  while(d_pos != d_end) {
++    if(!val.empty())
++      val.append(1, ' ');
++
++    skipSpaces();
++    if(d_string[d_pos]!='"')
++      throw RecordTextException("Data field in DNS should start with quote (\") at position "+lexical_cast<string>(d_pos)+" of '"+d_string+"'");
++
++    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++]);
++      }
++      val.append(1, d_string[d_pos]);
+     }
+-    val.append(1, d_string[d_pos]);
+-  }
+-  if(d_pos == d_end)
+-    throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'");
+-  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)
++      break;
++  }
+ }
+ 
+@@ -251,11 +288,28 @@
+ 
+   char tmp[17];
+-  snprintf(tmp, sizeof(tmp)-1, "%u.%u.%u.%u", 
+-	   (val >> 24)&0xff,
+-	   (val >> 16)&0xff,
+-	   (val >>  8)&0xff,
+-	   (val      )&0xff);
+-  
+-  d_string+=tmp;
++  uint32_t ip=htonl(val);
++  uint8_t vals[4];
++
++  memcpy(&vals[0], &ip, sizeof(ip));
++
++  char *pos=tmp;
++
++  for(int n=0; n < 4; ++n) {
++    if(vals[n]<10) {
++      *(pos++)=vals[n]+'0';
++    } else if(vals[n] < 100) {
++      *(pos++)=(vals[n]/10) +'0';
++      *(pos++)=(vals[n]%10) +'0';
++    } else {
++      *(pos++)=(vals[n]/100) +'0';
++      vals[n]%=100;
++      *(pos++)=(vals[n]/10) +'0';
++      *(pos++)=(vals[n]%10) +'0';
++    }
++    if(n!=3)
++      *(pos++)='.';
++  }
++  *pos=0;
++  d_string.append(tmp, pos);
+ }
+ 
+@@ -338,23 +392,10 @@
+ }
+ 
+-void RecordTextWriter::xfrText(const string& val)
+-{
+-  if(!d_string.empty())
+-    d_string.append(1,' ');
+-  d_string.append(1,'"');
+-
+-  if(val.find_first_of("\\\"") == string::npos)
+-    d_string+=val;
+-  else {
+-    string::size_type end=val.size();
+-    
+-    for(string::size_type pos=0; pos < end; ++pos) {
+-      if(val[pos]=='\'' || val[pos]=='"')
+-	d_string.append(1,'\\');
+-      d_string.append(1, val[pos]);
+-    }
+-  }
+-
+-  d_string.append(1,'"');
++void RecordTextWriter::xfrText(const string& val, bool multi)
++{
++  if(!d_string.empty())
++    d_string.append(1,' ');
++
++  d_string.append(val);
+ }
+ 

>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070902204123.B7BB973033>