Net::DNS::SEC::Tools::Donuts::Rule(3) Define donuts DNS record-checking rules


This class wraps around a rule definition which is used by the donuts DNS zone file checker. It stores the data that implements a given rule.

Rules are defined in donuts rule configuration files using the following syntax. See the donuts manual page for details on where to place those files and how to load them.


Each rule file can contain multiple rules. Each rule is composed of a number of parts. Minimally, it must contain a name and a test portion. Everything else is optional and/or has defaults associated with it. The rule file format follows this example:

  name: rulename
  class: Warning
    my ($record) = @_;
    return "problem found"
      if ($record{xxx} != yyy);

Further details about each section can be found below. Besides the tokens below, other rule-specific data can be stored in tokens and each rule is a hash of the above tokens as keys and their associated data. However, there are a few exceptions where special tokens imply special meanings. These special tokens include test and init. See below for details.

Each rule definition within a file should be separated using a blank line.

Lines beginning with the '#' character will be discarded as a comment.

The name of the rule. This is mandatory, as the user may need to refer to names in the future for use with the -i flag, specifying behavior in configuration files, and for other uses.

By convention, all names should be specified using capital letters and '_' characters between the words. The leftmost word should give an indication of a global test category, such as ``DNSSEC''. The better-named the rules, the more power the user will have for selecting certain types of rules via donuts -i and other flags.


The rule's execution level, as recognized by donuts. donuts will run only those rules at or above donuts' current execution level. The execution level is specified by the -l option to donuts; if not given, then the default execution level is 5.

The default level of every rule is 5.

Generally, more serious problems should receive lower numbers and less serious problems should be placed at a higher number. The maximum value is 9, which is reserved for debugging rules only. 8 is the maximum rule level that user-defined rules should use.


  level: 2
The class code indicates the type of problem associated with the rule. It defaults to "Error``, and the only other value that should be used is ''Warning".

This value is displayed to the user. Technically, any value could be specified, but using anything other than the Error/Warning convention could break portability in future versions.

 class: Warning

Rules fall into one of two types (currently): record or name. record rules have their test section evaluated for each record in a zone file. name rules, on the other hand, get called once per record name stored in the database. See the test description below for further details on the arguments passed to each rule type.

The default value for this clause is record.


  ruletype: record
Rules that test a particular type of record should specify the type field with the type of record it will test. The rule will only be executed for records of that type.

For example, if a rule is testing a particular aspect of an MX record, it should specify ``MX'' in this field.


  type: MX
A block of code to be executed immediately as the rule is being parsed from the rule definition file. This is useful for boot-strap code to be performed only at start-up. For example, perl "use MODULE::NAME;" or similar statements should be used in init sections.

init sections are wrapped in an XML-like syntax which specifies the start and end of the init section of code.


    use My::Module;
    $value = calculate();
A block of code defining the test to be executed for each record or record name. The test statement follows the same multi-line code specification described in the init clause above. Specifically, all the lines between the <test> and </test> braces are considered part of the test code.

The test contents must be a block of perl code. If it is not in the form of an anonymous subroutine (surrounded by ``sub {'' and ``}'' markers), then the code will be automatically put inside a basic subroutine block to turn it into an anonymous subroutine.

EG, the resulting code for a record test will look like this:

  package main;
  no strict;
    my ($record, $rule) = @_;  

And for name test will be:

  package main;
  no strict;
    my ($records, $rule, $recordname) = @_;  

(Again, this structure is only created if the test definition does notb begin with ``sub {'' already)

When the testcode is run and the test fails, it should return an error string which will be displayed for the user. The text will be line-wrapped before display (and thus should be unformatted text.) If the test is checking for multiple problems, a reference to an array of error strings may be returned. A test block that has no errors to report should return either an empty string or a reference to an empty array.

There are two types of tests (currently), and the test code is called with arguments that depend on the ruletype clause of the rule. These arguments and calling conventions are as follows:

record tests
These code snippets are expected to test a single Net::DNS::RR record.

It is called with two arguments:

  1) $record: The record which is to be tested
  2) $recordname: The Net::DNS::SEC::Tools::Donuts::Rule object
     reference and rule definition information.

These are bound to $record and $rule automatically for the test code to use.

name tests
These code snippets are expected to test all the records associated with a given name record.

It is called with three arguments:

  1) $records: A hash reference to all the record types associated
     with that record name (e.g., '' might have a hash
     reference containing an entry for 'A', 'MX', ...).  Each value of
     the hash will contain an array of all the records for that type
     (for example, the hash entry for the 'A' key may contain an array
     with 2 Net::DNS::RR records, one for each A record attached to
     the '' entry).
  2) $rule: The Net::DNS::SEC::Tools::Donuts::Rule object reference
     and rule definition information.
  3) $recordname: The record name being checked (the name associated
     with the data from 1) above which might be "" for
     instance, or "">).

These are bound to $records, $rule and $recordname automatically for the test code to use.

Example rules:

  # local rule to mandate that each record must have a
  # TTL > 60 seconds
  name: DNS_TTL_AT_LEAST_60
  level: 8
  type: record
    return "TTL for $record->{name} is too small" if ($record->ttl < 60);
  # local policy rule to mandate that anything with an A record
  # must have an HINFO record too
  level: 8
  type: name
    return "$recordname has an A record but does not have an HINFO record"
      if (exists($records->{'A'}) && !exists($records->{'HINFO'}));
feature: NAME
The feature tag prevents this rule from running unless the NAME keyword was specified using the --features flag.
A short description of what the rule tests that will be printed to the user in help output or in the error summary when donuts outputs the results.
This allows rules to depend on installed perl modules. They'll be required and imported as the rule starts executing. If they don't exist, an error will be logged using donuts_error() stating that the module is required for that rule to work.
If the rule is configurable via the user's .donuts.conf file, this describes the configuration tokens for the user when they request configuration help via the -H or --help-config flags. Tokens may be used within rules by accessing them using the $rule reference passed to the code (the second argument).


  1) In the rule file (this is an incomplete rule definition):
     name:           SOME_TEST
     myconfig:       40
     help: myconfig: A special number to configure this test
      # ... use $rule->{'myconfig'}
  2) This allows the user to change the value of myconfig via their
     .donuts.conf file:
     # change SOME_TEST config...
     name:     SOME_TEST
     myconfig: 40
  3) and running donuts -H will show the help line for myconfig.
noindent: 1
nowrap: 1
Normally donuts will line-wrap the error summary produced by a rule to enable automatic pretty-printing of error results. Sometimes, however, rules may wish to self-format their outputs. The nowrap option indicates to donuts that the output is pre-formatted but should still be indented to align with the output of the rest of the error text (currently about 15 spaces.) The noindent tag, however, indicates that neither wrapping nor indenting should be performed, but that the error should be printed as is.


Copyright 2004-2013 SPARTA, Inc. All rights reserved. See the COPYING file included with the DNSSEC-Tools package for details.


Wes Hardaker <[email protected]>