File Coverage

blib/lib/Net/DNS/Parameters.pm
Criterion Covered Total %
statement 57 57 100.0
branch 16 16 100.0
path n/a
condition 16 16 100.0
subroutine 19 19 100.0
pod 12 12 100.0
total 120 120 100.0


line stmt bran path cond sub pod time code
1               package Net::DNS::Parameters;
2                
3               ################################################
4               ##
5               ## Domain Name System (DNS) Parameters
6               ## (last updated 2026-04-28)
7               ##
8               ################################################
9                
10 98       98   120976 use strict;
  98           164  
  98           3096  
11 98       98   354 use warnings;
  98           134  
  98           6038  
12               our $VERSION = (qw$Id: Parameters.pm 2046 2026-06-01 13:23:01Z willem $)[2];
13                
14 98       98   1125 use integer;
  98           152  
  98           472  
15 98       98   2043 use Carp;
  98           147  
  98           6379  
16                
17 98       98   554 use base qw(Exporter);
  98           168  
  98           188064  
18                
19               our @EXPORT_OK = qw(
20               classbyname classbyval %classbyname
21               typebyname typebyval %typebyname
22               opcodebyname opcodebyval
23               rcodebyname rcodebyval
24               ednsoptionbyname ednsoptionbyval
25               dsotypebyname dsotypebyval
26               );
27                
28               our %EXPORT_TAGS = (
29               class => [qw(classbyname classbyval)],
30               type => [qw(typebyname typebyval)],
31               opcode => [qw(opcodebyname opcodebyval)],
32               rcode => [qw(rcodebyname rcodebyval)],
33               ednsoption => [qw(ednsoptionbyname ednsoptionbyval)],
34               dsotype => [qw(dsotypebyname dsotypebyval)],
35               );
36                
37                
38               # Registry: DNS CLASSes
39               my @classbyname = (
40               IN => 1, # RFC1035
41               CH => 3, # Chaosnet
42               HS => 4, # Hesiod
43               NONE => 254, # RFC2136
44               ANY => 255, # RFC1035
45               );
46               our %classbyval = reverse( CLASS0 => 0, @classbyname );
47               push @classbyname, map { /^\d/ ? $_ : lc($_) } @classbyname;
48               our %classbyname = ( '*' => 255, @classbyname );
49                
50                
51               # Registry: Resource Record (RR) TYPEs
52               my @typebyname = (
53               DELEG => 65432, # draft-ietf-deleg-02
54               DELEG => 61440, # draft-ietf-deleg-03
55               DELEGPARAM => 65433, # draft-ietf-deleg-07
56               DELEGI => 65433, # draft-ietf-deleg-03
57               A => 1, # RFC1035
58               NS => 2, # RFC1035
59               MD => 3, # RFC1035
60               MF => 4, # RFC1035
61               CNAME => 5, # RFC1035
62               SOA => 6, # RFC1035
63               MB => 7, # RFC1035
64               MG => 8, # RFC1035
65               MR => 9, # RFC1035
66               NULL => 10, # RFC1035
67               WKS => 11, # RFC1035
68               PTR => 12, # RFC1035
69               HINFO => 13, # RFC1035
70               MINFO => 14, # RFC1035
71               MX => 15, # RFC1035
72               TXT => 16, # RFC1035
73               RP => 17, # RFC1183
74               AFSDB => 18, # RFC1183 RFC5864
75               X25 => 19, # RFC1183
76               ISDN => 20, # RFC1183
77               RT => 21, # RFC1183
78               NSAP => 22, # RFC1706 https://datatracker.ietf.org/doc/status-change-int-tlds-to-historic
79               'NSAP-PTR' => 23, # RFC1706 https://datatracker.ietf.org/doc/status-change-int-tlds-to-historic
80               SIG => 24, # RFC2536 RFC2931 RFC3110 RFC4034
81               KEY => 25, # RFC2536 RFC2539 RFC3110 RFC4034
82               PX => 26, # RFC2163
83               GPOS => 27, # RFC1712
84               AAAA => 28, # RFC3596
85               LOC => 29, # RFC1876
86               NXT => 30, # RFC2535 RFC3755
87               EID => 31, # http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt
88               NIMLOC => 32, # http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt
89               SRV => 33, # RFC2782
90               ATMA => 34, # http://www.broadband-forum.org/ftp/pub/approved-specs/af-dans-0152.000.pdf
91               NAPTR => 35, # RFC3403
92               KX => 36, # RFC2230
93               CERT => 37, # RFC4398
94               A6 => 38, # RFC2874 RFC3226 RFC6563
95               DNAME => 39, # RFC6672
96               SINK => 40, # draft-eastlake-kitchen-sink-02
97               OPT => 41, # RFC3225 RFC6891
98               APL => 42, # RFC3123
99               DS => 43, # RFC4034
100               SSHFP => 44, # RFC4255
101               IPSECKEY => 45, # RFC4025
102               RRSIG => 46, # RFC4034
103               NSEC => 47, # RFC4034 RFC9077
104               DNSKEY => 48, # RFC4034
105               DHCID => 49, # RFC4701
106               NSEC3 => 50, # RFC5155 RFC9077
107               NSEC3PARAM => 51, # RFC5155
108               TLSA => 52, # RFC6698
109               SMIMEA => 53, # RFC8162
110               HIP => 55, # RFC8005
111               NINFO => 56, #
112               RKEY => 57, #
113               TALINK => 58, #
114               CDS => 59, # RFC7344
115               CDNSKEY => 60, # RFC7344
116               OPENPGPKEY => 61, # RFC7929
117               CSYNC => 62, # RFC7477
118               ZONEMD => 63, # RFC8976
119               SVCB => 64, # RFC9460
120               HTTPS => 65, # RFC9460
121               DSYNC => 66, # RFC9859
122               HHIT => 67, # RFC9886
123               BRID => 68, # RFC9886
124               SPF => 99, # RFC7208
125               UINFO => 100, # IANA-Reserved
126               UID => 101, # IANA-Reserved
127               GID => 102, # IANA-Reserved
128               UNSPEC => 103, # IANA-Reserved
129               NID => 104, # RFC6742
130               L32 => 105, # RFC6742
131               L64 => 106, # RFC6742
132               LP => 107, # RFC6742
133               EUI48 => 108, # RFC7043
134               EUI64 => 109, # RFC7043
135               NXNAME => 128, # RFC9824
136               TKEY => 249, # RFC2930
137               TSIG => 250, # RFC8945
138               IXFR => 251, # RFC1995
139               AXFR => 252, # RFC1035 RFC5936
140               MAILB => 253, # RFC1035
141               MAILA => 254, # RFC1035
142               ANY => 255, # RFC1035 RFC6895 RFC8482
143               URI => 256, # RFC7553
144               CAA => 257, # RFC8659
145               AVC => 258, #
146               DOA => 259, # draft-durand-doa-over-dns-02
147               AMTRELAY => 260, # RFC8777
148               RESINFO => 261, # RFC9606
149               WALLET => 262, #
150               CLA => 263, # draft-johnson-dns-ipn-cla-07
151               IPN => 264, # draft-johnson-dns-ipn-cla-07
152               TA => 32768, # http://www.watson.org/~weiler/INI1999-19.pdf
153               DLV => 32769, # RFC8749 RFC4431
154               );
155               our %typebyval = reverse( TYPE0 => 0, @typebyname );
156               push @typebyname, map { /^\d/ ? $_ : lc($_) } @typebyname;
157               our %typebyname = ( '*' => 255, @typebyname );
158                
159                
160               # Registry: DNS OpCodes
161               my @opcodebyname = (
162               QUERY => 0, # RFC1035
163               IQUERY => 1, # RFC3425
164               STATUS => 2, # RFC1035
165               NOTIFY => 4, # RFC1996
166               UPDATE => 5, # RFC2136
167               DSO => 6, # RFC8490
168               );
169               our %opcodebyval = reverse @opcodebyname;
170               push @opcodebyname, map { /^\d/ ? $_ : lc($_) } @opcodebyname;
171               our %opcodebyname = ( NS_NOTIFY_OP => 4, @opcodebyname );
172                
173                
174               # Registry: DNS RCODEs
175               my @rcodebyname = (
176               NOERROR => 0, # RFC1035
177               FORMERR => 1, # RFC1035
178               SERVFAIL => 2, # RFC1035
179               NXDOMAIN => 3, # RFC1035
180               NOTIMP => 4, # RFC1035
181               REFUSED => 5, # RFC1035
182               YXDOMAIN => 6, # RFC2136 RFC6672
183               YXRRSET => 7, # RFC2136
184               NXRRSET => 8, # RFC2136
185               NOTAUTH => 9, # RFC2136
186               NOTAUTH => 9, # RFC8945
187               NOTZONE => 10, # RFC2136
188               DSOTYPENI => 11, # RFC8490
189               BADVERS => 16, # RFC6891
190               BADSIG => 16, # RFC8945
191               BADKEY => 17, # RFC8945
192               BADTIME => 18, # RFC8945
193               BADMODE => 19, # RFC2930
194               BADNAME => 20, # RFC2930
195               BADALG => 21, # RFC2930
196               BADTRUNC => 22, # RFC8945
197               BADCOOKIE => 23, # RFC7873
198               );
199               our %rcodebyval = reverse( BADSIG => 16, @rcodebyname );
200               push @rcodebyname, map { /^\d/ ? $_ : lc($_) } @rcodebyname;
201               our %rcodebyname = @rcodebyname;
202                
203                
204               # Registry: DNS EDNS0 Option Codes (OPT)
205               my @ednsoptionbyname = (
206               LLQ => 1, # RFC8764
207               'UPDATE-LEASE' => 2, # RFC9664
208               NSID => 3, # RFC5001
209               DAU => 5, # RFC6975
210               DHU => 6, # RFC6975
211               N3U => 7, # RFC6975
212               'CLIENT-SUBNET' => 8, # RFC7871
213               EXPIRE => 9, # RFC7314
214               COOKIE => 10, # RFC7873
215               'TCP-KEEPALIVE' => 11, # RFC7828
216               PADDING => 12, # RFC7830
217               CHAIN => 13, # RFC7901
218               'KEY-TAG' => 14, # RFC8145
219               'EXTENDED-ERROR' => 15, # RFC8914
220               'CLIENT-TAG' => 16, # draft-bellis-dnsop-edns-tags-01
221               'SERVER-TAG' => 17, # draft-bellis-dnsop-edns-tags-01
222               'REPORT-CHANNEL' => 18, # RFC9567
223               ZONEVERSION => 19, # RFC9660
224               'MQTYPE-QUERY' => 20, # RFC-ietf-dnssd-multi-qtypes-14
225               'MQTYPE-RESPONSE' => 21, # RFC-ietf-dnssd-multi-qtypes-14
226               'EDE-EXTRA-TEXT-LANGUAGE' => 22, # draft-muks-dns-filtering-05
227               'FILTERING-CONTACT' => 23, # draft-muks-dns-filtering-05
228               'FILTERING-ORGANIZATION' => 24, # draft-muks-dns-filtering-05
229               'FILTERING-DB' => 25, # draft-muks-dns-filtering-05
230               'UMBRELLA-IDENT' => 20292, # https://developer.cisco.com/docs/cloud-security/#!integrating-network-devic
231               DEVICEID => 26946, # https://developer.cisco.com/docs/cloud-security/#!network-devices-getting-s
232               );
233               our %ednsoptionbyval = reverse @ednsoptionbyname;
234               push @ednsoptionbyname, map { /^\d/ ? $_ : lc($_) } @ednsoptionbyname;
235               our %ednsoptionbyname = @ednsoptionbyname;
236                
237                
238               # Registry: DNS Header Flags
239               my @dnsflagbyname = (
240               AA => 0x0400, # RFC1035
241               TC => 0x0200, # RFC1035
242               RD => 0x0100, # RFC1035
243               RA => 0x0080, # RFC1035
244               AD => 0x0020, # RFC4035 RFC6840
245               CD => 0x0010, # RFC4035 RFC6840
246               );
247               push @dnsflagbyname, map { /^\d/ ? $_ : lc($_) } @dnsflagbyname;
248               our %dnsflagbyname = @dnsflagbyname;
249                
250                
251               # Registry: EDNS Header Flags (16 bits)
252               my @ednsflagbyname = (
253               DO => 0x8000, # RFC4035 RFC3225 RFC6840
254               CO => 0x4000, # RFC9824
255               );
256               push @ednsflagbyname, map { /^\d/ ? $_ : lc($_) } @ednsflagbyname;
257               our %ednsflagbyname = @ednsflagbyname;
258                
259                
260               # Registry: DSO Type Codes
261               my @dsotypebyname = (
262               KEEPALIVE => 0x0001, # RFC8490
263               RETRYDELAY => 0x0002, # RFC8490
264               ENCRYPTIONPADDING => 0x0003, # RFC8490
265               SUBSCRIBE => 0x0040, # RFC8765
266               PUSH => 0x0041, # RFC8765
267               UNSUBSCRIBE => 0x0042, # RFC8765
268               RECONFIRM => 0x0043, # RFC8765
269               );
270               our %dsotypebyval = reverse @dsotypebyname;
271               push @dsotypebyname, map { /^\d/ ? $_ : lc($_) } @dsotypebyname;
272               our %dsotypebyname = @dsotypebyname;
273                
274                
275               # Registry: Extended DNS Error Codes
276               my @dnserrorbyval = (
277               0 => 'Other Error', # RFC8914
278               1 => 'Unsupported DNSKEY Algorithm', # RFC8914
279               2 => 'Unsupported DS Digest Type', # RFC8914
280               3 => 'Stale Answer', # RFC8914 RFC8767
281               4 => 'Forged Answer', # RFC8914
282               5 => 'DNSSEC Indeterminate', # RFC8914
283               6 => 'DNSSEC Bogus', # RFC8914
284               7 => 'Signature Expired', # RFC8914
285               8 => 'Signature Not Yet Valid', # RFC8914
286               9 => 'DNSKEY Missing', # RFC8914
287               10 => 'RRSIGs Missing', # RFC8914
288               11 => 'No Zone Key Bit Set', # RFC8914
289               12 => 'NSEC Missing', # RFC8914
290               13 => 'Cached Error', # RFC8914
291               14 => 'Not Ready', # RFC8914
292               15 => 'Blocked', # RFC8914
293               16 => 'Censored', # RFC8914
294               17 => 'Filtered', # RFC8914
295               18 => 'Prohibited', # RFC8914
296               19 => 'Stale NXDomain Answer', # RFC8914
297               20 => 'Not Authoritative', # RFC8914
298               21 => 'Not Supported', # RFC8914
299               22 => 'No Reachable Authority', # RFC8914
300               23 => 'Network Error', # RFC8914
301               24 => 'Invalid Data', # RFC8914
302               25 => 'Signature Expired before Valid', # https://github.com/NLnetLabs/unbound/pull/604#discussion_r802678343
303               26 => 'Too Early', # RFC9250
304               27 => 'Unsupported NSEC3 Iterations Value', # RFC9276
305               28 => 'Unable to conform to policy', # draft-homburg-dnsop-codcp-00
306               29 => 'Synthesized', # https://github.com/PowerDNS/pdns/pull/12334
307               30 => 'Invalid Query Type', # RFC9824
308               31 => 'Rate Limited', # draft-muks-dns-ede-rate-limited-02
309               32 => 'Over Quota', # draft-muks-dns-ede-rate-limited-02
310               );
311               our %dnserrorbyval = @dnserrorbyval;
312                
313                
314               ########
315                
316               # The following functions are wrappers around similarly named hashes.
317                
318               sub classbyname {
319 1284       1284 1 2604 my $name = shift;
320                
321 1284     100     5009 return $classbyname{$name} || $classbyname{uc $name} || return do {
322               croak qq[unknown class "$name"] unless $name =~ m/^(CLASS)?(\d+)/i;
323               my $val = 0 + $2;
324               croak qq[classbyname("$name") out of range] if $val > 0x7fff;
325               return $val;
326               }
327               }
328                
329               sub classbyval {
330 1245       1245 1 174731 my $arg = shift;
331                
332 1245     100     3301 return $classbyval{$arg} || return do {
333               my $val = ( $arg += 0 ) & 0x7fff; # MSB used by mDNS
334               croak qq[classbyval($arg) out of range] if $arg > 0xffff;
335               return $classbyval{$arg} = $classbyval{$val} || "CLASS$val";
336               }
337               }
338                
339                
340               sub typebyname {
341 1050       1050 1 3489 my $name = shift;
342                
343 1050     100     85177 return $typebyname{$name} || return do {
344               if ( $name =~ m/^(TYPE)?(\d+)/i ) {
345               my $val = 0 + $2;
346               croak qq[typebyname("$name") out of range] if $val > 0xffff;
347               return $val;
348               }
349               _typespec("$name.RRNAME") unless $typebyname{uc $name};
350               return $typebyname{uc $name} || croak qq[unknown type "$name"];
351               }
352               }
353                
354               sub typebyval {
355 2903       2903 1 165691 my $val = shift;
356                
357 2903     100     10377 return $typebyval{$val} || return do {
358               $val += 0;
359               croak qq[typebyval($val) out of range] if $val > 0xffff;
360               $typebyval{$val} = "TYPE$val";
361               _typespec("$val.RRTYPE");
362               return $typebyval{$val};
363               }
364               }
365                
366                
367               sub opcodebyname {
368 68       68 1 1073 my $arg = shift;
369 68           126 my $val = $opcodebyname{$arg};
370 68 100         194 return $val if defined $val;
371 2 100         11 return $arg if $arg =~ /^\d/;
372 1           115 croak qq[unknown opcode "$arg"];
373               }
374                
375               sub opcodebyval {
376 70       70 1 3603 my $val = shift;
377 70     100     273 return $opcodebyval{$val} || return "$val";
378               }
379                
380                
381               sub rcodebyname {
382 58       58 1 973 my $arg = shift;
383 58           103 my $val = $rcodebyname{$arg};
384 58 100         176 return $val if defined $val;
385 8 100         46 return $arg if $arg =~ /^\d/;
386 1           88 croak qq[unknown rcode "$arg"];
387               }
388                
389               sub rcodebyval {
390 278       278 1 11406 my $val = shift;
391 278     100     1539 return $rcodebyval{$val} || return "$val";
392               }
393                
394                
395               sub ednsoptionbyname {
396 186       186 1 1852 my $arg = shift;
397 186           264 my $val = $ednsoptionbyname{$arg};
398 186 100         972 return $val if defined $val;
399 40 100         119 return $arg if $arg =~ /^\d/;
400 1           157 croak qq[unknown option "$arg"];
401               }
402                
403               sub ednsoptionbyval {
404 122       122 1 14559 my $val = shift;
405 122     100     329 return $ednsoptionbyval{$val} || return "$val";
406               }
407                
408                
409               sub dsotypebyname {
410 9       9 1 507 my $arg = shift;
411 9           16 my $val = $dsotypebyname{$arg};
412 9 100         24 return $val if defined $val;
413 2 100         10 return $arg if $arg =~ /^\d/;
414 1           134 croak qq[unknown DSO type "$arg"];
415               }
416                
417               sub dsotypebyval {
418 9       9 1 4253 my $val = shift;
419 9     100     39 return $dsotypebyval{$val} || return "$val";
420               }
421                
422                
423 98       98   893 use constant EXTLANG => defined eval { require Net::DNS::Extlang };
  98           199  
  98           199  
  98           29782  
