Commit 13674dda authored by Jelte Jansen's avatar Jelte Jansen
Browse files

[master] Merge branch 'trac2498'

Conflicts:
	src/lib/dns/gen-rdatacode.py.in
parents 715a6f61 9a0d024c
......@@ -126,7 +126,6 @@ libb10_dns___la_SOURCES += tsig.h tsig.cc
libb10_dns___la_SOURCES += tsigerror.h tsigerror.cc
libb10_dns___la_SOURCES += tsigkey.h tsigkey.cc
libb10_dns___la_SOURCES += tsigrecord.h tsigrecord.cc
libb10_dns___la_SOURCES += character_string.h character_string.cc
libb10_dns___la_SOURCES += master_loader_callbacks.h master_loader_callbacks.cc
libb10_dns___la_SOURCES += master_loader.h
libb10_dns___la_SOURCES += rrset_collection_base.h
......
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "character_string.h"
#include "rdata.h"
using namespace std;
using namespace isc::dns::rdata;
namespace isc {
namespace dns {
namespace {
bool isDigit(char c) {
return (('0' <= c) && (c <= '9'));
}
}
std::string
characterstr::getNextCharacterString(const std::string& input_str,
std::string::const_iterator& input_iterator,
bool* quoted)
{
string result;
// If the input string only contains white-spaces, it is an invalid
// <character-string>
if (input_iterator >= input_str.end()) {
isc_throw(InvalidRdataText, "Invalid text format, \
<character-string> field is missing.");
}
// Whether the <character-string> is separated with double quotes (")
bool quotes_separated = (*input_iterator == '"');
// Whether the quotes are pared if the string is quotes separated
bool quotes_paired = false;
if (quotes_separated) {
++input_iterator;
}
while(input_iterator < input_str.end()){
// Escaped characters processing
if (*input_iterator == '\\') {
if (input_iterator + 1 == input_str.end()) {
isc_throw(InvalidRdataText, "<character-string> ended \
prematurely.");
} else {
if (isDigit(*(input_iterator + 1))) {
// \DDD where each D is a digit. It its the octet
// corresponding to the decimal number described by DDD
if (input_iterator + 3 >= input_str.end()) {
isc_throw(InvalidRdataText, "<character-string> ended \
prematurely.");
} else {
int n = 0;
++input_iterator;
for (int i = 0; i < 3; ++i) {
if (isDigit(*input_iterator)) {
n = n*10 + (*input_iterator - '0');
++input_iterator;
} else {
isc_throw(InvalidRdataText, "Illegal decimal \
escaping series");
}
}
if (n > 255) {
isc_throw(InvalidRdataText, "Illegal octet \
number");
}
result.push_back(n);
continue;
}
} else {
++input_iterator;
result.push_back(*input_iterator);
++input_iterator;
continue;
}
}
}
if (quotes_separated) {
// If the <character-string> is seperated with quotes symbol and
// another quotes symbol is encountered, it is the end of the
// <character-string>
if (*input_iterator == '"') {
quotes_paired = true;
++input_iterator;
// Reach the end of character string
break;
}
} else if (*input_iterator == ' ') {
// If the <character-string> is not seperated with quotes symbol,
// it is seperated with <space> char
break;
}
result.push_back(*input_iterator);
++input_iterator;
}
if (result.size() > MAX_CHARSTRING_LEN) {
isc_throw(CharStringTooLong, "<character-string> is too long");
}
if (quotes_separated && !quotes_paired) {
isc_throw(InvalidRdataText, "The quotes are not paired");
}
if (quoted != NULL) {
*quoted = quotes_separated;
}
return (result);
}
std::string
characterstr::getNextCharacterString(util::InputBuffer& buffer, size_t len) {
uint8_t str_len = buffer.readUint8();
size_t pos = buffer.getPosition();
if (len - pos < str_len) {
isc_throw(InvalidRdataLength, "Invalid string length");
}
uint8_t buf[MAX_CHARSTRING_LEN];
buffer.readData(buf, str_len);
return (string(buf, buf + str_len));
}
} // end of namespace dns
} // end of namespace isc
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef CHARACTER_STRING_H
#define CHARACTER_STRING_H
#include <string>
#include <exceptions/exceptions.h>
#include <util/buffer.h>
namespace isc {
namespace dns {
// \brief Some utility functions to extract <character-string> from string
// or InputBuffer
//
// <character-string> is expressed in one or two ways: as a contiguous set
// of characters without interior spaces, or as a string beginning with a "
// and ending with a ". Inside a " delimited string any character can
// occur, except for a " itself, which must be quoted using \ (back slash).
// Ref. RFC1035
namespace characterstr {
/// Get a <character-string> from a string
///
/// \param input_str The input string
/// \param input_iterator The iterator from which to start extracting,
/// the iterator will be updated to new position after the function
/// is returned
/// \param quoted If not \c NULL, returns \c true at this address if
/// the string is quoted, \cfalse otherwise
/// \return A std::string that contains the extracted <character-string>
std::string getNextCharacterString(const std::string& input_str,
std::string::const_iterator& input_iterator,
bool* quoted = NULL);
/// Get a <character-string> from a input buffer
///
/// \param buffer The input buffer
/// \param len The input buffer total length
/// \return A std::string that contains the extracted <character-string>
std::string getNextCharacterString(util::InputBuffer& buffer, size_t len);
} // namespace characterstr
} // namespace dns
} // namespace isc
#endif // CHARACTER_STRING_H
......@@ -32,8 +32,13 @@ import sys
#
# Example:
# new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
new_rdata_factory_users = [('soa', 'generic'), ('txt', 'generic'),
('aaaa', 'in'), ('spf', 'generic')]
new_rdata_factory_users = [('aaaa', 'in'),
('hinfo', 'generic'),
('naptr', 'generic'),
('soa', 'generic'),
('spf', 'generic'),
('txt', 'generic')
]
re_typecode = re.compile('([\da-z]+)_(\d+)')
classcode2txt = {}
......
......@@ -14,9 +14,11 @@
#include <exceptions/exceptions.h>
#include <dns/exceptions.h>
#include <dns/rdata.h>
#include <dns/master_lexer.h>
#include <dns/rdata/generic/detail/char_string.h>
#include <util/buffer.h>
#include <boost/lexical_cast.hpp>
......@@ -114,6 +116,60 @@ charStringToString(const CharString& char_string) {
return (s);
}
int compareCharStrings(const detail::CharString& self,
const detail::CharString& other) {
if (self.size() == 0 && other.size() == 0) {
return (0);
}
if (self.size() == 0) {
return (-1);
}
if (other.size() == 0) {
return (1);
}
const size_t self_len = self[0];
const size_t other_len = other[0];
const size_t cmp_len = std::min(self_len, other_len);
const int cmp = memcmp(&self[1], &other[1], cmp_len);
if (cmp < 0) {
return (-1);
} else if (cmp > 0) {
return (1);
} else if (self_len < other_len) {
return (-1);
} else if (self_len > other_len) {
return (1);
} else {
return (0);
}
}
size_t
bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
CharString& target) {
if (rdata_len < 1 || buffer.getLength() - buffer.getPosition() < 1) {
isc_throw(isc::dns::DNSMessageFORMERR,
"insufficient data to read character-string length");
}
const uint8_t len = buffer.readUint8();
if (rdata_len < len + 1) {
isc_throw(isc::dns::DNSMessageFORMERR,
"character string length is too large: " <<
static_cast<int>(len));
}
if (buffer.getLength() - buffer.getPosition() < len) {
isc_throw(isc::dns::DNSMessageFORMERR,
"not enough data in buffer to read character-string of len"
<< static_cast<int>(len));
}
target.resize(len + 1);
target[0] = len;
buffer.readData(&target[0] + 1, len);
return (len + 1);
}
} // end of detail
} // end of generic
} // end of rdata
......
......@@ -19,6 +19,7 @@
#include <string>
#include <vector>
#include <algorithm>
#include <stdint.h>
namespace isc {
......@@ -66,6 +67,38 @@ void stringToCharString(const MasterToken::StringRegion& str_region,
/// \return A string representation of \c char_string.
std::string charStringToString(const CharString& char_string);
/// \brief Compare two CharString objects
///
/// \param self The CharString field to compare
/// \param other The CharString field to compare to
///
/// \return -1 if \c self would be sorted before \c other
/// 1 if \c self would be sorted after \c other
/// 0 if \c self and \c other are equal
int compareCharStrings(const CharString& self, const CharString& other);
/// \brief Convert a buffer containing a character-string to CharString
///
/// This method reads one character-string from the given buffer (in wire
/// format) and places the result in the given \c CharString object.
/// Since this is expected to be used in message parsing, the exception it
/// raises is of that type.
///
/// On success, the buffer position is advanced to the end of the char-string,
/// and the number of bytes read is returned.
///
/// \param buffer The buffer to read from.
/// \param rdata_len The total size of the rr's rdata currently being read
/// (used for integrity checks in the wire data)
/// \param target The \c CharString where the result will be stored. Any
/// existing data in the target will be overwritten.
/// \throw DNSMessageFORMERR If the available data is not enough to read
/// the character-string, or if the character-string length is out of bounds
/// \return The number of bytes read
size_t bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
CharString& target);
} // namespace detail
} // namespace generic
} // namespace rdata
......
......@@ -14,66 +14,105 @@
#include <config.h>
#include <string>
#include <boost/lexical_cast.hpp>
#include <exceptions/exceptions.h>
#include <dns/name.h>
#include <dns/messagerenderer.h>
#include <dns/exceptions.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/character_string.h>
#include <util/strutil.h>
#include <dns/rdata/generic/detail/char_string.h>
#include <util/buffer.h>
using namespace std;
using boost::lexical_cast;
using namespace isc::util;
using namespace isc::dns;
using namespace isc::dns::characterstr;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
class HINFOImpl {
public:
HINFOImpl(const std::string& hinfo_str) {
std::istringstream ss(hinfo_str);
MasterLexer lexer;
lexer.pushSource(ss);
try {
parseHINFOData(lexer);
// Should be at end of data now
if (lexer.getNextToken(MasterToken::QSTRING, true).getType() !=
MasterToken::END_OF_FILE) {
isc_throw(InvalidRdataText,
"Invalid HINFO text format: too many fields.");
}
} catch (const MasterLexer::LexerError& ex) {
isc_throw(InvalidRdataText, "Failed to construct HINFO RDATA from "
<< hinfo_str << "': " << ex.what());
}
}
HINFO::HINFO(const std::string& hinfo_str) {
string::const_iterator input_iterator = hinfo_str.begin();
HINFOImpl(InputBuffer& buffer, size_t rdata_len) {
rdata_len -= detail::bufferToCharString(buffer, rdata_len, cpu);
rdata_len -= detail::bufferToCharString(buffer, rdata_len, os);
if (rdata_len != 0) {
isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " <<
"HINFO RDATA: bytes left at end: " <<
static_cast<int>(rdata_len));
}
}
bool quoted;
cpu_ = getNextCharacterString(hinfo_str, input_iterator, &quoted);
HINFOImpl(MasterLexer& lexer)
{
parseHINFOData(lexer);
}
skipLeftSpaces(hinfo_str, input_iterator, quoted);
private:
void
parseHINFOData(MasterLexer& lexer) {
MasterToken token = lexer.getNextToken(MasterToken::QSTRING);
stringToCharString(token.getStringRegion(), cpu);
token = lexer.getNextToken(MasterToken::QSTRING);
stringToCharString(token.getStringRegion(), os);
}
os_ = getNextCharacterString(hinfo_str, input_iterator);
public:
detail::CharString cpu;
detail::CharString os;
};
// Skip whitespace at the end.
while (input_iterator < hinfo_str.end() && isspace(*input_iterator)) {
++input_iterator;
}
if (input_iterator < hinfo_str.end()) {
isc_throw(InvalidRdataText,
"Invalid HINFO text format: too many fields.");
}
}
HINFO::HINFO(const std::string& hinfo_str) : impl_(new HINFOImpl(hinfo_str))
{}
HINFO::HINFO(InputBuffer& buffer, size_t rdata_len) {
cpu_ = getNextCharacterString(buffer, rdata_len);
os_ = getNextCharacterString(buffer, rdata_len);
}
HINFO::HINFO(InputBuffer& buffer, size_t rdata_len) :
impl_(new HINFOImpl(buffer, rdata_len))
{}
HINFO::HINFO(const HINFO& source):
Rdata(), cpu_(source.cpu_), os_(source.os_)
Rdata(), impl_(new HINFOImpl(*source.impl_))
{
}
HINFO::HINFO(MasterLexer& lexer, const Name*,
MasterLoader::Options, MasterLoaderCallbacks&) :
impl_(new HINFOImpl(lexer))
{}
HINFO&
HINFO::operator=(const HINFO& source)
{
impl_.reset(new HINFOImpl(*source.impl_));
return (*this);
}
HINFO::~HINFO() {
}
std::string
HINFO::toText() const {
string result;
result += "\"";
result += cpu_;
result += detail::charStringToString(impl_->cpu);
result += "\" \"";
result += os_;
result += detail::charStringToString(impl_->os);
result += "\"";
return (result);
}
......@@ -92,49 +131,28 @@ int
HINFO::compare(const Rdata& other) const {
const HINFO& other_hinfo = dynamic_cast<const HINFO&>(other);
if (cpu_ < other_hinfo.cpu_) {
return (-1);
} else if (cpu_ > other_hinfo.cpu_) {
return (1);
}
if (os_ < other_hinfo.os_) {
return (-1);
} else if (os_ > other_hinfo.os_) {
return (1);
const int cmp = compareCharStrings(impl_->cpu, other_hinfo.impl_->cpu);
if (cmp != 0) {
return (cmp);
}
return (0);
return (compareCharStrings(impl_->os, other_hinfo.impl_->os));
}
const std::string&
const std::string
HINFO::getCPU() const {
return (cpu_);
return (detail::charStringToString(impl_->cpu));
}
const std::string&
const std::string
HINFO::getOS() const {
return (os_);
return (detail::charStringToString(impl_->os));
}
template <typename T>
void
HINFO::skipLeftSpaces(const std::string& input_str,
std::string::const_iterator& input_iterator,
bool optional)
{
if (input_iterator >= input_str.end()) {
isc_throw(InvalidRdataText,
"Invalid HINFO text format: field is missing.");
}
if (!isspace(*input_iterator) && !optional) {
isc_throw(InvalidRdataText,
"Invalid HINFO text format: fields are not separated by space.");
}
// Skip white spaces
while (input_iterator < input_str.end() && isspace(*input_iterator)) {
++input_iterator;
}
HINFO::toWireHelper(T& outputer) const {
outputer.writeData(&impl_->cpu[0], impl_->cpu.size());
outputer.writeData(&impl_->os[0], impl_->os.size());
}
// END_RDATA_NAMESPACE
......
......@@ -17,6 +17,9 @@
#include <string>
#include <boost/scoped_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <dns/name.h>
#include <dns/rdata.h>
#include <util/buffer.h>
......@@ -28,6 +31,8 @@
// BEGIN_RDATA_NAMESPACE
class HINFOImpl;
/// \brief \c HINFO class represents the HINFO rdata defined in
/// RFC1034, RFC1035
///
......@@ -40,38 +45,21 @@ public:
// END_COMMON_MEMBERS
// HINFO specific methods
const std::string& getCPU() const;
const std::string& getOS() const;
~HINFO();
private:
/// Skip the left whitespaces of the input string
///
/// If \c optional argument is \c true and no spaces occur at the
/// current location, then nothing happens. If \c optional is
/// \c false and no spaces occur at the current location, then
/// the \c InvalidRdataText exception is thrown.
///
/// \param input_str The input string
/// \param input_iterator From which the skipping started
/// \param optional If true, the spaces are optionally skipped.
void skipLeftSpaces(const std::string& input_str,
std::string::const_iterator& input_iterator,
bool optional);
HINFO& operator=(const HINFO&);
const std::string getCPU() const;
const std::string getOS() const;
private:
/// Helper template function for toWire()
///
/// \param outputer Where to write data in
template <typename T>
void toWireHelper(T& outputer) const {
outputer.writeUint8(cpu_.size());
outputer.writeData(cpu_.c_str(), cpu_.size());
outputer.writeUint8(os_.size());
outputer.writeData(os_.c_str(), os_.size());
}