[net-dns-users] List of API changes in versions after 0.68?

Willem Toorop willem at nlnetlabs.nl
Wed Dec 19 09:39:58 UTC 2012

Hi Calle,

I have tried to make such an overview (with Dick, for internal
communication and archival purposes). It is not complete, but I believe
it gives a good overview of the architectural choices with their
argumentation and the accountability towards breaking backwards
compatibility. I have it attached.

I hope it can help you.
The 0.69-0.71 releases have lead to a few good resolutions:
* More releases with fewer changes
* Better interaction with maintainers of other packages that critically
depend on Net::DNS (this list is a result)

I intend to post about future release candidates (developer releases) on
this list to let you all evaluate a new release and give feedback.
I also intent to inventory the packages using Net::DNS and attend them
to the list.

Best regards,

-- Willem

Op 19-12-12 08:40, Calle Dybedahl schreef:
> Hi there.
> Is there a list somewhere of all the API changes in post-0.68 versions of Net::DNS? I've noticed two of them (what Net::DNS::RR::SOA->rname returns changed, and Net::DNS::RR->new($string) throws an exception instead of returning undef on failure), since they made our unit tests fail. I see here on the list that John Kristoff happened onto another (header count values aren't settable any longer). Which raises the suspicion that there are more of them.
> Is there a list somewhere of all API changes? There is a Changes file, but as far as I can see none of the three changes above are mentioned in it. The diff between releases 0.68 and 0.71 is almost 35000 lines, so reading that is not really viable.
> Note that I'm not arguing against any of the changes, I just want to know what they are, so I can adjust our code if necessary.

-------------- next part --------------

Architectural changes

Resource record template

Resource record interface is implemented using the following functions
to facilitate conversions to and from string and wire format:

 ? decode_rdata  ## decode rdata from wire?format byte string
 ? encode_rdata  ## encode rdata as wire?format byte string
 ? format_rdata  ## format rdata portion of RR string
 ? parse_rdata   ## parse RR attributes in argument list

Some of these functions may be omitted, the interface model then being
completed by default implementations inherited from the RR base type.
These functions loosely replace the previously required new, rr_rdata,
new_from_string and rdatastr functions.

If all interface functions are omitted, the RR is an unknown RRTYPE with
implementation defined by RFC3597.

The new functions provide (much clearer) separation of concerns. Note
that in the old architecture, all RRs should be constructed via
Net::DNS::RR::new() and new_from_string() functions of the type?specific
subclass, which were not intended to be called directly.

Additionally the functions _normalize_dnames and _canonicalRdata are no
longer needed as they are now handled by the classes implementing the
owner name and domain name rdata fields.

Default values for rdata fields may be set with the optional defaults()
function.  This was provided for completeness, and intended to offer
convenience when creating a new RR from a hash specification.

** Consequences

RR.pm currently contains a compatibility layer which implements the
"old" interface as methods which are inherited by the "new" architecture
RR subtype modules.  The compatibility layer is controlled by a
configuration constant COMPATIBLE, which switches between the two RR
subtype interfaces. This provides a useful method of testing if the
transition plan actually works.

There is no well defined relationship between releases of Net::DNS and
Net::DNS::SEC, so one possible migration scenario would be to operate
Net::DNS in compatible mode for some number of revisions.  This will
allow Net?DNS?SEC?0.16 and earlier to continue operating. Net?DNS?
SEC?0.17 and later versions could then be implemented using the "new"
interface, and operated using compatibility mode until such time as it
is deemed appropriate to turn it off (when 0.16 becomes too old to use).

Note that RRSIGs for wildcards, a feature that is in Net?DNS?SEC from
the subversion trunk only and not in the releases, does not currently
work with the new architecture.
[I have only tested against 0.16, being the latest release ? RWF]

Resource record owner names

RR owner names are represented internally by Net::DNS::DomainName1035
(compressible domain name) objects.  This makes it possible, when
Net::LibIDN is available, to construct RRs with Unicode owner names
which will be represented in IDN A?label format.

** Consequences:

This has no impact on backwards compatibility as the user only has
access to Perl native strings.  Conversions between character encodings
occur (conceptually at least) somewhere close to the wire.  You need to
be aware that domain labels are stored in wire?format, which minimises
the total number of conversions for the core functionality of resolving
domain names.  Other uses, zone file parsing and pretty printing for
example, incur less favourable treatment, with two conversions where
none might be expected.

Resource record rdata domain name fields

RDATA domain names are represented internally by Net::DNS::DomainName
objects. This makes it possible, when Net::LibIDN is available, to
construct RDATA containing Unicode domain names which will be
represented in IDN A?label format.

RR subtype modules which are subject to compression and/or downcasing
requirements are implemented using Net::DNS::DomainName1035 and
Net::DNS::DomainName2535 objects which specialise the base type by the
substitution of a new encode() method.  The list of modules affected
appears in RFC3597 as amended.

Canonicalisation of RR wire?format data is implemented by calling the RR
subtype encode() method with an undefined value instead of the reference
to the name compression hash.

