File Coverage

blib/lib/Net/DNS/Header.pm
Criterion Covered Total %
statement 124 124 100.0
branch 30 30 100.0
condition 11 11 100.0
subroutine 32 32 100.0
pod 24 24 100.0
total 221 221 100.0


line stmt bran cond sub pod time code
1             package Net::DNS::Header;
2              
3 92     92   658 use strict;
  92         191  
  92         2717  
4 92     92   457 use warnings;
  92         184  
  92         4450  
5              
6             our $VERSION = (qw$Id: Header.pm 1910 2023-03-30 19:16:30Z willem $)[2];
7              
8              
9             =head1 NAME
10              
11             Net::DNS::Header - DNS packet header
12              
13             =head1 SYNOPSIS
14              
15             use Net::DNS;
16              
17             $packet = Net::DNS::Packet->new();
18             $header = $packet->header;
19              
20              
21             =head1 DESCRIPTION
22              
23             C represents the header portion of a DNS packet.
24              
25             =cut
26              
27              
28 92     92   537 use integer;
  92         259  
  92         495  
29 92     92   2160 use Carp;
  92         241  
  92         7076  
30              
31 92     92   693 use Net::DNS::Parameters qw(:opcode :rcode);
  92         250  
  92         170515  
32              
33              
34             =head1 METHODS
35              
36              
37             =head2 $packet->header
38              
39             $packet = Net::DNS::Packet->new();
40             $header = $packet->header;
41              
42             Net::DNS::Header objects emanate from the Net::DNS::Packet header()
43             method, and contain an opaque reference to the parent Packet object.
44              
45             Header objects may be assigned to suitably scoped lexical variables.
46             They should never be stored in global variables or persistent data
47             structures.
48              
49              
50             =head2 string
51              
52             print $packet->header->string;
53              
54             Returns a string representation of the packet header.
55              
56             =cut
57              
58             sub string {
59 30     30 1 56 my $self = shift;
60              
61 30         76 my $id = $self->id;
62 30         76 my $qr = $self->qr;
63 30         64 my $opcode = $self->opcode;
64 30         65 my $rcode = $self->rcode;
65 30         77 my $qd = $self->qdcount;
66 30         71 my $an = $self->ancount;
67 30         73 my $ns = $self->nscount;
68 30         63 my $ar = $self->arcount;
69 30 100       119 return <<"QQ" if $opcode eq 'DSO';
70             ;; id = $id
71             ;; qr = $qr opcode = $opcode rcode = $rcode
72             ;; qdcount = $qd ancount = $an nscount = $ns arcount = $ar
73             QQ
74 25 100       96 return <<"QQ" if $opcode eq 'UPDATE';
75             ;; id = $id
76             ;; qr = $qr opcode = $opcode rcode = $rcode
77             ;; zocount = $qd prcount = $an upcount = $ns adcount = $ar
78             QQ
79 19         38 my $aa = $self->aa;
80 19         41 my $tc = $self->tc;
81 19         59 my $rd = $self->rd;
82 19         47 my $ra = $self->ra;
83 19         53 my $zz = $self->z;
84 19         43 my $ad = $self->ad;
85 19         47 my $cd = $self->cd;
86 19         54 my $do = $self->do;
87 19         158 return <<"QQ";
88             ;; id = $id
89             ;; qr = $qr aa = $aa tc = $tc rd = $rd opcode = $opcode
90             ;; ra = $ra z = $zz ad = $ad cd = $cd rcode = $rcode
91             ;; qdcount = $qd ancount = $an nscount = $ns arcount = $ar
92             ;; do = $do
93             QQ
94             }
95              
96              
97             =head2 print
98              
99             $packet->header->print;
100              
101             Prints the string representation of the packet header.
102              
103             =cut
104              
105             sub print {
106 1     1 1 11132 print &string;
107 1         7 return;
108             }
109              
110              
111             =head2 id
112              
113             print "query id = ", $packet->header->id, "\n";
114             $packet->header->id(1234);
115              
116             Gets or sets the query identification number.
117              
118             A random value is assigned if the argument value is undefined.
119              
120             =cut
121              
122             my ( $cache1, $cache2, $limit ); # two layer cache
123              
124             sub id {
125 659     659 1 4161 my ( $self, @value ) = @_;
126 659         1315 for (@value) { $$self->{id} = $_ }
  88         304  
127 659         1335 my $ident = $$self->{id};
128 659 100       2994 return $ident if $ident;
129 187 100 100     569 return $ident if defined($ident) && $self->opcode eq 'DSO';
130 185 100       539 ( $cache1, $cache2, $limit ) = ( {0 => 1}, $cache1, 50 ) unless $limit--;
131 185         835 $ident = int rand(0xffff); # preserve short-term uniqueness
132 185         1025 $ident = int rand(0xffff) while $cache1->{$ident}++ + exists( $cache2->{$ident} );
133 185         1026 return $$self->{id} = $ident;
134             }
135              
136              
137             =head2 opcode
138              
139             print "query opcode = ", $packet->header->opcode, "\n";
140             $packet->header->opcode("UPDATE");
141              
142             Gets or sets the query opcode (the purpose of the query).
143              
144             =cut
145              
146             sub opcode {
147 126     126 1 1828 my ( $self, $arg ) = @_;
148 126         179 my $opcode;
149 126         274 for ( $$self->{status} ) {
150 126 100       415 return opcodebyval( ( $_ >> 11 ) & 0x0f ) unless defined $arg;
151 61         187 $opcode = opcodebyname($arg);
152 61         178 $_ = ( $_ & 0x87ff ) | ( $opcode << 11 );
153             }
154 61         121 return $opcode;
155             }
156              
157              
158             =head2 rcode
159              
160             print "query response code = ", $packet->header->rcode, "\n";
161             $packet->header->rcode("SERVFAIL");
162              
163             Gets or sets the query response code (the status of the query).
164              
165             =cut
166              
167             sub rcode {
168 293     293 1 4553 my ( $self, $arg ) = @_;
169 293         472 my $rcode;
170 293         680 for ( $$self->{status} ) {
171 293         805 my $opt = $$self->edns;
172 293 100       747 unless ( defined $arg ) {
173 279         894 $rcode = ( $opt->rcode & 0xff0 ) | ( $_ & 0x00f );
174 279         876 $opt->rcode($rcode); # write back full 12-bit rcode
175 279 100       1131 return $rcode == 16 ? 'BADVERS' : rcodebyval($rcode);
176             }
177 14         47 $rcode = rcodebyname($arg);
178 14         54 $opt->rcode($rcode); # full 12-bit rcode
179 14         24 $_ &= 0xfff0; # low 4-bit rcode
180 14         34 $_ |= ( $rcode & 0x000f );
181             }
182 14         32 return $rcode;
183             }
184              
185              
186             =head2 qr
187              
188             print "query response flag = ", $packet->header->qr, "\n";
189             $packet->header->qr(0);
190              
191             Gets or sets the query response flag.
192              
193             =cut
194              
195             sub qr {
196 229     229 1 2074 my ( $self, @value ) = @_;
197 229         670 return $self->_dnsflag( 0x8000, @value );
198             }
199              
200              
201             =head2 aa
202              
203             print "response is ", $packet->header->aa ? "" : "non-", "authoritative\n";
204             $packet->header->aa(0);
205              
206             Gets or sets the authoritative answer flag.
207              
208             =cut
209              
210             sub aa {
211 30     30 1 1621 my ( $self, @value ) = @_;
212 30         67 return $self->_dnsflag( 0x0400, @value );
213             }
214              
215              
216             =head2 tc
217              
218             print "packet is ", $packet->header->tc ? "" : "not ", "truncated\n";
219             $packet->header->tc(0);
220              
221             Gets or sets the truncated packet flag.
222              
223             =cut
224              
225             sub tc {
226 138     138 1 1992 my ( $self, @value ) = @_;
227 138         404 return $self->_dnsflag( 0x0200, @value );
228             }
229              
230              
231             =head2 rd
232              
233             print "recursion was ", $packet->header->rd ? "" : "not ", "desired\n";
234             $packet->header->rd(0);
235              
236             Gets or sets the recursion desired flag.
237              
238             =cut
239              
240             sub rd {
241 187     187 1 1950 my ( $self, @value ) = @_;
242 187         388 return $self->_dnsflag( 0x0100, @value );
243             }
244              
245              
246             =head2 ra
247              
248             print "recursion is ", $packet->header->ra ? "" : "not ", "available\n";
249             $packet->header->ra(0);
250              
251             Gets or sets the recursion available flag.
252              
253             =cut
254              
255             sub ra {
256 27     27 1 1652 my ( $self, @value ) = @_;
257 27         56 return $self->_dnsflag( 0x0080, @value );
258             }
259              
260              
261             =head2 z
262              
263             Unassigned bit, should always be zero.
264              
265             =cut
266              
267             sub z {
268 19     19 1 30 my ( $self, @value ) = @_;
269 19         43 return $self->_dnsflag( 0x0040, @value );
270             }
271              
272              
273             =head2 ad
274              
275             print "The response has ", $packet->header->ad ? "" : "not", "been verified\n";
276              
277             Relevant in DNSSEC context.
278              
279             (The AD bit is only set on a response where signatures have been
280             cryptographically verified or the server is authoritative for the data
281             and is allowed to set the bit by policy.)
282              
283             =cut
284              
285             sub ad {
286 127     127 1 1868 my ( $self, @value ) = @_;
287 127         361 return $self->_dnsflag( 0x0020, @value );
288             }
289              
290              
291             =head2 cd
292              
293             print "checking was ", $packet->header->cd ? "not" : "", "desired\n";
294             $packet->header->cd(0);
295              
296             Gets or sets the checking disabled flag.
297              
298             =cut
299              
300             sub cd {
301 139     139 1 2239 my ( $self, @value ) = @_;
302 139         276 return $self->_dnsflag( 0x0010, @value );
303             }
304              
305              
306             =head2 qdcount, zocount
307              
308             print "# of question records: ", $packet->header->qdcount, "\n";
309              
310             Returns the number of records in the question section of the packet.
311             In dynamic update packets, this field is known as C and refers
312             to the number of RRs in the zone section.
313              
314             =cut
315              
316             sub qdcount {
317 37     37 1 724 my ( $self, @value ) = @_;
318 37         69 for (@value) { $self->_warn('packet->header->qdcount is read-only') }
  2         18  
319 37   100     233 return $$self->{count}[0] || scalar @{$$self->{question}};
320             }
321              
322              
323             =head2 ancount, prcount
324              
325             print "# of answer records: ", $packet->header->ancount, "\n";
326              
327             Returns the number of records in the answer section of the packet
328             which may, in the case of corrupt packets, differ from the actual
329             number of records.
330             In dynamic update packets, this field is known as C and refers
331             to the number of RRs in the prerequisite section.
332              
333             =cut
334              
335             sub ancount {
336 64     64 1 693 my ( $self, @value ) = @_;
337 64         134 for (@value) { $self->_warn('packet->header->ancount is read-only') }
  1         5  
338 64   100     340 return $$self->{count}[1] || scalar @{$$self->{answer}};
339             }
340              
341              
342             =head2 nscount, upcount
343              
344             print "# of authority records: ", $packet->header->nscount, "\n";
345              
346             Returns the number of records in the authority section of the packet
347             which may, in the case of corrupt packets, differ from the actual
348             number of records.
349             In dynamic update packets, this field is known as C and refers
350             to the number of RRs in the update section.
351              
352             =cut
353              
354             sub nscount {
355 50     50 1 552 my ( $self, @value ) = @_;
356 50         93 for (@value) { $self->_warn('packet->header->nscount is read-only') }
  1         4  
357 50   100     192 return $$self->{count}[2] || scalar @{$$self->{authority}};
358             }
359              
360              
361             =head2 arcount, adcount
362              
363             print "# of additional records: ", $packet->header->arcount, "\n";
364              
365             Returns the number of records in the additional section of the packet
366             which may, in the case of corrupt packets, differ from the actual
367             number of records.
368             In dynamic update packets, this field is known as C.
369              
370             =cut
371              
372             sub arcount {
373 50     50 1 90 my ( $self, @value ) = @_;
374 50         88 for (@value) { $self->_warn('packet->header->arcount is read-only') }
  1         3  
375 50   100     195 return $$self->{count}[3] || scalar @{$$self->{additional}};
376             }
377              
378 1     1 1 8 sub zocount { return &qdcount; }
379 1     1 1 3 sub prcount { return &ancount; }
380 1     1 1 4 sub upcount { return &nscount; }
381 3     3 1 462 sub adcount { return &arcount; }
382              
383              
384             =head1 EDNS Protocol Extensions
385              
386              
387             =head2 do
388              
389             print "DNSSEC_OK flag was ", $packet->header->do ? "not" : "", "set\n";
390             $packet->header->do(1);
391              
392             Gets or sets the EDNS DNSSEC OK flag.
393              
394             =cut
395              
396             sub do {
397 33     33 1 2023 my ( $self, @value ) = @_;
398 33         77 return $self->_ednsflag( 0x8000, @value );
399             }
400              
401              
402             =head2 Extended rcode
403              
404             EDNS extended rcodes are handled transparently by $packet->header->rcode().
405              
406              
407             =head2 UDP packet size
408              
409             $udp_max = $packet->edns->UDPsize;
410              
411             EDNS offers a mechanism to advertise the maximum UDP packet size
412             which can be assembled by the local network stack.
413              
414             =cut
415              
416             sub size { ## historical
417 1     1 1 5 my ( $self, @value ) = @_;
418 1         5 return $$self->edns->UDPsize(@value);
419             }
420              
421              
422             =head2 edns
423              
424             $header = $packet->header;
425             $version = $header->edns->version;
426             @options = $header->edns->options;
427             $option = $header->edns->option(n);
428             $udp_max = $packet->edns->UDPsize;
429              
430             Auxiliary function which provides access to the EDNS protocol
431             extension OPT RR.
432              
433             =cut
434              
435             sub edns {
436 1     1 1 5 my $self = shift;
437 1         4 return $$self->edns;
438             }
439              
440              
441             ########################################
442              
443             sub _dnsflag {
444 896     896   1674 my ( $self, $flag, @value ) = @_;
445 896         1948 for ( $$self->{status} ) {
446 896         1422 my $set = $_ | $flag;
447 896 100       2384 $_ = ( shift @value ) ? $set : ( $set ^ $flag ) if @value;
    100          
448 896         1718 $flag &= $_;
449             }
450 896 100       3321 return $flag ? 1 : 0;
451             }
452              
453              
454             sub _ednsflag {
455 33     33   77 my ( $self, $flag, @value ) = @_;
456 33         78 my $edns = $$self->edns;
457 33         95 for ( $edns->flags ) {
458 33         55 my $set = $_ | $flag;
459 33 100       123 $edns->flags( $_ = ( shift @value ) ? $set : ( $set ^ $flag ) ) if @value;
    100          
460 33         59 $flag &= $_;
461             }
462 33 100       96 return $flag ? 1 : 0;
463             }
464              
465              
466             my %warned;
467              
468             sub _warn {
469 5     5   13 my ( undef, @note ) = @_;
470 5 100       472 return carp "usage; @note" unless $warned{"@note"}++;
471             }
472              
473              
474             1;
475             __END__