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   656 use strict;
  92         193  
  92         2774  
4 92     92   489 use warnings;
  92         190  
  92         4487  
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   579 use integer;
  92         193  
  92         550  
29 92     92   2258 use Carp;
  92         294  
  92         7648  
30              
31 92     92   731 use Net::DNS::Parameters qw(:opcode :rcode);
  92         273  
  92         177571  
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 49 my $self = shift;
60              
61 30         67 my $id = $self->id;
62 30         75 my $qr = $self->qr;
63 30         61 my $opcode = $self->opcode;
64 30         67 my $rcode = $self->rcode;
65 30         81 my $qd = $self->qdcount;
66 30         59 my $an = $self->ancount;
67 30         67 my $ns = $self->nscount;
68 30         56 my $ar = $self->arcount;
69 30 100       111 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       118 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         83 my $tc = $self->tc;
81 19         53 my $rd = $self->rd;
82 19         43 my $ra = $self->ra;
83 19         43 my $zz = $self->z;
84 19         50 my $ad = $self->ad;
85 19         38 my $cd = $self->cd;
86 19         53 my $do = $self->do;
87 19         150 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 10495 print &string;
107 1         8 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 613     613 1 4058 my ( $self, @value ) = @_;
126 613         1400 for (@value) { $$self->{id} = $_ }
  76         297  
127 613         1627 my $ident = $$self->{id};
128 613 100       3329 return $ident if $ident;
129 175 100 100     634 return $ident if defined($ident) && $self->opcode eq 'DSO';
130 173 100       567 ( $cache1, $cache2, $limit ) = ( {0 => 1}, $cache1, 50 ) unless $limit--;
131 173         1011 $ident = int rand(0xffff); # preserve short-term uniqueness
132 173         1124 $ident = int rand(0xffff) while $cache1->{$ident}++ + exists( $cache2->{$ident} );
133 173         1339 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 1772 my ( $self, $arg ) = @_;
148 126         184 my $opcode;
149 126         292 for ( $$self->{status} ) {
150 126 100       408 return opcodebyval( ( $_ >> 11 ) & 0x0f ) unless defined $arg;
151 61         175 $opcode = opcodebyname($arg);
152 61         184 $_ = ( $_ & 0x87ff ) | ( $opcode << 11 );
153             }
154 61         115 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 271     271 1 4537 my ( $self, $arg ) = @_;
169 271         516 my $rcode;
170 271         720 for ( $$self->{status} ) {
171 271         862 my $opt = $$self->edns;
172 271 100       843 unless ( defined $arg ) {
173 257         1027 $rcode = ( $opt->rcode & 0xff0 ) | ( $_ & 0x00f );
174 257         963 $opt->rcode($rcode); # write back full 12-bit rcode
175 257 100       1189 return $rcode == 16 ? 'BADVERS' : rcodebyval($rcode);
176             }
177 14         61 $rcode = rcodebyname($arg);
178 14         65 $opt->rcode($rcode); # full 12-bit rcode
179 14         24 $_ &= 0xfff0; # low 4-bit rcode
180 14         32 $_ |= ( $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 218     218 1 2157 my ( $self, @value ) = @_;
197 218         822 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 1710 my ( $self, @value ) = @_;
212 30         68 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 126     126 1 1956 my ( $self, @value ) = @_;
227 126         629 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 183     183 1 2012 my ( $self, @value ) = @_;
242 183         386 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 1635 my ( $self, @value ) = @_;
257 27         57 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 33 my ( $self, @value ) = @_;
269 19         31 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 123     123 1 1952 my ( $self, @value ) = @_;
287 123         446 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 135     135 1 1874 my ( $self, @value ) = @_;
302 135         302 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 752 my ( $self, @value ) = @_;
318 37         75 for (@value) { $self->_warn('packet->header->qdcount is read-only') }
  2         9  
319 37   100     190 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 690 my ( $self, @value ) = @_;
337 64         146 for (@value) { $self->_warn('packet->header->ancount is read-only') }
  1         3  
338 64   100     375 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 556 my ( $self, @value ) = @_;
356 50         118 for (@value) { $self->_warn('packet->header->nscount is read-only') }
  1         4  
357 50   100     193 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         90 for (@value) { $self->_warn('packet->header->arcount is read-only') }
  1         3  
375 50   100     182 return $$self->{count}[3] || scalar @{$$self->{additional}};
376             }
377              
378 1     1 1 7 sub zocount { return &qdcount; }
379 1     1 1 4 sub prcount { return &ancount; }
380 1     1 1 3 sub upcount { return &nscount; }
381 3     3 1 470 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 2117 my ( $self, @value ) = @_;
398 33         100 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 4 my ( $self, @value ) = @_;
418 1         4 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         3 return $$self->edns;
438             }
439              
440              
441             ########################################
442              
443             sub _dnsflag {
444 861     861   1719 my ( $self, $flag, @value ) = @_;
445 861         2391 for ( $$self->{status} ) {
446 861         1557 my $set = $_ | $flag;
447 861 100       2377 $_ = ( shift @value ) ? $set : ( $set ^ $flag ) if @value;
    100          
448 861         1782 $flag &= $_;
449             }
450 861 100       3580 return $flag ? 1 : 0;
451             }
452              
453              
454             sub _ednsflag {
455 33     33   82 my ( $self, $flag, @value ) = @_;
456 33         92 my $edns = $$self->edns;
457 33         110 for ( $edns->flags ) {
458 33         67 my $set = $_ | $flag;
459 33 100       136 $edns->flags( $_ = ( shift @value ) ? $set : ( $set ^ $flag ) ) if @value;
    100          
460 33         86 $flag &= $_;
461             }
462 33 100       96 return $flag ? 1 : 0;
463             }
464              
465              
466             my %warned;
467              
468             sub _warn {
469 5     5   16 my ( undef, @note ) = @_;
470 5 100       444 return carp "usage; @note" unless $warned{"@note"}++;
471             }
472              
473              
474             1;
475             __END__