File Coverage

blib/lib/Net/DNS/Header.pm
Criterion Covered Total %
statement 125 125 100.0
branch 26 26 100.0
condition 8 8 100.0
subroutine 34 34 100.0
pod 26 26 100.0
total 219 219 100.0


line stmt bran cond sub pod time code
1             package Net::DNS::Header;
2              
3 94     94   692 use strict;
  94         234  
  94         5101  
4 94     94   1947 use warnings;
  94         172  
  94         7827  
5              
6             our $VERSION = (qw$Id: Header.pm 2042 2025-12-24 10:23:11Z 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 94     94   687 use integer;
  94         174  
  94         613  
29 94     94   4100 use Carp;
  94         246  
  94         7986  
30              
31 94     94   683 use Net::DNS::Parameters qw(:opcode :rcode);
  94         216  
  94         204490  
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 31     31 1 64 my $self = shift;
60              
61 31         84 my $id = $self->id;
62 31         61 my $qr = $self->qr;
63 31         60 my $opcode = $self->opcode;
64 31         61 my $rcode = $self->rcode;
65 31         102 my $qd = $self->qdcount;
66 31         60 my $an = $self->ancount;
67 31         63 my $ns = $self->nscount;
68 31         59 my $ar = $self->arcount;
69 31 100       83 my $dispid = defined $id ? $id : 'undef';
70 31 100       70 return <<"QQ" if $opcode eq 'DSO';
71             ;; id = $dispid qr = $qr
72             ;; opcode = $opcode rcode = $rcode
73             QQ
74 29 100       86 return <<"QQ" if $opcode eq 'UPDATE';
75             ;; id = $dispid qr = $qr
76             ;; opcode = $opcode rcode = $rcode
77             ;; zocount = $qd prcount = $an
78             ;; upcount = $ns adcount = $ar
79             QQ
80 20         42 my $aa = $self->aa;
81 20         38 my $tc = $self->tc;
82 20         39 my $rd = $self->rd;
83 20         35 my $ra = $self->ra;
84 20         41 my $zz = $self->z;
85 20         37 my $ad = $self->ad;
86 20         68 my $cd = $self->cd;
87 20         52 my $do = $self->do;
88 20         42 my $co = $self->co;
89 20         41 my $de = $self->de;
90 20         134 return <<"QQ";
91             ;; id = $dispid
92             ;; qr = $qr aa = $aa tc = $tc rd = $rd opcode = $opcode
93             ;; ra = $ra z = $zz ad = $ad cd = $cd rcode = $rcode
94             ;; do = $do co = $co de = $de
95             ;; qdcount = $qd ancount = $an
96             ;; nscount = $ns arcount = $ar
97             QQ
98             }
99              
100              
101             =head2 print
102              
103             $packet->header->print;
104              
105             Prints the string representation of the packet header.
106              
107             =cut
108              
109             sub print {
110 1     1 1 8670 print &string;
111 1         4 return;
112             }
113              
114              
115             =head2 id
116              
117             print "query id = ", $packet->header->id, "\n";
118             $packet->header->id(1234);
119              
120             Gets or sets the query identification number.
121              
122             =cut
123              
124             sub id {
125 326     326 1 3417 my ( $self, @value ) = @_;
126 326         674 for (@value) { $$self->{id} = $_ }
  52         184  
127 326         4545 return $$self->{id};
128             }
129              
130              
131             =head2 opcode
132              
133             print "query opcode = ", $packet->header->opcode, "\n";
134             $packet->header->opcode("UPDATE");
135              
136             Gets or sets the query opcode (the purpose of the query).
137              
138             =cut
139              
140             sub opcode {
141 121     121 1 287 my ( $self, $arg ) = @_;
142 121         197 my $opcode;
143 121         353 for ( $$self->{status} ) {
144 121 100       387 return opcodebyval( ( $_ >> 11 ) & 0x0f ) unless defined $arg;
145 58         198 $opcode = opcodebyname($arg);
146 58         186 $_ = ( $_ & 0x87ff ) | ( $opcode << 11 );
147             }
148 58         127 return $opcode;
149             }
150              
151              
152             =head2 rcode
153              
154             print "query response code = ", $packet->header->rcode, "\n";
155             $packet->header->rcode("SERVFAIL");
156              
157             Gets or sets the query response code (the status of the query).
158              
159             =cut
160              
161             sub rcode {
162 227     227 1 5258 my ( $self, $arg ) = @_;
163 227         350 my $rcode;
164 227         605 for ( $$self->{status} ) {
165 227         828 my $opt = $$self->edns;
166 227 100       760 unless ( defined $arg ) {
167 213         1160 $rcode = ( $opt->rcode & 0xff0 ) | ( $_ & 0x00f );
168 213         758 $opt->rcode($rcode); # write back full 12-bit rcode
169 213 100       1044 return $rcode == 16 ? 'BADVERS' : rcodebyval($rcode);
170             }
171 14         39 $rcode = rcodebyname($arg);
172 14         59 $opt->rcode($rcode); # full 12-bit rcode
173 14         22 $_ &= 0xfff0; # low 4-bit rcode
174 14         34 $_ |= ( $rcode & 0x000f );
175             }
176 14         33 return $rcode;
177             }
178              
179              
180             =head2 qr
181              
182             print "query response flag = ", $packet->header->qr, "\n";
183             $packet->header->qr(0);
184              
185             Gets or sets the query response flag.
186              
187             =cut
188              
189             sub qr {
190 213     213 1 3228 my ( $self, @value ) = @_;
191 213         2128 return $self->_dnsflag( 0x8000, @value );
192             }
193              
194              
195             =head2 aa
196              
197             print "response is ", $packet->header->aa ? "" : "non-", "authoritative\n";
198             $packet->header->aa(0);
199              
200             Gets or sets the authoritative answer flag.
201              
202             =cut
203              
204             sub aa {
205 31     31 1 2901 my ( $self, @value ) = @_;
206 31         75 return $self->_dnsflag( 0x0400, @value );
207             }
208              
209              
210             =head2 tc
211              
212             print "packet is ", $packet->header->tc ? "" : "not ", "truncated\n";
213             $packet->header->tc(0);
214              
215             Gets or sets the truncated packet flag.
216              
217             =cut
218              
219             sub tc {
220 106     106 1 3142 my ( $self, @value ) = @_;
221 106         385 return $self->_dnsflag( 0x0200, @value );
222             }
223              
224              
225             =head2 rd
226              
227             print "recursion was ", $packet->header->rd ? "" : "not ", "desired\n";
228             $packet->header->rd(0);
229              
230             Gets or sets the recursion desired flag.
231              
232             =cut
233              
234             sub rd {
235 175     175 1 3209 my ( $self, @value ) = @_;
236 175         453 return $self->_dnsflag( 0x0100, @value );
237             }
238              
239              
240             =head2 ra
241              
242             print "recursion is ", $packet->header->ra ? "" : "not ", "available\n";
243             $packet->header->ra(0);
244              
245             Gets or sets the recursion available flag.
246              
247             =cut
248              
249             sub ra {
250 28     28 1 2575 my ( $self, @value ) = @_;
251 28         67 return $self->_dnsflag( 0x0080, @value );
252             }
253              
254              
255             =head2 z
256              
257             Unassigned bit, should always be zero.
258              
259             =cut
260              
261             sub z {
262 20     20 1 29 my ( $self, @value ) = @_;
263 20         39 return $self->_dnsflag( 0x0040, @value );
264             }
265              
266              
267             =head2 ad
268              
269             print "The response has ", $packet->header->ad ? "" : "not", "been verified\n";
270              
271             Relevant in DNSSEC context.
272              
273             (The AD bit is only set on a response where signatures have been
274             cryptographically verified or the server is authoritative for the data
275             and is allowed to set the bit by policy.)
276              
277             =cut
278              
279             sub ad {
280 115     115 1 1976 my ( $self, @value ) = @_;
281 115         369 return $self->_dnsflag( 0x0020, @value );
282             }
283              
284              
285             =head2 cd
286              
287             print "checking was ", $packet->header->cd ? "not" : "", "desired\n";
288             $packet->header->cd(0);
289              
290             Gets or sets the checking disabled flag.
291              
292             =cut
293              
294             sub cd {
295 127     127 1 1995 my ( $self, @value ) = @_;
296 127         297 return $self->_dnsflag( 0x0010, @value );
297             }
298              
299              
300             =head2 qdcount, zocount
301              
302             print "# of question records: ", $packet->header->qdcount, "\n";
303              
304             Returns the number of records in the question section of the packet.
305             In dynamic update packets, this field is known as C and refers
306             to the number of RRs in the zone section.
307              
308             =cut
309              
310             sub qdcount {
311 38     38 1 526 my ( $self, @value ) = @_;
312 38         64 for (@value) { $self->_warn('packet->header->qdcount is read-only') }
  2         7  
313 38   100     137 return $$self->{count}[0] || scalar @{$$self->{question}};
314             }
315              
316              
317             =head2 ancount, prcount
318              
319             print "# of answer records: ", $packet->header->ancount, "\n";
320              
321             Returns the number of records in the answer section of the packet
322             which may, in the case of corrupt packets, differ from the actual
323             number of records.
324             In dynamic update packets, this field is known as C and refers
325             to the number of RRs in the prerequisite section.
326              
327             =cut
328              
329             sub ancount {
330 65     65 1 463 my ( $self, @value ) = @_;
331 65         137 for (@value) { $self->_warn('packet->header->ancount is read-only') }
  1         3  
332 65   100     410 return $$self->{count}[1] || scalar @{$$self->{answer}};
333             }
334              
335              
336             =head2 nscount, upcount
337              
338             print "# of authority records: ", $packet->header->nscount, "\n";
339              
340             Returns the number of records in the authority section of the packet
341             which may, in the case of corrupt packets, differ from the actual
342             number of records.
343             In dynamic update packets, this field is known as C and refers
344             to the number of RRs in the update section.
345              
346             =cut
347              
348             sub nscount {
349 51     51 1 370 my ( $self, @value ) = @_;
350 51         91 for (@value) { $self->_warn('packet->header->nscount is read-only') }
  1         3  
351 51   100     172 return $$self->{count}[2] || scalar @{$$self->{authority}};
352             }
353              
354              
355             =head2 arcount, adcount
356              
357             print "# of additional records: ", $packet->header->arcount, "\n";
358              
359             Returns the number of records in the additional section of the packet
360             which may, in the case of corrupt packets, differ from the actual
361             number of records.
362             In dynamic update packets, this field is known as C.
363              
364             =cut
365              
366             sub arcount {
367 51     51 1 89 my ( $self, @value ) = @_;
368 51         92 for (@value) { $self->_warn('packet->header->arcount is read-only') }
  1         3  
369 51   100     171 return $$self->{count}[3] || scalar @{$$self->{additional}};
370             }
371              
372 1     1 1 5 sub zocount { return &qdcount; }
373 1     1 1 2 sub prcount { return &ancount; }
374 1     1 1 2 sub upcount { return &nscount; }
375 3     3 1 306 sub adcount { return &arcount; }
376              
377              
378             =head1 EDNS Protocol Extensions
379              
380             =head2 do, co, de
381              
382             print "DNSSEC_OK flag was ", $packet->header->do ? "not" : "", "set\n";
383             $packet->header->do(1);
384              
385             Gets or sets the named EDNS flag.
386              
387             =cut
388              
389             sub do {
390 34     34 1 2004 my ( $self, @value ) = @_;
391 34         83 return $self->_ednsflag( 0x8000, @value );
392             }
393              
394             sub co {
395 28     28 1 2327 my ( $self, @value ) = @_;
396 28         44 return $self->_ednsflag( 0x4000, @value );
397             }
398              
399             sub de {
400 20     20 1 30 my ( $self, @value ) = @_;
401 20         34 return $self->_ednsflag( 0x2000, @value );
402             }
403              
404              
405             =head2 Extended rcode
406              
407             EDNS extended rcodes are handled transparently by $packet->header->rcode().
408              
409              
410             =head2 UDP packet size
411              
412             $udp_max = $packet->edns->UDPsize;
413              
414             EDNS offers a mechanism to advertise the maximum UDP packet size
415             which can be assembled by the local network stack.
416              
417             =cut
418              
419             sub size { ## historical
420 1     1 1 5 my ( $self, @value ) = @_;
421 1         4 return $$self->edns->UDPsize(@value);
422             }
423              
424              
425             =head2 edns
426              
427             $header = $packet->header;
428             $version = $header->edns->version;
429             @options = $header->edns->options;
430             $option = $header->edns->option(n);
431             $udp_max = $packet->edns->UDPsize;
432              
433             Auxiliary function which provides access to the EDNS protocol
434             extension OPT RR.
435              
436             =cut
437              
438             sub edns {
439 1     1 1 6 my $self = shift;
440 1         4 return $$self->edns;
441             }
442              
443              
444             ########################################
445              
446             sub _dnsflag {
447 815     815   1633 my ( $self, $flag, @value ) = @_;
448 815         1961 for ( $$self->{status} ) {
449 815         1501 my $set = $_ | $flag;
450 815 100       2268 $_ = ( shift @value ) ? $set : ( $set ^ $flag ) if @value;
    100          
451 815         1557 $flag &= $_;
452             }
453 815 100       3564 return $flag ? 1 : 0;
454             }
455              
456              
457             sub _ednsflag {
458 82     82   129 my ( $self, $flag, @value ) = @_;
459 82         200 my $edns = $$self->edns;
460 82         1807 for ( $edns->flags ) {
461 82         112 my $set = $_ | $flag;
462 82 100       151 $edns->flags( $_ = ( shift @value ) ? $set : ( $set ^ $flag ) ) if @value;
    100          
463 82         124 $flag &= $_;
464             }
465 82 100       173 return $flag ? 1 : 0;
466             }
467              
468              
469             my %warned;
470              
471             sub _warn {
472 5     5   9 my ( undef, @note ) = @_;
473 5 100       494 return carp "usage; @note" unless $warned{"@note"}++;
474             }
475              
476              
477             1;
478             __END__