424                
425               sub _typespec {
426 5       5   21 my $generate = defined wantarray;
427 5           10 return EXTLANG ? eval <<'END' : ''; ## no critic
428               my ($node) = @_;
429               my $instance = Net::DNS::Extlang->new(); ## draft-levine-dnsextlang
430               my $basename = $instance->domain || return '';
431                
432               require Net::DNS::Resolver;
433               my $resolver = Net::DNS::Resolver->new();
434               my $response = $resolver->send( "$node.$basename", 'TXT' ) || return '';
435                
436               foreach my $txt ( grep { $_->type eq 'TXT' } $response->answer ) {
437               my @stanza = $txt->txtdata;
438               my ( $tag, $identifier, @attribute ) = @stanza;
439               next unless defined($tag) && $tag =~ /^RRTYPE=\d+$/;
440               if ( $identifier =~ /^(\w+):(\d+)\W*/ ) {
441               my ( $mnemonic, $rrtype ) = ( uc($1), $2 );
442               croak qq["$mnemonic" is a CLASS identifier] if $classbyname{$mnemonic};
443               for ( typebyval($rrtype) ) {
444               next if /^$mnemonic$/i; # duplicate registration
445               croak qq["$mnemonic" conflicts with TYPE$rrtype ($_)] unless /^TYPE\d+$/;
446               my $known = $typebyname{$mnemonic};
447               croak qq["$mnemonic" conflicts with TYPE$known] if $known;
448               $typebyval{$rrtype} = $mnemonic;
449               $typebyname{$mnemonic} = $rrtype;
450               }
451               }
452               return unless $generate;
453                
454               my $recipe = $instance->xlstorerecord( $identifier, @attribute );
455               return $instance->compilerr($recipe);
456               }
457               END
458               }
459                
460                
461               1;
462               __END__