// Copyright (C) 2010 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 __MASTERLOAD_H #define __MASTERLOAD_H 1 #include #include #include #include namespace isc { namespace dns { class Name; class RRClass; /// \brief An exception that is thrown if an error occurs while loading a /// master zone data. class MasterLoadError : public isc::Exception { public: MasterLoadError(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) {} }; /// The type of the \c callback parameter of \c masterLoad(). /// /// This represents a functor object or a function that takes one parameter /// of type \c RRsetPtr and returns nothing. typedef boost::function MasterLoadCallback; /// /// \name Master zone file loader functions. /// //@{ /// Master zone file loader from a file. /// /// This function parses a given file as a master DNS zone file for /// the given origin name and RR class, constructs a sequence of \c RRset /// from the RRs containing in the file, and calls the given \c callback /// functor object or function with each \c RRset. /// /// The \c callback parameter is a functor object or a function that /// takes one parameter of type \c RRsetPtr and returns nothing, /// i.e. \c void (see below for specific examples). /// More precisely, it can be anything that this form of boost::function /// can represent, but the caller normally doesn't have to care about /// that level of details. /// /// The ownership of constructed RRsets is transferred to the callback /// and this function never uses it once it is called. /// The callback can freely modify the passed \c RRset. /// /// This function performs minimum level of validation on the input: /// - Each RR is a valid textual representation per the DNS protocol. /// - The class of each RR must be identical to the specified RR class. /// - The owner name of each RR must be a subdomain of the origin name /// (that can be equal to the origin). /// - If an SOA RR is included, its owner name must be the origin name. /// If any of these validation checks fails, this function throws an /// exception of class \c MasterLoadError. /// /// It does not perform other semantical checks, however. For example, /// it doesn't check if an NS RR of the origin name is included or if /// there is more than one SOA RR. Such further checks are the caller's /// (or the callback's) responsibility. /// /// Acceptable Format /// /// The current implementation only supports a restricted form of master files /// for simplicity. One easy way to ensure that a handwritten zone file is /// acceptable to this implementation is to preprocess it with BIND 9's /// named-compilezone tool with both the input and output formats being /// "text". /// Here is an example: /// \code % named-compilezone -f text -F text -o example.com.norm /// example.com example.com.zone /// \endcode /// where example.com.zone is the original zone file for the "example.com" /// zone. The output file is example.com.norm, which should be acceptable /// by this implementation. /// /// Below are specific restrictions that this implementation assumes. /// Basically, each RR must consist of exactly one line /// (so there shouldn't be a multi-line RR) in the following format: /// \code /// \endcode /// Here are some more details about the restrictions: /// - No special directives such as $TTL are supported. /// - The owner name must be absolute, that is, it must end with a period. /// - "@" is not recognized as a valid owner name. /// - Owner names, TTL and RRCLASS cannot be omitted. /// - As a corollary, a non blank line must not begin with a space character. /// - The order of the RR parameters is fixed, for example, this is acceptable: /// \code example.com. 3600 IN A 192.0.2.1 /// \endcode /// but this is not even though it's valid per RFC1035: /// \code example.com. IN 3600 A 192.0.2.1 /// \endcode /// - "TTL", "RRCLASS", and "RRTYPE" must be recognizable by the \c RRTTL, /// RRClass and RRType class implementations of this library. In particular, /// as of this writing TTL must be a decimal number (a convenient extension /// such as "1H" instead of 3600 cannot be used). Not all standard RR /// classes and RR types are supported yet, so the mnemonics of them will /// be rejected, too. /// - RR TTLs of the same RRset must be the same; even if they are different, /// this implementation simply uses the TTL of the first RR. /// /// Blank lines and lines beginning with a semi-colon are allowed, and will /// be simply ignored. Comments cannot coexist with an RR line, however. /// For example, this will be rejected: /// \code example.com. 3600 IN A 192.0.2.1 ; this is a comment /// \endcode /// /// This implementation assumes that RRs of a single RRset are not /// interleaved with RRs of a different RRset. /// That is, the following sequence shouldn't happen: /// \code example.com. 3600 IN A 192.0.2.1 /// example.com. 3600 IN AAAA 2001:db8::1 /// example.com. 3600 IN A 192.0.2.2 /// \endcode /// But it does not consider this an error; it will simply regard each RR /// as a separate RRset and call the callback with them separately. /// It is up to the callback to merge multiple RRsets into one if possible /// and necessary. /// /// Exceptions /// /// This function throws an exception of class \c MasterLoadError in the /// following cases: /// - Any of the validation checks fails (see the class description). /// - The input data is not in the acceptable format (see the details of /// the format above). /// - The specified file cannot be opened for loading. /// - An I/O error occurs during the loading. /// /// In addition, this function requires resource allocation for parsing and /// constructing RRsets. If it fails, the corresponding standard exception /// will be thrown. /// /// The callback may throw its own function. This function doesn't catch it /// and will simply propagate it towards the caller. /// /// Usage Examples /// /// A simplest example usage of this function would be to parse a zone /// file and (after validation) dump the content to the standard output. /// This is an example functor object and a call to \c masterLoad /// that implements this scenario: /// \code struct ZoneDumper { /// void operator()(ConstRRsetPtr rrset) const { /// std::cout << *rrset; /// } /// }; /// ... /// masterLoad(zone_file, Name("example.com"), RRClass::IN(), ZoneDumper()); /// \endcode /// Alternatively, you can use a normal function instead of a functor: /// \code void zoneDumper(ConstRRsetPtr rrset) { /// std::cout << *rrset; /// } /// ... /// masterLoad(zone_file, Name("example.com"), RRClass::IN(), zoneDumper); /// \endcode /// Or, if you want to use it with a member function of some other class, /// wrapping things with \c boost::bind would be handy: /// \code class ZoneDumper { /// public: /// void dump(ConstRRsetPtr rrset) const { /// std::cout << *rrset; /// } /// }; /// ... /// ZoneDumper dumper; /// masterLoad(rr_stream, Name("example.com"), RRClass::IN(), /// boost::bind(&ZoneDumper::dump, &dumper, _1)); /// \endcode /// You can find a bit more complicated examples in the unit tests code for /// this function. /// /// Implementation Notes /// /// The current implementation is in a preliminary level and needs further /// extensions. Some design decisions may also have to be reconsidered as /// we gain experiences. Those include: /// - We should be more flexible about the input format. /// - We may want to allow optional conditions. For example, we may want to /// be generous about some validation failures and be able to continue /// parsing. /// - Especially if we allow to be generous, we may also want to support /// returning an error code instead of throwing an exception when we /// encounter validation failure. /// - We may want to support incremental loading. /// - If we add these optional features we may want to introduce a class /// that encapsulates loading status and options. /// - RRSIGs are handled as separate RRsets, i.e. they are not included in /// the RRset they cover. /// /// \param filename A path to a master zone file to be loaded. /// \param origin The origin name of the zone. /// \param zone_class The RR class of the zone. /// \param callback A callback functor or function that is to be called /// for each RRset. void masterLoad(const char* const filename, const Name& origin, const RRClass& zone_class, MasterLoadCallback callback); /// Master zone file loader from input stream. /// /// This function is same as the other version /// (\c masterLoad(const char* const, const Name&, const RRClass&, MasterLoadCallback)) /// except that it takes a \c std::istream instead of a file. /// It extracts lines from the stream and handles each line just as a line /// of a file for the other version of function. /// All descriptions of the other version apply to this version except those /// specific to file I/O. /// /// \param input An input stream object that is to emit zone's RRs. /// \param origin The origin name of the zone. /// \param zone_class The RR class of the zone. /// \param callback A callback functor or function that is to be called for /// each RRset. void masterLoad(std::istream& input, const Name& origin, const RRClass& zone_class, MasterLoadCallback callback); } //@} } #endif // __MASTERLOAD_H // Local Variables: // mode: c++ // End: