18 #include <boost/format.hpp>
19 #include <boost/algorithm/string/predicate.hpp>
20 #include <boost/scoped_ptr.hpp>
21 #include <boost/shared_ptr.hpp>
30 using std::unique_ptr;
33 using boost::algorithm::iequals;
34 using boost::shared_ptr;
46 InternalException(
const char* filename,
size_t line,
const char* what) :
47 Exception(filename, line, what)
82 const Name& zone_origin,
88 zone_origin_(zone_origin),
89 active_origin_(zone_origin),
90 zone_class_(zone_class),
91 callbacks_(callbacks),
92 add_callback_(add_callback),
94 master_file_(master_file),
98 previous_name_(false),
119 isc_throw(InternalException, error.c_str());
122 reportError(
"", 0, error);
127 include_info_.push_back(IncludeInfo(current_origin, last_name_));
129 previous_name_ =
false;
161 void reportError(
const std::string& filename,
size_t line,
162 const std::string& reason)
165 callbacks_.
error(filename, line, reason);
190 assert(!include_info_.empty());
191 const IncludeInfo&
info(include_info_.back());
192 active_origin_ =
info.first;
193 last_name_ =
info.second;
194 include_info_.pop_back();
195 previous_name_ =
false;
200 const string getString() {
202 return (string_token_);
219 MasterToken handleInitialToken();
228 std::string generateForIter(
const std::string& str,
const int it);
236 void doOrigin(
bool is_optional) {
245 const MasterToken::StringRegion&
246 name_string(name_tok.getStringRegion());
247 active_origin_ = Name(name_string.beg, name_string.len,
249 if (name_string.len > 0 &&
250 name_string.beg[name_string.len - 1] !=
'.') {
253 "The new origin is relative, did you really"
254 " mean " + active_origin_.toText() +
"?");
283 const Name current_origin = active_origin_;
299 RRType parseRRParams(
bool& explicit_ttl, MasterToken rrparam_token) {
309 if (setCurrentTTL(rrparam_token.getString())) {
317 boost::scoped_ptr<RRClass> rrclass
320 if (*rrclass != zone_class_) {
321 isc_throw(InternalException,
"Class mismatch: " << *rrclass <<
322 " vs. " << zone_class_);
329 if (!explicit_ttl && setCurrentTTL(rrparam_token.getString())) {
335 return (RRType(rrparam_token.getString()));
357 void limitTTL(RRTTL& ttl,
bool post_parsing) {
360 (post_parsing ? 1 : 0);
362 "TTL " + ttl.toText() +
" > MAXTTL, "
363 "setting to 0 per RFC2181");
373 void setDefaultTTL(
const RRTTL& ttl,
bool post_parsing) {
374 assignTTL(default_ttl_, ttl);
375 limitTTL(*default_ttl_, post_parsing);
387 bool setCurrentTTL(
const string& ttl_txt) {
393 current_ttl_.reset(rrttl);
394 limitTTL(*current_ttl_,
false);
409 const RRTTL& getCurrentTTL(
bool explicit_ttl,
const RRType& rrtype,
416 if (!current_ttl_ && !default_ttl_) {
420 "using SOA MINTTL instead");
421 const uint32_t ttl_val =
422 dynamic_cast<const rdata::generic::SOA&
>(*rdata).
424 setDefaultTTL(RRTTL(ttl_val),
true);
425 assignTTL(current_ttl_, *default_ttl_);
430 throw InternalException(__FILE__, __LINE__,
431 "no TTL specified; load rejected");
433 }
else if (!explicit_ttl && default_ttl_) {
434 assignTTL(current_ttl_, *default_ttl_);
439 "using RFC1035 TTL semantics; default to the "
440 "last explicitly stated TTL");
443 assert(current_ttl_);
444 return (*current_ttl_);
451 void handleDirective(
const char* directive,
size_t length) {
452 if (iequals(directive,
"INCLUDE")) {
454 }
else if (iequals(directive,
"ORIGIN")) {
457 }
else if (iequals(directive,
"GENERATE")) {
460 }
else if (iequals(directive,
"TTL")) {
461 setDefaultTTL(RRTTL(getString()),
false);
464 isc_throw(InternalException,
"Unknown directive '" <<
465 string(directive, directive + length) <<
"'");
470 void eatUntilEOL(
bool reportExtra) {
474 switch (token.getType()) {
478 "File does not end with newline");
492 "Extra tokens at the end of line");
502 static void assignTTL(boost::scoped_ptr<RRTTL>& left,
const RRTTL& right) {
504 left.reset(
new RRTTL(right));
512 const Name zone_origin_;
515 shared_ptr<Name> last_name_;
516 const RRClass zone_class_;
517 MasterLoaderCallbacks callbacks_;
519 boost::scoped_ptr<RRTTL> default_ttl_;
522 boost::scoped_ptr<RRTTL> current_ttl_;
527 const std::string master_file_;
528 std::string string_token_;
531 const bool many_errors_;
536 typedef pair<Name, shared_ptr<Name> > IncludeInfo;
537 vector<IncludeInfo> include_info_;
605 genNibbles(
int num,
unsigned int width,
bool uppercase) {
606 static const char *hex =
"0123456789abcdef0123456789ABCDEF";
610 char ch = hex[(num & 0x0f) + (uppercase ? 16 : 0)];
621 if (width > 0 || num != 0) {
628 }
while ((num != 0) || (width > 0));
636 MasterLoader::MasterLoaderImpl::generateForIter(
const std::string& str,
641 for (std::string::const_iterator it = str.begin(); it != str.end();) {
648 if ((it != str.end()) && (*it ==
'$')) {
655 if ((it == str.end()) || (*it !=
'{')) {
662 const char* scan_str =
663 str.c_str() + std::distance(str.begin(), it);
666 char base[2] = {
'd', 0};
668 const int n = sscanf(scan_str,
"{%d,%u,%1[doxXnN]}",
669 &offset, &width, base);
681 const std::string fmt =
689 if ((base[0] ==
'n') || (base[0] ==
'N')) {
692 rstr += genNibbles(num + offset, width, (base[0] ==
'N'));
697 const std::string fmt =
706 "Invalid $GENERATE format modifiers");
712 while ((it != str.end()) && (*it !=
'}')) {
716 if (it != str.end()) {
729 if (it == str.end()) {
750 MasterLoader::MasterLoaderImpl::doGenerate() {
754 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
755 "Invalid $GENERATE syntax");
758 const std::string range = range_token.getString();
763 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
764 "Invalid $GENERATE syntax");
767 const std::string lhs = lhs_token.getString();
779 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
780 "Invalid $GENERATE syntax");
784 bool explicit_ttl =
false;
785 const RRType rrtype = parseRRParams(explicit_ttl, param_token);
792 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
793 "Invalid $GENERATE syntax");
796 const std::string rhs = rhs_token.getString();
805 const int n = sscanf(range.c_str(),
"%u-%u/%u", &start, &stop, &step);
806 if ((n < 2) || (stop < start)) {
807 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
808 "$GENERATE: invalid range: " + range);
817 for (
unsigned int i = start; i <= stop; i += step) {
820 const std::string generated_name = generateForIter(lhs, i);
821 const std::string generated_rdata = generateForIter(rhs, i);
822 if (generated_name.empty() || generated_rdata.empty()) {
825 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
836 (
new Name(Name(generated_name).concatenate(active_origin_)));
837 previous_name_ =
true;
845 add_callback_(*last_name_, zone_class_, rrtype,
846 getCurrentTTL(explicit_ttl, rrtype, rdata),
857 isc_throw(MasterLoaderError,
"Invalid RR data");
864 MasterLoader::MasterLoaderImpl::handleInitialToken() {
865 const MasterToken& initial_token =
871 const MasterToken& next_token = lexer_.getNextToken();
881 if (last_name_.get() == NULL) {
882 isc_throw(InternalException,
"No previous name to use in "
883 "place of initial whitespace");
884 }
else if (!previous_name_) {
885 callbacks_.warning(lexer_.getSourceName(), lexer_.getSourceLine(),
886 "Owner name omitted around $INCLUDE, the result "
887 "might not be as expected");
893 const MasterToken::StringRegion&
894 name_string(initial_token.getStringRegion());
896 if (name_string.len > 0 && name_string.beg[0] ==
'$') {
902 handleDirective(name_string.beg + 1, name_string.len - 1);
910 last_name_.reset(
new Name(name_string.beg, name_string.len,
912 previous_name_ =
true;
916 switch (initial_token.getType()) {
919 return (initial_token);
928 return (initial_token);
931 isc_throw(InternalException, initial_token.getErrorText());
934 isc_throw(InternalException,
"Parser got confused (unexpected "
935 "token " << initial_token.getType() <<
")");
941 if (count_limit == 0) {
946 "Trying to load when already loaded");
949 pushSource(master_file_, active_origin_);
952 while (ok_ && count < count_limit) {
954 const MasterToken next_token = handleInitialToken();
964 bool explicit_ttl =
false;
965 const RRType rrtype = parseRRParams(explicit_ttl, next_token);
970 &active_origin_, options_, callbacks_);
977 add_callback_(*last_name_, zone_class_, rrtype,
978 getCurrentTTL(explicit_ttl, rrtype, rdata),
994 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
998 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
1002 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
1005 }
catch (
const InternalException& e) {
1006 reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
1016 const Name& zone_origin,
1022 if (!add_callback) {
1026 zone_class, callbacks, add_callback, options);
1030 const Name& zone_origin,
1036 if (!add_callback) {
1039 unique_ptr<MasterLoaderImpl>
1041 callbacks, add_callback, options));
1043 impl_ = impl.release();
The Name class encapsulates DNS names.
MasterLoaderImpl(const char *master_file, const Name &zone_origin, const RRClass &zone_class, const MasterLoaderCallbacks &callbacks, const AddRRCallback &add_callback, MasterLoader::Options options)
Constructor.
static const RRTTL & MAX_TTL()
The TTL of the max allowable value, per RFC2181 Section 8.
bool pushSource(const char *filename, std::string *error=NULL)
Open a file and make it the current input source of MasterLexer.
Base class for all sorts of text parse errors.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
size_t getSourceLine() const
Return the input source line number.
static const RRType & SOA()
boost::shared_ptr< const Rdata > ConstRdataPtr
Error detected in getting a token.
size_t getPosition() const
Return the position of lexer in the pushed sources so far.
Exception thrown from a wrapper version of MasterLexer::getNextToken() for non fatal errors...
Private implementation class for the MasterLoader.
bool loadedSuccessfully() const
Was the loading successful?
RdataPtr createRdata(const RRType &rrtype, const RRClass &rrclass, const std::string &rdata_string)
Create RDATA of a given pair of RR type and class from a string.
size_t getSize() const
Return the total size of the zone files and streams.
static RRClass * createFromText(const std::string &class_str)
A separate factory of RRClass from text.
The RRClass class encapsulates DNS resource record classes.
void warning(const std::string &source_name, size_t source_line, const std::string &reason) const
Call callback for potential problems.
Options
Options how the parsing should work.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
White spaces at the beginning of a line after an end of line or at the beginning of file (if asked...
void uppercase(std::string &text)
Uppercase String.
bool loadIncremental(size_t count_limit)
Implementation of MasterLoader::loadIncremental()
recognize begin-of-line spaces after an end-of-line
A single string quoted by double-quotes (").
size_t getSize() const
Return the total size of the input sources pushed so far.
Exception thrown when we fail to read from the input stream or file.
std::string getSourceName() const
Return the name of the current input source name.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
const MasterToken & getNextToken(Options options=NONE)
Parse and return another token from the input.
void popSource()
Stop using the most recently opened input source (file or stream).
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-dhcp-ddns.
size_t getTotalSourceSize() const
Return the total size of pushed sources.
static RRTTL * createFromText(const std::string &ttlstr)
A separate factory of RRTTL from text.
void ungetToken()
Return the last token back to the lexer.
size_t getPosition() const
Return the position of the loader in zone.
Error while loading by MasterLoader without specifying the MANY_ERRORS option.
The RRType class encapsulates DNS resource record types.
A generic exception that is thrown if a function is called in a prohibited way.
size_t getSourceCount() const
Get number of sources inside the lexer.
size_t getPosition() const
Return the line number being parsed in the pushed input sources.
Type getType() const
Return the token type.
bool loadIncremental(size_t count_limit)
Load some RRs.
MasterLoader(const char *master_file, const Name &zone_origin, const RRClass &zone_class, const MasterLoaderCallbacks &callbacks, const AddRRCallback &add_callback, Options options=DEFAULT)
Constructor.
std::string getString() const
Return the value of a string-variant token as a string object.
Lenient mode (see documentation of MasterLoader constructor).
void pushSource(const std::string &filename, const Name ¤t_origin)
Wrapper around MasterLexer::pushSource() (file version)
std::function< void(const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &rrttl, const rdata::RdataPtr &rdata)> AddRRCallback
Type of callback to add a RR.
Set of issue callbacks for a loader.
boost::shared_ptr< Rdata > RdataPtr
The RdataPtr type is a pointer-like type, pointing to an object of some concrete derived class of Rda...
void pushStreamSource(std::istream &stream)
Wrapper around MasterLexer::pushSource() (stream version)
std::string format(const std::string &format, const std::vector< std::string > &args)
Apply Formatting.
void error(const std::string &source_name, size_t source_line, const std::string &reason) const
Call callback for serious errors.
~MasterLoader()
Destructor.