(Dick, for creating and verifying RRSIGs?)  Yes, at least to the extent
tested by Net::DNS::SEC test suite.

** Consequences:

This has no impact on backwards compatibility as the user only has
access to Perl native strings.

Resource records with rdata fields containing text

Rdata fields containing text are represented internally by
Net::DNS::Text objects. This allows text rdata fields to be constructed
using the full Unicode character set.

Affected rdata fields are: HINFO?>cpu, HINFO?>os, NAPTR?>flags,
NAPTR?>service, NAPTR?>regexp and TXT?>txtdata.  Of these, TXT is the
only RR where Unicode text is likely to be used.

** Consequences:

The relevent RFCs define text to be encoded on the wire using ASCII,
which is a proper subset of the UTF8 encoding used by the Text module.
The interpretation of non?ASCII character codes has never been defined,
and presumably never (ab)used.  There is therefore no impact on
backwards compatibility.

Text rdata fields will return a standard Perl string using the internal
encoding appropriate for the platform.  Characters which cannot
otherwise be represented will be expressed as RFC1035 numeric escape

Resource records with rdata fields containing mailboxes

Mailboxes rdata fields are represented internally by Net::DNS::Mailbox
objects and can now be constructed with the mailbox name in RFC822
format; i.e. user at domain or name<user at domain>.

Affected rdata fields are: MINFO?>rmailbx, MINFO?>emailbx, RP?>mbox and

RFC1035 defines the encoding method to be used for mail addresses and
therefore responsibility for such encoding/decoding should lie with
Net::DNS and not be devolved to the user.

** Consequences:

Those rdata fields will now return the email box in RFC822 format. This
is a difference that we are willing to accept because of the enrichment
it provides for the type. The "old" encoded form is also accepted when
modifying these fields.

The packet header incorporates EDNS0

Header extensions provided by the EDNS0 OPT resource record are now
accessible transparently through the $packet?>header interface.  This
includes the DO flag, extended response codes and UDP packet size.

Directly accessing opt?>class or opt?>ttl functions now triggers a
warning (once) advising the use of the appropriate function instead.

** Consequences:

Net::DNS::Header now needs to be associated with a Net::DNS::Packet and
must not be constructed independently any more.  The quantity attributes
qdcount, ancount, nscount and arcount (or their dynamic update
counterparts) now return the number of RRs in the addressed section. As
a consequence they can not be set directly.

For a decoded packet, the counter value is derived from the packet
header and may differ from the actual number of RRs in the corresponding
section if a decoding error occurred.  However, for a newly constructed
packet, the header count reflects the current length of the section.

DNS parameters in separate module

The DNS parameters are now also provided in a separate module
Net::DNS::Parameters. This file will (in the future) automatically be
generated from the authoritative resource at IANA:

Net::DNS internally uses Net::DNS::Parameters for all dns parameters,
but they are also still present in DNS.pm for backwards compatibility.

This change also removes the circularities present in the module
dependency "tree" which results in unnecessary multiple compilation of
some modules.  It now really _is_ a tree.

** Consequences:

The name of opcode 4 is altered from NS_NOTIFY_OP to NOTIFY.  This pulls
the code into line with the opcode registry but will break backwards

Dick, Should we change this back and put it on the wish list for a more
major version update?
No, I think not; we should regard the IANA registry as the definitive
source of mnemonics. As this occurs in both forward and reverse tables,
there is no backward compatibility workaround that will please everyone.
Users are likely to respond positively if we are seen to be tying
ourselves to published standards which will offer them long?term
stability albeit incurring a small one?off inconvenience.  We are very
lucky that this appears to be the only inconsistent mnemonic.

Packet decoding errors

Packet decoding errors are now collected in the $@ ($EVAL_ERROR)
variable. Before the error message was returned in the second item of
the array returned when construction a Net::DNS::Packet in array
context. Now that second argument contains the number of octets
successfully decoded.

This makes packet decoding more robust and gives more refined control
over the decoding process (by returning a pointer to potentially
uninterpreted data).

** Consequences:

We believe it is safe because requesting an error message before also
required a test for the returned packet to be defined (i.e. not undef).
This behaviour is backwards compatible. The only thing different is the
error message which is now in $@. In the worst case a number will be
printed as an error message.  Exception-based error handling schemes
can now be supported simply by adding 'die if $@' to propagate the

The entire packet is now decoded immediately; the previous deferred
decoding scheme has been abandoned. As a consequence, no exceptions
will be raised for decoding errors during calls to the packet->answer
and similar methods.

This was a design response to the problem of determining the length of a
decoded packet encountered by Mark Andrews.

Upgradable aplists in APL RRs

APL RRs now allow for gradually appending (negate,family)address/prefix

** Consequences:

Net::DNS::RR::APL::ApItem is replaced with Net::DNS::RR::APL::Item that
cannot be constructed independently. It is unlikely (and not the
intention) that people ever used  Net::DNS::RR::APL::ApItem directly.
Therefore we believe it is safe.

More information about the net-dns-users mailing list