File Coverage

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


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