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 DNSPacketWriter::DNSPacketWriter(vector& 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 sep('\\', ' ' , '"'); + tokenizer > tok(text, sep); + + tokenizer >::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& 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(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(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(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); }