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   642 use strict;
  92         172  
  92         2697  
4 92     92   455 use warnings;
  92         186  
  92         4251  
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   558 use integer;
  92         218  
  92         456  
29 92     92   2320 use Carp;
  92         218  
  92         7049  
30              
31 92     92   684 use Net::DNS::Parameters qw(:opcode :rcode);
  92         247  
  92         168734  
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 60 my $self = shift;
60              
61 30         57 my $id = $self->id;
62 30         80 my $qr = $self->qr;
63 30         62 my $opcode = $self->opcode;
64 30         67 my $rcode = $self->rcode;
65 30         69 my $qd = $self->qdcount;
66 30         68 my $an = $self->ancount;
67 30         62 my $ns = $self->nscount;
68 30         54 my $ar = $self->arcount;
69 30 100       120 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       117 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         42 my $rd = $self->rd;
82 19         41 my $ra = $self->ra;
83 19         41 my $zz = $self->z;
84 19         40 my $ad = $self->ad;
85 19         42 my $cd = $self->cd;
86 19         40 my $do = $self->do;
87 19         154 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 10490 print &string;
107 1         6 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 4050 my ( $self, @value ) = @_;
126 659         1572 for (@value) { $$self->{id} = $_ }
  88         290  
127 659         1424 my $ident = $$self->{id};
128 659 100       3270 return $ident if $ident;
129 187 100 100     702 return $ident if defined($ident) && $self->opcode eq 'DSO';
130 185 100       671 ( $cache1, $cache2, $limit ) = ( {0 => 1}, $cache1, 50 ) unless $limit--;
131 185         928 $ident = int rand(0xffff); # preserve short-term uniqueness
132 185         1089 $ident = int rand(0xffff) while $cache1->{$ident}++ + exists( $cache2->{$ident} );
133 185         1252 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 1722 my ( $self, $arg ) = @_;
148 126         169 my $opcode;
149 126         270 for ( $$self->{status} ) {
150 126 100       384 return opcodebyval( ( $_ >> 11 ) & 0x0f ) unless defined $arg;
151 61         159 $opcode = opcodebyname($arg);
152 61         179 $_ = ( $_ & 0x87ff ) | ( $opcode << 11 );
153             }
154 61         110 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 4412 my ( $self, $arg ) = @_;
169 293         500 my $rcode;
170 293         712 for ( $$self->{status} ) {
171 293         822 my $opt = $$self->edns;
172 293 100       857 unless ( defined $arg ) {
173 279         921 $rcode = ( $opt->rcode & 0xff0 ) | ( $_ & 0x00f );
174 279         987 $opt->rcode($rcode); # write back full 12-bit rcode
175 279 100       1223 return $rcode == 16 ? 'BADVERS' : rcodebyval($rcode);
176             }
177 14         41 $rcode = rcodebyname($arg);
178 14         52 $opt->rcode($rcode); # full 12-bit rcode
179 14         24 $_ &= 0xfff0; # low 4-bit rcode
180 14         35 $_ |= ( $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 2072 my ( $self, @value ) = @_;
197 229         691 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 1522 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 138     138 1 1938 my ( $self, @value ) = @_;
227 138         485 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 1934 my ( $self, @value ) = @_;
242 187         431 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 1624 my ( $self, @value ) = @_;
257 27         51 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 37 my ( $self, @value ) = @_;
269 19         29 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 1856 my ( $self, @value ) = @_;
287 127         356 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 1919 my ( $self, @value ) = @_;
302 139         301 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 731 my ( $self, @value ) = @_;
318 37         71 for (@value) { $self->_warn('packet->header->qdcount is read-only') }
  2         8  
319 37   100     191 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 738 my ( $self, @value ) = @_;
337 64         145 for (@value) { $self->_warn('packet->header->ancount is read-only') }
  1         4  
338 64   100     352 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 540 my ( $self, @value ) = @_;
356 50         95 for (@value) { $self->_warn('packet->header->nscount is read-only') }
  1         4  
357 50   100     208 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 96 my ( $self, @value ) = @_;
374 50         93 for (@value) { $self->_warn('packet->header->arcount is read-only') }
  1         4  
375 50   100     178 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 4 sub upcount { return &nscount; }
381 3     3 1 452 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 1990 my ( $self, @value ) = @_;
398 33         72 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 6 my $self = shift;
437 1         3 return $$self->edns;
438             }
439              
440              
441             ########################################
442              
443             sub _dnsflag {
444 896     896   1762 my ( $self, $flag, @value ) = @_;
445 896         1928 for ( $$self->{status} ) {
446 896         1591 my $set = $_ | $flag;
447 896 100       2212 $_ = ( shift @value ) ? $set : ( $set ^ $flag ) if @value;
    100          
448 896         1850 $flag &= $_;
449             }
450 896 100       3530 return $flag ? 1 : 0;
451             }
452              
453              
454             sub _ednsflag {
455 33     33   72 my ( $self, $flag, @value ) = @_;
456 33         84 my $edns = $$self->edns;
457 33         92 for ( $edns->flags ) {
458 33         60 my $set = $_ | $flag;
459 33 100       105 $edns->flags( $_ = ( shift @value ) ? $set : ( $set ^ $flag ) ) if @value;
    100          
460 33         64 $flag &= $_;
461             }
462 33 100       92 return $flag ? 1 : 0;
463             }
464              
465              
466             my %warned;
467              
468             sub _warn {
469 5     5   12 my ( undef, @note ) = @_;
470 5 100       443 return carp "usage; @note" unless $warned{"@note"}++;
471             }
472              
473              
474             1;
475             __END__