File Coverage

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


line stmt bran path cond sub pod time code
1               package Net::DNS::Header;
2                
3 94       94   546 use strict;
  94           143  
  94           2752  
4 94       94   336 use warnings;
  94           135  
  94           5880  
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   468 use integer;
  94           164  
  94           485  
29 94       94   2158 use Carp;
  94           169  
  94           6252  
30                
31 94       94   461 use Net::DNS::Parameters qw(:opcode :rcode);
  94           152  
  94           135885  
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 42 my $self = shift;
60                
61 31           71 my $id = $self->id;
62 31           46 my $qr = $self->qr;
63 31           50 my $opcode = $self->opcode;
64 31           52 my $rcode = $self->rcode;
65 31           55 my $qd = $self->qdcount;
66 31           56 my $an = $self->ancount;
67 31           53 my $ns = $self->nscount;
68 31           54 my $ar = $self->arcount;
69 31 100         54 my $dispid = defined $id ? $id : 'undef';
70 31 100         57 return <<"QQ" if $opcode eq 'DSO';
71               ;; id = $dispid qr = $qr
72               ;; opcode = $opcode rcode = $rcode
73               QQ
74 29 100         79 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           37 my $aa = $self->aa;
81 20           34 my $tc = $self->tc;
82 20           30 my $rd = $self->rd;
83 20           29 my $ra = $self->ra;
84 20           33 my $zz = $self->z;
85 20           33 my $ad = $self->ad;
86 20           35 my $cd = $self->cd;
87 20           33 my $do = $self->do;
88 20           34 my $co = $self->co;
89 20           38 my $de = $self->de;
90 20           111 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 8249 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 324       324 1 3584 my ( $self, @value ) = @_;
126 324           539 for (@value) { $$self->{id} = $_ }
  52           141  
127 324           1410 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 213 my ( $self, $arg ) = @_;
142 121           133 my $opcode;
143 121           258 for ( $$self->{status} ) {
144 121 100         320 return opcodebyval( ( $_ >> 11 ) & 0x0f ) unless defined $arg;
145 58           136 $opcode = opcodebyname($arg);
146 58           138 $_ = ( $_ & 0x87ff ) | ( $opcode << 11 );
147               }
148 58           87 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 224       224 1 4537 my ( $self, $arg ) = @_;
163 224           280 my $rcode;
164 224           443 for ( $$self->{status} ) {
165 224           582 my $opt = $$self->edns;
166 224 100         485 unless ( defined $arg ) {
167 210           684 $rcode = ( $opt->rcode & 0xff0 ) | ( $_ & 0x00f );
168 210           586 $opt->rcode($rcode); # write back full 12-bit rcode
169 210 100         808 return $rcode == 16 ? 'BADVERS' : rcodebyval($rcode);
170               }
171 14           34 $rcode = rcodebyname($arg);
172 14           51 $opt->rcode($rcode); # full 12-bit rcode
173 14           18 $_ &= 0xfff0; # low 4-bit rcode
174 14           24 $_ |= ( $rcode & 0x000f );
175               }
176 14           22 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 212       212 1 2051 my ( $self, @value ) = @_;
191 212           646 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 1749 my ( $self, @value ) = @_;
206 31           50 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 104       104 1 1893 my ( $self, @value ) = @_;
221 104           273 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 173       173 1 2086 my ( $self, @value ) = @_;
236 173           309 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 1983 my ( $self, @value ) = @_;
251 28           45 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 24 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 113       113 1 2650 my ( $self, @value ) = @_;
281 113           274 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 125       125 1 1872 my ( $self, @value ) = @_;
296 125           211 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 560 my ( $self, @value ) = @_;
312 38           52 for (@value) { $self->_warn('packet->header->qdcount is read-only') }
  2           6  
313 38     100     133 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 435 my ( $self, @value ) = @_;
331 65           92 for (@value) { $self->_warn('packet->header->ancount is read-only') }
  1           3  
332 65     100     251 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 371 my ( $self, @value ) = @_;
350 51           63 for (@value) { $self->_warn('packet->header->nscount is read-only') }
  1           3  
351 51     100     125 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 63 my ( $self, @value ) = @_;
368 51           78 for (@value) { $self->_warn('packet->header->arcount is read-only') }
  1           3  
369 51     100     167 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 316 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 114       114 1 2139 my ( $self, @value ) = @_;
391 114           261 return $self->_ednsflag( 0x8000, @value );
392               }
393                
394               sub co {
395 28       28 1 2481 my ( $self, @value ) = @_;
396 28           42 return $self->_ednsflag( 0x4000, @value );
397               }
398                
399               sub de {
400 20       20 1 25 my ( $self, @value ) = @_;
401 20           32 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 3 my ( $self, @value ) = @_;
421 1           3 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 4 my $self = shift;
440 1           2 return $$self->edns;
441               }
442                
443                
444               ########################################
445                
446               sub _dnsflag {
447 806       806   1199 my ( $self, $flag, @value ) = @_;
448 806           1435 for ( $$self->{status} ) {
449 806           1034 my $set = $_ | $flag;
450 806 100         4615 $_ = ( shift @value ) ? $set : ( $set ^ $flag ) if @value;
    100            
451 806           1137 $flag &= $_;
452               }
453 806 100         2762 return $flag ? 1 : 0;
454               }
455                
456                
457               sub _ednsflag {
458 162       162   282 my ( $self, $flag, @value ) = @_;
459 162           310 my $edns = $$self->edns;
460 162           390 for ( $edns->flags ) {
461 162           237 my $set = $_ | $flag;
462 162 100         471 $edns->flags( $_ = ( shift @value ) ? $set : ( $set ^ $flag ) ) if @value;
    100            
463 162           216 $flag &= $_;
464               }
465 162 100         341 return $flag ? 1 : 0;
466               }
467                
468                
469               my %warned;
470                
471               sub _warn {
472 5       5   11 my ( undef, @note ) = @_;
473 5 100         464 return carp "usage; @note" unless $warned{"@note"}++;
474               }
475                
476                
477               1;
478               __END__